From 2f402c45e0b499454397b17c01be443c90b345cd Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Thu, 24 Oct 2024 16:33:01 +0300 Subject: [PATCH 01/12] feat: adding igniter dep --- mix.exs | 4 +++- mix.lock | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 9717667..087aeb0 100644 --- a/mix.exs +++ b/mix.exs @@ -140,7 +140,9 @@ defmodule AshPhoenix.MixProject do {:dialyxir, ">= 0.0.0", only: [:dev, :test], runtime: false}, {:sobelow, ">= 0.0.0", only: [:dev, :test], runtime: false}, {:mix_audit, ">= 0.0.0", only: [:dev, :test], runtime: false}, - {:mix_test_watch, "~> 1.0", only: [:dev, :test]} + {:mix_test_watch, "~> 1.0", only: [:dev, :test]}, + # Code Generators + {:igniter, "~> 0.3 and >= 0.3.74"} ] end diff --git a/mix.lock b/mix.lock index 9ca519b..a773006 100644 --- a/mix.lock +++ b/mix.lock @@ -14,8 +14,8 @@ "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, - "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.63", "ac27c466e6f779cf5f39d200a7d433cd91c8d465277e001661dc9b4680ca9eb3", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "5e24f71479cfd3575f79a767db51de0b38a633f05107b05d94ef1a54fde9093f"}, + "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, + "igniter": {:hex, :igniter, "0.3.74", "6eec335141229700a99e63eecac62aa3c7733964c6b38c5cbd4732e82cd7f6c9", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "aee7466c7ee67120ce841956cd65482730c1c9dcf19f25d0c74cb98e42e24777"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From c16012f8e43124f07d4ec7137c0686e612d1d3bf Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Thu, 31 Oct 2024 13:33:23 +0200 Subject: [PATCH 02/12] using igniter --- lib/ash_phoenix/gen/live.ex | 46 ++++++++++----------- lib/mix/tasks/ash_phoenix.gen.live.ex | 57 ++++++++++++++++++++------- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 8569cf9..2d6e9d0 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -1,17 +1,21 @@ defmodule AshPhoenix.Gen.Live do @moduledoc false - def generate_from_cli(argv) do - {domain, resource, opts, _rest} = AshPhoenix.Gen.parse_opts(argv) + def generate_from_cli(%Igniter{} = igniter, options) do + domain = Keyword.fetch!(options, :domain) + resource = Keyword.fetch!(options, :resource) + _resourceplural = Keyword.fetch!(options, :resourceplural) + opts = [] generate( + igniter, domain, resource, Keyword.put(opts, :interactive?, true) ) end - def generate(domain, resource, opts \\ []) do + def generate(igniter, domain, resource, opts \\ []) do Code.ensure_compiled!(domain) Code.ensure_compiled!(resource) @@ -55,13 +59,14 @@ defmodule AshPhoenix.Gen.Live do [ domain: inspect(domain), resource: inspect(resource), - web_module: inspect(web_module()), + web_module: inspect(web_module(igniter)), actor: opts[:actor], actor_opt: actor_opt(opts) ] |> add_resource_assigns(resource, opts) - web_live = Path.join([web_path(), "live", "#{assigns[:resource_singular]}_live"]) + # web_live should not be needed + web_live = Path.join([web_path(igniter), "live", "#{assigns[:resource_singular]}_live"]) generate_opts = if opts[:interactive?] do @@ -71,6 +76,7 @@ defmodule AshPhoenix.Gen.Live do end write_formatted_template( + igniter, "ash_phoenix.gen.live/index.ex.eex", "index.ex", web_live, @@ -80,6 +86,7 @@ defmodule AshPhoenix.Gen.Live do if assigns[:update_action] || assigns[:create_action] do write_formatted_template( + igniter, "ash_phoenix.gen.live/form_component.ex.eex", "form_component.ex", web_live, @@ -89,6 +96,7 @@ defmodule AshPhoenix.Gen.Live do end write_formatted_template( + igniter, "ash_phoenix.gen.live/show.ex.eex", "show.ex", web_live, @@ -99,7 +107,7 @@ defmodule AshPhoenix.Gen.Live do if opts[:interactive?] do Mix.shell().info(""" - Add the live routes to your browser scope in #{web_path()}/router.ex: + Add the live routes to your browser scope in #{web_path(igniter)}/router.ex: #{for line <- live_route_instructions(assigns), do: " #{line}"} """) @@ -123,7 +131,7 @@ defmodule AshPhoenix.Gen.Live do |> Enum.reject(&is_nil/1) end - defp write_formatted_template(path, destination, web_live, assigns, generate_opts) do + defp write_formatted_template(igniter, path, destination, web_live, assigns, generate_opts) do destination_path = web_live |> Path.join(destination) @@ -137,7 +145,10 @@ defmodule AshPhoenix.Gen.Live do |> EEx.eval_file(assigns: assigns) |> formatter_function.() - Mix.Generator.create_file(destination_path, contents, generate_opts) + # igniter + Igniter.create_new_file(igniter, destination_path, contents, generate_opts) + + # Mix.Generator.create_file(destination_path, contents, generate_opts) end defp add_resource_assigns(assigns, resource, opts) do @@ -305,8 +316,8 @@ defmodule AshPhoenix.Gen.Live do end end - defp web_path do - web_module().module_info[:compile][:source] + defp web_path(igniter) do + web_module(igniter).module_info[:compile][:source] |> Path.relative_to(root_path()) |> Path.rootname() end @@ -316,19 +327,8 @@ defmodule AshPhoenix.Gen.Live do |> Path.dirname() end - defp web_module do - base = Mix.Phoenix.base() - - cond do - Mix.Phoenix.context_app() != Mix.Phoenix.otp_app() -> - Module.concat([base]) - - String.ends_with?(base, "Web") -> - Module.concat([base]) - - true -> - Module.concat(["#{base}Web"]) - end + defp web_module(igniter) do + Igniter.Libs.Phoenix.web_module(igniter) end defp template(path) do diff --git a/lib/mix/tasks/ash_phoenix.gen.live.ex b/lib/mix/tasks/ash_phoenix.gen.live.ex index 89b3f2c..6bc436f 100644 --- a/lib/mix/tasks/ash_phoenix.gen.live.ex +++ b/lib/mix/tasks/ash_phoenix.gen.live.ex @@ -1,29 +1,58 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Live do + use Igniter.Mix.Task + + @example "mix ash_phoenix.gen.live --domain ExistingDomainName --resource ExistingResourceName --resource-plural ExistingResourceNames" + + @shortdoc "Generates liveviews for a given domain and resource." + + # --domain + # --resource + # --resource-plural @moduledoc """ + #{@shortdoc} + Generates liveviews for a given domain and resource. The domain and resource must already exist, this task does not define them. - #{AshPhoenix.Gen.docs()} - - For example: + ## Example ```bash - mix ash_phoenix.gen.live ExistingDomainName ExistingResourceName + #{@example} ``` + + ## Options + + * `--domain` - Existing domain + * `--resource` - Existing resource + * `--resourceplural` - Plural resource name """ - use Mix.Task - @shortdoc "Generates liveviews for a resource" - def run(argv) do - Mix.Task.run("compile") + def info(_argv, _composing_task) do + %Igniter.Mix.Task.Info{ + # Groups allow for overlapping arguments for tasks by the same author + # See the generators guide for more. + group: :ash_phoenix, + example: @example, + schema: [domain: :string, resource: :string, resourceplural: :string], + # Default values for the options in the `schema`. + defaults: [], + # CLI aliases + aliases: [], + # A list of options in the schema that are required + required: [:domain, :resource, :resourceplural] + } + end - if Mix.Project.umbrella?() do - Mix.raise( - "mix phx.gen.live must be invoked from within your *_web application root directory" - ) - end + def igniter(igniter, argv) do + # extract positional arguments according to `positional` above + {arguments, argv} = positional_args!(argv) + # extract options according to `schema` and `aliases` above + options = options!(argv) |> dbg() - AshPhoenix.Gen.Live.generate_from_cli(argv) + # Do your work here and return an updated igniter + igniter + # |> AshPhoenix.Gen.Live.generate_from_cli1(options) + |> Igniter.add_warning("mix ash_phoenix.gen.live is under construction") end end From d782d39f921b9017a3f5c314f334d4effa404160 Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Fri, 1 Nov 2024 10:40:06 +0200 Subject: [PATCH 03/12] working generation for a resource of a domain --- lib/ash_phoenix/gen/live.ex | 43 +++++++++++++++------------ lib/mix/tasks/ash_phoenix.gen.live.ex | 7 ++--- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 2d6e9d0..0260802 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -2,16 +2,16 @@ defmodule AshPhoenix.Gen.Live do @moduledoc false def generate_from_cli(%Igniter{} = igniter, options) do - domain = Keyword.fetch!(options, :domain) - resource = Keyword.fetch!(options, :resource) - _resourceplural = Keyword.fetch!(options, :resourceplural) + domain = Keyword.fetch!(options, :domain) |> String.to_existing_atom() + resource = Keyword.fetch!(options, :resource) |> String.to_existing_atom() + resource_plural = Keyword.fetch!(options, :resourceplural) opts = [] generate( igniter, domain, resource, - Keyword.put(opts, :interactive?, true) + Keyword.put(opts, :interactive?, true) |> Keyword.put(:resource_plural, resource_plural) ) end @@ -75,25 +75,29 @@ defmodule AshPhoenix.Gen.Live do [force: true, quiet: true] end - write_formatted_template( - igniter, - "ash_phoenix.gen.live/index.ex.eex", - "index.ex", - web_live, - assigns, - generate_opts - ) - - if assigns[:update_action] || assigns[:create_action] do + igniter = write_formatted_template( igniter, - "ash_phoenix.gen.live/form_component.ex.eex", - "form_component.ex", + "ash_phoenix.gen.live/index.ex.eex", + "index.ex", web_live, assigns, generate_opts ) - end + + igniter = + if assigns[:update_action] || assigns[:create_action] do + write_formatted_template( + igniter, + "ash_phoenix.gen.live/form_component.ex.eex", + "form_component.ex", + web_live, + assigns, + generate_opts + ) + else + igniter + end write_formatted_template( igniter, @@ -112,6 +116,8 @@ defmodule AshPhoenix.Gen.Live do #{for line <- live_route_instructions(assigns), do: " #{line}"} """) end + + igniter end defp live_route_instructions(assigns) do @@ -317,9 +323,8 @@ defmodule AshPhoenix.Gen.Live do end defp web_path(igniter) do - web_module(igniter).module_info[:compile][:source] + Igniter.Project.Module.proper_location(igniter, web_module(igniter)) |> Path.relative_to(root_path()) - |> Path.rootname() end defp root_path do diff --git a/lib/mix/tasks/ash_phoenix.gen.live.ex b/lib/mix/tasks/ash_phoenix.gen.live.ex index 6bc436f..a5f22b8 100644 --- a/lib/mix/tasks/ash_phoenix.gen.live.ex +++ b/lib/mix/tasks/ash_phoenix.gen.live.ex @@ -45,14 +45,11 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Live do end def igniter(igniter, argv) do - # extract positional arguments according to `positional` above - {arguments, argv} = positional_args!(argv) # extract options according to `schema` and `aliases` above - options = options!(argv) |> dbg() + options = options!(argv) # Do your work here and return an updated igniter igniter - # |> AshPhoenix.Gen.Live.generate_from_cli1(options) - |> Igniter.add_warning("mix ash_phoenix.gen.live is under construction") + |> AshPhoenix.Gen.Live.generate_from_cli(options) end end From 9fae17f02a6372b2cf8e8b19f6bac4b0bfe693be Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Mon, 4 Nov 2024 19:18:02 +0200 Subject: [PATCH 04/12] adding test and removing comments --- lib/ash_phoenix/gen/live.ex | 4 - mix.exs | 2 +- mix.lock | 9 +- test/mix/tasks/ash_phoenix.gen.live_test.exs | 122 +++++++++++++++++++ 4 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 test/mix/tasks/ash_phoenix.gen.live_test.exs diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 0260802..acae091 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -65,7 +65,6 @@ defmodule AshPhoenix.Gen.Live do ] |> add_resource_assigns(resource, opts) - # web_live should not be needed web_live = Path.join([web_path(igniter), "live", "#{assigns[:resource_singular]}_live"]) generate_opts = @@ -151,10 +150,7 @@ defmodule AshPhoenix.Gen.Live do |> EEx.eval_file(assigns: assigns) |> formatter_function.() - # igniter Igniter.create_new_file(igniter, destination_path, contents, generate_opts) - - # Mix.Generator.create_file(destination_path, contents, generate_opts) end defp add_resource_assigns(assigns, resource, opts) do diff --git a/mix.exs b/mix.exs index 087aeb0..6e7e75b 100644 --- a/mix.exs +++ b/mix.exs @@ -142,7 +142,7 @@ defmodule AshPhoenix.MixProject do {:mix_audit, ">= 0.0.0", only: [:dev, :test], runtime: false}, {:mix_test_watch, "~> 1.0", only: [:dev, :test]}, # Code Generators - {:igniter, "~> 0.3 and >= 0.3.74"} + {:igniter, "~> 0.4 and >= 0.4.3"} ] end diff --git a/mix.lock b/mix.lock index a773006..98af960 100644 --- a/mix.lock +++ b/mix.lock @@ -14,8 +14,8 @@ "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, - "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.3.74", "6eec335141229700a99e63eecac62aa3c7733964c6b38c5cbd4732e82cd7f6c9", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "aee7466c7ee67120ce841956cd65482730c1c9dcf19f25d0c74cb98e42e24777"}, + "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, + "igniter": {:hex, :igniter, "0.4.3", "cf4c4404e761bee456441a427a42a7dd815df7445362d69a4a21bcf7c74305d0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "bcee7e30caa7ef8d4a4d0d6e9968d62cf162d1991af8afe67bfefb2e625c6cf9"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -35,15 +35,16 @@ "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, - "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, + "rewrite": {:hex, :rewrite, "1.0.1", "2a249d703e47c050ad251fa43a3d019d4c08159ead95ec30ef48357ba88af609", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "79869f0bdb22840cf233b99e0dc7b6682a35d7e4747bdf2e78d3bc156b2c7c14"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, + "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, "spark": {:hex, :spark, "2.2.34", "1f0a3bd86d37f86a1d26db4a34d6b0e5fb091940aee25cd40041dab1397c8ada", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "93f94b8f511a72f8764465ea32ff2e5376695f70e747884de2ce64bb6ac22a59"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, diff --git a/test/mix/tasks/ash_phoenix.gen.live_test.exs b/test/mix/tasks/ash_phoenix.gen.live_test.exs new file mode 100644 index 0000000..2c800f2 --- /dev/null +++ b/test/mix/tasks/ash_phoenix.gen.live_test.exs @@ -0,0 +1,122 @@ +defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do + use ExUnit.Case + import Igniter.Test + + setup do + current_shell = Mix.shell() + + :ok = Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(current_shell) + end) + end + + test "generate phoenix live views from resource" do + send(self(), {:mix_shell_input, :yes?, "n"}) + send(self(), {:mix_shell_input, :prompt, ""}) + + opts = [ + files: %{ + "lib/test/support/ticket/status.ex" => """ + defmodule Test.Support.Ticket.Status do + use Ash.Type.Enum, values: [:open, :closed] + end + """, + "lib/test/support/ticket.ex" => """ + defmodule Test.Support.Ticket do + use Ash.Resource, + otp_app: :test, + domain: Test.Support, + data_layer: Ash.DataLayer.Ets + + alias Test.Support.Ticket.Status + + ets do + private? true + end + + actions do + defaults [:read, :destroy] + + create :create do + accept [:subject, :status] + end + + create :open do + accept [:subject] + end + + update :update do + primary? true + accept [:subject] + end + + update :close do + accept [] + + validate attribute_does_not_equal(:status, :closed) do + message "Ticket is already closed" + end + + change set_attribute(:status, :closed) + end + + update :assign do + accept [:representative_id] + end + end + + + attributes do + uuid_primary_key :id + + attribute :subject, :string do + allow_nil? false + public? true + end + + attribute :status, Status do + default :open + allow_nil? false + end + end + end + """, + "lib/test/support.ex" => """ + defmodule Test.Support do + use Ash.Domain + + resources do + resource Test.Support.Ticket + end + end + """ + } + ] + + assert test_project(opts) + |> apply_igniter!() + |> compile() + |> Igniter.compose_task("ash_phoenix.gen.live", [ + "--domain", + "Elixir.Test.Support", + "--resource", + "Elixir.Test.Support.Ticket", + "--resourceplural", + "Tickets" + ]) + end + + def compile(igniter) do + igniter.rewrite + |> Stream.map(fn source -> + Kernel.ParallelCompiler.async(fn -> + Code.compile_string(Rewrite.Source.get(source, :content)) + end) + end) + |> Enum.to_list() + + igniter + end +end From b3d369a89025bb2412ae79a7788d827c8002d6c9 Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Tue, 5 Nov 2024 22:02:10 +0200 Subject: [PATCH 05/12] using test/support domain and resource for generating live view code --- lib/ash_phoenix/gen/live.ex | 11 +- test/mix/tasks/ash_phoenix.gen.live_test.exs | 207 ++++++++++--------- 2 files changed, 122 insertions(+), 96 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index acae091..4d0512e 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -147,8 +147,11 @@ defmodule AshPhoenix.Gen.Live do contents = path |> template() - |> EEx.eval_file(assigns: assigns) + |> EEx.eval_file([assigns: assigns], trim: true) |> formatter_function.() + |> indent() + |> Code.format_string!() + |> IO.iodata_to_binary() Igniter.create_new_file(igniter, destination_path, contents, generate_opts) end @@ -426,4 +429,10 @@ defmodule AshPhoenix.Gen.Live do defp default_options(_), do: [] defp label(key), do: Phoenix.Naming.humanize(to_string(key)) + + defp indent(string) do + string + |> String.split("\n", trim: true) + |> Enum.map_join("\n", &" #{&1}") + end end diff --git a/test/mix/tasks/ash_phoenix.gen.live_test.exs b/test/mix/tasks/ash_phoenix.gen.live_test.exs index 2c800f2..075054c 100644 --- a/test/mix/tasks/ash_phoenix.gen.live_test.exs +++ b/test/mix/tasks/ash_phoenix.gen.live_test.exs @@ -16,107 +16,124 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do send(self(), {:mix_shell_input, :yes?, "n"}) send(self(), {:mix_shell_input, :prompt, ""}) - opts = [ - files: %{ - "lib/test/support/ticket/status.ex" => """ - defmodule Test.Support.Ticket.Status do - use Ash.Type.Enum, values: [:open, :closed] + form_path = "lib/ash_phoenix_web.ex/live/artist_live/form_component.ex" + + form_contents = + """ + defmodule AshPhoenixWeb.ArtistLive.FormComponent do + use AshPhoenixWeb, :live_component + + @impl true + def render(assigns) do + ~H\"\"\" +
+ <.header> + <%= @title %> + <:subtitle>Use this form to manage artist records in your database. + + + <.simple_form + for={@form} + id="artist-form" + phx-target={@myself} + phx-change="validate" + phx-submit="save" + > + + + <.input field={@form[:name]} type="text" label="Name" /> + + + <:actions> + <.button phx-disable-with="Saving...">Save Artist + + +
+ \"\"\" + end + + @impl true + def update(assigns, socket) do + {:ok, + socket + |> assign(assigns) + |> assign_form()} + end + + @impl true + def handle_event("validate", %{"artist" => artist_params}, socket) do + {:noreply, assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, artist_params))} + end + + def handle_event("save", %{"artist" => artist_params}, socket) do + case AshPhoenix.Form.submit(socket.assigns.form, params: artist_params) do + {:ok, artist} -> + notify_parent({:saved, artist}) + + socket = + socket + |> put_flash(:info, "Artist \#{socket.assigns.form.source.type}d successfully") + |> push_patch(to: socket.assigns.patch) + + {:noreply, socket} + + {:error, form} -> + {:noreply, assign(socket, form: form)} end - """, - "lib/test/support/ticket.ex" => """ - defmodule Test.Support.Ticket do - use Ash.Resource, - otp_app: :test, - domain: Test.Support, - data_layer: Ash.DataLayer.Ets - - alias Test.Support.Ticket.Status - - ets do - private? true + end + + defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) + + defp assign_form(%{assigns: %{artist: artist}} = socket) do + form = + if artist do + AshPhoenix.Form.for_update(artist, :update, + as: "artist", + actor: socket.assigns.current_user + ) + else + AshPhoenix.Form.for_create(AshPhoenix.Test.Artist, :create, + as: "artist", + actor: socket.assigns.current_user + ) end - actions do - defaults [:read, :destroy] - - create :create do - accept [:subject, :status] - end - - create :open do - accept [:subject] - end - - update :update do - primary? true - accept [:subject] - end - - update :close do - accept [] - - validate attribute_does_not_equal(:status, :closed) do - message "Ticket is already closed" - end - - change set_attribute(:status, :closed) - end - - update :assign do - accept [:representative_id] - end - end - - - attributes do - uuid_primary_key :id - - attribute :subject, :string do - allow_nil? false - public? true - end + assign(socket, form: to_form(form)) + end + end + """ + |> format_contents(form_path) + |> indent() + |> Code.format_string!() + |> IO.iodata_to_binary() + + Igniter.new() + |> Igniter.include_glob("**/.formatter.exs") + |> Igniter.include_glob(".formatter.exs") + |> Igniter.compose_task("ash_phoenix.gen.live", [ + "--domain", + "Elixir.AshPhoenix.Test.Domain", + "--resource", + "Elixir.AshPhoenix.Test.Artist", + "--resourceplural", + "Artists" + ]) + |> assert_creates( + form_path, + form_contents + ) + end - attribute :status, Status do - default :open - allow_nil? false - end - end - end - """, - "lib/test/support.ex" => """ - defmodule Test.Support do - use Ash.Domain + defp format_contents(contents, path) do + {formatter_function, _options} = + Mix.Tasks.Format.formatter_for_file(path) - resources do - resource Test.Support.Ticket - end - end - """ - } - ] - - assert test_project(opts) - |> apply_igniter!() - |> compile() - |> Igniter.compose_task("ash_phoenix.gen.live", [ - "--domain", - "Elixir.Test.Support", - "--resource", - "Elixir.Test.Support.Ticket", - "--resourceplural", - "Tickets" - ]) + formatter_function.(contents) end - def compile(igniter) do - igniter.rewrite - |> Stream.map(fn source -> - Kernel.ParallelCompiler.async(fn -> - Code.compile_string(Rewrite.Source.get(source, :content)) - end) - end) - |> Enum.to_list() - - igniter + defp indent(string) do + string + |> String.split("\n", trim: true) + |> Enum.map_join("\n", &" #{&1}") end end From 6098e1624998d41629b264f20625f075b476e30f Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Tue, 5 Nov 2024 22:33:39 +0200 Subject: [PATCH 06/12] remove root_path fn --- lib/ash_phoenix/gen/live.ex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 4d0512e..9890b73 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -323,12 +323,6 @@ defmodule AshPhoenix.Gen.Live do defp web_path(igniter) do Igniter.Project.Module.proper_location(igniter, web_module(igniter)) - |> Path.relative_to(root_path()) - end - - defp root_path do - Mix.Project.get().module_info[:compile][:source] - |> Path.dirname() end defp web_module(igniter) do From 8564efd1420ee290d191efd5f645e85491fef3d5 Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Tue, 5 Nov 2024 22:37:35 +0200 Subject: [PATCH 07/12] adding LiveView HTMLFormatter plugins to .formatter --- .formatter.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/.formatter.exs b/.formatter.exs index 3392b8e..1188490 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,6 @@ # Used by "mix format" [ + plugins: [Phoenix.LiveView.HTMLFormatter], import_deps: [:ash], inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] ] From 748a17e45a0a72e84a1dc3beb7f4c614e6e80e21 Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Wed, 6 Nov 2024 08:25:18 +0200 Subject: [PATCH 08/12] assert_creates is working following changes led to it 1. removing trim option in EEx.eval_file 2. removing indent fn 3. Code.format_string --- .formatter.exs | 2 +- lib/ash_phoenix/gen/live.ex | 10 +--------- test/mix/tasks/ash_phoenix.gen.live_test.exs | 8 -------- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index 1188490..12f81df 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -2,5 +2,5 @@ [ plugins: [Phoenix.LiveView.HTMLFormatter], import_deps: [:ash], - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] + inputs: ["*.{heex,ex,exs}", "{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] ] diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 9890b73..768375f 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -147,11 +147,8 @@ defmodule AshPhoenix.Gen.Live do contents = path |> template() - |> EEx.eval_file([assigns: assigns], trim: true) + |> EEx.eval_file([assigns: assigns]) |> formatter_function.() - |> indent() - |> Code.format_string!() - |> IO.iodata_to_binary() Igniter.create_new_file(igniter, destination_path, contents, generate_opts) end @@ -424,9 +421,4 @@ defmodule AshPhoenix.Gen.Live do defp label(key), do: Phoenix.Naming.humanize(to_string(key)) - defp indent(string) do - string - |> String.split("\n", trim: true) - |> Enum.map_join("\n", &" #{&1}") - end end diff --git a/test/mix/tasks/ash_phoenix.gen.live_test.exs b/test/mix/tasks/ash_phoenix.gen.live_test.exs index 075054c..b8970de 100644 --- a/test/mix/tasks/ash_phoenix.gen.live_test.exs +++ b/test/mix/tasks/ash_phoenix.gen.live_test.exs @@ -103,9 +103,6 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do end """ |> format_contents(form_path) - |> indent() - |> Code.format_string!() - |> IO.iodata_to_binary() Igniter.new() |> Igniter.include_glob("**/.formatter.exs") @@ -131,9 +128,4 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do formatter_function.(contents) end - defp indent(string) do - string - |> String.split("\n", trim: true) - |> Enum.map_join("\n", &" #{&1}") - end end From 2c1ca2519f06f46f02261fdd034378fc0905c6ed Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Wed, 6 Nov 2024 09:12:37 +0200 Subject: [PATCH 09/12] fixing web_module path, asserting created index.ex file --- lib/ash_phoenix/gen/live.ex | 5 +- test/mix/tasks/ash_phoenix.gen.live_test.exs | 117 ++++++++++++++++++- 2 files changed, 118 insertions(+), 4 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 768375f..8ebbfe8 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -319,7 +319,10 @@ defmodule AshPhoenix.Gen.Live do end defp web_path(igniter) do - Igniter.Project.Module.proper_location(igniter, web_module(igniter)) + web_module_path = Igniter.Project.Module.proper_location(igniter, web_module(igniter)) + lib_dir = Path.dirname(web_module_path) + + Path.join([lib_dir, Path.basename(web_module_path, ".ex")]) end defp web_module(igniter) do diff --git a/test/mix/tasks/ash_phoenix.gen.live_test.exs b/test/mix/tasks/ash_phoenix.gen.live_test.exs index b8970de..c2eba87 100644 --- a/test/mix/tasks/ash_phoenix.gen.live_test.exs +++ b/test/mix/tasks/ash_phoenix.gen.live_test.exs @@ -16,7 +16,7 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do send(self(), {:mix_shell_input, :yes?, "n"}) send(self(), {:mix_shell_input, :prompt, ""}) - form_path = "lib/ash_phoenix_web.ex/live/artist_live/form_component.ex" + form_path = "lib/ash_phoenix_web/live/artist_live/form_component.ex" form_contents = """ @@ -104,9 +104,118 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do """ |> format_contents(form_path) + index_path = "lib/ash_phoenix_web/live/artist_live/index.ex" + index_contents = """ + defmodule AshPhoenixWeb.ArtistLive.Index do + use AshPhoenixWeb, :live_view + + @impl true + def render(assigns) do + ~H\"\"\" + <.header> + Listing Artists + <:actions> + <.link patch={~p"/Artists/new"}> + <.button>New Artist + + + + + <.table + id="Artists" + rows={@streams.Artists} + row_click={fn {_id, artist} -> JS.navigate(~p"/Artists/\#{artist}") end} + > + <:col :let={{_id, artist}} label="Id"><%= artist.id %> + + <:col :let={{_id, artist}} label="Name"><%= artist.name %> + + <:action :let={{_id, artist}}> +
+ <.link navigate={~p"/Artists/\#{artist}"}>Show +
+ + <.link patch={~p"/Artists/\#{artist}/edit"}>Edit + + + <:action :let={{id, artist}}> + <.link + phx-click={JS.push("delete", value: %{id: artist.id}) |> hide("#\#{id}")} + data-confirm="Are you sure?" + > + Delete + + + + + <.modal + :if={@live_action in [:new, :edit]} + id="artist-modal" + show + on_cancel={JS.patch(~p"/Artists")} + > + <.live_component + module={AshPhoenixWeb.ArtistLive.FormComponent} + id={(@artist && @artist.id) || :new} + title={@page_title} + current_user={@current_user} + action={@live_action} + artist={@artist} + patch={~p"/Artists"} + /> + + \"\"\" + end + + @impl true + def mount(_params, _session, socket) do + {:ok, + socket + |> stream(:Artists, Ash.read!(AshPhoenix.Test.Artist, actor: socket.assigns[:current_user])) + |> assign_new(:current_user, fn -> nil end)} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :edit, %{"id" => id}) do + socket + |> assign(:page_title, "Edit Artist") + |> assign(:artist, Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user)) + end + + defp apply_action(socket, :new, _params) do + socket + |> assign(:page_title, "New Artist") + |> assign(:artist, nil) + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Artists") + |> assign(:artist, nil) + end + + @impl true + def handle_info({AshPhoenixWeb.ArtistLive.FormComponent, {:saved, artist}}, socket) do + {:noreply, stream_insert(socket, :Artists, artist)} + end + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + artist = Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user) + Ash.destroy!(artist, actor: socket.assigns.current_user) + + {:noreply, stream_delete(socket, :Artists, artist)} + end + end + """ + |> format_contents(index_path) + + Igniter.new() - |> Igniter.include_glob("**/.formatter.exs") - |> Igniter.include_glob(".formatter.exs") |> Igniter.compose_task("ash_phoenix.gen.live", [ "--domain", "Elixir.AshPhoenix.Test.Domain", @@ -119,6 +228,8 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do form_path, form_contents ) + |> assert_creates(index_path, index_contents) + end defp format_contents(contents, path) do From f9841804711c7eb86fec469f7746dd952071196d Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Wed, 6 Nov 2024 09:42:27 +0200 Subject: [PATCH 10/12] fixed missed return of igniter from show file create asserting show.ex file creation --- lib/ash_phoenix/gen/live.ex | 2 +- test/mix/tasks/ash_phoenix.gen.live_test.exs | 217 ++++++++++++------- 2 files changed, 142 insertions(+), 77 deletions(-) diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 8ebbfe8..8405264 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -98,7 +98,7 @@ defmodule AshPhoenix.Gen.Live do igniter end - write_formatted_template( + igniter = write_formatted_template( igniter, "ash_phoenix.gen.live/show.ex.eex", "show.ex", diff --git a/test/mix/tasks/ash_phoenix.gen.live_test.exs b/test/mix/tasks/ash_phoenix.gen.live_test.exs index c2eba87..d3f30fa 100644 --- a/test/mix/tasks/ash_phoenix.gen.live_test.exs +++ b/test/mix/tasks/ash_phoenix.gen.live_test.exs @@ -104,64 +104,159 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do """ |> format_contents(form_path) - index_path = "lib/ash_phoenix_web/live/artist_live/index.ex" - index_contents = """ - defmodule AshPhoenixWeb.ArtistLive.Index do + index_path = "lib/ash_phoenix_web/live/artist_live/index.ex" + + index_contents = + """ + defmodule AshPhoenixWeb.ArtistLive.Index do + use AshPhoenixWeb, :live_view + + @impl true + def render(assigns) do + ~H\"\"\" + <.header> + Listing Artists + <:actions> + <.link patch={~p"/Artists/new"}> + <.button>New Artist + + + + + <.table + id="Artists" + rows={@streams.Artists} + row_click={fn {_id, artist} -> JS.navigate(~p"/Artists/\#{artist}") end} + > + <:col :let={{_id, artist}} label="Id"><%= artist.id %> + + <:col :let={{_id, artist}} label="Name"><%= artist.name %> + + <:action :let={{_id, artist}}> +
+ <.link navigate={~p"/Artists/\#{artist}"}>Show +
+ + <.link patch={~p"/Artists/\#{artist}/edit"}>Edit + + + <:action :let={{id, artist}}> + <.link + phx-click={JS.push("delete", value: %{id: artist.id}) |> hide("#\#{id}")} + data-confirm="Are you sure?" + > + Delete + + + + + <.modal + :if={@live_action in [:new, :edit]} + id="artist-modal" + show + on_cancel={JS.patch(~p"/Artists")} + > + <.live_component + module={AshPhoenixWeb.ArtistLive.FormComponent} + id={(@artist && @artist.id) || :new} + title={@page_title} + current_user={@current_user} + action={@live_action} + artist={@artist} + patch={~p"/Artists"} + /> + + \"\"\" + end + + @impl true + def mount(_params, _session, socket) do + {:ok, + socket + |> stream(:Artists, Ash.read!(AshPhoenix.Test.Artist, actor: socket.assigns[:current_user])) + |> assign_new(:current_user, fn -> nil end)} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :edit, %{"id" => id}) do + socket + |> assign(:page_title, "Edit Artist") + |> assign(:artist, Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user)) + end + + defp apply_action(socket, :new, _params) do + socket + |> assign(:page_title, "New Artist") + |> assign(:artist, nil) + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Artists") + |> assign(:artist, nil) + end + + @impl true + def handle_info({AshPhoenixWeb.ArtistLive.FormComponent, {:saved, artist}}, socket) do + {:noreply, stream_insert(socket, :Artists, artist)} + end + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + artist = Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user) + Ash.destroy!(artist, actor: socket.assigns.current_user) + + {:noreply, stream_delete(socket, :Artists, artist)} + end + end + """ + |> format_contents(index_path) + + show_path = "lib/ash_phoenix_web/live/artist_live/show.ex" + show_contents = """ + defmodule AshPhoenixWeb.ArtistLive.Show do use AshPhoenixWeb, :live_view @impl true def render(assigns) do ~H\"\"\" <.header> - Listing Artists + Artist <%= @artist.id %> + <:subtitle>This is a artist record from your database. + <:actions> - <.link patch={~p"/Artists/new"}> - <.button>New Artist + <.link patch={~p"/Artists/\#{@artist}/show/edit"} phx-click={JS.push_focus()}> + <.button>Edit artist - <.table - id="Artists" - rows={@streams.Artists} - row_click={fn {_id, artist} -> JS.navigate(~p"/Artists/\#{artist}") end} - > - <:col :let={{_id, artist}} label="Id"><%= artist.id %> - - <:col :let={{_id, artist}} label="Name"><%= artist.name %> + <.list> + <:item title="Id"><%= @artist.id %> - <:action :let={{_id, artist}}> -
- <.link navigate={~p"/Artists/\#{artist}"}>Show -
+ <:item title="Name"><%= @artist.name %> + - <.link patch={~p"/Artists/\#{artist}/edit"}>Edit - - - <:action :let={{id, artist}}> - <.link - phx-click={JS.push("delete", value: %{id: artist.id}) |> hide("#\#{id}")} - data-confirm="Are you sure?" - > - Delete - - - + <.back navigate={~p"/Artists"}>Back to Artists <.modal - :if={@live_action in [:new, :edit]} + :if={@live_action == :edit} id="artist-modal" show - on_cancel={JS.patch(~p"/Artists")} + on_cancel={JS.patch(~p"/Artists/\#{@artist}")} > <.live_component module={AshPhoenixWeb.ArtistLive.FormComponent} - id={(@artist && @artist.id) || :new} + id={@artist.id} title={@page_title} - current_user={@current_user} action={@live_action} + current_user={@current_user} artist={@artist} - patch={~p"/Artists"} + patch={~p"/Artists/\#{@artist}"} /> \"\"\" @@ -169,53 +264,24 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do @impl true def mount(_params, _session, socket) do - {:ok, - socket - |> stream(:Artists, Ash.read!(AshPhoenix.Test.Artist, actor: socket.assigns[:current_user])) - |> assign_new(:current_user, fn -> nil end)} - end - - @impl true - def handle_params(params, _url, socket) do - {:noreply, apply_action(socket, socket.assigns.live_action, params)} - end - - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Artist") - |> assign(:artist, Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user)) - end - - defp apply_action(socket, :new, _params) do - socket - |> assign(:page_title, "New Artist") - |> assign(:artist, nil) - end - - defp apply_action(socket, :index, _params) do - socket - |> assign(:page_title, "Listing Artists") - |> assign(:artist, nil) + {:ok, socket} end @impl true - def handle_info({AshPhoenixWeb.ArtistLive.FormComponent, {:saved, artist}}, socket) do - {:noreply, stream_insert(socket, :Artists, artist)} + def handle_params(%{"id" => id}, _, socket) do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:artist, Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user))} end - @impl true - def handle_event("delete", %{"id" => id}, socket) do - artist = Ash.get!(AshPhoenix.Test.Artist, id, actor: socket.assigns.current_user) - Ash.destroy!(artist, actor: socket.assigns.current_user) - - {:noreply, stream_delete(socket, :Artists, artist)} - end + defp page_title(:show), do: "Show Artist" + defp page_title(:edit), do: "Edit Artist" end """ - |> format_contents(index_path) - + |> format_contents(show_path) - Igniter.new() + assert Igniter.new() |> Igniter.compose_task("ash_phoenix.gen.live", [ "--domain", "Elixir.AshPhoenix.Test.Domain", @@ -229,7 +295,7 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do form_contents ) |> assert_creates(index_path, index_contents) - + |> assert_creates(show_path, show_contents) end defp format_contents(contents, path) do @@ -238,5 +304,4 @@ defmodule Mix.Tasks.AshPhoenix.Gen.LiveTest do formatter_function.(contents) end - end From 02898cb8eab273b6e6864dda41c113ecb44719fa Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Wed, 6 Nov 2024 11:53:06 +0200 Subject: [PATCH 11/12] formatting live.ex --- .formatter.exs | 4 ++-- lib/ash_phoenix/gen/live.ex | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index 12f81df..223c6af 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,6 +1,6 @@ # Used by "mix format" [ + import_deps: [:ash, :phoenix], plugins: [Phoenix.LiveView.HTMLFormatter], - import_deps: [:ash], - inputs: ["*.{heex,ex,exs}", "{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] + inputs: ["{mix}.exs", "{config,lib,test}/**/*.{ex,exs,heex}"] ] diff --git a/lib/ash_phoenix/gen/live.ex b/lib/ash_phoenix/gen/live.ex index 8405264..4e3ac1c 100644 --- a/lib/ash_phoenix/gen/live.ex +++ b/lib/ash_phoenix/gen/live.ex @@ -98,14 +98,15 @@ defmodule AshPhoenix.Gen.Live do igniter end - igniter = write_formatted_template( - igniter, - "ash_phoenix.gen.live/show.ex.eex", - "show.ex", - web_live, - assigns, - generate_opts - ) + igniter = + write_formatted_template( + igniter, + "ash_phoenix.gen.live/show.ex.eex", + "show.ex", + web_live, + assigns, + generate_opts + ) if opts[:interactive?] do Mix.shell().info(""" @@ -147,7 +148,7 @@ defmodule AshPhoenix.Gen.Live do contents = path |> template() - |> EEx.eval_file([assigns: assigns]) + |> EEx.eval_file(assigns: assigns) |> formatter_function.() Igniter.create_new_file(igniter, destination_path, contents, generate_opts) @@ -423,5 +424,4 @@ defmodule AshPhoenix.Gen.Live do defp default_options(_), do: [] defp label(key), do: Phoenix.Naming.humanize(to_string(key)) - end From 0265dd2c65e79526d0d33e94f877264316bff70d Mon Sep 17 00:00:00 2001 From: Srikanth Kyatham Date: Wed, 6 Nov 2024 12:32:32 +0200 Subject: [PATCH 12/12] updating igniter dep --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 98af960..385783a 100644 --- a/mix.lock +++ b/mix.lock @@ -15,7 +15,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.4.3", "cf4c4404e761bee456441a427a42a7dd815df7445362d69a4a21bcf7c74305d0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "bcee7e30caa7ef8d4a4d0d6e9968d62cf162d1991af8afe67bfefb2e625c6cf9"}, + "igniter": {:hex, :igniter, "0.4.5", "cdb5f5b9ff8b6cd7764613b5eb66332fbbbd9f4b345e59e4c8d6e5270b0f982b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "b858319a36b6ebd12084a20844afcb1d64c8f20bc6790dedfad9d6dec38baa3f"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"},