Packages
ash_phoenix
1.2.21
2.3.24
2.3.23
2.3.22
2.3.21
2.3.20
2.3.19
2.3.18
2.3.17
2.3.16
2.3.15
2.3.14
2.3.13
2.3.12
2.3.11
2.3.10
2.3.9
2.3.8
2.3.7
2.3.6
2.3.5
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.0
2.1.26
2.1.25
2.1.24
2.1.23
2.1.22
2.1.21
2.1.20
2.1.19
2.1.18
2.1.17
2.1.16
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.8
2.0.0-rc.7
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.26
1.2.25
1.2.24
1.2.23
1.2.22
1.2.21
1.2.20
1.2.19
1.2.18
1.2.17
1.2.16
1.2.15
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.1.0-rc.3
1.1.0-rc.2
1.1.0-rc.1
1.1.0-rc.0
1.0.0-rc.1
1.0.0-rc.0
1.0.0-pre.2
1.0.0-pre.1
1.0.0-pre.0
0.7.7
0.7.6-rc.0
0.7.5
0.7.4
0.7.3
0.7.2-rc.2
0.7.2-rc.1
0.7.2-rc.0
0.7.1
0.7.0
0.6.0-rc.7
0.6.0-rc.6
0.6.0-rc.5
0.6.0-rc.4
0.6.0-rc.3
0.6.0-rc.2
0.6.0-rc.1
0.6.0-rc.0
0.5.19-rc.2
0.5.19-rc.1
0.5.19-rc.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.24
0.4.23
0.4.23-rc.1
0.4.23-rc.0
0.4.22-rc2
0.4.22-rc1
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Utilities for integrating Ash and Phoenix
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/ash_phoenix.gen.html.ex
defmodule Mix.Tasks.AshPhoenix.Gen.Html do
use Mix.Task
@shortdoc "Generates a controller and HTML views for an existing Ash resource."
@moduledoc """
This task renders .ex and .heex templates and copies them to specified directories.
## Arguments
api The API (e.g. "Shop").
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
Mix.shell().info("""
#{Mix.Task.shortdoc(__MODULE__)}
#{Mix.Task.moduledoc(__MODULE__)}
""")
end
def run(args) when length(args) == 3 do
Mix.Task.run("compile")
[api, resource, plural] = args
singular = String.downcase(resource)
opts = %{
api: api,
resource: resource,
singular: singular,
plural: plural
}
if Code.ensure_loaded?(resource_module(opts)) do
source_path = Application.app_dir(:ash_phoenix, "priv/templates/ash_phoenix.gen.html")
resource_html_dir = Macro.underscore(opts[:resource]) <> "_html"
template_files(resource_html_dir, opts)
|> generate_files(assigns([:api, :resource, :singular, :plural], opts), source_path)
print_shell_instructions(opts[:resource], opts[:plural])
else
Mix.shell().info(
"The resource #{app_name()}.#{opts[:api]}.#{opts[:resource]} does not exist."
)
end
end
defp assigns(keys, opts) do
binding = Enum.map(keys, fn key -> {key, opts[key]} end)
binding = [{:route_prefix, Macro.underscore(opts[:plural])} | binding]
binding = [{:app_name, app_name()} | binding]
binding = [{:attributes, attributes(opts)} | binding]
Enum.into(binding, %{})
end
defp template_files(resource_html_dir, opts) do
app_web_path = "lib/#{Macro.underscore(app_name())}_web"
%{
"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",
"resource_form.html.heex" =>
"#{app_web_path}/controllers/#{resource_html_dir}/#{Macro.underscore(opts[:resource])}_form.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",
"controller.ex" =>
"#{app_web_path}/controllers/#{Macro.underscore(opts[:resource])}_controller.ex",
"html.ex" => "#{app_web_path}/controllers/#{Macro.underscore(opts[:resource])}_html.ex"
}
end
defp generate_files(template_files, assigns, source_path) do
Enum.each(template_files, fn {source_file, dest_file} ->
Mix.Generator.create_file(
dest_file,
EEx.eval_file("#{source_path}/#{source_file}", assigns: assigns)
)
end)
end
defp app_name do
app_name_atom = Mix.Project.config()[:app]
Macro.camelize(Atom.to_string(app_name_atom))
end
defp print_shell_instructions(resource, plural) do
Mix.shell().info("""
Add the resource to your browser scope in lib/#{Macro.underscore(resource)}_web/router.ex:
resources "/#{plural}", #{resource}Controller
""")
end
defp resource_module(opts) do
Module.concat(["#{app_name()}.#{opts[:api]}.#{opts[:resource]}"])
end
defp attributes(opts) do
resource_module(opts)
|> Ash.Resource.Info.attributes()
|> Enum.map(&attribute_map/1)
|> Enum.reject(&reject_attribute?/1)
end
defp attribute_map(attr) do
%{name: attr.name, type: attr.type, writable?: attr.writable?, private?: attr.private?}
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