From 150169e9b717ee0d53e186a91275a9ae587ae05e Mon Sep 17 00:00:00 2001 From: Cypress Reed Date: Fri, 24 Jul 2026 17:15:02 -0600 Subject: [PATCH 1/3] fix missing page titles and add checks --- apps/dashboard/package.json | 2 +- apps/dashboard/scripts/check-svelte-head.js | 82 +++++++++++++++++++ .../src/lib/components/PageTitle.svelte | 7 ++ apps/dashboard/src/routes/(app)/+error.svelte | 1 + apps/dashboard/src/routes/(app)/+page.svelte | 5 +- .../routes/(app)/admin/emails/+page.svelte | 5 +- .../routes/(app)/admin/features/+page.svelte | 3 + .../routes/(app)/admin/images/+page.svelte | 3 + .../src/routes/(app)/admin/ipam/+page.svelte | 3 + .../(app)/admin/projects/[[id]]/+page.svelte | 5 +- .../(app)/admin/users/[[id]]/+page.svelte | 5 +- .../routes/(app)/admin/vm-types/+page.svelte | 3 + .../(app)/admin/vms/[[id]]/+page.svelte | 5 +- .../(app)/projects/[projectid]/+page.svelte | 6 ++ .../projects/[projectid]/billing/+page.svelte | 7 +- .../[projectid]/colocation/[id]/+page.svelte | 3 + .../colocation/[id]/images/+page.svelte | 3 + .../colocation/[id]/ipmi/+page.svelte | 3 + .../colocation/[id]/networking/+page.svelte | 3 + .../colocation/[id]/sensors/+page.svelte | 3 + .../colocation/[id]/settings/+page.svelte | 3 + .../[projectid]/firewall/+page.svelte | 3 + .../projects/[projectid]/images/+page.svelte | 3 + .../projects/[projectid]/logs/+page.svelte | 3 + .../[projectid]/networking/+page.svelte | 3 + .../[projectid]/servers/+layout.svelte | 6 ++ .../projects/[projectid]/servers/+page.svelte | 3 + .../[projectid]/servers/[id]/+page.svelte | 3 + .../servers/[id]/backups/+page.svelte | 3 + .../servers/[id]/console/+page.svelte | 3 + .../servers/[id]/images/+page.svelte | 3 + .../servers/[id]/logs/+page.svelte | 3 + .../servers/[id]/networking/+page.svelte | 3 + .../servers/[id]/rebuild/+page.svelte | 3 + .../servers/[id]/rescue/+page.svelte | 3 + .../servers/[id]/resize/+page.svelte | 3 + .../servers/[id]/settings/+page.svelte | 3 + .../servers/[id]/snapshots/+page.svelte | 3 + .../[projectid]/servers/create/+page.svelte | 5 +- .../[projectid]/settings/+page.svelte | 5 +- .../projects/[projectid]/volumes/+page.svelte | 3 + .../[invitationId]/+page.svelte | 5 +- .../src/routes/forgot-password/+page.svelte | 5 +- apps/dashboard/src/routes/login/+page.svelte | 5 +- .../login/two-factor/passkey/+page.svelte | 5 +- .../routes/login/two-factor/totp/+page.svelte | 5 +- .../src/routes/register/+page.svelte | 5 +- .../src/routes/reset-password/+page.svelte | 5 +- 48 files changed, 215 insertions(+), 47 deletions(-) create mode 100644 apps/dashboard/scripts/check-svelte-head.js create mode 100644 apps/dashboard/src/lib/components/PageTitle.svelte diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index e6c97a3..35eae44 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -15,7 +15,7 @@ "cf:deploy:preview": "pnpm run build && wrangler deploy --env preview", "email:dev": "bse dev -c src/routes/layout.css", "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --tsgo-experimental-api", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --tsgo-experimental-api && node scripts/check-svelte-head.js", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check .", "format": "prettier --write .", diff --git a/apps/dashboard/scripts/check-svelte-head.js b/apps/dashboard/scripts/check-svelte-head.js new file mode 100644 index 0000000..66d60dc --- /dev/null +++ b/apps/dashboard/scripts/check-svelte-head.js @@ -0,0 +1,82 @@ +#!/usr/bin/env node +import { readdir, readFile } from 'node:fs/promises'; +import { join, relative } from 'node:path'; + +const ROUTES_DIR = new URL('../src/routes', import.meta.url).pathname; +const OPT_OUT_COMMENT = 'check:allow-missing-head'; +const HARD_EXCLUDES = ['src/routes/+layout.svelte']; +const strict = process.argv.includes('--strict'); + +async function* walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + yield* walk(path); + } else if (entry.isFile()) { + yield path; + } + } +} + +async function main() { + const missing = []; + + for await (const filePath of walk(ROUTES_DIR)) { + const fileName = filePath.split('/').pop(); + const projectRelative = relative(join(ROUTES_DIR, '..', '..'), filePath); + + if (HARD_EXCLUDES.some((ex) => projectRelative.endsWith(ex))) { + continue; + } + + let shouldCheck = false; + if (fileName === '+page.svelte' || fileName === '+error.svelte') { + shouldCheck = true; + } + + if (!shouldCheck) { + continue; + } + + const content = await readFile(filePath, 'utf-8'); + if (content.includes('')) { + continue; + } + if (content.includes(' component, a section, or an opt-out comment.' + ); + process.exit(0); + } + + console.error('✗ Missing or in the following route files:\n'); + for (const file of missing) { + console.error(` - ${file}`); + } + console.error( + '\nAdd a component to each file, or add to opt out.' + ); + + if (strict) { + process.exit(1); + } else { + console.error('\n(passing because --strict was not set)'); + process.exit(0); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/apps/dashboard/src/lib/components/PageTitle.svelte b/apps/dashboard/src/lib/components/PageTitle.svelte new file mode 100644 index 0000000..8bc19cd --- /dev/null +++ b/apps/dashboard/src/lib/components/PageTitle.svelte @@ -0,0 +1,7 @@ + + + + {title} / Stack + diff --git a/apps/dashboard/src/routes/(app)/+error.svelte b/apps/dashboard/src/routes/(app)/+error.svelte index e0a0731..ae1d16f 100644 --- a/apps/dashboard/src/routes/(app)/+error.svelte +++ b/apps/dashboard/src/routes/(app)/+error.svelte @@ -3,6 +3,7 @@ import { Button } from '$lib/components/ui/button'; import { goto } from '$app/navigation'; import { resolve } from '$app/paths'; + import PageTitle from '$lib/components/PageTitle.svelte'; const isNotFound = $derived(page.status === 404); const isServerError = $derived(page.status >= 500); diff --git a/apps/dashboard/src/routes/(app)/+page.svelte b/apps/dashboard/src/routes/(app)/+page.svelte index 4fcbeca..24eca31 100644 --- a/apps/dashboard/src/routes/(app)/+page.svelte +++ b/apps/dashboard/src/routes/(app)/+page.svelte @@ -1,6 +1,7 @@ - - Projects / Stack - +
diff --git a/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte b/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte index f065097..5c835e3 100644 --- a/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte +++ b/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte @@ -1,5 +1,6 @@ - - Emails - +
diff --git a/apps/dashboard/src/routes/(app)/admin/features/+page.svelte b/apps/dashboard/src/routes/(app)/admin/features/+page.svelte index 122812a..372bcee 100644 --- a/apps/dashboard/src/routes/(app)/admin/features/+page.svelte +++ b/apps/dashboard/src/routes/(app)/admin/features/+page.svelte @@ -1,5 +1,6 @@ + +
{#if admin.featureFlagError} diff --git a/apps/dashboard/src/routes/(app)/admin/images/+page.svelte b/apps/dashboard/src/routes/(app)/admin/images/+page.svelte index 0eafee9..d883081 100644 --- a/apps/dashboard/src/routes/(app)/admin/images/+page.svelte +++ b/apps/dashboard/src/routes/(app)/admin/images/+page.svelte @@ -1,5 +1,6 @@ + +