From b52d7c0f5b6b1a0d428ec9db5d501dd551540ca5 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Thu, 19 Mar 2026 19:26:36 -0700 Subject: [PATCH] fix(signals): per-signal expand state, error rollback, type safety in InterviewCard --- web/src/components/InterviewCard.vue | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/web/src/components/InterviewCard.vue b/web/src/components/InterviewCard.vue index 358fb7b..23bb944 100644 --- a/web/src/components/InterviewCard.vue +++ b/web/src/components/InterviewCard.vue @@ -55,7 +55,13 @@ async function dismissSignal(sig: StageSignal) { await useApiFetch(`/api/stage-signals/${sig.id}/dismiss`, { method: 'POST' }) } -const bodyExpanded = ref(false) +const expandedSignalIds = ref(new Set()) +function toggleBodyExpand(sigId: number) { + const next = new Set(expandedSignalIds.value) + if (next.has(sigId)) next.delete(sigId) + else next.add(sigId) + expandedSignalIds.value = next +} // Re-classify chips — neutral triggers two-call dismiss path const RECLASSIFY_CHIPS = [ @@ -67,7 +73,7 @@ const RECLASSIFY_CHIPS = [ { label: '— Neutral', value: 'neutral' }, ] as const -async function reclassifySignal(sig: StageSignal, newLabel: string) { +async function reclassifySignal(sig: StageSignal, newLabel: StageSignal['stage_signal'] | 'neutral') { if (newLabel === 'neutral') { // Optimistic removal — neutral signals are dismissed const arr = props.job.stage_signals @@ -82,12 +88,14 @@ async function reclassifySignal(sig: StageSignal, newLabel: string) { await useApiFetch(`/api/stage-signals/${sig.id}/dismiss`, { method: 'POST' }) } else { // Optimistic local re-label — Vue 3 proxy tracks the mutation - sig.stage_signal = newLabel as StageSignal['stage_signal'] - await useApiFetch(`/api/stage-signals/${sig.id}/reclassify`, { + const prev = sig.stage_signal + sig.stage_signal = newLabel + const { error } = await useApiFetch(`/api/stage-signals/${sig.id}/reclassify`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ stage_signal: newLabel }), }) + if (error) sig.stage_signal = prev } } @@ -180,8 +188,8 @@ const columnColor = computed(() => { {{ sig.subject.slice(0, 60) }}{{ sig.subject.length > 60 ? '…' : '' }}
-
-
+
From: {{ sig.from_addr }}
{{ sig.body }}
No email body available.
@@ -361,7 +369,6 @@ const columnColor = computed(() => { } .signal-label { font-size: 0.82em; } .signal-subject { font-size: 0.78em; color: var(--color-text-muted); } -.signal-actions { display: flex; gap: 6px; align-items: center; } .btn-signal-move { background: var(--color-primary); color: #fff; border: none; border-radius: 4px; padding: 2px 8px; font-size: 0.78em; cursor: pointer;