diff --git a/CHANGELOG.md b/CHANGELOG.md index e49c534..8378f3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG (v0.1.X) +## 0.1.12 () + +### Backwards incompatible changes for 0.1.11 + * None + +### Bug fixes + * None + +### Enhancements + * [[`PR-27`](https://github.com/thiagoesteves/observer_web/pull/27)] Adding Igniter. + ## 0.1.11 🚀 (2025-08-29) ### Backwards incompatible changes for 0.1.10 diff --git a/assets/package-lock.json b/assets/package-lock.json index 1ad1666..498fed5 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -14,35 +14,55 @@ } }, "../deps/phoenix": { - "version": "1.7.18", - "license": "MIT" + "version": "1.8.1", + "license": "MIT", + "devDependencies": { + "@babel/cli": "7.28.3", + "@babel/core": "7.28.3", + "@babel/preset-env": "7.28.3", + "@eslint/js": "^9.28.0", + "@stylistic/eslint-plugin": "^5.0.0", + "documentation": "^14.0.3", + "eslint": "9.34.0", + "eslint-plugin-jest": "29.0.1", + "jest": "^30.0.0", + "jest-environment-jsdom": "^30.0.0", + "jsdom": "^26.1.0", + "mock-socket": "^9.3.1" + } }, "../deps/phoenix_html": { - "version": "4.2.0" + "version": "4.3.0" }, "../deps/phoenix_live_view": { - "version": "1.0.3", + "version": "1.1.14", "license": "MIT", "dependencies": { - "morphdom": "2.7.4" + "morphdom": "2.7.7" }, "devDependencies": { - "@babel/cli": "7.26.4", - "@babel/core": "7.26.0", - "@babel/preset-env": "7.26.0", - "@eslint/js": "^9.18.0", - "@playwright/test": "^1.49.1", - "@stylistic/eslint-plugin-js": "^2.12.1", + "@babel/cli": "7.27.2", + "@babel/core": "7.27.4", + "@babel/preset-env": "7.27.2", + "@babel/preset-typescript": "^7.27.1", + "@eslint/js": "^9.29.0", + "@playwright/test": "^1.53.0", + "@types/jest": "^30.0.0", + "@types/phoenix": "^1.6.6", "css.escape": "^1.5.1", - "eslint": "9.18.0", - "eslint-plugin-jest": "28.10.0", - "eslint-plugin-playwright": "^2.1.0", - "globals": "^15.14.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", + "eslint": "9.29.0", + "eslint-plugin-jest": "28.14.0", + "eslint-plugin-playwright": "^2.2.0", + "globals": "^16.2.0", + "jest": "^30.0.0", + "jest-environment-jsdom": "^30.0.0", "jest-monocart-coverage": "^1.1.1", - "monocart-reporter": "^2.9.13", - "phoenix": "1.7.18" + "monocart-reporter": "^2.9.21", + "phoenix": "1.7.21", + "prettier": "3.5.3", + "ts-jest": "^29.4.0", + "typescript": "^5.8.3", + "typescript-eslint": "^8.34.0" } }, "node_modules/echarts": { @@ -96,7 +116,21 @@ } }, "phoenix": { - "version": "file:../deps/phoenix" + "version": "file:../deps/phoenix", + "requires": { + "@babel/cli": "7.28.3", + "@babel/core": "7.28.3", + "@babel/preset-env": "7.28.3", + "@eslint/js": "^9.28.0", + "@stylistic/eslint-plugin": "^5.0.0", + "documentation": "^14.0.3", + "eslint": "9.34.0", + "eslint-plugin-jest": "29.0.1", + "jest": "^30.0.0", + "jest-environment-jsdom": "^30.0.0", + "jsdom": "^26.1.0", + "mock-socket": "^9.3.1" + } }, "phoenix_html": { "version": "file:../deps/phoenix_html" @@ -104,23 +138,29 @@ "phoenix_live_view": { "version": "file:../deps/phoenix_live_view", "requires": { - "@babel/cli": "7.26.4", - "@babel/core": "7.26.0", - "@babel/preset-env": "7.26.0", - "@eslint/js": "^9.18.0", - "@playwright/test": "^1.49.1", - "@stylistic/eslint-plugin-js": "^2.12.1", + "@babel/cli": "7.27.2", + "@babel/core": "7.27.4", + "@babel/preset-env": "7.27.2", + "@babel/preset-typescript": "^7.27.1", + "@eslint/js": "^9.29.0", + "@playwright/test": "^1.53.0", + "@types/jest": "^30.0.0", + "@types/phoenix": "^1.6.6", "css.escape": "^1.5.1", - "eslint": "9.18.0", - "eslint-plugin-jest": "28.10.0", - "eslint-plugin-playwright": "^2.1.0", - "globals": "^15.14.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", + "eslint": "9.29.0", + "eslint-plugin-jest": "28.14.0", + "eslint-plugin-playwright": "^2.2.0", + "globals": "^16.2.0", + "jest": "^30.0.0", + "jest-environment-jsdom": "^30.0.0", "jest-monocart-coverage": "^1.1.1", - "monocart-reporter": "^2.9.13", - "morphdom": "2.7.4", - "phoenix": "1.7.18" + "monocart-reporter": "^2.9.21", + "morphdom": "2.7.7", + "phoenix": "1.7.21", + "prettier": "3.5.3", + "ts-jest": "^29.4.0", + "typescript": "^5.8.3", + "typescript-eslint": "^8.34.0" } }, "topbar": { diff --git a/guides/installation.md b/guides/installation.md index 01f9b11..7bd5a86 100644 --- a/guides/installation.md +++ b/guides/installation.md @@ -3,17 +3,48 @@ Observer Web is delivered as a hex package named `observer_web`. The package is entirely self contained—it doesn't hook into your asset pipeline. -## Prerequisites +There are three installation mechanisms available: -1. Ensure [Phoenix Live View][plv] is installed and working in your application. If you don't have - Live View, follow [these instructions][lvi] to get started. +- [Semi-Automatic Installation](#semi-automatic-installation) using an igniter powered mix task +- [Igniter Installation](#igniter-installation) fully automatic installation using igniter +- [Manual Installation](#manual-installation) add Observer Web and handle all steps manually -> #### Clustering Required {: .info} -> -> The Observer Web **requires your app to be clustered**. Otherwise, observability will only be -> available on the current node. +## Semi-Automatic Installation + +You can use the `observer_web.install` task without the `igniter.install` escript available. +First, add `observer_web` and `igniter` to your deps in `mix.exs`: + +```elixir +{:observer_web, "~> 0.1.0"}, +{:igniter, "~> 0.5", only: [:dev]}, +``` + +Run `mix deps.get` to fetch `observer_web`, then run the install task: + +```bash +mix observer_web.install +``` + +This will automate all of the manual setup steps for you! + +## Igniter Installation + +For projects that have [igniter][igniter] available, Observer Web can be installed and configured with +a single command: + +```bash +mix igniter.install observer_web +``` + +that will add the latest version of `observer_web` to your dependencies before running the installer, +then mount it as `/observer` within the `:dev_routes` conditional. + +## Manual Installation -## Configuration +Before installing Observer Web, ensure you have: + +1. **Phoenix Live View** - Ensure [Phoenix Live View][plv] is installed and working. If you + don't have Live View yet, follow [these instructions][lvi]. Add `observer_web` as a dependency for your application. Open `mix.exs` and add the following line: @@ -50,10 +81,6 @@ end Here we're using `"/observer"` as the mount point, but it can be anywhere you like. See the `Observer.Web.Router` docs for additional options. -After you've verified that the dashboard is loading you'll probably want to restrict access to the -dashboard via authentication, either with a [custom resolver's][ac] access controls or [Basic -Auth][ba]. - ### Embedding Observer Web in your app page In some cases, you may prefer to run the Observer in the same page as your app rather than in @@ -122,6 +149,28 @@ path `/observer"`. However, using the iframe approach allows you to display your application's information alongside the Observer in your main page, providing a more integrated monitoring experience. +> ## Clustering Required {: .info} +> +> The Observer Web **requires your app to be clustered**. Otherwise, observability will only be +> available on the current node. + +## Post-Installation + +After installation (by any method), you should consider the following configuration steps: + +### Secure Dashboard Access + +After you've verified that the dashboard is loading you'll probably want to restrict access to the +dashboard via authentication, either with a [custom resolver's][ac] access controls or [Basic +Auth][ba]. + +### Customize the Dashboard + +Web customization is done through the `Observer.Web.Resolver` behaviour. It allows you to enable +access controls, control formatting, and provide query limits for filtering and searching. Using a +custom resolver is optional, but you should familiarize yourself with the default limits +and functionality. + ### Metrics #### 1. Retention period for metrics diff --git a/lib/mix/tasks/observer_web.install.ex b/lib/mix/tasks/observer_web.install.ex new file mode 100644 index 0000000..afe9a87 --- /dev/null +++ b/lib/mix/tasks/observer_web.install.ex @@ -0,0 +1,138 @@ +defmodule Mix.Tasks.ObserverWeb.Install.Docs do + @moduledoc false + + def short_doc do + "Installs Observer Web into your Phoenix application" + end + + def example do + "mix observer_web.install" + end + + def long_doc do + """ + #{short_doc()} + + This task configures your Phoenix application to use the Observer Web dashboard: + + * Adds the required `Observer.Web.Router` import + * Sets up the dashboard route at "/observer" within the :dev_routes conditional + + ## Example + + ```bash + #{example()} + ``` + """ + end +end + +alias Igniter.Code.Common, as: IgniterCommon +alias Igniter.Code.Function, as: IgniterFunction +alias Igniter.Libs.Phoenix, as: IgniterPhoenix + +if Code.ensure_loaded?(Igniter) do + defmodule Mix.Tasks.ObserverWeb.Install do + @shortdoc "#{__MODULE__.Docs.short_doc()}" + + @moduledoc __MODULE__.Docs.long_doc() + use Igniter.Mix.Task + + @impl Igniter.Mix.Task + def info(_argv, _composing_task) do + %Igniter.Mix.Task.Info{ + group: :observer_web, + installs: [{:observer_web, "~> 0.1.0"}], + example: __MODULE__.Docs.example() + } + end + + @impl Igniter.Mix.Task + def igniter(igniter) do + case IgniterPhoenix.select_router(igniter) do + {igniter, nil} -> + Igniter.add_warning(igniter, """ + No Phoenix router found, Phoenix Liveview is needed for Observer Web + """) + + {igniter, router} -> + update_router(igniter, router) + end + end + + defp update_router(igniter, router) do + zipper = &do_update_router(igniter, &1) + + case Igniter.Project.Module.find_and_update_module(igniter, router, zipper) do + {:ok, igniter} -> + igniter + + {:error, igniter} -> + Igniter.add_warning(igniter, """ + Something went wrong, please check the Observer Web install docs for manual setup instructions + """) + end + end + + defp do_update_router(igniter, zipper) do + web_module = IgniterPhoenix.web_module(igniter) + app_name = Igniter.Project.Application.app_name(igniter) + + with {:ok, zipper} <- add_import(zipper, web_module) do + add_route(zipper, app_name) + end + end + + defp add_import(zipper, web_module) do + with {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, web_module) do + {:ok, IgniterCommon.add_code(zipper, "\nimport Observer.Web.Router")} + end + end + + defp add_route(zipper, app_name) do + matcher = &dev_routes?(&1, app_name) + + with {:ok, zipper} <- IgniterFunction.move_to_function_call(zipper, :if, 2, matcher), + {:ok, zipper} <- IgniterCommon.move_to_do_block(zipper) do + {:ok, + IgniterCommon.add_code(zipper, """ + scope "/" do + pipe_through :browser + + observer_dashboard "/observer" + end + """)} + end + end + + defp dev_routes?(zipper, app_name) do + case IgniterFunction.move_to_nth_argument(zipper, 0) do + {:ok, zipper} -> + IgniterFunction.function_call?(zipper, {Application, :compile_env}, 2) and + IgniterFunction.argument_equals?(zipper, 0, app_name) and + IgniterFunction.argument_equals?(zipper, 1, :dev_routes) + + _ -> + false + end + end + end +else + defmodule Mix.Tasks.ObserverWeb.Install do + @shortdoc "#{__MODULE__.Docs.short_doc()} | Install `igniter` to use" + + @moduledoc __MODULE__.Docs.long_doc() + + use Mix.Task + + def run(_argv) do + Mix.shell().error(""" + The task 'ObserverWeb.Task.Install' requires igniter. Please install igniter and try again. + + For more information, see: https://hexdocs.pm/igniter/readme.html#installation + """) + + exit({:shutdown, 1}) + end + end +end diff --git a/mix.exs b/mix.exs index e10a900..7405148 100644 --- a/mix.exs +++ b/mix.exs @@ -68,6 +68,7 @@ defmodule ObserverWeb.MixProject do [ main: "overview", source_ref: "v#{@version}", + source_url: @source_url, formatters: ["html"], api_reference: false, extra_section: "GUIDES", @@ -108,7 +109,7 @@ defmodule ObserverWeb.MixProject do [ {:jason, "~> 1.2"}, {:phoenix, "~> 1.7"}, - {:phoenix_html, "~> 4.0"}, + {:phoenix_html, "~> 3.3 or ~> 4.0"}, {:phoenix_live_view, "~> 1.0"}, {:phoenix_pubsub, "~> 2.1"}, @@ -132,6 +133,7 @@ defmodule ObserverWeb.MixProject do {:sobelow, "~> 0.13", only: [:dev, :test], runtime: false}, {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false}, {:mock, "~> 0.3.0", only: :test}, + {:igniter, "~> 0.5", only: [:dev, :test]}, # Docs and Publishing {:ex_doc, "~> 0.34", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 2ecfe1e..2eeed66 100644 --- a/mix.lock +++ b/mix.lock @@ -11,8 +11,11 @@ "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, "faker": {:hex, :faker, "0.18.0", "943e479319a22ea4e8e39e8e076b81c02827d9302f3d32726c5bf82f430e6e14", [:mix], [], "hexpm", "bfbdd83958d78e2788e99ec9317c4816e651ad05e24cfd1196ce5db5b3e81797"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, + "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, "floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"}, + "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, + "igniter": {:hex, :igniter, "0.6.30", "83a466369ebb8fe009e0823c7bf04314dc545122c2d48f896172fc79df33e99d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-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", "76a14d5b7f850bb03b5243088c3649d54a2e52e34a2aa1104dee23cf50a8bae0"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_diff": {:hex, :makeup_diff, "0.1.1", "01498f8c95970081297837eaf4686b6f3813e535795b8421f15ace17a59aea37", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "fadb0bf014bd328badb7be986eadbce1a29955dd51c27a9e401c3045cf24184e"}, @@ -20,11 +23,15 @@ "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "mock": {:hex, :mock, "0.3.9", "10e44ad1f5962480c5c9b9fa779c6c63de9bd31997c8e04a853ec990a9d841af", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "9e1b244c4ca2551bb17bb8415eed89e40ee1308e0fbaed0a4fdfe3ec8a4adbd3"}, "mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_ownership": {:hex, :nimble_ownership, "1.0.1", "f69fae0cdd451b1614364013544e66e4f5d25f36a2056a9698b793305c5aa3a6", [:mix], [], "hexpm", "3825e461025464f519f3f3e4a1f9b68c47dc151369611629ad08b636b73bb22d"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "owl": {:hex, :owl, "0.13.0", "26010e066d5992774268f3163506972ddac0a7e77bfe57fa42a250f24d6b876e", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "59bf9d11ce37a4db98f57cb68fbfd61593bf419ec4ed302852b6683d3d2f7475"}, "phoenix": {:hex, :phoenix, "1.7.18", "5310c21443514be44ed93c422e15870aef254cf1b3619e4f91538e7529d2b2e4", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "1797fcc82108442a66f2c77a643a62980f342bfeb63d6c9a515ab8294870004e"}, "phoenix_html": {:hex, :phoenix_html, "4.2.0", "83a4d351b66f472ebcce242e4ae48af1b781866f00ef0eb34c15030d4e2069ac", [:mix], [], "hexpm", "9713b3f238d07043583a94296cc4bbdceacd3b3a6c74667f4df13971e7866ec8"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, @@ -33,11 +40,16 @@ "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "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"}, + "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, + "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [: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", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, + "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, + "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"}, "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, + "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "thousand_island": {:hex, :thousand_island, "1.3.9", "095db3e2650819443e33237891271943fad3b7f9ba341073947581362582ab5a", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "25ab4c07badadf7f87adb4ab414e0ed374e5f19e72503aa85132caa25776e54f"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [: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", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, diff --git a/test/mix/tasks/observer_web.install_test.exs b/test/mix/tasks/observer_web.install_test.exs new file mode 100644 index 0000000..89f0e2c --- /dev/null +++ b/test/mix/tasks/observer_web.install_test.exs @@ -0,0 +1,65 @@ +defmodule Mix.Tasks.ObserverWeb.InstallTest do + use ExUnit.Case, async: true + + import Igniter.Test + + test "installation adds the route the neccessary setup to the router" do + test_project() + |> Igniter.Project.Module.create_module(TestWeb.Router, """ + use TestWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, {DevWeb.LayoutView, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + # Enable LiveDashboard and Swoosh mailbox preview in development + if Application.compile_env(:test, :dev_routes) do + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + import Phoenix.LiveDashboard.Router + + scope "/dev" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: testWeb.Telemetry + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end + """) + |> apply_igniter!() + |> Igniter.compose_task("observer_web.install") + |> assert_has_patch("lib/test_web/router.ex", """ + ...| + 2 2 | use TestWeb, :router + 3 3 | + 4 + | import Observer.Web.Router + 5 + | + 4 6 | pipeline :browser do + 5 7 | plug(:accepts, ["html"]) + ...| + 30 32 | forward("/mailbox", Plug.Swoosh.MailboxPreview) + 31 33 | end + 34 + | + 35 + | scope "/" do + 36 + | pipe_through(:browser) + 37 + | + 38 + | observer_dashboard("/observer") + 39 + | end + 32 40 | end + 33 41 |end + ...| + """) + end +end