diff --git a/db/knex_init_db.js b/db/knex_init_db.js index de9997dd4..46bff4bfa 100644 --- a/db/knex_init_db.js +++ b/db/knex_init_db.js @@ -202,10 +202,7 @@ async function createTables() { table.text("footer_text"); table.text("custom_css"); table.boolean("show_powered_by").notNullable().defaultTo(true); - table.string("analytics_id"); - table.string("analytics_domain_url"); - table.enu("analytics_type", [ "google", "umami", "plausible" ]).defaultTo(null); - + table.string("google_analytics_tag_id"); }); // maintenance_status_page diff --git a/db/knex_migrations/2025-02-17-2142-generalize-analytics.js b/db/knex_migrations/2025-02-17-2142-generalize-analytics.js index e4924feaf..8c5fda990 100644 --- a/db/knex_migrations/2025-02-17-2142-generalize-analytics.js +++ b/db/knex_migrations/2025-02-17-2142-generalize-analytics.js @@ -3,7 +3,7 @@ exports.up = function (knex) { return knex.schema .alterTable("status_page", function (table) { table.renameColumn("google_analytics_tag_id", "analytics_id"); - table.string("analytics_domain_url"); + table.string("analytics_script_url"); table.enu("analytics_type", [ "google", "umami", "plausible", "matomo" ]).defaultTo(null); }).then(() => { @@ -17,7 +17,7 @@ exports.up = function (knex) { exports.down = function (knex) { return knex.schema.alterTable("status_page", function (table) { table.renameColumn("analytics_id", "google_analytics_tag_id"); - table.dropColumn("analytics_domain_url"); + table.dropColumn("analytics_script_url"); table.dropColumn("analytics_type"); }); }; diff --git a/server/analytics/analytics.js b/server/analytics/analytics.js index 79e570b9b..229d463e0 100644 --- a/server/analytics/analytics.js +++ b/server/analytics/analytics.js @@ -14,11 +14,11 @@ function getAnalyticsScript(statusPage) { case "google": return googleAnalytics.getGoogleAnalyticsScript(statusPage.analyticsId); case "umami": - return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId); + return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId); case "plausible": - return plausibleAnalytics.getPlausibleAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId); + return plausibleAnalytics.getPlausibleAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId); case "matomo": - return matomoAnalytics.getMatomoAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId); + return matomoAnalytics.getMatomoAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId); default: return null; } @@ -36,7 +36,7 @@ function isValidAnalyticsConfig(statusPage) { case "umami": case "plausible": case "matomo": - return statusPage.analyticsId != null && statusPage.analyticsDomainUrl != null; + return statusPage.analyticsId != null && statusPage.analyticsScriptUrl != null; default: return false; } diff --git a/server/analytics/plausible-analytics.js b/server/analytics/plausible-analytics.js index 14df98115..131f1136b 100644 --- a/server/analytics/plausible-analytics.js +++ b/server/analytics/plausible-analytics.js @@ -4,16 +4,16 @@ const { escape } = require("html-escaper"); /** * Returns a string that represents the javascript that is required to insert the Plausible Analytics script * into a webpage. - * @param {string} plausibleDomainUrl Domain name with tld to use with the Plausible Analytics script. + * @param {string} scriptUrl the Plausible Analytics script url. * @param {string} domainsToMonitor Domains to track seperated by a ',' to add Plausible Analytics script. * @returns {string} HTML script tags to inject into page */ -function getPlausibleAnalyticsScript(plausibleDomainUrl, domainsToMonitor) { - let escapedDomainUrlJS = jsesc(plausibleDomainUrl, { isScriptContext: true }); +function getPlausibleAnalyticsScript(scriptUrl, domainsToMonitor) { + let escapedScriptUrlJS = jsesc(scriptUrl, { isScriptContext: true }); let escapedWebsiteIdJS = jsesc(domainsToMonitor, { isScriptContext: true }); - if (escapedDomainUrlJS) { - escapedDomainUrlJS = escapedDomainUrlJS.trim(); + if (escapedScriptUrlJS) { + escapedScriptUrlJS = escapedScriptUrlJS.trim(); } if (escapedWebsiteIdJS) { @@ -21,13 +21,13 @@ function getPlausibleAnalyticsScript(plausibleDomainUrl, domainsToMonitor) { } // Escape the domain url for use in an HTML attribute. - let escapedDomainUrlHTMLAttribute = escape(escapedDomainUrlJS); + let escapedScriptUrlHTMLAttribute = escape(escapedScriptUrlJS); // Escape the website id for use in an HTML attribute. let escapedWebsiteIdHTMLAttribute = escape(escapedWebsiteIdJS); return ` - + `; } diff --git a/server/analytics/umami-analytics.js b/server/analytics/umami-analytics.js index 5a4a172f9..48c8b2eca 100644 --- a/server/analytics/umami-analytics.js +++ b/server/analytics/umami-analytics.js @@ -4,30 +4,30 @@ const { escape } = require("html-escaper"); /** * Returns a string that represents the javascript that is required to insert the Umami Analytics script * into a webpage. - * @param {string} domainUrl Domain name with tld to use with the Umami Analytics script. + * @param {string} scriptUrl the Umami Analytics script url. * @param {string} websiteId Website ID to use with the Umami Analytics script. * @returns {string} HTML script tags to inject into page */ -function getUmamiAnalyticsScript(domainUrl, websiteId) { - let escapedDomainUrlJS = jsesc(domainUrl, { isScriptContext: true }); +function getUmamiAnalyticsScript(scriptUrl, websiteId) { + let escapedScriptUrlJS = jsesc(scriptUrl, { isScriptContext: true }); let escapedWebsiteIdJS = jsesc(websiteId, { isScriptContext: true }); - if (escapedDomainUrlJS) { - escapedDomainUrlJS = escapedDomainUrlJS.trim(); + if (escapedScriptUrlJS) { + escapedScriptUrlJS = escapedScriptUrlJS.trim(); } if (escapedWebsiteIdJS) { escapedWebsiteIdJS = escapedWebsiteIdJS.trim(); } - // Escape the domain url for use in an HTML attribute. - let escapedDomainUrlHTMLAttribute = escape(escapedDomainUrlJS); + // Escape the Script url for use in an HTML attribute. + let escapedScriptUrlHTMLAttribute = escape(escapedScriptUrlJS); // Escape the website id for use in an HTML attribute. let escapedWebsiteIdHTMLAttribute = escape(escapedWebsiteIdJS); return ` - + `; } diff --git a/server/model/status_page.js b/server/model/status_page.js index 32188ffaa..f4af41cfb 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -408,7 +408,7 @@ class StatusPage extends BeanModel { footerText: this.footer_text, showPoweredBy: !!this.show_powered_by, analyticsId: this.analytics_id, - analyticsDomainUrl: this.analytics_domain_url, + analyticsScriptUrl: this.analytics_script_url, analyticsType: this.analytics_type, showCertificateExpiry: !!this.show_certificate_expiry, }; @@ -433,7 +433,7 @@ class StatusPage extends BeanModel { footerText: this.footer_text, showPoweredBy: !!this.show_powered_by, analyticsId: this.analytics_id, - analyticsDomainUrl: this.analytics_domain_url, + analyticsScriptUrl: this.analytics_script_url, analyticsType: this.analytics_type, showCertificateExpiry: !!this.show_certificate_expiry, }; diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index 60957d49d..5d0320e10 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -167,7 +167,7 @@ module.exports.statusPageSocketHandler = (socket) => { statusPage.show_certificate_expiry = config.showCertificateExpiry; statusPage.modified_date = R.isoDateTime(); statusPage.analytics_id = config.analyticsId; - statusPage.analytics_domain_url = config.analyticsDomainUrl; + statusPage.analytics_script_url = config.analyticsScriptUrl; statusPage.analytics_type = config.analyticsType; await R.store(statusPage); diff --git a/src/lang/en.json b/src/lang/en.json index 94deb0a81..333e9e56f 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -789,9 +789,7 @@ "Google Analytics ID": "Google Analytics ID", "Analytics Type": "Analytics Type", "Analytics ID": "Analytics ID", - "Analytics Domain URL": "Analytics Domain URL", - "Umami Analytics Domain Url": "Umami Analytics Domain Url", - "Umami Analytics Website ID": "Umami Analytics Website ID", + "Analytics Script URL": "Analytics Script URL", "Edit Tag": "Edit Tag", "Server Address": "Server Address", "Learn More": "Learn More", @@ -1072,5 +1070,9 @@ "YZJ Robot Token": "YZJ Robot token", "Plain Text": "Plain Text", "Message Template": "Message Template", - "Template Format": "Template Format" + "Template Format": "Template Format", + "Google": "Google", + "Plausible": "Plausible", + "Matomo": "Matomo", + "Umami": "Umami" } diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index 8a35fef60..78e592b36 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -124,19 +124,19 @@ const analyticsOptions = [ -
+
-
- - +
+ +
diff --git a/test/e2e/specs/status-page.spec.js b/test/e2e/specs/status-page.spec.js index e75f3c993..b5c92578b 100644 --- a/test/e2e/specs/status-page.spec.js +++ b/test/e2e/specs/status-page.spec.js @@ -18,11 +18,11 @@ test.describe("Status Page", () => { const refreshInterval = 30; const theme = "dark"; const googleAnalyticsId = "G-123"; - const umamiAnalyticsDomainUrl = "example.com"; + const umamiAnalyticsScriptUrl = "https://umami.example.com/script.js"; const umamiAnalyticsWebsiteId = "606487e2-bc25-45f9-9132-fa8b065aad46"; - const plausibleAnalyticsDomainUrl = "example.com"; + const plausibleAnalyticsScriptUrl = "https://plausible.example.com/js/script.js"; const plausibleAnalyticsDomainsUrls = "one.com,two.com"; - const matomoUrl = "matomo.com"; + const matomoUrl = "https://matomoto.example.com"; const matomoSiteId = "123456789"; const customCss = "body { background: rgb(0, 128, 128) !important; }"; const descriptionText = "This is an example status page."; @@ -124,7 +124,7 @@ test.describe("Status Page", () => { // Fill in umami analytics after editing await page.getByTestId("analytics-type-select").selectOption("umami"); - await page.getByTestId("analytics-domain-url-input").fill(umamiAnalyticsDomainUrl); + await page.getByTestId("analytics-script-url-input").fill(umamiAnalyticsScriptUrl); await page.getByTestId("analytics-id-input").fill(umamiAnalyticsWebsiteId); await page.getByTestId("save-button").click(); @@ -134,23 +134,23 @@ test.describe("Status Page", () => { await screenshot(testInfo, page); - expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsDomainUrl); + expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsScriptUrl); expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsWebsiteId); await page.getByTestId("edit-button").click(); // Fill in plausible analytics after editing await page.getByTestId("analytics-type-select").selectOption("plausible"); - await page.getByTestId("analytics-domain-url-input").fill(plausibleAnalyticsDomainUrl); + await page.getByTestId("analytics-script-url-input").fill(plausibleAnalyticsScriptUrl); await page.getByTestId("analytics-id-input").fill(plausibleAnalyticsDomainsUrls); await page.getByTestId("save-button").click(); await screenshot(testInfo, page); - expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainUrl); + expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsScriptUrl); expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainsUrls); await page.getByTestId("edit-button").click(); // Fill in matomo analytics after editing await page.getByTestId("analytics-type-select").selectOption("matomo"); - await page.getByTestId("analytics-domain-url-input").fill(matomoUrl); + await page.getByTestId("analytics-script-url-input").fill(matomoUrl); await page.getByTestId("analytics-id-input").fill(matomoSiteId); await page.getByTestId("save-button").click(); await screenshot(testInfo, page);