diff --git a/CHANGELOG.md b/CHANGELOG.md index f23ed566..2fbd41a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ## 0.1.0-dev +### Breaking Changes + * Require minimum Gettext v0.26 to use the new backend module + * Default `:sort` option value in `Content.list_pages/2` changed from `:title` to `:path` + +### Fixes + * [Media Library] Guard against invalid values for `:sort` option in `MediaLibrary.list_assets/2` + * [Content] Guard against invalid values for `:sort` option in `Content.list_layouts/2` + * [Content] Guard against invalid values for `:sort` option in `Content.list_pages/2` + * [HEEx Decoder] Handle attr values with `nil` values, for example the `defer` in script tags + ## 0.1.0-rc.1 (2024-08-27) ### Enhancements @@ -11,10 +21,12 @@ event handler in all pages. ### Breaking Changes - * Remove Page Event Handlers in favor of Shared Event Handlers. + * Removed Page Event Handlers in favor of Shared Event Handlers. With Shared Event Handlers, it doesn't make sense to have page event handlers unless overriding becomes a neccessity. The data is automatically migrated in a best-effort way, duplicated event handler names (from multiple pages) are consolidated into a single shared event handler. See the migration `V002` for more info. + * Removed "page event handlers" in `Content` API in favor of "event handlers" (removed the prefix `page`), + for example: `update_event_handler_for_page -> create_event_handler` and `change_page_event_handler -> change_event_handler`. ## Fixes * Display parsed page title on live renders diff --git a/guides/introduction/your-first-site.md b/guides/introduction/your-first-site.md index 936525e0..0cc43cba 100644 --- a/guides/introduction/your-first-site.md +++ b/guides/introduction/your-first-site.md @@ -96,7 +96,7 @@ mix phx.server Visit http://localhost:4000 to see the default home page created by Beacon. -## Acessing LiveAdmin to manage your site +## Accessing LiveAdmin to manage your site Let's customize the home page. Visit http://localhost:4000/admin and you should see the `my_site` that you just created listed on the admin interface. @@ -104,7 +104,7 @@ Now let's create the resources for our first site, and we'll starting by creatin ## Live Data -We want to display the current yeat at the footer of the home page as the assign `<%= @current_year %>`. In Beacon we use Live Data to create and modify assigns at runtime, let's do it. +We want to display the current year at the footer of the home page as the assign `<%= @current_year %>`. In Beacon we use Live Data to create and modify assigns at runtime, let's do it. Go to http://localhost:4000/admin/my_site/live_data to create a new path `/` and then create a new assign named `current_year` using the `elixir` format with the following value: diff --git a/lib/beacon/content.ex b/lib/beacon/content.ex index 019f4c98..ab9699dc 100644 --- a/lib/beacon/content.ex +++ b/lib/beacon/content.ex @@ -327,6 +327,7 @@ defmodule Beacon.Content do * `:query` - search layouts by title. Defaults to `nil`, doesn't filter query. * `:preloads` - a list of preloads to load. * `:sort` - column in which the result will be ordered by. Defaults to `:title`. + Allowed values: `:title`, `:template`, `:meta_tags`, `:resource_links`, `:inserted_at`, `:updated_at`. """ @doc type: :layouts @@ -336,7 +337,8 @@ defmodule Beacon.Content do page = Keyword.get(opts, :page, 1) search = Keyword.get(opts, :query) preloads = Keyword.get(opts, :preloads, []) - sort = Keyword.get(opts, :sort, :title) + sort = Keyword.get(opts, :sort) + sort = if sort in [:title, :template, :meta_tags, :resource_links, :inserted_at, :updated_at], do: sort, else: :title site |> query_list_layouts_base() @@ -835,7 +837,8 @@ defmodule Beacon.Content do * `:page` - returns records from a specfic page. Defaults to 1. * `:query` - search pages by path or title. * `:preloads` - a list of preloads to load. - * `:sort` - column in which the result will be ordered by. Defaults to `:title`. + * `:sort` - column in which the result will be ordered by. Defaults to `:path`. + Allowed values: `:path`, `:title`, `:description`, `:template`, `:meta_tags`, `:raw_schema`, `:format`, `:inserted_at`, `:updated_at`. """ @doc type: :pages @@ -845,7 +848,8 @@ defmodule Beacon.Content do page = Keyword.get(opts, :page, 1) search = Keyword.get(opts, :query) preloads = Keyword.get(opts, :preloads, []) - sort = Keyword.get(opts, :sort, :title) + sort = Keyword.get(opts, :sort) + sort = if sort in [:path, :title, :description, :template, :meta_tags, :raw_schema, :format, :inserted_at, :updated_at], do: sort, else: :path site |> query_list_pages_base() diff --git a/lib/beacon/gettext.ex b/lib/beacon/gettext.ex new file mode 100644 index 00000000..ba3c0b1e --- /dev/null +++ b/lib/beacon/gettext.ex @@ -0,0 +1,4 @@ +defmodule Beacon.Gettext do + @moduledoc false + use Gettext.Backend, otp_app: :beacon +end diff --git a/lib/beacon/media_library.ex b/lib/beacon/media_library.ex index 9cd451f8..d3e2c42e 100644 --- a/lib/beacon/media_library.ex +++ b/lib/beacon/media_library.ex @@ -238,6 +238,7 @@ defmodule Beacon.MediaLibrary do * `:query` - search assets by file name. Defaults to `nil`, doesn't filter query. * `:preloads` - a list of preloads to load. Defaults to `[:thumbnail]`. * `:sort` - column in which the result will be ordered by. Defaults to `:file_name`. + Allowed values: `:file_name`, `:media_type`, `:inserted_at`, `:updated_at`. """ @doc type: :assets @@ -247,7 +248,8 @@ defmodule Beacon.MediaLibrary do page = Keyword.get(opts, :page, 1) search = Keyword.get(opts, :query) preloads = Keyword.get(opts, :preloads, [:thumbnail]) - sort = Keyword.get(opts, :sort, :file_name) + sort = Keyword.get(opts, :sort) + sort = if sort in [:file_name, :media_type, :inserted_at, :updated_at], do: sort, else: :file_name site |> query_list_assets_base() diff --git a/lib/beacon/template/heex/heex_decoder.ex b/lib/beacon/template/heex/heex_decoder.ex index 14843e6e..82bc864c 100644 --- a/lib/beacon/template/heex/heex_decoder.ex +++ b/lib/beacon/template/heex/heex_decoder.ex @@ -126,6 +126,10 @@ defmodule Beacon.Template.HEEx.HEExDecoder do [name, "=", ?{, content, ?}] end + defp reconstruct_attr({name, _, _}) do + [name] + end + defp decode_eex_block(ast) do %{"type" => "eex_block", "content" => content, "children" => children} = Jason.decode!(ast) diff --git a/lib/beacon/web/components/core_components.ex b/lib/beacon/web/components/core_components.ex index 240e4755..ca1be3bd 100644 --- a/lib/beacon/web/components/core_components.ex +++ b/lib/beacon/web/components/core_components.ex @@ -6,7 +6,7 @@ defmodule Beacon.Web.CoreComponents do use Phoenix.Component alias Phoenix.LiveView.JS - import Beacon.Web.Gettext + use Gettext, backend: Beacon.Gettext @doc """ Renders a modal. @@ -629,9 +629,9 @@ defmodule Beacon.Web.CoreComponents do # with our gettext backend as first argument. Translations are # available in the errors.po file (as we use the "errors" domain). if count = opts[:count] do - Gettext.dngettext(Beacon.Web.Gettext, "errors", msg, msg, count, opts) + Gettext.dngettext(Beacon.Gettext, "errors", msg, msg, count, opts) else - Gettext.dgettext(Beacon.Web.Gettext, "errors", msg, opts) + Gettext.dgettext(Beacon.Gettext, "errors", msg, opts) end end diff --git a/lib/beacon/web/gettext.ex b/lib/beacon/web/gettext.ex deleted file mode 100644 index b6ef32a5..00000000 --- a/lib/beacon/web/gettext.ex +++ /dev/null @@ -1,4 +0,0 @@ -defmodule Beacon.Web.Gettext do - @moduledoc false - use Gettext, otp_app: :beacon -end diff --git a/lib/beacon_web.ex b/lib/beacon_web.ex index bcc31986..3c274380 100644 --- a/lib/beacon_web.ex +++ b/lib/beacon_web.ex @@ -46,7 +46,7 @@ defmodule Beacon.Web do layouts: [html: Beacon.Web.Layouts] import Plug.Conn - import Beacon.Web.Gettext + use Gettext, backend: Beacon.Gettext end end diff --git a/mix.exs b/mix.exs index b1ec47bd..15d735a4 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Beacon.MixProject do use Mix.Project - @version "0.1.0-rc.1" + @version "0.1.0-dev" @source_url "https://github.com/BeaconCMS/beacon" @homepage_url "https://beaconcms.org" @@ -65,7 +65,7 @@ defmodule Beacon.MixProject do {:ex_aws, "~> 2.4.0"}, {:ex_aws_s3, "~> 2.4.0"}, {:floki, ">= 0.30.0"}, - {:gettext, "~> 0.20"}, + {:gettext, "~> 0.26"}, {:hackney, "~> 1.16"}, {:image, "~> 0.40"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index f1342af3..574e0f16 100644 --- a/mix.lock +++ b/mix.lock @@ -21,8 +21,10 @@ "ex_brotli": {:hex, :ex_brotli, "0.4.1", "b9d43d1ba0641b460b8477b1dc20f224827651c5af5977419b92c4e63c27d619", [:mix], [{:phoenix, ">= 0.0.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:rustler, "~> 0.29", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "840eeace8354abfa470fa094b8b0231ef184f5692cd4b219143c403bcf8f0756"}, "ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"}, "exconstructor": {:hex, :exconstructor, "1.2.13", "7021eed1450202dcbcd1ef021d6aacf7351854ff9d7964f166931567f9dfa9fb", [:mix], [], "hexpm", "69d3f0251a07bb7c5ef85bde22a1eee577dfbb49852d77fb7ad7b937035aeef2"}, + "expo": {:hex, :expo, "1.0.1", "f9e2f984f5b8d195815d52d0ba264798c12c8d2f2606f76fa4c60e8ebe39474d", [:mix], [], "hexpm", "f250b33274e3e56513644858c116f255d35c767c2b8e96a512fe7839ef9306a1"}, "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, + "gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, diff --git a/test/beacon/template/heex/heex_decoder_test.exs b/test/beacon/template/heex/heex_decoder_test.exs index 73feaad1..060a4590 100644 --- a/test/beacon/template/heex/heex_decoder_test.exs +++ b/test/beacon/template/heex/heex_decoder_test.exs @@ -162,4 +162,11 @@ defmodule Beacon.Template.HEEx.HEExDecoderTest do test "live data assigns" do assert_equal(~S|<%= @name %>|, %{name: "Beacon"}) end + + test "script tag" do + assert_equal(~S""" + + """) + end end