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
+15 -3
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import type { PageData } from './$types.js';
import { invalidateAll } from '$app/navigation';
import Board from '$lib/components/board/Board.svelte';
import BoardHeader from '$lib/components/board/BoardHeader.svelte';
import BoardShareDialog from '$lib/components/board/BoardShareDialog.svelte';
@@ -8,16 +9,23 @@
let { data }: { data: PageData } = $props();
let showShareDialog = $state(false);
let guestToggleError = $state('');
async function handleGuestToggle(value: boolean) {
guestToggleError = '';
try {
await fetch(`/api/boards/${data.board.id}`, {
const res = await fetch(`/api/boards/${data.board.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ isGuestAccessible: value })
});
} catch (err) {
console.error('Failed to update guest access:', err);
if (res.ok) {
await invalidateAll();
} else {
guestToggleError = 'Failed to update guest access';
}
} catch {
guestToggleError = 'Network error updating guest access';
}
}
</script>
@@ -37,6 +45,10 @@
onShare={() => { showShareDialog = true; }}
/>
{#if guestToggleError}
<p class="mb-2 text-sm text-destructive">{guestToggleError}</p>
{/if}
<Board sections={data.board.sections} allApps={data.allApps} />
</div>
</div>