Current section
9 Versions
Jump to
Current section
9 Versions
Compare versions
7
files changed
+108
additions
-79
deletions
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/oscar345/phutilx">>}]}. |
| 2 2 | {<<"name">>,<<"phutilx">>}. |
| 3 | - {<<"version">>,<<"0.1.0">>}. |
| 3 | + {<<"version">>,<<"0.1.1">>}. |
| 4 4 | {<<"description">>, |
| 5 5 | <<"A collection of utilities and helpers for Phoenix and Elixir projects.">>}. |
| 6 6 | {<<"elixir">>,<<"~> 1.18">>}. |
| @@ -30,6 +30,6 @@ | |
| 30 30 | {<<"files">>, |
| 31 31 | [<<"lib">>,<<"lib/database">>,<<"lib/database/paginate.ex">>, |
| 32 32 | <<"lib/phutilx.ex">>,<<"lib/inertia">>,<<"lib/inertia/controller.ex">>, |
| 33 | - <<"lib/inertia/form.ex">>,<<"lib/json.ex">>,<<".formatter.exs">>, |
| 33 | + <<"lib/inertia/errors.ex">>,<<"lib/json.ex">>,<<".formatter.exs">>, |
| 34 34 | <<"mix.exs">>,<<"README.md">>]}. |
| 35 35 | {<<"build_tools">>,[<<"mix">>]}. |
| @@ -1,15 +1,30 @@ | |
| 1 1 | defmodule Phutilx.Inertia.Controller do |
| 2 2 | alias Plug.Conn |
| 3 3 | |
| 4 | + @doc """ |
| 5 | + Assign a title to both the normal assigns from plug and to the inertia prop assigns so the title |
| 6 | + can be used on the server and on the client. |
| 7 | + """ |
| 4 8 | def assign_title(conn, title) do |
| 5 9 | conn |
| 6 10 | |> Conn.assign(:page_title, title) |
| 7 11 | |> Inertia.Controller.assign_prop(:page_title, title) |
| 8 12 | end |
| 9 13 | |
| 10 | - def assign_meta(conn, map) do |
| 14 | + @doc """ |
| 15 | + Assign metadata to both the normal assigns from plug and to the inertia prop assigns so the metadata |
| 16 | + can be used on the server and on the client. |
| 17 | + |
| 18 | + The maps parameter should be a list containing maps with the keys `:name` and `:content`. |
| 19 | + |
| 20 | + ## Examples |
| 21 | + |
| 22 | + iex> assign_meta(conn, [%{name: "description", content: "A description of the page"}, %{name: "keywords", content: "elixir, phoenix, inertia"}]) |
| 23 | + %Plug.Conn{...} |
| 24 | + """ |
| 25 | + def assign_meta(conn, maps) do |
| 11 26 | conn |
| 12 | - |> Conn.assign(:meta, map) |
| 13 | - |> Inertia.Controller.assign_prop(:meta, map) |
| 27 | + |> Conn.assign(:meta, maps) |
| 28 | + |> Inertia.Controller.assign_prop(:meta, maps) |
| 14 29 | end |
| 15 30 | end |
| @@ -0,0 +1,84 @@ | |
| 1 | + defmodule Phutilx.Inertia.Errors do |
| 2 | + @moduledoc """ |
| 3 | + A module to help with sending validation errors to the client when using Inertia.js. You can prepend keys |
| 4 | + to the errors when you have all your data underneath a key on the client. For example when you have a form |
| 5 | + for a user, you might want to have all the fields and errors under the `user` key. |
| 6 | + |
| 7 | + It also makes the experience for returning errors from maps equivalent to returning errors from changesets. So |
| 8 | + those errors are also flattened and can be prefixed with a key. |
| 9 | + |
| 10 | + In order to translate the error messages, you need to set the `:gettext_module` configuration option in your |
| 11 | + `config/config.exs` file. For example: `config :phutilx, :gettext_module, MyAppWeb.Gettext`. |
| 12 | + """ |
| 13 | + |
| 14 | + defstruct key: nil, changeset: nil, map: nil |
| 15 | + |
| 16 | + @type t :: %__MODULE__{ |
| 17 | + key: atom() | nil, |
| 18 | + changeset: Ecto.Changeset.t() | nil, |
| 19 | + map: map() | nil |
| 20 | + } |
| 21 | + |
| 22 | + def from_changeset(%Ecto.Changeset{} = changeset, key \\ nil) do |
| 23 | + %__MODULE__{key: key, changeset: changeset} |
| 24 | + end |
| 25 | + |
| 26 | + def from_map(map, key \\ nil) when is_map(map) do |
| 27 | + %__MODULE__{key: key, map: map} |
| 28 | + end |
| 29 | + |
| 30 | + defimpl Inertia.Errors do |
| 31 | + alias Ecto.Changeset |
| 32 | + |
| 33 | + @gettext_module Application.compile_env(:phutilx, :gettext_module) |
| 34 | + |
| 35 | + def to_errors(%Phutilx.Inertia.Errors{changeset: %Changeset{} = changeset} = value, fun) do |
| 36 | + errors = |
| 37 | + if fun != nil do |
| 38 | + Inertia.Errors.to_errors(changeset, fun) |
| 39 | + else |
| 40 | + Inertia.Errors.to_errors(changeset) |
| 41 | + end |
| 42 | + |
| 43 | + if value.key == nil do |
| 44 | + errors |
| 45 | + else |
| 46 | + # Prefix the keys with the form's key |
| 47 | + errors |> Enum.map(fn {k, v} -> {"#{value.key}.#{k}", v} end) |> Map.new() |
| 48 | + end |
| 49 | + end |
| 50 | + |
| 51 | + def to_errors(%Phutilx.Inertia.Errors{changeset: %Changeset{}} = value) do |
| 52 | + to_errors(value, fn {msg, opts} -> |
| 53 | + if count = opts[:count] do |
| 54 | + Gettext.dngettext(@gettext_module, "errors", msg, msg, count, opts) |
| 55 | + else |
| 56 | + Gettext.dgettext(@gettext_module, "errors", msg, opts) |
| 57 | + end |
| 58 | + end) |
| 59 | + end |
| 60 | + |
| 61 | + def to_errors(%Phutilx.Inertia.Errors{map: %{} = map} = value) do |
| 62 | + errors = flatten_map(map) |
| 63 | + |
| 64 | + if value.key == nil do |
| 65 | + errors |
| 66 | + else |
| 67 | + # Prefix the keys with the form's key |
| 68 | + errors |> Enum.map(fn {k, v} -> {"#{value.key}.#{k}", v} end) |> Map.new() |
| 69 | + end |
| 70 | + end |
| 71 | + |
| 72 | + defp flatten_map(map, parent_key \\ nil, acc \\ %{}) do |
| 73 | + Enum.reduce(map, acc, fn {k, v}, acc -> |
| 74 | + key = if parent_key, do: "#{parent_key}.#{k}", else: to_string(k) |
| 75 | + |
| 76 | + if is_map(v) do |
| 77 | + flatten_map(v, key, acc) |
| 78 | + else |
| 79 | + Map.put(acc, key, v) |
| 80 | + end |
| 81 | + end) |
| 82 | + end |
| 83 | + end |
| 84 | + end |
| @@ -1,72 +0,0 @@ | |
| 1 | - defmodule Phutilx.Inertia.Form do |
| 2 | - defstruct key: nil, changeset: nil, map: nil |
| 3 | - |
| 4 | - @type t :: %__MODULE__{ |
| 5 | - key: atom() | nil, |
| 6 | - changeset: Ecto.Changeset.t() | nil, |
| 7 | - map: map() | nil |
| 8 | - } |
| 9 | - |
| 10 | - def from_changeset(%Ecto.Changeset{} = changeset, key \\ nil) do |
| 11 | - %__MODULE__{key: key, changeset: changeset} |
| 12 | - end |
| 13 | - |
| 14 | - def from_map(map, key \\ nil) when is_map(map) do |
| 15 | - %__MODULE__{key: key, map: map} |
| 16 | - end |
| 17 | - |
| 18 | - defimpl Inertia.Errors do |
| 19 | - alias Ecto.Changeset |
| 20 | - |
| 21 | - @gettext_module Application.compile_env(:phutilx, :gettext_module) |
| 22 | - |
| 23 | - def to_errors(%Phutilx.Inertia.Form{changeset: %Changeset{} = changeset} = value, fun) do |
| 24 | - errors = |
| 25 | - if fun != nil do |
| 26 | - Inertia.Errors.to_errors(changeset, fun) |
| 27 | - else |
| 28 | - Inertia.Errors.to_errors(changeset) |
| 29 | - end |
| 30 | - |
| 31 | - if value.key == nil do |
| 32 | - errors |
| 33 | - else |
| 34 | - # Prefix the keys with the form's key |
| 35 | - errors |> Enum.map(fn {k, v} -> {"#{value.key}.#{k}", v} end) |> Map.new() |
| 36 | - end |
| 37 | - end |
| 38 | - |
| 39 | - def to_errors(%Phutilx.Inertia.Form{changeset: %Changeset{}} = value) do |
| 40 | - to_errors(value, fn {msg, opts} -> |
| 41 | - if count = opts[:count] do |
| 42 | - Gettext.dngettext(@gettext_module, "errors", msg, msg, count, opts) |
| 43 | - else |
| 44 | - Gettext.dgettext(@gettext_module, "errors", msg, opts) |
| 45 | - end |
| 46 | - end) |
| 47 | - end |
| 48 | - |
| 49 | - def to_errors(%Phutilx.Inertia.Form{map: %{} = map} = value) do |
| 50 | - errors = flatten_map(map) |
| 51 | - |
| 52 | - if value.key == nil do |
| 53 | - errors |
| 54 | - else |
| 55 | - # Prefix the keys with the form's key |
| 56 | - errors |> Enum.map(fn {k, v} -> {"#{value.key}.#{k}", v} end) |> Map.new() |
| 57 | - end |
| 58 | - end |
| 59 | - |
| 60 | - defp flatten_map(map, parent_key \\ nil, acc \\ %{}) do |
| 61 | - Enum.reduce(map, acc, fn {k, v}, acc -> |
| 62 | - key = if parent_key, do: "#{parent_key}.#{k}", else: to_string(k) |
| 63 | - |
| 64 | - if is_map(v) do |
| 65 | - flatten_map(v, key, acc) |
| 66 | - else |
| 67 | - Map.put(acc, key, v) |
| 68 | - end |
| 69 | - end) |
| 70 | - end |
| 71 | - end |
| 72 | - end |
| @@ -10,7 +10,6 @@ defmodule Phutilx.JSON do | |
| 10 10 | * `:except` - A list of fields to exclude from the JSON output. This option is ignored if `:only` |
| 11 11 | is provided. `:__struct__` and `:__meta__` are always excluded. |
| 12 12 | """ |
| 13 | - |
| 14 13 | defmacro encoder(opts \\ []) do |
| 15 14 | quote do |
| 16 15 | defimpl JSON.Encoder do |
Loading more files…