chore: cleanup and refactoring

This commit is contained in:
hadestructhor 2025-02-18 00:45:53 +01:00
parent afae736972
commit e44ec55eda
9 changed files with 91 additions and 43 deletions

View file

@ -202,9 +202,10 @@ async function createTables() {
table.text("footer_text"); table.text("footer_text");
table.text("custom_css"); table.text("custom_css");
table.boolean("show_powered_by").notNullable().defaultTo(true); table.boolean("show_powered_by").notNullable().defaultTo(true);
table.string("google_analytics_tag_id"); table.string("analytics_id");
table.string("umami_analytics_domain_url"); table.string("analytics_domain_url");
table.string("umami_analytics_website_id"); table.enu("analytics_type", [ "google", "umami", "plausible" ]).defaultTo(null);
}); });
// maintenance_status_page // maintenance_status_page

View file

@ -0,0 +1,23 @@
// Udpate status_page table to generalize analytics fields
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.enu("analytics_type", [ "google", "umami", "plausible" ]).defaultTo(null);
}).then(() => {
// After a succesful migration, add google as default for previous pages
knex("status_page").whereNotNull("analytics_id").update({
"analytics_type": "google",
});
});
};
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_type");
});
};

View file

@ -1,10 +0,0 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE status_page
ADD umami_analytics_domain_url VARCHAR;
ALTER TABLE status_page
ADD umami_analytics_website_id VARCHAR;
COMMIT;

View file

@ -95,7 +95,6 @@ class Database {
"patch-maintenance-table2.sql": true, "patch-maintenance-table2.sql": true,
"patch-add-gamedig-monitor.sql": true, "patch-add-gamedig-monitor.sql": true,
"patch-add-google-analytics-status-page-tag.sql": true, "patch-add-google-analytics-status-page-tag.sql": true,
"patch-add-umami-analytics-status-page.sql": true,
"patch-http-body-encoding.sql": true, "patch-http-body-encoding.sql": true,
"patch-add-description-monitor.sql": true, "patch-add-description-monitor.sql": true,
"patch-api-key-table.sql": true, "patch-api-key-table.sql": true,

View file

@ -121,13 +121,13 @@ class StatusPage extends BeanModel {
const head = $("head"); const head = $("head");
if (statusPage.googleAnalyticsTagId) { if (statusPage.analyticsType === "google" && statusPage.analyticsId) {
let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId); let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.analyticsId);
head.append($(escapedGoogleAnalyticsScript)); head.append($(escapedGoogleAnalyticsScript));
} }
if (statusPage.umamiAnalyticsDomainUrl && statusPage.umamiAnalyticsWebsiteId) { if (statusPage.analyticsType === "umami" && statusPage.analyticsDomainUrl && statusPage.analyticsId) {
let escapedUmamiAnalyticsScript = umamiAnalytics.getUmamiAnalyticsScript(statusPage.umamiAnalyticsDomainUrl, statusPage.umamiAnalyticsWebsiteId); let escapedUmamiAnalyticsScript = umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
head.append($(escapedUmamiAnalyticsScript)); head.append($(escapedUmamiAnalyticsScript));
} }
@ -413,9 +413,9 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css, customCSS: this.custom_css,
footerText: this.footer_text, footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by, showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id, analyticsId: this.analytics_id,
umamiAnalyticsDomainUrl: this.umami_analytics_domain_url, analyticsDomainUrl: this.analytics_domain_url,
umamiAnalyticsWebsiteId: this.umami_analytics_website_id, analyticsType: this.analytics_type,
showCertificateExpiry: !!this.show_certificate_expiry, showCertificateExpiry: !!this.show_certificate_expiry,
}; };
} }
@ -438,9 +438,9 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css, customCSS: this.custom_css,
footerText: this.footer_text, footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by, showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id, analyticsId: this.analytics_id,
umamiAnalyticsDomainUrl: this.umami_analytics_domain_url, analyticsDomainUrl: this.analytics_domain_url,
umamiAnalyticsWebsiteId: this.umami_analytics_website_id, analyticsType: this.analytics_type,
showCertificateExpiry: !!this.show_certificate_expiry, showCertificateExpiry: !!this.show_certificate_expiry,
}; };
} }

View file

@ -166,9 +166,9 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.show_powered_by = config.showPoweredBy; statusPage.show_powered_by = config.showPoweredBy;
statusPage.show_certificate_expiry = config.showCertificateExpiry; statusPage.show_certificate_expiry = config.showCertificateExpiry;
statusPage.modified_date = R.isoDateTime(); statusPage.modified_date = R.isoDateTime();
statusPage.google_analytics_tag_id = config.googleAnalyticsId; statusPage.analytics_id = config.analyticsId;
statusPage.umami_analytics_domain_url = config.umamiAnalyticsDomainUrl; statusPage.analytics_domain_url = config.analyticsDomainUrl;
statusPage.umami_analytics_website_id = config.umamiAnalyticsWebsiteId; statusPage.analytics_type = config.analyticsType;
await R.store(statusPage); await R.store(statusPage);

View file

@ -782,6 +782,9 @@
"wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .", "wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .",
"Custom Monitor Type": "Custom Monitor Type", "Custom Monitor Type": "Custom Monitor Type",
"Google Analytics ID": "Google Analytics ID", "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 Domain Url": "Umami Analytics Domain Url",
"Umami Analytics Website ID": "Umami Analytics Website ID", "Umami Analytics Website ID": "Umami Analytics Website ID",
"Edit Tag": "Edit Tag", "Edit Tag": "Edit Tag",

View file

@ -1,3 +1,25 @@
<script setup>
// Analytics options
const analyticsOptions = [
{
name: "None",
value: null
},
{
name: "Google",
value: "google"
},
{
name: "Umami",
value: "umami"
},
{
name: "Plausible",
value: "plausible"
}
];
</script>
<template> <template>
<div v-if="loadedTheme" class="container mt-3"> <div v-if="loadedTheme" class="container mt-3">
<!-- Sidebar for edit mode --> <!-- Sidebar for edit mode -->
@ -92,20 +114,25 @@
</ul> </ul>
</div> </div>
<!-- Google Analytics --> <!-- Analytics -->
<div class="my-3"> <div class="my-3">
<label for="googleAnalyticsTag" class="form-label">{{ $t("Google Analytics ID") }}</label> <label for="analyticsType" class="form-label">{{ $t("Analytics Type") }}</label>
<input id="googleAnalyticsTag" v-model="config.googleAnalyticsId" type="text" class="form-control" data-testid="google-analytics-input"> <select id="analyticsType" v-model="config.analyticsType" class="form-select" data-testid="analytics-type-select">
<option v-for="(analyticOption, index) in analyticsOptions" :key="index" :value="analyticOption.value">
{{ analyticOption.name }}
</option>
</select>
</div> </div>
<!-- Umami Analytics --> <div v-if="config.analyticsType !== null && config.analyticsType !== undefined" class="my-3">
<div class="my-3"> <label for="analyticsId" class="form-label">{{ $t("Analytics ID") }}</label>
<label for="umamiAnalyticsDomainUrl" class="form-label">{{ $t("Umami Analytics Domain Url") }}</label> <input id="analyticsId" v-model="config.analyticsId" type="text" class="form-control" data-testid="analytics-id-input">
<input id="umamiAnalyticsDomainUrl" v-model="config.umamiAnalyticsDomainUrl" type="text" class="form-control" data-testid="umami-analytics-domain-url-input">
</div> </div>
<div class="my-3">
<label for="umamiAnalyticsWebsite" class="form-label">{{ $t("Umami Analytics Website ID") }}</label> <div v-if="config.analyticsType !== null && config.analyticsType !== undefined && config.analyticsType !== 'google'" class="my-3">
<input id="umamiAnalyticsWebsite" v-model="config.umamiAnalyticsWebsiteId" type="text" class="form-control" data-testid="umami-analytics-website-id-input"> <label for="analyticsDomainUrl" class="form-label">{{ $t("Analytics Domain URL") }}</label>
<input id="analyticsDomainUrl" v-model="config.analyticsDomainUrl" type="text" class="form-control" data-testid="analytics-domain-url-input">
</div> </div>
<!-- Custom CSS --> <!-- Custom CSS -->

View file

@ -59,9 +59,8 @@ test.describe("Status Page", () => {
await page.getByTestId("show-tags-checkbox").uncheck(); await page.getByTestId("show-tags-checkbox").uncheck();
await page.getByTestId("show-powered-by-checkbox").uncheck(); await page.getByTestId("show-powered-by-checkbox").uncheck();
await page.getByTestId("show-certificate-expiry-checkbox").uncheck(); await page.getByTestId("show-certificate-expiry-checkbox").uncheck();
await page.getByTestId("google-analytics-input").fill(googleAnalyticsId); await page.getByTestId("analytics-type-select").selectOption("google");
await page.getByTestId("umami-analytics-domain-url-input").fill(umamiAnalyticsDomainUrl); await page.getByTestId("analytics-id-input").fill(googleAnalyticsId);
await page.getByTestId("umami-analytics-website-id-input").fill(umamiAnalyticsWebsiteId);
await page.getByTestId("custom-css-input").getByTestId("textarea").fill(customCss); // Prism await page.getByTestId("custom-css-input").getByTestId("textarea").fill(customCss); // Prism
await expect(page.getByTestId("description-editable")).toHaveText(descriptionText); await expect(page.getByTestId("description-editable")).toHaveText(descriptionText);
await expect(page.getByTestId("custom-footer-editable")).toHaveText(footerText); await expect(page.getByTestId("custom-footer-editable")).toHaveText(footerText);
@ -104,14 +103,12 @@ test.describe("Status Page", () => {
expect(updateCountdown).toBeLessThanOrEqual(refreshInterval + 10); expect(updateCountdown).toBeLessThanOrEqual(refreshInterval + 10);
await expect(page.locator("body")).toHaveClass(theme); await expect(page.locator("body")).toHaveClass(theme);
expect(await page.locator("head").innerHTML()).toContain(googleAnalyticsId);
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsDomainUrl);
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsWebsiteId);
const backgroundColor = await page.evaluate(() => window.getComputedStyle(document.body).backgroundColor); const backgroundColor = await page.evaluate(() => window.getComputedStyle(document.body).backgroundColor);
expect(backgroundColor).toEqual("rgb(0, 128, 128)"); expect(backgroundColor).toEqual("rgb(0, 128, 128)");
await screenshot(testInfo, page); await screenshot(testInfo, page);
expect(await page.locator("head").innerHTML()).toContain(googleAnalyticsId);
// Flip the "Show Tags" and "Show Powered By" switches: // Flip the "Show Tags" and "Show Powered By" switches:
await page.getByTestId("edit-button").click(); await page.getByTestId("edit-button").click();
@ -120,6 +117,11 @@ test.describe("Status Page", () => {
await page.getByTestId("show-powered-by-checkbox").setChecked(true); await page.getByTestId("show-powered-by-checkbox").setChecked(true);
await screenshot(testInfo, page); await screenshot(testInfo, 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-id-input").fill(umamiAnalyticsWebsiteId);
await page.getByTestId("save-button").click(); await page.getByTestId("save-button").click();
await expect(page.getByTestId("edit-sidebar")).toHaveCount(0); await expect(page.getByTestId("edit-sidebar")).toHaveCount(0);
@ -127,6 +129,9 @@ test.describe("Status Page", () => {
await expect(page.getByTestId("monitor-tag")).toContainText(tagValue); await expect(page.getByTestId("monitor-tag")).toContainText(tagValue);
await screenshot(testInfo, page); await screenshot(testInfo, page);
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsDomainUrl);
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsWebsiteId);
}); });
// @todo Test certificate expiry // @todo Test certificate expiry