mirror of
https://github.com/ash-project/ash_phoenix.git
synced 2024-09-19 23:02:48 +12:00
improvement: make generators more consistent
This commit is contained in:
parent
6b80d0fe50
commit
459dca3dfe
11 changed files with 201 additions and 113 deletions
|
@ -2385,9 +2385,8 @@ defmodule AshPhoenix.Form do
|
||||||
defp get_non_attribute_non_argument_param(changeset, form, field) do
|
defp get_non_attribute_non_argument_param(changeset, form, field) do
|
||||||
if Ash.Resource.Info.attribute(changeset.resource, field) ||
|
if Ash.Resource.Info.attribute(changeset.resource, field) ||
|
||||||
Enum.any?(changeset.action.arguments, &(&1.name == field)) do
|
Enum.any?(changeset.action.arguments, &(&1.name == field)) do
|
||||||
with :error <- Map.fetch(changeset.params, field),
|
with :error <- Map.fetch(changeset.params, field) do
|
||||||
:error <- Map.fetch(changeset.params, to_string(field)) do
|
Map.fetch(changeset.params, to_string(field))
|
||||||
:error
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Map.fetch(AshPhoenix.Form.params(form), Atom.to_string(field))
|
Map.fetch(AshPhoenix.Form.params(form), Atom.to_string(field))
|
||||||
|
|
79
lib/ash_phoenix/gen/gen.ex
Normal file
79
lib/ash_phoenix/gen/gen.ex
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
defmodule AshPhoenix.Gen do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
def docs do
|
||||||
|
"""
|
||||||
|
## Positional Arguments
|
||||||
|
|
||||||
|
- `api` - The API (e.g. "Shop").
|
||||||
|
- `resource` - The resource (e.g. "Product").
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- `--resource-plural` - The plural resource name (e.g. "products")
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_opts(argv) do
|
||||||
|
{api, resource, rest} =
|
||||||
|
case argv do
|
||||||
|
[api, resource | rest] ->
|
||||||
|
{api, resource, rest}
|
||||||
|
|
||||||
|
argv ->
|
||||||
|
raise "Not enough arguments. Expected 2, got #{Enum.count(argv)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if String.starts_with?(api, "-") do
|
||||||
|
raise "Expected first argument to be an api module, not an option"
|
||||||
|
end
|
||||||
|
|
||||||
|
if String.starts_with?(resource, "-") do
|
||||||
|
raise "Expected second argument to be a resource module, not an option"
|
||||||
|
end
|
||||||
|
|
||||||
|
{parsed, _, _} =
|
||||||
|
OptionParser.parse(rest,
|
||||||
|
strict: [resource_plural: :string, actor: :string, no_actor: :boolean]
|
||||||
|
)
|
||||||
|
|
||||||
|
api = Module.concat([api])
|
||||||
|
resource = Module.concat([resource])
|
||||||
|
|
||||||
|
parsed =
|
||||||
|
Keyword.put_new_lazy(rest, :resource_plural, fn ->
|
||||||
|
plural_name!(resource, parsed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
{api, resource, parsed, rest}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp plural_name!(resource, opts) do
|
||||||
|
plural_name =
|
||||||
|
opts[:resource_plural] ||
|
||||||
|
Ash.Resource.Info.plural_name(resource) ||
|
||||||
|
Mix.shell().prompt(
|
||||||
|
"""
|
||||||
|
Please provide a plural_name for #{inspect(resource)}. For example the plural of tweet is tweets.
|
||||||
|
|
||||||
|
This can also be configured on the resource. To do so, press enter to abort,
|
||||||
|
and add the following configuration to your resource (using the proper plural name)
|
||||||
|
|
||||||
|
resource do
|
||||||
|
plural_name :tweets
|
||||||
|
end
|
||||||
|
>
|
||||||
|
"""
|
||||||
|
|> String.trim()
|
||||||
|
)
|
||||||
|
|> String.trim()
|
||||||
|
|
||||||
|
case plural_name do
|
||||||
|
empty when empty in ["", nil] ->
|
||||||
|
raise("Must configure `plural_name` on resource or provide --resource-plural")
|
||||||
|
|
||||||
|
plural_name ->
|
||||||
|
to_string(plural_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,38 +2,12 @@ defmodule AshPhoenix.Gen.Live do
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
|
|
||||||
def generate_from_cli(argv) do
|
def generate_from_cli(argv) do
|
||||||
if Mix.Project.umbrella?() do
|
{api, resource, opts, _rest} = AshPhoenix.Gen.parse_opts(argv)
|
||||||
Mix.raise(
|
|
||||||
"mix phx.gen.live must be invoked from within your *_web application root directory"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
{api, resource, rest} =
|
|
||||||
case argv do
|
|
||||||
[api, resource | rest] ->
|
|
||||||
{api, resource, rest}
|
|
||||||
|
|
||||||
argv ->
|
|
||||||
raise "Not enough arguments. Expected 2, got #{Enum.count(argv)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
if String.starts_with?(api, "-") do
|
|
||||||
raise "Expected first argument to be an api module, not an option"
|
|
||||||
end
|
|
||||||
|
|
||||||
if String.starts_with?(resource, "-") do
|
|
||||||
raise "Expected second argument to be a resource module, not an option"
|
|
||||||
end
|
|
||||||
|
|
||||||
{parsed, _, _} =
|
|
||||||
OptionParser.parse(rest,
|
|
||||||
strict: [resource_plural: :string, actor: :string, no_actor: :boolean]
|
|
||||||
)
|
|
||||||
|
|
||||||
generate(
|
generate(
|
||||||
Module.concat([api]),
|
api,
|
||||||
Module.concat([resource]),
|
resource,
|
||||||
Keyword.put(parsed, :interactive?, true)
|
Keyword.put(opts, :interactive?, true)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,11 +21,11 @@ defmodule AshPhoenix.Gen.Live do
|
||||||
"Would you like to name your actor? For example: `current_user`. If you choose no, we will not add any actor logic."
|
"Would you like to name your actor? For example: `current_user`. If you choose no, we will not add any actor logic."
|
||||||
) do
|
) do
|
||||||
actor =
|
actor =
|
||||||
Mix.shell().prompt("What would you like to name it? For example: `current_user`")
|
Mix.shell().prompt("What would you like to name it? Default: `current_user`")
|
||||||
|> String.trim()
|
|> String.trim()
|
||||||
|
|
||||||
if actor == "" do
|
if actor == "" do
|
||||||
opts
|
Keyword.put(opts, :actor, "current_user")
|
||||||
else
|
else
|
||||||
Keyword.put(opts, :actor, actor)
|
Keyword.put(opts, :actor, actor)
|
||||||
end
|
end
|
||||||
|
@ -172,7 +146,7 @@ defmodule AshPhoenix.Gen.Live do
|
||||||
|> Ash.Resource.Info.short_name()
|
|> Ash.Resource.Info.short_name()
|
||||||
|> to_string()
|
|> to_string()
|
||||||
|
|
||||||
plural_name = plural_name!(resource, opts)
|
plural_name = opts[:resource_plural]
|
||||||
|
|
||||||
pkey =
|
pkey =
|
||||||
case Ash.Resource.Info.primary_key(resource) do
|
case Ash.Resource.Info.primary_key(resource) do
|
||||||
|
@ -331,33 +305,6 @@ defmodule AshPhoenix.Gen.Live do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp plural_name!(resource, opts) do
|
|
||||||
plural_name =
|
|
||||||
opts[:resource_plural] ||
|
|
||||||
Ash.Resource.Info.plural_name(resource) ||
|
|
||||||
Mix.shell().prompt(
|
|
||||||
"""
|
|
||||||
Please provide a plural_name. For example the plural of tweet is tweets.
|
|
||||||
You can press enter to abort, and then configure one on the resource, for example:
|
|
||||||
|
|
||||||
resource do
|
|
||||||
plural_name :tweets
|
|
||||||
end
|
|
||||||
>
|
|
||||||
"""
|
|
||||||
|> String.trim()
|
|
||||||
)
|
|
||||||
|> String.trim()
|
|
||||||
|
|
||||||
case plural_name do
|
|
||||||
empty when empty in ["", nil] ->
|
|
||||||
raise("Must configure `plural_name` on resource or provide --resource-plural")
|
|
||||||
|
|
||||||
plural_name ->
|
|
||||||
to_string(plural_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp web_path do
|
defp web_path do
|
||||||
web_module().module_info[:compile][:source]
|
web_module().module_info[:compile][:source]
|
||||||
|> Path.relative_to(root_path())
|
|> Path.relative_to(root_path())
|
||||||
|
|
|
@ -6,18 +6,14 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
This task renders .ex and .heex templates and copies them to specified directories.
|
This task renders .ex and .heex templates and copies them to specified directories.
|
||||||
|
|
||||||
## Arguments
|
#{AshPhoenix.Gen.docs()}
|
||||||
|
|
||||||
api The API (e.g. "Shop").
|
mix ash_phoenix.gen.html MyApp.Shop MyApp.Shop.Product --plural-name products
|
||||||
resource The resource (e.g. "Product").
|
|
||||||
plural The plural schema name (e.g. "products").
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
mix ash_phoenix.gen.html Shop Product products
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def run([]) do
|
def run([]) do
|
||||||
|
not_umbrella!()
|
||||||
|
|
||||||
Mix.shell().info("""
|
Mix.shell().info("""
|
||||||
#{Mix.Task.shortdoc(__MODULE__)}
|
#{Mix.Task.shortdoc(__MODULE__)}
|
||||||
|
|
||||||
|
@ -25,55 +21,70 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
|
||||||
""")
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(args) when length(args) == 3 do
|
def run(args) do
|
||||||
|
not_umbrella!()
|
||||||
Mix.Task.run("compile")
|
Mix.Task.run("compile")
|
||||||
|
|
||||||
[api, resource, plural] = args
|
{api, resource, opts, _} = AshPhoenix.Gen.parse_opts(args)
|
||||||
singular = String.downcase(resource)
|
|
||||||
|
singular = to_string(Ash.Resource.Info.short_name(resource))
|
||||||
|
|
||||||
opts = %{
|
opts = %{
|
||||||
api: api,
|
resource: List.last(Module.split(resource)),
|
||||||
resource: resource,
|
full_resource: resource,
|
||||||
|
full_api: api,
|
||||||
singular: singular,
|
singular: singular,
|
||||||
plural: plural
|
plural: opts[:resource_plural]
|
||||||
}
|
}
|
||||||
|
|
||||||
if Code.ensure_loaded?(resource_module(opts)) do
|
if Code.ensure_loaded?(resource) do
|
||||||
source_path = Application.app_dir(:ash_phoenix, "priv/templates/ash_phoenix.gen.html")
|
source_path = Application.app_dir(:ash_phoenix, "priv/templates/ash_phoenix.gen.html")
|
||||||
resource_html_dir = Macro.underscore(opts[:resource]) <> "_html"
|
resource_html_dir = to_string(opts[:singular]) <> "_html"
|
||||||
|
|
||||||
template_files(resource_html_dir, opts)
|
template_files(resource_html_dir, opts)
|
||||||
|> generate_files(assigns([:api, :resource, :singular, :plural], opts), source_path)
|
|> generate_files(
|
||||||
|
assigns([:api, :full_resource, :full_api, :resource, :singular, :plural], resource, opts),
|
||||||
|
source_path
|
||||||
|
)
|
||||||
|
|
||||||
print_shell_instructions(opts[:resource], opts[:plural])
|
print_shell_instructions(opts)
|
||||||
else
|
else
|
||||||
Mix.shell().info(
|
Mix.shell().info(
|
||||||
"The resource #{app_name()}.#{opts[:api]}.#{opts[:resource]} does not exist."
|
"The resource #{inspect(opts[:api])}.#{inspect(opts[:resource])} does not exist."
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assigns(keys, opts) do
|
defp not_umbrella! do
|
||||||
|
if Mix.Project.umbrella?() do
|
||||||
|
Mix.raise(
|
||||||
|
"mix phx.gen.html must be invoked from within your *_web application root directory"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assigns(keys, resource, opts) do
|
||||||
binding = Enum.map(keys, fn key -> {key, opts[key]} end)
|
binding = Enum.map(keys, fn key -> {key, opts[key]} end)
|
||||||
binding = [{:route_prefix, Macro.underscore(opts[:plural])} | binding]
|
binding = [{:route_prefix, to_string(opts[:plural])} | binding]
|
||||||
binding = [{:app_name, app_name()} | binding]
|
binding = [{:app_name, app_name()} | binding]
|
||||||
binding = [{:attributes, attributes(opts)} | binding]
|
binding = [{:attributes, attributes(resource)} | binding]
|
||||||
|
binding = [{:update_attributes, update_attributes(resource)} | binding]
|
||||||
|
binding = [{:create_attributes, create_attributes(resource)} | binding]
|
||||||
Enum.into(binding, %{})
|
Enum.into(binding, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp template_files(resource_html_dir, opts) do
|
defp template_files(resource_html_dir, opts) do
|
||||||
app_web_path = "lib/#{Macro.underscore(app_name())}_web"
|
app_web_path = "lib/#{app_name_underscore()}_web"
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"index.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/index.html.heex",
|
"index.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/index.html.heex",
|
||||||
"show.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/show.html.heex",
|
"show.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/show.html.heex",
|
||||||
"resource_form.html.heex" =>
|
"resource_form.html.heex" =>
|
||||||
"#{app_web_path}/controllers/#{resource_html_dir}/#{Macro.underscore(opts[:resource])}_form.html.heex",
|
"#{app_web_path}/controllers/#{resource_html_dir}/#{opts[:singular]}_form.html.heex",
|
||||||
"new.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/new.html.heex",
|
"new.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/new.html.heex",
|
||||||
"edit.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/edit.html.heex",
|
"edit.html.heex" => "#{app_web_path}/controllers/#{resource_html_dir}/edit.html.heex",
|
||||||
"controller.ex" =>
|
"controller.ex" => "#{app_web_path}/controllers/#{opts[:singular]}_controller.ex",
|
||||||
"#{app_web_path}/controllers/#{Macro.underscore(opts[:resource])}_controller.ex",
|
"html.ex" => "#{app_web_path}/controllers/#{opts[:singular]}_html.ex"
|
||||||
"html.ex" => "#{app_web_path}/controllers/#{Macro.underscore(opts[:resource])}_html.ex"
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -86,36 +97,63 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp app_name_underscore do
|
||||||
|
Mix.Project.config()[:app]
|
||||||
|
end
|
||||||
|
|
||||||
defp app_name do
|
defp app_name do
|
||||||
app_name_atom = Mix.Project.config()[:app]
|
app_name_atom = Mix.Project.config()[:app]
|
||||||
Macro.camelize(Atom.to_string(app_name_atom))
|
Macro.camelize(Atom.to_string(app_name_atom))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp print_shell_instructions(resource, plural) do
|
defp print_shell_instructions(opts) do
|
||||||
Mix.shell().info("""
|
Mix.shell().info("""
|
||||||
|
|
||||||
Add the resource to your browser scope in lib/#{Macro.underscore(resource)}_web/router.ex:
|
Add the resource to your browser scope in lib/#{opts[:singular]}_web/router.ex:
|
||||||
|
|
||||||
resources "/#{plural}", #{resource}Controller
|
resources "/#{opts[:plural]}", #{opts[:resource]}Controller
|
||||||
""")
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp resource_module(opts) do
|
defp attributes(resource) do
|
||||||
Module.concat(["#{app_name()}.#{opts[:api]}.#{opts[:resource]}"])
|
resource
|
||||||
|
|> Ash.Resource.Info.public_attributes()
|
||||||
|
|> Enum.reject(&(&1.type == Ash.Type.UUID))
|
||||||
|
|> Enum.map(&attribute_map/1)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp attributes(opts) do
|
defp create_attributes(resource) do
|
||||||
resource_module(opts)
|
create_action = Ash.Resource.Info.primary_action!(resource, :create)
|
||||||
|> Ash.Resource.Info.attributes()
|
|
||||||
|
attrs =
|
||||||
|
create_action.accept
|
||||||
|
|> Enum.map(&Ash.Resource.Info.attribute(resource, &1))
|
||||||
|
|> Enum.filter(& &1.writable?)
|
||||||
|
|
||||||
|
create_action.arguments
|
||||||
|
|> Enum.concat(attrs)
|
||||||
|
|> Enum.map(&attribute_map/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_attributes(resource) do
|
||||||
|
update_action = Ash.Resource.Info.primary_action!(resource, :update)
|
||||||
|
|
||||||
|
attrs =
|
||||||
|
update_action.accept
|
||||||
|
|> Enum.map(&Ash.Resource.Info.attribute(resource, &1))
|
||||||
|
|> Enum.filter(& &1.writable?)
|
||||||
|
|
||||||
|
update_action.arguments
|
||||||
|
|> Enum.concat(attrs)
|
||||||
|> Enum.map(&attribute_map/1)
|
|> Enum.map(&attribute_map/1)
|
||||||
|> Enum.reject(&reject_attribute?/1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp attribute_map(attr) do
|
defp attribute_map(attr) do
|
||||||
%{name: attr.name, type: attr.type, writable?: attr.writable?, private?: attr.private?}
|
%{
|
||||||
|
name: attr.name,
|
||||||
|
type: attr.type,
|
||||||
|
writable?: Map.get(attr, :writable?, true),
|
||||||
|
private?: attr.private?
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp reject_attribute?(%{name: :id, type: Ash.Type.UUID}), do: true
|
|
||||||
defp reject_attribute?(%{private?: true}), do: true
|
|
||||||
defp reject_attribute?(_), do: false
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,8 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Live do
|
||||||
|
|
||||||
The api and resource must already exist, this task does not define them.
|
The api and resource must already exist, this task does not define them.
|
||||||
|
|
||||||
|
#{AshPhoenix.Gen.docs()}
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -15,6 +17,13 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Live do
|
||||||
@shortdoc "Generates liveviews for a resource"
|
@shortdoc "Generates liveviews for a resource"
|
||||||
def run(argv) do
|
def run(argv) do
|
||||||
Mix.Task.run("compile")
|
Mix.Task.run("compile")
|
||||||
|
|
||||||
|
if Mix.Project.umbrella?() do
|
||||||
|
Mix.raise(
|
||||||
|
"mix phx.gen.live must be invoked from within your *_web application root directory"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
AshPhoenix.Gen.Live.generate_from_cli(argv)
|
AshPhoenix.Gen.Live.generate_from_cli(argv)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
4
mix.exs
4
mix.exs
|
@ -124,6 +124,10 @@ defmodule AshPhoenix.MixProject do
|
||||||
AshPhoenix.LiveView,
|
AshPhoenix.LiveView,
|
||||||
AshPhoenix.SubdomainPlug
|
AshPhoenix.SubdomainPlug
|
||||||
],
|
],
|
||||||
|
Generators: [
|
||||||
|
Mix.Tasks.AshPhoenix.Gen.Html,
|
||||||
|
Mix.Tasks.AshPhoenix.Gen.Live
|
||||||
|
],
|
||||||
Forms: [
|
Forms: [
|
||||||
AshPhoenix.Form,
|
AshPhoenix.Form,
|
||||||
AshPhoenix.Form.Auto,
|
AshPhoenix.Form.Auto,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule <%= @app_name %>Web.<%= @resource %>Controller do
|
defmodule <%= @app_name %>Web.<%= @resource %>Controller do
|
||||||
use <%= @app_name %>Web, :controller
|
use <%= @app_name %>Web, :controller
|
||||||
|
|
||||||
alias <%= @app_name %>.<%= @api %>.<%= @resource %>
|
alias <%= inspect @full_resource %>
|
||||||
|
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
<%= @plural %> = <%= @resource %>.read!()
|
<%= @plural %> = <%= @resource %>.read!()
|
||||||
|
@ -69,10 +69,10 @@ defmodule <%= @app_name %>Web.<%= @resource %>Controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp create_form(params \\ nil) do
|
defp create_form(params \\ nil) do
|
||||||
AshPhoenix.Form.for_create(<%= @resource %>, :create, as: "<%= @singular %>", api: <%= @app_name %>.<%= @api %>, params: params)
|
AshPhoenix.Form.for_create(<%= @resource %>, :create, as: "<%= @singular %>", api: <%= @full_api %>, params: params)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp update_form(<%= @singular %>, params \\ nil) do
|
defp update_form(<%= @singular %>, params \\ nil) do
|
||||||
AshPhoenix.Form.for_update(<%= @singular %>, :update, as: "<%= @singular %>", api: <%= @app_name %>.<%= @api %>, params: params)
|
AshPhoenix.Form.for_update(<%= @singular %>, :update, as: "<%= @singular %>", api: <%= @full_api %>, params: params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<.table id="<%= @plural %>" rows={@<%= @plural %>} row_click={&JS.navigate(~p"/<%= @route_prefix %>/#{&1}")}>
|
<.table id="<%= @plural %>" rows={@<%= @plural %>} row_click={&JS.navigate(~p"/<%= @route_prefix %>/#{&1}")}>
|
||||||
<%= for attribute <- @attributes do %>
|
<%= for attribute <- @attributes do %>
|
||||||
<:col :let={<%= @singular %>} label="<%= attribute.name %>"><%%= <%= @singular %>.<%= attribute.name %> %></:col>
|
<:col :let={<%= @singular %>} label="<%= Phoenix.Naming.humanize(attribute.name) %>"><%%= <%= @singular %>.<%= attribute.name %> %></:col>
|
||||||
<% end %>
|
<% end %>
|
||||||
<:action :let={<%= @singular %>}>
|
<:action :let={<%= @singular %>}>
|
||||||
<div class="sr-only">
|
<div class="sr-only">
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
|
|
||||||
<.<%= @singular %>_form form={@form} action={~p"/<%= @plural %>/"} />
|
<.<%= @singular %>_form form={@form} action={~p"/<%= @plural %>/"} />
|
||||||
|
|
||||||
<.back navigate={~p"/products"}>Back to <%= @plural %></.back>
|
<.back navigate={~p"/<%= @plural %>"}>Back to <%= @plural %></.back>
|
||||||
|
|
|
@ -2,13 +2,25 @@
|
||||||
<.error :if={@form.submitted_once?}>
|
<.error :if={@form.submitted_once?}>
|
||||||
Oops, something went wrong! Please check the errors below.
|
Oops, something went wrong! Please check the errors below.
|
||||||
</.error>
|
</.error>
|
||||||
<%= for attribute <- @attributes do %>
|
<%%= if @form.type == :update do %>
|
||||||
|
<%= for attribute <- @update_attributes do %>
|
||||||
<%= if attribute.type in [Ash.Type.Integer] do %>
|
<%= if attribute.type in [Ash.Type.Integer] do %>
|
||||||
<.input field={f[:<%= attribute.name %>]} type="number" label="<%= attribute.name %>" />
|
<.input field={f[:<%= attribute.name %>]} type="number" label="<%= Phoenix.Naming.humanize(attribute.name) %>" />
|
||||||
<% else %>
|
<% else %>
|
||||||
<.input field={f[:<%= attribute.name %>]} type="text" label="<%= attribute.name %>" />
|
<.input field={f[:<%= attribute.name %>]} type="text" label="<%= Phoenix.Naming.hunamize(attribute.name) %>" />
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<%% end %>
|
||||||
|
|
||||||
|
<%%= if @form.type == :create do %>
|
||||||
|
<%= for attribute <- @update_attributes do %>
|
||||||
|
<%= if attribute.type in [Ash.Type.Integer] do %>
|
||||||
|
<.input field={f[:<%= attribute.name %>]} type="number" label="<%= Phoenix.Naming.humanize(attribute.name) %>" />
|
||||||
|
<% else %>
|
||||||
|
<.input field={f[:<%= attribute.name %>]} type="text" label="<%= Phoenix.Naming.humanize(attribute.name) %>" />
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<%% end %>
|
||||||
<:actions>
|
<:actions>
|
||||||
<.button>Save Product</.button>
|
<.button>Save Product</.button>
|
||||||
</:actions>
|
</:actions>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<.list>
|
<.list>
|
||||||
<%= for attribute <- @attributes do %>
|
<%= for attribute <- @attributes do %>
|
||||||
<:item title="<%= attribute.name %>"><%%= @<%= @singular %>.<%= attribute.name %> %></:item>
|
<:item title="<%= Phoenix.Naming.hunamize(attribute.name) %>"><%%= @<%= @singular %>.<%= attribute.name %> %></:item>
|
||||||
<% end %>
|
<% end %>
|
||||||
</.list>
|
</.list>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue