Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 .",
Expand Down
82 changes: 82 additions & 0 deletions apps/dashboard/scripts/check-svelte-head.js
Original file line number Diff line number Diff line change
@@ -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('<svelte:head>')) {
continue;
}
if (content.includes('<PageTitle')) {
continue;
}
if (content.includes(OPT_OUT_COMMENT)) {
continue;
}

missing.push(projectRelative);
}

if (missing.length === 0) {
console.log(
'✓ All routes have a <PageTitle> component, a <svelte:head> section, or an opt-out comment.'
);
process.exit(0);
}

console.error('✗ Missing <PageTitle> or <svelte:head> in the following route files:\n');
for (const file of missing) {
console.error(` - ${file}`);
}
console.error(
'\nAdd a <PageTitle> component to each file, or add <!-- check:allow-missing-head --> 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);
});
10 changes: 10 additions & 0 deletions apps/dashboard/src/lib/components/PageTitle.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
let { title }: { title: string } = $props();

const MAX_LEN = 40;
const formatted = $derived(title.length > MAX_LEN ? title.slice(0, MAX_LEN - 1) + '…' : title);
</script>

<svelte:head>
<title>{formatted} / Stack</title>
</svelte:head>
1 change: 1 addition & 0 deletions apps/dashboard/src/routes/(app)/+error.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/src/routes/(app)/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { goto, invalidate } from '$app/navigation';
import { authClient } from '$lib/auth-client';
import PageTitle from '$lib/components/PageTitle.svelte';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import * as Dialog from '$lib/components/ui/dialog';
import { Button } from '$lib/components/ui/button';
Expand Down Expand Up @@ -108,9 +109,7 @@
}
</script>

<svelte:head>
<title>Projects / Stack</title>
</svelte:head>
<PageTitle title="Projects" />

<div class="flex min-h-0 flex-1 flex-col overflow-auto bg-background/30">
<div class="mx-auto flex w-full max-w-7xl flex-1 flex-col px-6 py-8 sm:px-8 lg:px-10">
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/src/routes/(app)/admin/emails/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount, untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
Expand Down Expand Up @@ -336,9 +337,7 @@
}
</script>

<svelte:head>
<title>Emails</title>
</svelte:head>
<PageTitle title="Emails" />

<div class="flex-1 overflow-auto">
<div class="mx-auto flex w-full max-w-3xl flex-col gap-6 p-5">
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/src/routes/(app)/admin/features/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import {
featureFlagKeys,
featureFlagLabels,
Expand Down Expand Up @@ -68,6 +69,8 @@
}
</script>

<PageTitle title="Features" />

<div class="flex-1 overflow-auto">
<div class="flex flex-col gap-5 p-5">
{#if admin.featureFlagError}
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/src/routes/(app)/admin/images/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { Button } from '$lib/components/ui/button';
import { Badge } from '$lib/components/ui/badge';
import { Input } from '$lib/components/ui/input';
Expand Down Expand Up @@ -79,6 +80,8 @@
);
</script>

<PageTitle title="Images" />

<div class="flex-1 overflow-auto">
<div class="flex items-center justify-end gap-2 border-b border-border/60 px-5 py-2">
<Button
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/src/routes/(app)/admin/ipam/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { invalidate } from '$app/navigation';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
Expand Down Expand Up @@ -157,6 +158,8 @@
}
</script>

<PageTitle title="IPAM" />

<div class="flex-1 overflow-auto">
<div class="flex items-center gap-4 border-b border-border/60 px-5 py-3">
<div class="flex items-center gap-2 text-xs text-muted-foreground">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { goto, invalidate } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/state';
Expand Down Expand Up @@ -438,9 +439,7 @@
}
</script>

<svelte:head>
<title>Projects</title>
</svelte:head>
<PageTitle title="Projects" />

{#snippet projectDetail(project: AdminProject)}
{@const vmsForProject = projectVms(project.id)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/state';
Expand Down Expand Up @@ -281,9 +282,7 @@
}
</script>

<svelte:head>
<title>Users</title>
</svelte:head>
<PageTitle title="Users" />

<div class="flex-1 overflow-auto">
<div class="flex flex-col gap-5 p-5">
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/src/routes/(app)/admin/vm-types/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { untrack } from 'svelte';
import PageTitle from '$lib/components/PageTitle.svelte';
import { Button } from '$lib/components/ui/button';
import { Badge } from '$lib/components/ui/badge';
import { Input } from '$lib/components/ui/input';
Expand Down Expand Up @@ -60,6 +61,8 @@
}
</script>

<PageTitle title="VM Types" />

<div class="flex-1 overflow-auto">
<div class="flex items-center justify-end border-b border-border/60 px-5 py-2">
<Button size="sm" class="h-7 gap-1.5 text-xs" onclick={() => admin.vtOpenCreate()}>
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/src/routes/(app)/admin/vms/[[id]]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import PageTitle from '$lib/components/PageTitle.svelte';
import { resolve } from '$app/paths';
import { page } from '$app/state';
import { Button } from '$lib/components/ui/button';
Expand Down Expand Up @@ -184,9 +185,7 @@
}
</script>

<svelte:head>
<title>VMs</title>
</svelte:head>
<PageTitle title="VMs" />

<div class="flex-1 overflow-auto">
<div class="flex flex-col gap-5 p-5">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
</script>

<PageTitle title="Dashboard" />

<div class="flex h-full items-center justify-center">
<p class="text-sm text-muted-foreground">Redirecting to servers...</p>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import BillingSetupDialog from '$lib/components/billing-setup-dialog.svelte';
import { openBillingPortal } from '$lib/remote/billing.remote';
import { getErrorMessage } from '$lib/utils';
Expand Down Expand Up @@ -133,11 +134,9 @@
}
</script>

<svelte:head>
<title>Billing / Stack</title>
</svelte:head>
<PageTitle title="Billing" />

<div class="flex flex-1 flex-col overflow-hidden">
<div class="flex flex-1 flex-col overflow-auto">
<BillingSetupDialog
bind:open={billingSetupOpen}
{projectId}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import { getColocationContext } from '../colocation-context.svelte';

const colo = getColocationContext();
Expand Down Expand Up @@ -67,6 +68,8 @@
});
</script>

<PageTitle title="Colocation" />

{#if colo.selectedUnit}
<div class="flex min-h-0 flex-1 flex-col overflow-auto">
<div class="shrink-0">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import Icon from '$lib/components/icon.svelte';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
Expand Down Expand Up @@ -184,6 +185,8 @@
}
</script>

<PageTitle title="Colocation Images" />

{#if colo.selectedUnit}
<div class="flex flex-1 flex-col overflow-hidden">
{#if mountedImage}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import { Button } from '$lib/components/ui/button';
import Check from '~icons/lucide/check';
import Copy from '~icons/nucleo/copy';
Expand Down Expand Up @@ -67,6 +68,8 @@
}
</script>

<PageTitle title="IPMI" />

{#if colo.selectedUnit}
<div class="flex-1 overflow-auto">
<div class="divide-y divide-border/50">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog';
Expand Down Expand Up @@ -71,6 +72,8 @@
}
</script>

<PageTitle title="Colocation Networking" />

{#if colo.selectedUnit}
<div class="flex-1 overflow-auto">
<div class="divide-y divide-border/50">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import Activity from '~icons/nucleo/activity';
import Cpu from '~icons/nucleo/cpu';
import Fan from '~icons/nucleo/wind';
Expand Down Expand Up @@ -35,6 +36,8 @@
});
</script>

<PageTitle title="Sensors" />

{#if colo.selectedUnit}
<div class="flex-1 overflow-auto">
{#if sensorData}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import PageTitle from '$lib/components/PageTitle.svelte';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import Check from '~icons/lucide/check';
Expand All @@ -22,6 +23,8 @@
}
</script>

<PageTitle title="Colocation Settings" />

{#if colo.selectedUnit}
<div class="flex-1 overflow-auto">
<div class="divide-y divide-border/50">
Expand Down
Loading