From 699e525cb9e3cde2c1fa29560227bff5816e3fbc Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 26 Mar 2026 22:43:59 -0400 Subject: [PATCH] =?UTF-8?q?refactor:=20DRY=20pass=20on=20frontend=20?= =?UTF-8?q?=E2=80=94=20shared=20palette,=20composable,=20and=20tab=20loade?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract milestoneColor to utils/palette.ts; remove duplicate in HomeView + ProjectListView - Create useBackgroundRefresh composable; wire into HomeView + BriefingView (removes manual setInterval/clearInterval boilerplate) - Extract _loadTabContent() in SettingsView so watch and onMounted share one tab→loader mapping - Move raw fetch() api-key calls to typed helpers in api/client.ts (listApiKeys, createApiKey, revokeApiKey) - Drop unused onUnmounted import from BriefingView Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/api/client.ts | 18 +++++++ .../src/composables/useBackgroundRefresh.ts | 29 +++++++++++ frontend/src/utils/palette.ts | 13 +++++ frontend/src/views/BriefingView.vue | 17 +++---- frontend/src/views/HomeView.vue | 24 ++------- frontend/src/views/ProjectListView.vue | 12 +---- frontend/src/views/SettingsView.vue | 51 ++++++++----------- 7 files changed, 95 insertions(+), 69 deletions(-) create mode 100644 frontend/src/composables/useBackgroundRefresh.ts create mode 100644 frontend/src/utils/palette.ts diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 5ae97d0..78e565a 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -580,3 +580,21 @@ export async function updateEvent(id: number, payload: EventUpdatePayload): Prom export async function deleteEvent(id: number): Promise { return apiDelete(`/api/events/${id}`); } + +// ─── API Keys ───────────────────────────────────────────────────────────────── + +export interface ApiKeyEntry { + id: number + name: string + scope: string + key_prefix: string + last_used_at: string | null +} + +export const listApiKeys = () => + apiGet<{ api_keys: ApiKeyEntry[] }>('/api/api-keys').then(r => r.api_keys) + +export const createApiKey = (name: string, scope: 'read' | 'write') => + apiPost<{ key: string; api_key: ApiKeyEntry }>('/api/api-keys', { name, scope }) + +export const revokeApiKey = (id: number) => apiDelete(`/api/api-keys/${id}`) diff --git a/frontend/src/composables/useBackgroundRefresh.ts b/frontend/src/composables/useBackgroundRefresh.ts new file mode 100644 index 0000000..9aa2912 --- /dev/null +++ b/frontend/src/composables/useBackgroundRefresh.ts @@ -0,0 +1,29 @@ +import { onMounted, onUnmounted } from 'vue' + +/** + * Runs `refreshFn` on a recurring interval while the page is visible. + * Safe to use in any component — timer is cleared on unmount. + * + * @param refreshFn Called each tick. Should be silent (no loading state changes). + * @param intervalMs Polling interval in milliseconds. + * @param canRun Optional guard — refresh is skipped when this returns false. + */ +export function useBackgroundRefresh( + refreshFn: () => void, + intervalMs: number, + canRun?: () => boolean, +): void { + let timer: ReturnType | null = null + + onMounted(() => { + timer = setInterval(() => { + if (document.hidden) return + if (canRun && !canRun()) return + refreshFn() + }, intervalMs) + }) + + onUnmounted(() => { + if (timer !== null) clearInterval(timer) + }) +} diff --git a/frontend/src/utils/palette.ts b/frontend/src/utils/palette.ts new file mode 100644 index 0000000..e04101d --- /dev/null +++ b/frontend/src/utils/palette.ts @@ -0,0 +1,13 @@ +/** Cyclic color palette for milestone progress bars. */ +export const MILESTONE_PALETTE = [ + 'var(--color-primary)', + 'var(--color-success, #22c55e)', + '#c98a00', + '#8b5cf6', + 'var(--color-danger, #ef4444)', + '#06b6d4', +] + +export function milestoneColor(index: number): string { + return MILESTONE_PALETTE[index % MILESTONE_PALETTE.length] +} diff --git a/frontend/src/views/BriefingView.vue b/frontend/src/views/BriefingView.vue index 63c236d..d3c0fce 100644 --- a/frontend/src/views/BriefingView.vue +++ b/frontend/src/views/BriefingView.vue @@ -1,5 +1,6 @@ diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 40664c3..ca79eda 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -1,6 +1,8 @@