feat(phase2): per-board access control UI

- BoardAccessControl component with user/group autocomplete
- BoardShareDialog modal with copy link, guest toggle, quick add
- Board permissions REST API (GET/POST/DELETE)
- Access indicators on BoardCard (lock, globe, shared icons)
- Guest access toggle in board editor with status preview
- Enhanced PermissionEditor with search autocomplete
- i18n translations for all new strings (EN/RU)
This commit is contained in:
2026-03-24 23:29:19 +03:00
parent 477c0e4d52
commit 5bb4fbcedf
16 changed files with 1166 additions and 57 deletions
+22 -1
View File
@@ -3,6 +3,8 @@ import type { PageServerLoad } from './$types.js';
import * as boardService from '$lib/server/services/boardService.js';
import * as appService from '$lib/server/services/appService.js';
import * as permissionService from '$lib/server/services/permissionService.js';
import * as userService from '$lib/server/services/userService.js';
import * as groupService from '$lib/server/services/groupService.js';
import { EntityType, PermissionLevel, UserRole } from '$lib/utils/constants.js';
import { isBoardGuestAccessible } from '$lib/server/middleware/guestAccess.js';
@@ -54,7 +56,26 @@ export const load: PageServerLoad = async ({ params, locals }) => {
}
}
return { board, canEdit, allApps };
// Load users and groups for the share dialog (only if user can edit)
let users: { id: string; name: string }[] = [];
let groups: { id: string; name: string }[] = [];
if (canEdit) {
const [allUsers, allGroups] = await Promise.all([
userService.findAll(),
groupService.findAll()
]);
users = allUsers.map((u) => ({
id: u.id,
name: u.displayName || u.email
}));
groups = allGroups.map((g) => ({
id: g.id,
name: g.name
}));
}
return { board, canEdit, allApps, users, groups };
} catch (err) {
const message = err instanceof Error ? err.message : 'Board not found';
if (message.includes('not found')) {