/** * Admin > People > Groups */ const { html } = window; const { useState, useEffect, useCallback } = hooks; export default function GroupsSection() { const [groups, setGroups] = useState([]); const [loading, setLoading] = useState(true); const [detail, setDetail] = useState(null); const [members, setMembers] = useState([]); const [allPerms, setAllPerms] = useState([]); const [allUsers, setAllUsers] = useState([]); const [groupData, setGroupData] = useState({}); const [showCreate, setShowCreate] = useState(false); const [showAddMember, setShowAddMember] = useState(false); const loadGroups = useCallback(async () => { try { const data = await sw.api.admin.groups.list(); setGroups(data || []); } catch (e) { sw.toast(e.message, 'error'); } finally { setLoading(false); } }, []); useEffect(() => { loadGroups(); }, []); async function openDetail(group) { setDetail(group); setGroupData({ permissions: group.permissions || [], }); try { const [m, p, u] = await Promise.all([ sw.api.admin.groups.members(group.id), sw.api.admin.permissions.list(), sw.api.admin.users.list(), ]); setMembers(m || []); setAllPerms(p.permissions || []); setAllUsers(u || []); } catch (e) { sw.toast(e.message, 'error'); } } async function createGroup(e) { e.preventDefault(); const form = e.target; try { await sw.api.admin.groups.create({ name: form.name.value.trim(), description: form.desc.value.trim(), scope: form.scope.value, }); sw.toast('Group created', 'success'); setShowCreate(false); loadGroups(); } catch (e) { sw.toast(e.message, 'error'); } } async function savePermissions() { try { await sw.api.admin.groups.update(detail.id, { permissions: groupData.permissions, }); sw.toast('Saved', 'success'); } catch (e) { sw.toast(e.message, 'error'); } } function togglePerm(perm) { setGroupData(prev => { const perms = prev.permissions.includes(perm) ? prev.permissions.filter(p => p !== perm) : [...prev.permissions, perm]; return { ...prev, permissions: perms }; }); } async function addMember(e) { e.preventDefault(); const uid = e.target.userId.value; if (!uid) return; try { await sw.api.admin.groups.addMember(detail.id, uid); sw.toast('Member added', 'success'); setShowAddMember(false); const m = await sw.api.admin.groups.members(detail.id); setMembers(m || []); } catch (e) { sw.toast(e.message, 'error'); } } async function removeMember(uid) { try { await sw.api.admin.groups.removeMember(detail.id, uid); sw.toast('Member removed', 'success'); setMembers(prev => prev.filter(m => (m.user_id || m.id) !== uid)); } catch (e) { sw.toast(e.message, 'error'); } } async function deleteGroup() { const ok = await sw.confirm('Delete this group?', true); if (!ok) return; try { await sw.api.admin.groups.del(detail.id); sw.toast('Group deleted', 'success'); setDetail(null); loadGroups(); } catch (e) { sw.toast(e.message, 'error'); } } if (loading) return html`
Loading\u2026
`; if (detail) return html`

${detail.name}

${detail.scope}
Permissions
${allPerms.map(p => html` `)}

Members
${members.map(m => html`
${m.username || m.user_id}
`)}
${showAddMember ? html`
` : html`` }
`; return html`
${showCreate && html`
`}
${groups.length === 0 && html`
No groups
`} ${groups.map(g => html`
openDetail(g)}> ${g.name} ${g.scope}
`)}
`; }