From d6812584b4b10f13e114c3a886418372932a4586 Mon Sep 17 00:00:00 2001 From: tznthou Date: Tue, 26 May 2026 23:41:25 +0800 Subject: [PATCH] fix(storage): allow excluding 0-session projects The "Exclude this project" button on 0 B / 0-session projects silently did nothing because the UI guard bailed on sessionCount === 0. Relax the guard to only bail for date-range-only rules, and show a prevention-focused confirmation dialog for empty project exclusions. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Storage/ConfirmExclusionDialog.tsx | 22 +++++++++++++------ .../components/Storage/StoragePage.tsx | 3 ++- src/renderer/i18n/messages.ts | 8 +++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/renderer/components/Storage/ConfirmExclusionDialog.tsx b/src/renderer/components/Storage/ConfirmExclusionDialog.tsx index 64b213b..5397f23 100644 --- a/src/renderer/components/Storage/ConfirmExclusionDialog.tsx +++ b/src/renderer/components/Storage/ConfirmExclusionDialog.tsx @@ -18,18 +18,24 @@ const HIGH_IMPACT_RATIO = 0.5 export default function ConfirmExclusionDialog({ title, preview, totalSessions, isApplying, onConfirm, onCancel }: Props) { const { t } = useI18n() const [acknowledged, setAcknowledged] = useState(false) + const isEmpty = preview.sessionCount === 0 const impactRatio = totalSessions > 0 ? preview.sessionCount / totalSessions : 0 - const highImpact = impactRatio > HIGH_IMPACT_RATIO + const highImpact = !isEmpty && impactRatio > HIGH_IMPACT_RATIO return (
{ if (!isApplying) onCancel() }}>
e.stopPropagation()}>
{title}
- - {totalSessions > 0 && ( - {t('storage.confirm.impactRatio', { percent: (impactRatio * 100).toFixed(1) })} - )} + {isEmpty + ? {t('storage.confirm.emptyProjectHint')} + : <> + + {totalSessions > 0 && ( + {t('storage.confirm.impactRatio', { percent: (impactRatio * 100).toFixed(1) })} + )} + + }
{highImpact && ( @@ -45,7 +51,7 @@ export default function ConfirmExclusionDialog({ title, preview, totalSessions, disabled={isApplying} onChange={e => setAcknowledged(e.target.checked)} /> - {t('storage.confirm.acknowledge')} + {isEmpty ? t('storage.confirm.acknowledgeExclude') : t('storage.confirm.acknowledge')}
@@ -55,7 +61,9 @@ export default function ConfirmExclusionDialog({ title, preview, totalSessions, disabled={!acknowledged || isApplying} onClick={onConfirm} > - {isApplying ? t('storage.confirm.deleting') : t('storage.confirm.deleteAction')} + {isApplying + ? isEmpty ? t('storage.confirm.excluding') : t('storage.confirm.deleting') + : isEmpty ? t('storage.confirm.excludeAction') : t('storage.confirm.deleteAction')}
diff --git a/src/renderer/components/Storage/StoragePage.tsx b/src/renderer/components/Storage/StoragePage.tsx index d82d9a9..8823a82 100644 --- a/src/renderer/components/Storage/StoragePage.tsx +++ b/src/renderer/components/Storage/StoragePage.tsx @@ -41,7 +41,8 @@ export default function StoragePage() { const openConfirm = useCallback(async (rule: ExclusionRuleInput, title: string) => { try { const preview = await window.api.previewExclusion(rule) - if (preview.sessionCount === 0) { + const isProjectOnly = !!(rule.projectId && !rule.dateFrom && !rule.dateTo) + if (preview.sessionCount === 0 && !isProjectOnly) { return } setPending({ preview, title }) diff --git a/src/renderer/i18n/messages.ts b/src/renderer/i18n/messages.ts index 5bba476..acf4789 100644 --- a/src/renderer/i18n/messages.ts +++ b/src/renderer/i18n/messages.ts @@ -153,6 +153,10 @@ const zhTW = { 'storage.confirm.impactRatio': '(佔全部 {percent}%)', 'storage.confirm.warningHighImpact': '⚠️ 此操作將刪除超過一半的資料。請再次確認。', 'storage.confirm.acknowledge': '我了解此操作不可復原', + 'storage.confirm.acknowledgeExclude': '我了解排除後該專案不再被索引', + 'storage.confirm.emptyProjectHint': '此專案目前無任何 session。排除後,未來的 session 也不會被索引。', + 'storage.confirm.excludeAction': '確認排除', + 'storage.confirm.excluding': '排除中...', 'storage.confirm.deleting': '刪除中...', 'storage.confirm.deleteAction': '確認刪除', 'dashboard.title': '儀表板', @@ -423,6 +427,10 @@ const en = { 'storage.confirm.impactRatio': '({percent}% of total)', 'storage.confirm.warningHighImpact': '⚠️ This will delete more than half of the data. Please confirm.', 'storage.confirm.acknowledge': 'I understand this is irreversible', + 'storage.confirm.acknowledgeExclude': 'I understand this project will no longer be indexed', + 'storage.confirm.emptyProjectHint': 'This project currently has no sessions. Once excluded, future sessions will not be indexed either.', + 'storage.confirm.excludeAction': 'Confirm exclude', + 'storage.confirm.excluding': 'Excluding...', 'storage.confirm.deleting': 'Deleting...', 'storage.confirm.deleteAction': 'Confirm delete', 'dashboard.title': 'Dashboard',