feat(upload): warn on duplicate filename with link to existing document
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
- storeDocument now returns StoreResult(document, isNew) to distinguish new uploads from updates to existing documents - QuickUploadResult gains an `updated` list alongside `created` - Frontend shows an amber warning with a "View document" link for duplicates instead of silently re-uploading and leaving the user confused Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@ let isDragging = $state(false);
|
||||
let windowDragging = $state(false);
|
||||
let dragCounter = 0;
|
||||
let isUploading = $state(false);
|
||||
let uploadMessages = $state<{ text: string; isError: boolean }[]>([]);
|
||||
let uploadMessages = $state<{ text: string; isError: boolean; link?: string }[]>([]);
|
||||
let fileInput: HTMLInputElement;
|
||||
|
||||
let searchTimer: ReturnType<typeof setTimeout>;
|
||||
@@ -67,7 +67,7 @@ async function handleFileSelect(e: Event) {
|
||||
async function uploadFiles(files: File[]) {
|
||||
if (files.length === 0) return;
|
||||
|
||||
const messages: { text: string; isError: boolean }[] = [];
|
||||
const messages: { text: string; isError: boolean; link?: string }[] = [];
|
||||
|
||||
// Client-side type validation
|
||||
const valid: File[] = [];
|
||||
@@ -101,6 +101,13 @@ async function uploadFiles(files: File[]) {
|
||||
if (result.created?.length > 0) {
|
||||
messages.push({ text: m.upload_success({ count: result.created.length }), isError: false });
|
||||
}
|
||||
for (const doc of result.updated ?? []) {
|
||||
messages.push({
|
||||
text: m.upload_duplicate({ filename: doc.originalFilename }),
|
||||
isError: false,
|
||||
link: `/documents/${doc.id}`
|
||||
});
|
||||
}
|
||||
for (const err of result.errors ?? []) {
|
||||
messages.push({
|
||||
text: `${err.filename}: ${getErrorMessage(err.code)}`,
|
||||
@@ -374,8 +381,18 @@ $effect(() => {
|
||||
{#if uploadMessages.length > 0}
|
||||
<div class="mb-4 flex flex-col gap-1">
|
||||
{#each uploadMessages as msg, i (i)}
|
||||
<p class="font-sans text-sm {msg.isError ? 'text-red-600' : 'text-green-700'}">
|
||||
<p
|
||||
class="font-sans text-sm {msg.isError
|
||||
? 'text-red-600'
|
||||
: msg.link
|
||||
? 'text-amber-700'
|
||||
: 'text-green-700'}"
|
||||
>
|
||||
{msg.text}
|
||||
{#if msg.link}
|
||||
<a href={msg.link} class="underline hover:no-underline">{m.upload_duplicate_link()}</a
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user