fix: address all code review findings

- Extract shared permission logic into boardPermissions.ts utility
- Fix DnD drag revert: add dirty flag to prevent  overwrite
- Wrap OAuth group sync in Prisma transaction (N+1 fix)
- Add empty widgetIds validation in widget reorder API
- Add invalidateAll() after guest toggle PATCH
- Replace console.error with user-visible error banners
- Extract WidgetCreationForm component (DraggableSection was 448 lines)
- Remove unused boardId prop from DraggableSection
- Always include OAuth state parameter + validate in callback
- Clean up copyLink timer on component destroy
- Add type-specific widget config validation in addWidget action
This commit is contained in:
2026-03-25 00:03:32 +03:00
parent 5a6002be76
commit cba160ecb8
15 changed files with 588 additions and 447 deletions
+13 -3
View File
@@ -11,6 +11,7 @@
let showAddSection = $state(false);
let addWidgetSectionId = $state<string | null>(null);
let errorMessage = $state('');
function handleToggleAddWidget(sectionId: string) {
addWidgetSectionId = addWidgetSectionId === sectionId ? null : sectionId;
@@ -27,7 +28,7 @@
});
await invalidateAll();
} catch (err) {
console.error('Failed to delete section:', err);
errorMessage = err instanceof Error ? err.message : 'Failed to delete section';
}
}
@@ -80,7 +81,7 @@
addWidgetSectionId = null;
await invalidateAll();
} catch (err) {
console.error('Failed to add widget:', err);
errorMessage = err instanceof Error ? err.message : 'Failed to add widget';
}
}
@@ -95,7 +96,7 @@
});
await invalidateAll();
} catch (err) {
console.error('Failed to delete widget:', err);
errorMessage = err instanceof Error ? err.message : 'Failed to delete widget';
}
}
</script>
@@ -106,6 +107,15 @@
<div class="p-6">
<div class="mx-auto max-w-4xl">
{#if errorMessage}
<div class="mb-4 rounded-lg border border-destructive bg-destructive/10 p-3">
<p class="text-sm text-destructive">{errorMessage}</p>
<button type="button" onclick={() => { errorMessage = ''; }} class="mt-1 text-xs text-destructive underline">
{$t('common.dismiss') ?? 'Dismiss'}
</button>
</div>
{/if}
<div class="mb-6 flex items-center justify-between">
<h1 class="text-2xl font-bold text-foreground">{$t('board.edit_board')}</h1>
<a