From a1a46f2a2bb1e0c83bf3ec4ad110b6c8658137f5 Mon Sep 17 00:00:00 2001 From: hyungi Date: Sun, 7 Jun 2026 20:10:43 +0900 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=EB=B0=B0=ED=8F=AC=20=EC=A0=84=20?= =?UTF-8?q?=EC=A0=81=EB=8C=80=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81=20?= =?UTF-8?q?=E2=80=94=20=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C/=EB=AC=B8?= =?UTF-8?q?=EC=84=9C/=EB=89=B4=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 15-에이전트 적대 리뷰의 확정 결함 수정: - dashboard: digest 헤드라인 날짜 d.date→d.digest_date ("undefined 브리핑" 버그/HIGH) + 빠른캡처 후 refresh() + 스탯띠 nowrap(줄바꿈 구분선 제거) + formatTime Invalid 가드 + chevron :global - documents: bulkAddTag 검색모드 데이터손실 방지(태그 미확인 시 풀문서 머지/HIGH) + selectDoc 풀 하이드레이션(인스펙터 메타 보강) + 검색모드 클라정렬 비활성 + 죽은 handleDocDelete 제거 - news: 인용 출처 국가 색칩 추가(+빈 국가 가드) + 읽음 스탬프(시안 충실) digest/memos = 확정 결함 0(무변). vite build PASS·토큰 청결. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/routes/+page.svelte | 9 ++-- frontend/src/routes/documents/+page.svelte | 51 ++++++++++++++-------- frontend/src/routes/news/+page.svelte | 8 +++- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index a92eb8d..66abf66 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -5,6 +5,7 @@ import { onMount } from 'svelte'; import { dashboardSummary, + refresh, type DashboardSummary, type PipelineStatus, type QueueLag, @@ -67,6 +68,7 @@ await api('/memos/', { method: 'POST', body: JSON.stringify({ content }) }); captureText = ''; addToast('success', '메모 저장됨'); + void refresh(); // 메모 수 등 요약 즉시 갱신(60s 폴 기다리지 않음) } catch { addToast('error', '메모 저장 실패'); } finally { @@ -103,7 +105,7 @@ article_count: topics[0].article_count, importance_score: topics[0].importance_score, country: topics[0].country, - date: d.date, + date: d.digest_date, }; } } catch { /* 디제스트 없으면 블록 자동 생략 */ } @@ -182,6 +184,7 @@ function formatTime(dateStr: string) { const d = new Date(dateStr); + if (isNaN(d.getTime())) return ''; // 빈 문자열/유효하지 않은 created_at → 'Invalid Date' 회피 const diff = Date.now() - d.getTime(); if (diff < 60000) return '방금'; if (diff < 3600000) return `${Math.floor(diff / 60000)}분 전`; @@ -262,7 +265,7 @@ -
+
{@render stat((summary.documents_count ?? 0).toLocaleString(), '문서', 'text-accent')} {@render stat((summary.news_count ?? 0).toLocaleString(), '뉴스')} {#if domainTotal > 0} @@ -480,6 +483,6 @@ {/snippet} diff --git a/frontend/src/routes/documents/+page.svelte b/frontend/src/routes/documents/+page.svelte index bc187f4..0aad960 100644 --- a/frontend/src/routes/documents/+page.svelte +++ b/frontend/src/routes/documents/+page.svelte @@ -231,8 +231,15 @@ goto(`/documents${qs ? '?' + qs : ''}`, { noScroll: true }); } - function selectDoc(doc) { - selectedDoc = selectedDoc?.id === doc.id ? null : doc; + async function selectDoc(doc) { + if (selectedDoc?.id === doc.id) { selectedDoc = null; return; } + selectedDoc = doc; // 즉시 표시(리더 + 기본 인스펙터) + // 인스펙터 풀 메타 하이드레이션 — 검색 결과(SearchResult)는 메타가 빈약(태그/크기/하위/md상태/읽음 없음). + // 풀 문서를 조회해 채운다(기존 GET /documents/{id}, 백엔드 무변). 리스트 모드도 md상태 등 보강. + try { + const full = await api(`/documents/${doc.id}`); + if (selectedDoc?.id === doc.id) selectedDoc = { ...doc, ...full }; + } catch { /* 실패 시 기본 정보 유지 */ } } // bulk 선택 @@ -271,7 +278,13 @@ if (!tag) return; await runBulk('태그 추가', async (id) => { const doc = sortedItems.find((d) => d.id === id); - const existing = Array.isArray(doc?.ai_tags) ? doc.ai_tags : []; + // ★ 검색 결과(SearchResult)는 ai_tags 가 없음 → 빈 배열로 PATCH 하면 기존 태그 전체 유실(덮어쓰기). + // 미확인이면 풀 문서를 조회해 실제 태그를 머지(데이터 손실 방지). + let existing = Array.isArray(doc?.ai_tags) ? doc.ai_tags : null; + if (existing == null) { + try { const full = await api(`/documents/${id}`); existing = Array.isArray(full?.ai_tags) ? full.ai_tags : []; } + catch { return; } // 현재 태그를 못 읽으면 덮어쓰지 않고 건너뜀 + } if (existing.includes(tag)) return; return api(`/documents/${id}`, { method: 'PATCH', body: JSON.stringify({ ai_tags: [...existing, tag] }) }); }); @@ -282,12 +295,6 @@ await runBulk('삭제', (id) => api(`/documents/${id}?delete_file=true`, { method: 'DELETE' })); } - function handleDocDelete() { - selectedDoc = null; - if (ui.isDrawerOpen('meta')) ui.closeDrawer(); - loadDocuments(); - } - function handleKeydown(e) { if (e.key === 'Escape') { if (selectedDoc && !ui.isDrawerOpen('meta') && !isXl.current) { selectedDoc = null; return; } @@ -298,7 +305,8 @@ let totalPages = $derived(Math.ceil(total / 50)); let items = $derived(searchResults || documents); let sortedItems = $derived.by(() => { - if (!sortKey) return items; + // 검색 모드는 서버 관련도순 유지 + SearchResult 에 updated_at 부재(NaN 비교=무의미) → 클라 정렬 비활성 + if (!sortKey || searchResults) return items; const arr = [...items]; const dir = sortDir === 'asc' ? 1 : -1; arr.sort((a, b) => { @@ -497,14 +505,21 @@
- - - {#if !loading}{total}건{/if} - + {#if searchResults} + + 관련도순 + + {#if !loading}{total}건{/if} + {:else} + + + {#if !loading}{total}건{/if} + + {/if}
diff --git a/frontend/src/routes/news/+page.svelte b/frontend/src/routes/news/+page.svelte index fed06d4..7f92075 100644 --- a/frontend/src/routes/news/+page.svelte +++ b/frontend/src/routes/news/+page.svelte @@ -205,6 +205,9 @@ {isLead ? 'mt-4' : ''} {topic.highlighted ? 'border-accent ring-2 ring-accent/25' : 'border-default'} {topic.is_read ? 'opacity-50 hover:opacity-80' : ''}"> + {#if topic.is_read} + 읽음 + {/if}
{q.quote}
-
{countryLabel(q.country)} · {q.source}
+
+ {#if q.country}{countryLabel(q.country)}{/if} + {q.source} +
{/each}