diff --git a/config/.env.dev b/config/.env.dev index 92b8554569fd..056f3fcb0cf4 100644 --- a/config/.env.dev +++ b/config/.env.dev @@ -29,4 +29,4 @@ S3_ENDPOINT=http://localhost:10000 S3_EXPORTS_BUCKET=dev-exports S3_IMPORTS_BUCKET=dev-imports -VERIFICATION_ENABLED=true +VERIFICATION_ENABLED=false diff --git a/lib/plausible_web/plugs/tracker.ex b/lib/plausible_web/plugs/tracker.ex index cd9a89b4e65e..1f10407c76f9 100644 --- a/lib/plausible_web/plugs/tracker.ex +++ b/lib/plausible_web/plugs/tracker.ex @@ -12,7 +12,8 @@ defmodule PlausibleWeb.Tracker do "file-downloads", "pageview-props", "tagged-events", - "revenue" + "revenue", + "live-view" ] # Generates Power Set of all variants diff --git a/lib/plausible_web/templates/site/snippet.html.heex b/lib/plausible_web/templates/site/snippet.html.heex index 729962354dc7..834959bd209a 100644 --- a/lib/plausible_web/templates/site/snippet.html.heex +++ b/lib/plausible_web/templates/site/snippet.html.heex @@ -20,7 +20,7 @@ id: "snippet_code", class: "transition overflow-hidden bg-gray-100 dark:bg-gray-900 appearance-none border border-transparent rounded w-full p-2 pr-6 text-gray-700 dark:text-gray-300 leading-normal appearance-none focus:outline-none focus:bg-white dark:focus:bg-gray-800 focus:border-gray-400 dark:focus:border-gray-500 text-xs mt-4 resize-none", - value: render_snippet(@site), + value: render_snippet(@site, ["live-view"]), rows: 3, readonly: "readonly" ) %> diff --git a/lib/plausible_web/views/site_view.ex b/lib/plausible_web/views/site_view.ex index a3ae89f77679..df5cccc28764 100644 --- a/lib/plausible_web/views/site_view.ex +++ b/lib/plausible_web/views/site_view.ex @@ -10,11 +10,12 @@ defmodule PlausibleWeb.SiteView do Plausible.Sites.shared_link_url(site, link) end - def render_snippet(site) do - tracker = "#{plausible_url()}/js/script.js" + def render_snippet(site, addons \\ []) do + filename = Enum.join(["script"] ++ addons ++ ["js"], ".") + src = "#{plausible_url()}/js/#{filename}" """ - + """ end diff --git a/mix.exs b/mix.exs index 6c69ef7bb46f..19b023a42717 100644 --- a/mix.exs +++ b/mix.exs @@ -8,7 +8,7 @@ defmodule Plausible.MixProject do docs: docs(), app: :plausible, version: System.get_env("APP_VERSION", "0.0.1"), - elixir: "~> 1.15", + elixir: "~> 1.17", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() in [:prod, :ce], aliases: aliases(), diff --git a/tracker/compile.js b/tracker/compile.js index 5896759cf131..1f2c90dc0ca0 100644 --- a/tracker/compile.js +++ b/tracker/compile.js @@ -26,7 +26,7 @@ function compilefile(input, output, templateVars = {}) { } } -const base_variants = ["hash", "outbound-links", "exclusions", "compat", "local", "manual", "file-downloads", "pageview-props", "tagged-events", "revenue"] +const base_variants = ["hash", "outbound-links", "exclusions", "compat", "local", "manual", "file-downloads", "pageview-props", "tagged-events", "revenue", "live-view"] const variants = [...g.clone.powerSet(base_variants)].filter(a => a.length > 0).map(a => a.sort()); compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.js')) diff --git a/tracker/src/plausible.js b/tracker/src/plausible.js index 7701c5d43d11..7617be9c427d 100644 --- a/tracker/src/plausible.js +++ b/tracker/src/plausible.js @@ -167,4 +167,27 @@ {{#if (any outbound_links file_downloads tagged_events)}} {{> customEvents}} {{/if}} + + {{#if live_view}} + {{#unless manual}} + window.addEventListener('phx:navigate', info => trigger('pageview', {u: info.detail.href})); + {{/unless}} + + ['phx-click', 'phx-change', 'phx-submit', 'phx-viewport-top', 'phx-viewport-bottom', 'phx-mounted', 'phx-connected', 'phx-disconnected'].map((name) => { + window.addEventListener(name, info => trigger('phx-event', {props: {event: name, detail: new URLSearchParams(info.detail || {}).toString()}})); + }); + + // form submit event + window.addEventListener("submit", e => trigger("js-submit", {props: {dom_id: e.target.id, ...Object.fromEntries(new FormData(e.target).entries())}})); + + //track socket activity + if (window.liveSocket) + window.liveSocket.socket.logger = (kind, msg, data) => { + if ((kind === 'push') && !msg.includes("phoenix heartbeat")){ + trigger('phx-push', {props: {msg, ...data}}); + } + } + else + console && console.error("No liveSocket initialized") + {{/if}} })(); diff --git a/tracker/test/fixtures/live-view.html b/tracker/test/fixtures/live-view.html new file mode 100644 index 000000000000..6e6aaabb5b7b --- /dev/null +++ b/tracker/test/fixtures/live-view.html @@ -0,0 +1,20 @@ + + + + + + + Plausible Playwright LiveView tests + + + + + + LiveView-related tests +
+ + + +
+ + diff --git a/tracker/test/live-view.spec.js b/tracker/test/live-view.spec.js new file mode 100644 index 000000000000..d3dd22940f32 --- /dev/null +++ b/tracker/test/live-view.spec.js @@ -0,0 +1,28 @@ +const { mockRequest, expectCustomEvent } = require('./support/test-utils'); +const { expect, test } = require('@playwright/test'); + +test.describe('script.live-view.js', () => { + let plausibleRequestMock; + + test.beforeEach(async ({ page }) => { + plausibleRequestMock = mockRequest(page, '/api/event') + await page.goto('/live-view.html'); + }); + + test('Sends pageview', async ({ page }) => { + await page.evaluate(() => window.dispatchEvent(new CustomEvent("phx:navigate", { detail: { href: "/navigate" } }))) + const request = await plausibleRequestMock; + expect(request.postDataJSON().u).toEqual("/navigate") + expectCustomEvent(request, 'pageview', {}) + }); + + test('Sends phx-event', async ({ page }) => { + await page.evaluate(() => window.liveSocket.socket.logger('push', '_message', { a: 1 })) + expectCustomEvent(await plausibleRequestMock, 'phx-event', { a: 1 }) + }); + + test('Sends submit event', async ({ page }) => { + await (await page.locator("#main-form-btn")).click() + expectCustomEvent(await plausibleRequestMock, 'js-submit', { 'user[name]': "name", dom_id: "main-form" }) + }); +});