From 4e4d613416ab444dc598f9c867c571f6bc497647 Mon Sep 17 00:00:00 2001 From: Devon Wells Date: Mon, 1 Dec 2025 17:16:34 -0500 Subject: [PATCH] refactor(dashboard): extract shared formatters and remove unused db functions --- .../src/lib/components/EventsList.svelte | 14 +-- .../src/lib/components/FlagsList.svelte | 5 +- .../src/lib/components/SessionDetail.svelte | 14 +-- .../src/lib/components/SessionsList.svelte | 16 +--- apps/dashboard/src/lib/db.ts | 90 ++----------------- apps/dashboard/src/lib/utils/formatters.ts | 38 ++++++++ 6 files changed, 48 insertions(+), 129 deletions(-) create mode 100644 apps/dashboard/src/lib/utils/formatters.ts diff --git a/apps/dashboard/src/lib/components/EventsList.svelte b/apps/dashboard/src/lib/components/EventsList.svelte index 1bcc9a6..38cbadb 100644 --- a/apps/dashboard/src/lib/components/EventsList.svelte +++ b/apps/dashboard/src/lib/components/EventsList.svelte @@ -2,6 +2,7 @@ import { useQuery } from "$lib/zero/client.svelte"; import { recentEvents } from "$lib/zero/queries"; import type { Event } from "$lib/zero/schema"; + import { formatTimestamp, formatProperties } from "$lib/utils/formatters"; let { projectId }: { projectId: string } = $props(); @@ -31,19 +32,6 @@ expandedId = expandedId === id ? null : id; } - function formatTimestamp(ts: number): string { - return new Date(ts).toLocaleString(); - } - - function formatProperties(props: Record | null | undefined): string { - if (!props) return "{}"; - try { - return JSON.stringify(props, null, 2); - } catch { - return String(props); - } - } - function loadMore() { displayLimit += 100; } diff --git a/apps/dashboard/src/lib/components/FlagsList.svelte b/apps/dashboard/src/lib/components/FlagsList.svelte index baaa3e2..b5d2f29 100644 --- a/apps/dashboard/src/lib/components/FlagsList.svelte +++ b/apps/dashboard/src/lib/components/FlagsList.svelte @@ -2,6 +2,7 @@ import { useQuery, getZero } from "$lib/zero/client.svelte"; import { flagsForProject } from "$lib/zero/queries"; import type { Flag } from "$lib/zero/schema"; + import { formatTimestamp } from "$lib/utils/formatters"; let { projectId }: { projectId: string } = $props(); @@ -40,10 +41,6 @@ if (!confirm("Delete this flag?")) return; await zero.mutate.flags.delete({ id }); } - - function formatTimestamp(ts: number): string { - return new Date(ts).toLocaleString(); - } diff --git a/apps/dashboard/src/lib/components/SessionDetail.svelte b/apps/dashboard/src/lib/components/SessionDetail.svelte index 7c279b4..7347642 100644 --- a/apps/dashboard/src/lib/components/SessionDetail.svelte +++ b/apps/dashboard/src/lib/components/SessionDetail.svelte @@ -2,6 +2,7 @@ import { useQuery, useQueryOne } from "$lib/zero/client.svelte"; import { sessionById, eventsForSession } from "$lib/zero/queries"; import type { Session, Event } from "$lib/zero/schema"; + import { formatTimestamp, formatProperties } from "$lib/utils/formatters"; let { sessionId }: { sessionId: string } = $props(); @@ -12,19 +13,6 @@ const loading = $derived(sessionQuery.loading || eventsQuery.loading); const session = $derived(sessionQuery.data); - function formatTimestamp(ts: number): string { - return new Date(ts).toLocaleString(); - } - - function formatProperties(props: Record | null | undefined): string { - if (!props) return "{}"; - try { - return JSON.stringify(props, null, 2); - } catch { - return String(props); - } - } - // Expanded event ID for properties view let expandedId = $state(null); diff --git a/apps/dashboard/src/lib/components/SessionsList.svelte b/apps/dashboard/src/lib/components/SessionsList.svelte index a6ad40c..f99eb7f 100644 --- a/apps/dashboard/src/lib/components/SessionsList.svelte +++ b/apps/dashboard/src/lib/components/SessionsList.svelte @@ -2,26 +2,12 @@ import { useQuery } from "$lib/zero/client.svelte"; import { recentSessions } from "$lib/zero/queries"; import type { Session } from "$lib/zero/schema"; + import { formatTimestamp, formatRelativeTime } from "$lib/utils/formatters"; let { projectId }: { projectId: string } = $props(); // Use getter function so query re-runs if projectId changes const sessionsQuery = useQuery(() => recentSessions(projectId, 100)); - - function formatTimestamp(ts: number): string { - return new Date(ts).toLocaleString(); - } - - function formatRelativeTime(ts: number): string { - const diff = Date.now() - ts; - const minutes = Math.floor(diff / 60000); - if (minutes < 1) return "Just now"; - if (minutes < 60) return `${minutes}m ago`; - const hours = Math.floor(minutes / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.floor(hours / 24); - return `${days}d ago`; - }
diff --git a/apps/dashboard/src/lib/db.ts b/apps/dashboard/src/lib/db.ts index d715e42..acb3276 100644 --- a/apps/dashboard/src/lib/db.ts +++ b/apps/dashboard/src/lib/db.ts @@ -1,88 +1,10 @@ +/** + * PostgreSQL client for server-side queries. + * + * Note: Most data fetching is handled by Zero synced queries on the client. + * This module is primarily used for auth-related queries. + */ import postgres from "postgres"; import { DATABASE_URL } from "$env/static/private"; export const sql = postgres(DATABASE_URL); - -// Projects -export async function getProjects() { - return sql`SELECT id, name, api_key, created_at FROM projects ORDER BY created_at DESC`; -} - -export async function getProject(id: string) { - const [project] = await sql`SELECT * FROM projects WHERE id = ${id}`; - return project; -} - -// Events -export async function getRecentEvents(projectId: string, limit = 100) { - return sql` - SELECT id, event_name, properties, timestamp, session_id, user_id - FROM events - WHERE project_id = ${projectId} - ORDER BY timestamp DESC - LIMIT ${limit} - `; -} - -export async function getEventCounts(projectId: string, days = 7) { - return sql` - SELECT - date_trunc('day', timestamp)::date as day, - event_name, - count(*)::int as count - FROM events - WHERE project_id = ${projectId} - AND timestamp > NOW() - INTERVAL '1 day' * ${days} - GROUP BY 1, 2 - ORDER BY 1 DESC, 3 DESC - `; -} - -// Sessions -export async function getSessions(projectId: string, limit = 50) { - return sql` - SELECT id, user_id, started_at, last_event_at, event_count, entry_url - FROM sessions - WHERE project_id = ${projectId} - ORDER BY started_at DESC - LIMIT ${limit} - `; -} - -export async function getSessionEvents(sessionId: string) { - return sql` - SELECT event_name, properties, timestamp - FROM events - WHERE session_id = ${sessionId} - ORDER BY timestamp ASC - `; -} - -// Flags -export async function getFlags(projectId: string) { - return sql` - SELECT id, key, name, enabled, updated_at - FROM flags - WHERE project_id = ${projectId} - ORDER BY key - `; -} - -export async function toggleFlag(flagId: string, enabled: boolean) { - const [flag] = await sql` - UPDATE flags - SET enabled = ${enabled}, updated_at = NOW() - WHERE id = ${flagId} - RETURNING * - `; - return flag; -} - -export async function createFlag(projectId: string, key: string, name: string) { - const [flag] = await sql` - INSERT INTO flags (project_id, key, name, enabled) - VALUES (${projectId}, ${key}, ${name}, false) - RETURNING * - `; - return flag; -} diff --git a/apps/dashboard/src/lib/utils/formatters.ts b/apps/dashboard/src/lib/utils/formatters.ts new file mode 100644 index 0000000..84e329f --- /dev/null +++ b/apps/dashboard/src/lib/utils/formatters.ts @@ -0,0 +1,38 @@ +/** + * Shared formatting utilities for the dashboard. + */ + +/** + * Format a Unix timestamp to a locale-specific date/time string. + */ +export function formatTimestamp(ts: number): string { + return new Date(ts).toLocaleString(); +} + +/** + * Format a properties object as pretty-printed JSON. + */ +export function formatProperties( + props: Record | null | undefined, +): string { + if (!props) return "{}"; + try { + return JSON.stringify(props, null, 2); + } catch { + return String(props); + } +} + +/** + * Format a timestamp as a relative time string (e.g., "5m ago", "2h ago"). + */ +export function formatRelativeTime(ts: number): string { + const diff = Date.now() - ts; + const minutes = Math.floor(diff / 60000); + if (minutes < 1) return "Just now"; + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.floor(hours / 24); + return `${days}d ago`; +}