diff --git a/packages/analytics/README.md b/packages/analytics/README.md index 35a7b95..5104d56 100644 --- a/packages/analytics/README.md +++ b/packages/analytics/README.md @@ -11,11 +11,23 @@ entry that earned them rather than to a URL string. > and an Analytics panel in the entry editor. Tested on EmDash 0.39 and 0.40. > See "Not in this version". +The screenshots show demo data on a site made from EmDash's blog template. + +## The dashboard widget + +A **Traffic** card on the dashboard: visits and page views for the last +seven days against the week before, the five most viewed pages with the +entry they belong to, and when the numbers were last synced. + +The Traffic widget: visits and page views for the last 7 days with their change against the previous week, and the five most viewed pages with entry title, path and views + ## The Analytics page **Plugins → Analytics** in the admin sidebar, or "Open analytics" on the dashboard widget. Editors and admins see it. +The Analytics page over 30 days: visits and page views with their change, a daily chart, top entries with collection, path, views and visits, and tables of referrers and countries + The page asks the provider live on every load, so it has numbers from the first minute after setup; it does not wait for the sync. It only ever asks for the days the provider still counts exactly (for Cloudflare, the last @@ -55,9 +67,14 @@ views, so the right one can be copied into the settings. The check only reads; values are entered in the plugin's settings form. It makes one request to Cloudflare. +The setup check with every row OK: data source, site URL, content index with 8 entries matched, scheduled sync and last sync + ## Analytics per entry **Plugins → Analytics per entry**, or "Per entry" on the Analytics page. + +Analytics per entry: every published entry with its collection, path, page views over 7 and 30 days and publish date, most viewed first + Every published entry with its page views over the last 7 and 30 days, today included, by collection or across all of them. Click a column header to sort; sorting ascending puts the entries nobody visited first, which @@ -84,6 +101,8 @@ URL. ## The editor panel +The Analytics panel in the entry editor: page views over the last 7 and 30 days and the path they are counted at + In the entry editor, the **Analytics** panel shows that entry's 7- and 30-day page views and the path they are counted at, and on a translated entry each language's numbers and their total. An entry that is not published @@ -97,6 +116,7 @@ at a public URL says so instead. | A Cloudflare account | with Web Analytics enabled for the site | | An API token | permission **Account → Account Analytics → Read** | | `EMDASH_ENCRYPTION_KEY` | set on the site, or the API token cannot be stored (`npx emdash secrets generate`) | +| URL patterns | each collection needs a **URL Pattern** (under Content Types), or no page can be matched to its entry. Sites made from EmDash's blog template start without them; the setup check says so | | Scheduled tasks | the sync runs as a plugin cron task. On Cloudflare Workers that needs the Cron Trigger and `scheduled` handler from EmDash's Cloudflare deployment guide; on Node, EmDash runs them itself | ### The token scope, precisely diff --git a/packages/analytics/emdash-plugin.jsonc b/packages/analytics/emdash-plugin.jsonc index 73b7a53..49b36ff 100644 --- a/packages/analytics/emdash-plugin.jsonc +++ b/packages/analytics/emdash-plugin.jsonc @@ -16,7 +16,16 @@ // break. The manifest has no advisory "tested up to" field to express // caution without blocking, so the tested range belongs in the README. "release": { - "requires": { "env:emdash": ">=0.39.0" } + "requires": { "env:emdash": ">=0.39.0" }, + "artifacts": { + "screenshots": [ + { "file": "screenshots/analytics-page.png", "lang": "en" }, + { "file": "screenshots/per-entry.png", "lang": "en" }, + { "file": "screenshots/widget.png", "lang": "en" }, + { "file": "screenshots/editor-panel.png", "lang": "en" }, + { "file": "screenshots/setup-check.png", "lang": "en" } + ] + } }, // Registry search indexes slug and description and has no keywords // field, so every provider this plugin supports has to be named here. diff --git a/packages/analytics/screenshots/analytics-page.png b/packages/analytics/screenshots/analytics-page.png new file mode 100644 index 0000000..8a9e0c6 Binary files /dev/null and b/packages/analytics/screenshots/analytics-page.png differ diff --git a/packages/analytics/screenshots/editor-panel.png b/packages/analytics/screenshots/editor-panel.png new file mode 100644 index 0000000..ae752c7 Binary files /dev/null and b/packages/analytics/screenshots/editor-panel.png differ diff --git a/packages/analytics/screenshots/per-entry.png b/packages/analytics/screenshots/per-entry.png new file mode 100644 index 0000000..893d606 Binary files /dev/null and b/packages/analytics/screenshots/per-entry.png differ diff --git a/packages/analytics/screenshots/setup-check.png b/packages/analytics/screenshots/setup-check.png new file mode 100644 index 0000000..137dbc9 Binary files /dev/null and b/packages/analytics/screenshots/setup-check.png differ diff --git a/packages/analytics/screenshots/widget.png b/packages/analytics/screenshots/widget.png new file mode 100644 index 0000000..d642e8d Binary files /dev/null and b/packages/analytics/screenshots/widget.png differ diff --git a/packages/analytics/src/i18n.ts b/packages/analytics/src/i18n.ts index 442d9e8..c26cd45 100644 --- a/packages/analytics/src/i18n.ts +++ b/packages/analytics/src/i18n.ts @@ -69,7 +69,7 @@ const en = { noEntriesYet: "No entries yet", noEntriesIndexing: "The content index is still being built. Entries appear as it progresses.", noEntriesNoUrls: - "No published entry has a public URL. Check that the site URL is set in EmDash and that the collections have URL patterns.", + "No published entry has a public URL. Check that the site URL is set in EmDash and that each collection has a URL Pattern (under Content Types), then press Rebuild index on the per-entry page.", noEntriesHere: "No published entries here.", panelNoPage: "No page for this entry yet", panelNoPageDetail: "Views appear once the entry is published at a public URL and the next sync has run.", @@ -123,7 +123,7 @@ const en = { hostsNone: "Cloudflare reports this site tag under {reported}, but the plugin counts only {counted}. Change Hostnames to count in the plugin's settings.", siteUrlMissing: - "EmDash has no site URL stored, so entries have no public address and page views cannot be matched to them. EmDash stores it (the emdash:site_url option) when the setup wizard runs on the live domain.", + "EmDash has no site URL, so entries have no public address and page views cannot be matched to them. EmDash stores it (the emdash:site_url option) when the setup wizard runs on the live domain; a server that was already running picks it up after a restart.", needsSiteUrl: "Needs the site URL.", indexMatched: { one: "{count} entry matched to its page.", other: "{count} entries matched to their pages." }, schedulerNotScheduled: "The sync is not scheduled yet. Opening the dashboard schedules it.", @@ -254,7 +254,7 @@ const de: Record = { noEntriesYet: "Noch keine Einträge", noEntriesIndexing: "Der Inhaltsindex wird noch aufgebaut. Einträge erscheinen nach und nach.", noEntriesNoUrls: - "Kein veröffentlichter Eintrag hat eine öffentliche URL. Prüfe, ob die URL der Webseite in EmDash eingetragen ist und die Kollektionen URL-Muster haben.", + "Kein veröffentlichter Eintrag hat eine öffentliche URL. Prüfe, ob die URL der Website in EmDash eingetragen ist und jede Kollektion ein URL-Muster hat (unter Inhaltstypen), und drücke dann „Index neu aufbauen“ auf der Seite pro Eintrag.", noEntriesHere: "Hier gibt es keine veröffentlichten Einträge.", panelNoPage: "Noch keine Seite für diesen Eintrag", panelNoPageDetail: @@ -310,7 +310,7 @@ const de: Record = { hostsNone: "Cloudflare meldet dieses Site-Tag unter {reported}, das Plugin zählt aber nur {counted}. Ändere Hostnames to count in den Einstellungen des Plugins.", siteUrlMissing: - "EmDash hat keine Website-URL gespeichert, deshalb haben Einträge keine öffentliche Adresse und Seitenaufrufe lassen sich ihnen nicht zuordnen. EmDash speichert sie (die Option emdash:site_url), wenn der Einrichtungsassistent auf der Live-Domain läuft.", + "EmDash hat keine Website-URL, deshalb haben Einträge keine öffentliche Adresse und Seitenaufrufe lassen sich ihnen nicht zuordnen. EmDash speichert sie (die Option emdash:site_url), wenn der Einrichtungsassistent auf der Live-Domain läuft; ein Server, der da schon lief, übernimmt sie nach einem Neustart.", needsSiteUrl: "Braucht die Website-URL.", indexMatched: { one: "{count} Eintrag ist seiner Seite zugeordnet.", diff --git a/packages/analytics/tests/setup.test.ts b/packages/analytics/tests/setup.test.ts index b599ba9..d105aba 100644 --- a/packages/analytics/tests/setup.test.ts +++ b/packages/analytics/tests/setup.test.ts @@ -129,7 +129,10 @@ describe("each failure, with the sentence that names its fix", () => { it("a finished index that matched nothing although the URL is set", () => { const facts = { ...healthy(), state: { ...healthy().state, indexed: 0 } }; - expect(check(facts, "index")).toMatchObject({ status: "problem", detail: expect.stringMatching(/URL patterns/) }); + expect(check(facts, "index")).toMatchObject({ + status: "problem", + detail: expect.stringMatching(/URL Pattern \(under Content Types\), then press Rebuild index/), + }); }); it("a host without a scheduler", () => {