From d7ba32c6aff25d5bc86abbd8a0e154fd36431a14 Mon Sep 17 00:00:00 2001 From: Oliver Marriott Date: Fri, 11 Nov 2022 20:44:55 +1100 Subject: [PATCH] dump work --- .formatter.exs | 1 + README.md | 40 ++++++ assets/js/app.js | 59 ++++++-- lib/necromancy_web.ex | 3 + lib/necromancy_web/live/necro_live.ex | 127 ++++++++++++++++++ lib/necromancy_web/router.ex | 2 +- mix.exs | 6 +- mix.lock | 4 +- .../controllers/page_controller_test.exs | 8 +- 9 files changed, 228 insertions(+), 22 deletions(-) create mode 100644 README.md create mode 100644 lib/necromancy_web/live/necro_live.ex diff --git a/.formatter.exs b/.formatter.exs index 8a6391c..490a6cc 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,4 +1,5 @@ [ + plugins: [Phoenix.LiveView.HTMLFormatter], import_deps: [:ecto, :phoenix], inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"], subdirectories: ["priv/*/migrations"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d7a0f2 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Necromancy + +Using Phoenix.LiveView inplace of classical controllers, optionally +resurrecting them from the dead. + +## Reasoning + +- A consistent developer experience. + +All your views are constructed in the same manner, with a mount, handle_params, +etc process flow. The "template render flow" is the same. + +- But not all views really need to be "live" + +Some static [sic] pages have no sever state to update. These could/can just be +regular Phoenix controller actions. + +- But, but some views might warrant starting dead and then *becoming* live. + +## Reasons against + +- Kinda weird +- Added complexity with expecting a liveview to never connect? +- Phoenix 1.7 *may* unify how templates are put together with the new + templating engine? + +## Direct usecase + +All pages show content, with a "live chat/form" pop-out. The live-chat should +integrate with the current page - it should not redirect. + +## Methods + +- Show button, on click spawn iframe with liveview in it, let this do the fancy + work. + - Simpler, no hacks + - iframes ugly? + +- Dead to live + - render view as dead-liveview, on click connect livesocket or import livesocket code diff --git a/assets/js/app.js b/assets/js/app.js index 2ca06a5..9dc8e4e 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -26,20 +26,55 @@ import {Socket} from "phoenix" import {LiveSocket} from "phoenix_live_view" import topbar from "../vendor/topbar" +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +var timeout = null +window.addEventListener("phx:page-loading-start", (info) => { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + timeout = setTimeout(topbar.show, 200) +}) +window.addEventListener("phx:page-loading-stop", (info) => { + topbar.hide() + if (timeout) { + clearTimeout(timeout) + timeout = null + } +}) + +// seems that its preferable to always construct the livesocket but not connect +// it, vs constructing it on demand as redispatched click events don't seem to +// be caught. let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) +liveSocket.enableDebug() -// Show progress bar on live navigation and form submits -topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) -window.addEventListener("phx:page-loading-start", info => topbar.show()) -window.addEventListener("phx:page-loading-stop", info => topbar.hide()) - -// connect if there are any LiveViews on the page -liveSocket.connect() +let bindConnectForEvent = (el, eventType) => { + el.addEventListener(eventType, (e) => { + // if we're not connected, connect and then refire the same event incase + // we're bound to a phx-click etc. + if (!liveSocket.isConnected()) { + window.addEventListener("phx:page-loading-stop", () => { + el.dispatchEvent(e) + }, {once: true}) + liveSocket.connect() + }}) +} -// expose liveSocket on window for web console debug logs and latency simulation: -// >> liveSocket.enableDebug() -// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session -// >> liveSocket.disableLatencySim() -window.liveSocket = liveSocket +window.addEventListener("DOMContentLoaded", () => { + // This is a generic connect, you could use click, hover, etc. + // + <%= inspect(@task) %> + <%= inspect(@bytes) %> +

+ +

+ I am DEAD. +

+ +

+ +

+ + +

Event has been run?: <%= @event_ran? %>

+ + Access form to connect + <.form + :let={f} + data-connect-liveview="input" + for={@changeset} + phx-change="validate" + phx-submit="submit" + phx-page-loading="false" + > + <%= text_input(f, :name) %> + <%= error_tag(f, :name) %> + + + """ + end +end diff --git a/lib/necromancy_web/router.ex b/lib/necromancy_web/router.ex index 6b71666..c55d6c5 100644 --- a/lib/necromancy_web/router.ex +++ b/lib/necromancy_web/router.ex @@ -17,7 +17,7 @@ defmodule NecromancyWeb.Router do scope "/", NecromancyWeb do pipe_through :browser - get "/", PageController, :index + live "/", NecroLive, :index end # Other scopes may use custom stacks. diff --git a/mix.exs b/mix.exs index 53003bc..3523ce2 100644 --- a/mix.exs +++ b/mix.exs @@ -7,7 +7,7 @@ defmodule Necromancy.MixProject do version: "0.1.0", elixir: "~> 1.12", elixirc_paths: elixirc_paths(Mix.env()), - compilers: [:gettext] ++ Mix.compilers(), + compilers: [] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, aliases: aliases(), deps: deps() @@ -39,9 +39,9 @@ defmodule Necromancy.MixProject do {:ecto_sqlite3, ">= 0.0.0"}, {:phoenix_html, "~> 3.0"}, {:phoenix_live_reload, "~> 1.2", only: :dev}, - {:phoenix_live_view, "~> 0.17.5"}, + {:phoenix_live_view, "~> 0.18.0"}, {:floki, ">= 0.30.0", only: :test}, - {:phoenix_live_dashboard, "~> 0.6"}, + {:phoenix_live_dashboard, "~> 0.7"}, {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, {:swoosh, "~> 1.3"}, {:telemetry_metrics, "~> 0.6"}, diff --git a/mix.lock b/mix.lock index 6ea9d00..155c9e4 100644 --- a/mix.lock +++ b/mix.lock @@ -21,9 +21,9 @@ "phoenix": {:hex, :phoenix, "1.6.14", "57678366dc1d5bad49832a0fc7f12c2830c10d3eacfad681bfe9602cd4445f04", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d48c0da00b3d4cd1aad6055387917491af9f6e1f1e96cedf6c6b7998df9dba26"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, - "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.1", "b0bf8f3348dec4910907a2ad1453e642f6fe4d444376c1c9b26222d63c73cf97", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "b6c5d744bf4b40692b1b361d3608bdfd05aeab83e17c7bc217d730f007f31abf"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.12", "74f4c0ad02d7deac2d04f50b52827a5efdc5c6e7fac5cede145f5f0e4183aedc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "af6dd5e0aac16ff43571f527a8e0616d62cb80b10eb87aac82170243e50d99c8"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.2", "635cf07de947235deb030cd6b776c71a3b790ab04cebf526aa8c879fe17c7784", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6 or ~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "da287a77327e996cc166e4c440c3ad5ab33ccdb151b91c793209b39ebbce5b75"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, "plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"}, diff --git a/test/necromancy_web/controllers/page_controller_test.exs b/test/necromancy_web/controllers/page_controller_test.exs index 73b7f73..0b15982 100644 --- a/test/necromancy_web/controllers/page_controller_test.exs +++ b/test/necromancy_web/controllers/page_controller_test.exs @@ -1,8 +1,8 @@ defmodule NecromancyWeb.PageControllerTest do use NecromancyWeb.ConnCase - test "GET /", %{conn: conn} do - conn = get(conn, "/") - assert html_response(conn, 200) =~ "Welcome to Phoenix!" - end + # test "GET /", %{conn: conn} do + # conn = get(conn, "/") + # assert html_response(conn, 200) =~ "Welcome to Phoenix!" + # end end