From 6c30f62d5d5f07c93f02328f0643b93c2ef6bcb4 Mon Sep 17 00:00:00 2001 From: Uku Taht Date: Mon, 13 Jan 2025 14:31:18 +0200 Subject: [PATCH] Upgrade deps, add storybook (#4947) * Add `<.dropdown_item>` * Make the ellipsis menu functional again * Upgrade deps so that storybook can be added * Add storybook and dropdown story * Remove lingering warnings/errors * Add color mode to storybook * Use new liveview used_input? function * Alpine improvements * Add select input to storybook * Bring back `render_form` for CRM * Configure eslint so it can see deps * Remove LiveViewTest patch * Fix test for phoenix liveview 1.0 * Build assets in prod * Fix tests * Attempt to fix lint error * Add explicit text color to input * mix format * Format after merge master * Add moduledocs * Only run storybook in production * Update storybook dependency * Mix format --- .formatter.exs | 7 +- Dockerfile | 1 + assets/.eslintrc.json | 3 + assets/css/storybook.css | 14 ++++ assets/js/liveview/live_socket.js | 6 +- assets/js/storybook.js | 39 ++++++++++ assets/package-lock.json | 14 ---- assets/package.json | 3 - assets/tailwind.config.js | 2 +- config/config.exs | 10 ++- config/dev.exs | 4 +- config/runtime.exs | 2 + .../lib/plausible_web/live/funnel_settings.ex | 4 +- .../live/funnel_settings/form.ex | 4 +- .../live/funnel_settings/list.ex | 4 +- .../plausible_web/views/help_scout_view.ex | 16 ++--- lib/plausible/billing/ecto/feature.ex | 15 ++-- lib/plausible/billing/ecto/limit.ex | 11 +-- lib/plausible_web.ex | 1 - .../components/billing/billing.ex | 26 +++---- .../components/billing/notice.ex | 6 +- .../components/billing/pageview_slider.ex | 6 +- .../components/billing/plan_benefits.ex | 2 +- .../components/billing/plan_box.ex | 18 ++--- lib/plausible_web/components/flow_progress.ex | 10 +-- lib/plausible_web/components/generic.ex | 71 ++++++++++--------- lib/plausible_web/components/site/feature.ex | 4 +- lib/plausible_web/components/two_factor.ex | 38 +++++----- .../controllers/auth_controller.ex | 1 + lib/plausible_web/live/choose_plan.ex | 5 +- .../live/components/combo_box.ex | 4 +- lib/plausible_web/live/components/form.ex | 58 ++++++++------- lib/plausible_web/live/components/modal.ex | 2 +- .../live/components/pagination.ex | 2 +- .../live/components/verification.ex | 10 +-- lib/plausible_web/live/csv_export.ex | 10 +-- lib/plausible_web/live/csv_import.ex | 12 ++-- lib/plausible_web/live/flash.ex | 16 ++--- lib/plausible_web/live/goal_settings/form.ex | 14 ++-- lib/plausible_web/live/goal_settings/list.ex | 8 +-- .../live/imports_exports_settings.ex | 12 ++-- lib/plausible_web/live/installation.ex | 4 +- .../live/plugins/api/settings.ex | 10 +-- .../live/plugins/api/token_form.ex | 2 +- lib/plausible_web/live/props_settings.ex | 4 +- lib/plausible_web/live/props_settings/form.ex | 8 +-- lib/plausible_web/live/props_settings/list.ex | 2 +- lib/plausible_web/live/register_form.ex | 8 +-- .../live/shields/country_rules.ex | 4 +- .../live/shields/hostname_rules.ex | 11 ++- lib/plausible_web/live/shields/ip_rules.ex | 6 +- lib/plausible_web/live/shields/page_rules.ex | 8 +-- lib/plausible_web/live/sites.ex | 10 +-- lib/plausible_web/router.ex | 10 +++ lib/plausible_web/storybook.ex | 13 ++++ .../templates/auth/activate.html.heex | 10 +-- .../generate_2fa_recovery_codes.html.heex | 2 +- .../templates/auth/login_form.html.heex | 6 +- .../auth/password_reset_form.html.heex | 4 +- .../password_reset_request_form.html.heex | 4 +- .../password_reset_request_success.html.heex | 2 +- .../billing/change_plan_preview.html.heex | 12 ++-- .../templates/billing/choose_plan.html.heex | 4 +- .../upgrade_to_enterprise_plan.html.heex | 18 ++--- .../templates/debug/clickhouse.html.heex | 8 +-- .../email/activation_email.html.heex | 2 +- ...approaching_accept_traffic_until.html.heex | 4 +- .../email/create_site_email.html.heex | 3 +- .../templates/email/csv_import.html.heex | 6 +- .../email/dashboard_locked.html.heex | 10 +-- .../email/drop_notification.html.heex | 4 +- .../enterprise_over_limit_internal.html.heex | 19 +++-- .../email/error_report_email.html.heex | 4 +- .../email/existing_user_invitation.html.heex | 2 +- .../existing_user_team_invitation.html.heex | 2 +- .../templates/email/export_failure.html.heex | 2 +- .../templates/email/export_success.html.heex | 4 +- .../email/google_analytics_import.html.heex | 6 +- .../email/guest_invitation_accepted.html.heex | 2 +- .../email/guest_invitation_rejected.html.heex | 2 +- .../email/new_user_invitation.html.heex | 2 +- .../email/new_user_team_invitation.html.heex | 2 +- .../templates/email/over_limit.html.heex | 10 +-- .../ownership_transfer_accepted.html.heex | 2 +- .../ownership_transfer_rejected.html.heex | 2 +- .../ownership_transfer_request.html.heex | 2 +- .../email/site_member_removed.html.heex | 2 +- .../email/site_setup_help_email.html.heex | 2 +- .../email/spike_notification.html.heex | 6 +- .../email/team_invitation_accepted.html.heex | 2 +- .../email/team_invitation_rejected.html.heex | 2 +- .../email/trial_over_email.html.heex | 3 +- .../email/trial_upgrade_email.html.heex | 16 ++--- .../yearly_expiration_notification.html.heex | 4 +- .../yearly_renewal_notification.html.heex | 4 +- .../templates/error/404_error.html.heex | 2 +- .../templates/error/generic_error.html.heex | 4 +- .../google_analytics/confirm.html.heex | 6 +- .../google_analytics/property_form.html.heex | 4 +- .../templates/layout/_flash.html.heex | 8 +-- .../templates/layout/_header.html.heex | 6 +- .../templates/layout/_notice.html.heex | 2 +- .../templates/layout/_settings_tab.html.heex | 2 +- .../layout/_site_settings_tab.html.heex | 2 +- .../templates/layout/app.html.heex | 16 ++--- .../templates/layout/base_email.html.heex | 10 ++- .../templates/layout/base_error.html.heex | 2 +- .../templates/layout/embedded.html.heex | 1 - .../templates/layout/priority_email.html.heex | 6 +- .../templates/layout/settings.html.heex | 14 ++-- .../templates/layout/site_settings.html.heex | 16 ++--- .../templates/settings/api_keys.html.heex | 6 +- .../templates/settings/invoices.html.heex | 4 +- .../templates/settings/new_api_key.html.heex | 2 +- .../templates/settings/security.html.heex | 4 +- .../templates/settings/subscription.html.heex | 8 +-- .../templates/site/csv_import.html.heex | 4 +- .../membership/invite_member_form.html.heex | 6 +- .../transfer_ownership_form.html.heex | 6 +- .../site/settings_danger_zone.html.heex | 6 +- .../site/settings_email_reports.html.heex | 16 ++--- .../templates/site/settings_funnels.html.heex | 4 +- .../templates/site/settings_goals.html.heex | 4 +- .../site/settings_imports_exports.html.heex | 10 +-- .../site/settings_integrations.html.heex | 4 +- .../templates/site/settings_people.html.heex | 10 +-- .../templates/site/settings_props.html.heex | 4 +- .../site/settings_search_console.html.heex | 4 +- .../templates/site/settings_shields.html.heex | 16 ++--- .../site/settings_visibility.html.heex | 4 +- .../stats/shared_link_password.html.heex | 2 +- .../templates/stats/site_locked.html.heex | 4 +- .../templates/unsubscribe/success.html.heex | 2 +- lib/plausible_web/views/error_helpers.ex | 34 --------- mix.exs | 19 +++-- mix.lock | 35 +++++---- storybook/_root.index.exs | 8 +++ storybook/dropdown.story.exs | 31 ++++++++ storybook/input.story.exs | 47 ++++++++++++ .../components/billing/notice_test.exs | 2 +- .../components/flow_progress_test.exs | 2 +- .../controllers/settings_controller_test.exs | 8 ++- .../controllers/site_controller_test.exs | 1 + .../live/components/combo_box_test.exs | 3 +- .../live/components/form_test.exs | 2 +- .../live/components/verification_test.exs | 2 +- test/plausible_web/live/verification_test.exs | 5 +- test/support/live_view_test_fix.ex | 42 ----------- 148 files changed, 683 insertions(+), 587 deletions(-) create mode 100644 assets/css/storybook.css create mode 100644 assets/js/storybook.js create mode 100644 lib/plausible_web/storybook.ex delete mode 100644 lib/plausible_web/views/error_helpers.ex create mode 100644 storybook/_root.index.exs create mode 100644 storybook/dropdown.story.exs create mode 100644 storybook/input.story.exs delete mode 100644 test/support/live_view_test_fix.ex diff --git a/.formatter.exs b/.formatter.exs index 0afac0f5fe..6f8425f230 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -2,5 +2,10 @@ plugins: [Phoenix.LiveView.HTMLFormatter], import_deps: [:ecto, :ecto_sql, :phoenix], subdirectories: ["priv/*/migrations"], - inputs: ["*.{heex,ex,exs}", "{config,lib,test,extra}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] + inputs: [ + "*.{heex,ex,exs}", + "{config,lib,test,extra}/**/*.{heex,ex,exs}", + "priv/*/seeds.exs", + "storybook/**/*.exs" + ] ] diff --git a/Dockerfile b/Dockerfile index 34d594ca93..3e62878f8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,6 +41,7 @@ COPY tracker ./tracker COPY priv ./priv COPY lib ./lib COPY extra ./extra +COPY storybook ./storybook RUN npm run deploy --prefix ./tracker && \ mix assets.deploy && \ diff --git a/assets/.eslintrc.json b/assets/.eslintrc.json index 7261a4b6a8..bea69f9255 100644 --- a/assets/.eslintrc.json +++ b/assets/.eslintrc.json @@ -50,6 +50,9 @@ "import/resolver": { "typescript": { "alwaysTryTypes": true // always try to resolve types under `@types` directory even it doesn't contain any source code, like `@types/unist` + }, + "node": { + "moduleDirectory": ["node_modules", "../deps"] } }, "react": { diff --git a/assets/css/storybook.css b/assets/css/storybook.css new file mode 100644 index 0000000000..e245aca2aa --- /dev/null +++ b/assets/css/storybook.css @@ -0,0 +1,14 @@ +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; + +/* + * Put your component styling within the Tailwind utilities layer. + * See the https://hexdocs.pm/phoenix_storybook/sandboxing.html guide for more info. + */ + +@layer utilities { + * { + font-family: system-ui; + } +} diff --git a/assets/js/liveview/live_socket.js b/assets/js/liveview/live_socket.js index b2d84dae51..87db6f7315 100644 --- a/assets/js/liveview/live_socket.js +++ b/assets/js/liveview/live_socket.js @@ -1,7 +1,11 @@ +// eslint-disable-next-line import/no-unresolved import "phoenix_html" -import Alpine from 'alpinejs' +// eslint-disable-next-line import/no-unresolved import { Socket } from "phoenix" +// eslint-disable-next-line import/no-unresolved import { LiveSocket } from "phoenix_live_view" +// eslint-disable-next-line import/no-unresolved +import Alpine from 'alpinejs' let csrfToken = document.querySelector("meta[name='csrf-token']") let websocketUrl = document.querySelector("meta[name='websocket-url']") diff --git a/assets/js/storybook.js b/assets/js/storybook.js new file mode 100644 index 0000000000..8838db5770 --- /dev/null +++ b/assets/js/storybook.js @@ -0,0 +1,39 @@ +import Alpine from 'alpinejs' +import dropdown from "./liveview/dropdown" + +// If your components require any hooks or custom uploaders, or if your pages +// require connect parameters, uncomment the following lines and declare them as +// such: +// +// import * as Hooks from "./hooks"; +// import * as Params from "./params"; +// import * as Uploaders from "./uploaders"; + +// (function () { +// window.storybook = { Hooks, Params, Uploaders }; +// })(); + + +window.Alpine = Alpine +document.addEventListener('DOMContentLoaded', () => { + window.Alpine.start(); +}); + +document.addEventListener('alpine:init', () => { + window.Alpine.data('dropdown', dropdown) +}); + + + (function () { + window.storybook = { + LiveSocketOptions: { + dom: { + onBeforeElUpdated(from, to) { + if (from._x_dataStack) { + window.Alpine.clone(from, to) + } + } + } + } + }; + })(); diff --git a/assets/package-lock.json b/assets/package-lock.json index 6aa0601961..1fe7a6dc22 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -26,9 +26,6 @@ "d3": "^7.9.0", "dayjs": "^1.11.7", "iframe-resizer": "^4.3.2", - "phoenix": "^1.7.2", - "phoenix_html": "^3.3.1", - "phoenix_live_view": "^0.18.18", "react": "^18.3.1", "react-dom": "^18.3.1", "react-flatpickr": "3.10.5", @@ -9308,17 +9305,6 @@ "node": ">=8" } }, - "node_modules/phoenix": { - "version": "1.7.2", - "license": "MIT" - }, - "node_modules/phoenix_html": { - "version": "3.3.1" - }, - "node_modules/phoenix_live_view": { - "version": "0.18.18", - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", diff --git a/assets/package.json b/assets/package.json index 09ca12902b..426f11441f 100644 --- a/assets/package.json +++ b/assets/package.json @@ -30,9 +30,6 @@ "d3": "^7.9.0", "dayjs": "^1.11.7", "iframe-resizer": "^4.3.2", - "phoenix": "^1.7.2", - "phoenix_html": "^3.3.1", - "phoenix_live_view": "^0.18.18", "react": "^18.3.1", "react-dom": "^18.3.1", "react-flatpickr": "3.10.5", diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js index e1a029ef9b..1034d05212 100644 --- a/assets/tailwind.config.js +++ b/assets/tailwind.config.js @@ -14,6 +14,7 @@ module.exports = { "max-w-screen-xl" ], darkMode: 'class', + important: '.plausible', theme: { container: { center: true, @@ -51,7 +52,6 @@ module.exports = { plugins: [ require('@tailwindcss/forms'), require('@tailwindcss/aspect-ratio'), - plugin(({ addVariant }) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), plugin(({ addVariant }) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), plugin(({ addVariant }) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), plugin(({ addVariant }) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])), diff --git a/config/config.exs b/config/config.exs index ce130a022b..a4a17ba942 100644 --- a/config/config.exs +++ b/config/config.exs @@ -20,7 +20,7 @@ config :esbuild, version: "0.17.11", default: [ args: - ~w(js/app.js js/dashboard.tsx js/embed.host.js js/embed.content.js --bundle --target=es2017 --loader:.js=jsx --outdir=../priv/static/js --define:BUILD_EXTRA=true), + ~w(js/app.js js/storybook.js js/dashboard.tsx js/embed.host.js js/embed.content.js --bundle --target=es2017 --loader:.js=jsx --outdir=../priv/static/js --define:BUILD_EXTRA=true), cd: Path.expand("../assets", __DIR__), env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} ] @@ -34,6 +34,14 @@ config :tailwind, --output=../priv/static/css/app.css ), cd: Path.expand("../assets", __DIR__) + ], + storybook: [ + args: ~w( + --config=tailwind.config.js + --input=css/storybook.css + --output=../priv/static/css/storybook.css + ), + cd: Path.expand("../assets", __DIR__) ] config :ua_inspector, diff --git a/config/dev.exs b/config/dev.exs index ecfa88de89..ca0dbec390 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -8,6 +8,7 @@ config :plausible, PlausibleWeb.Endpoint, watchers: [ esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}, tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}, + storybook_tailwind: {Tailwind, :install_and_run, [:storybook, ~w(--watch)]}, npm: ["--prefix", "assets", "run", "typecheck", "--", "--watch", "--preserveWatchOutput"], npm: [ "run", @@ -21,7 +22,8 @@ config :plausible, PlausibleWeb.Endpoint, ], patterns: [ ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$}, - ~r"lib/plausible_web/(controllers|live|components|templates|views|plugs)/.*(ex|heex)$" + ~r"lib/plausible_web/(controllers|live|components|templates|views|plugs)/.*(ex|heex)$", + ~r"storybook/.*(exs)$" ] ] diff --git a/config/runtime.exs b/config/runtime.exs index 93884f0573..17d0f8f0af 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -969,3 +969,5 @@ unless s3_disabled? do exports_bucket: s3_env_value.("S3_EXPORTS_BUCKET"), imports_bucket: s3_env_value.("S3_IMPORTS_BUCKET") end + +config :phoenix_storybook, enabled: env !== "prod" diff --git a/extra/lib/plausible_web/live/funnel_settings.ex b/extra/lib/plausible_web/live/funnel_settings.ex index dffe088663..f45b905fd7 100644 --- a/extra/lib/plausible_web/live/funnel_settings.ex +++ b/extra/lib/plausible_web/live/funnel_settings.ex @@ -48,7 +48,7 @@ defmodule PlausibleWeb.Live.FunnelSettings do <.flash_messages flash={@flash} /> <%= if @setup_funnel? do %> - <%= live_render( + {live_render( @socket, PlausibleWeb.Live.FunnelSettings.Form, id: "funnels-form", @@ -56,7 +56,7 @@ defmodule PlausibleWeb.Live.FunnelSettings do "domain" => @domain, "funnel_id" => @funnel_id } - ) %> + )} <% end %>
= Funnel.min_steps()}> <.live_component diff --git a/extra/lib/plausible_web/live/funnel_settings/form.ex b/extra/lib/plausible_web/live/funnel_settings/form.ex index 1fcd46f1fe..e7d5b0867a 100644 --- a/extra/lib/plausible_web/live/funnel_settings/form.ex +++ b/extra/lib/plausible_web/live/funnel_settings/form.ex @@ -64,7 +64,7 @@ defmodule PlausibleWeb.Live.FunnelSettings.Form do class="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4 mt-8" > <.title class="mb-6"> - <%= if @funnel, do: "Edit", else: "Add" %> Funnel + {if @funnel, do: "Edit", else: "Add"} Funnel <.input @@ -136,7 +136,7 @@ defmodule PlausibleWeb.Live.FunnelSettings.Form do length(@step_ids) > map_size(@selections_made) } > - <%= if @funnel, do: "Update", else: "Add" %> Funnel + {if @funnel, do: "Update", else: "Add"} Funnel
diff --git a/extra/lib/plausible_web/live/funnel_settings/list.ex b/extra/lib/plausible_web/live/funnel_settings/list.ex index ee76732bc8..18958dc16f 100644 --- a/extra/lib/plausible_web/live/funnel_settings/list.ex +++ b/extra/lib/plausible_web/live/funnel_settings/list.ex @@ -22,11 +22,11 @@ defmodule PlausibleWeb.Live.FunnelSettings.List do <.table rows={@funnels}> <:tbody :let={funnel}> <.td truncate> - <%= funnel.name %> + {funnel.name} <.td hide_on_mobile> - <%= funnel.steps_count %>-step funnel + {funnel.steps_count}-step funnel <.td actions> diff --git a/extra/lib/plausible_web/views/help_scout_view.ex b/extra/lib/plausible_web/views/help_scout_view.ex index 8a3b8c1bc2..5c5674b53b 100644 --- a/extra/lib/plausible_web/views/help_scout_view.ex +++ b/extra/lib/plausible_web/views/help_scout_view.ex @@ -17,7 +17,7 @@ defmodule PlausibleWeb.HelpScoutView do <%= if @conn.assigns[:error] do %>

- Failed to get details: <%= @error %> + Failed to get details: {@error}

<% else %>
@@ -25,7 +25,7 @@ defmodule PlausibleWeb.HelpScoutView do Status

- <%= @status_label %> + {@status_label}

@@ -34,13 +34,13 @@ defmodule PlausibleWeb.HelpScoutView do Plan

- <%= @plan_label %> + {@plan_label}

@@ -51,7 +51,7 @@ defmodule PlausibleWeb.HelpScoutView do

- <%= Phoenix.HTML.Format.text_to_html(@notes, escape: true) %> + {PhoenixHTMLHelpers.Format.text_to_html(@notes, escape: true)}
<% end %> @@ -64,7 +64,7 @@ defmodule PlausibleWeb.HelpScoutView do <.layout> <%= if @conn.assigns[:error] do %>

- Failed to run search: <%= @error %> + Failed to run search: {@error}

<% else %>