WIP: dashboard sharing UI (pre-merge)

This commit is contained in:
copilot-swe-agent[bot] 2026-07-02 15:11:58 +00:00 committed by GitHub
parent 247d56263a
commit f0735ae18c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 1 deletions

View file

@ -10,7 +10,8 @@
<div class="app-shell"> <div class="app-shell">
<aside class="sidebar"> <aside class="sidebar">
<h2>NOTXCS</h2> <h2>NOTXCS</h2>
<div class="user-info">Signed in as <strong id="username-display"></strong></div> <div class="user-info">Signed in as <strong id="username-display"></strong> <span id="role-badge" class="badge type-badge"></span></div>
<a id="admin-link" class="hidden" href="/admin.html" style="display:block;margin-bottom:12px;color:var(--accent);font-size:13px;">Manage users</a>
<button class="secondary" id="logout-btn" style="margin-bottom: 16px;">Log out</button> <button class="secondary" id="logout-btn" style="margin-bottom: 16px;">Log out</button>
<ul class="place-list" id="place-list"></ul> <ul class="place-list" id="place-list"></ul>
@ -76,6 +77,20 @@
<div id="access-groups-empty" class="empty-state hidden">No access groups yet for this place.</div> <div id="access-groups-empty" class="empty-state hidden">No access groups yet for this place.</div>
<ul class="acl-list" id="access-groups-list"></ul> <ul class="acl-list" id="access-groups-list"></ul>
</div> </div>
<div class="card" id="shared-access-card">
<h3>Shared access</h3>
<p style="margin-top:-8px;color:var(--muted);font-size:13px;">Grant other users access to manage this place's settings, readers and access groups.</p>
<form id="add-shared-access-form" class="inline-form">
<div class="field-group">
<label for="shared-access-username">Username</label>
<input type="text" id="shared-access-username" required>
</div>
<button type="submit" class="primary">Grant access</button>
</form>
<div id="shared-access-empty" class="empty-state hidden">No other users have been granted access to this place.</div>
<ul class="acl-list" id="shared-access-list"></ul>
</div>
</div> </div>
</main> </main>
</div> </div>

View file

@ -1,6 +1,15 @@
let currentPlaceId = null; let currentPlaceId = null;
let places = []; let places = [];
let accessGroups = []; let accessGroups = [];
let currentUser = null;
let currentPlaceAccessLevel = null;
const ROLE_LABELS = {
1: 'User',
2: 'Elevated',
3: 'Admin',
4: 'Superadmin'
};
async function api(path, options = {}) { async function api(path, options = {}) {
const res = await fetch(path, { const res = await fetch(path, {
@ -21,7 +30,10 @@ async function init() {
window.location.href = '/login.html'; window.location.href = '/login.html';
return; return;
} }
currentUser = me.user;
document.getElementById('username-display').textContent = me.user.username; document.getElementById('username-display').textContent = me.user.username;
document.getElementById('role-badge').textContent = ROLE_LABELS[me.user.role] || 'User';
document.getElementById('admin-link').classList.toggle('hidden', me.user.role < 3);
await loadPlaces(); await loadPlaces();
} }
@ -52,12 +64,21 @@ async function selectPlace(placeId) {
const data = await api(`/dashboard/places/${encodeURIComponent(placeId)}`); const data = await api(`/dashboard/places/${encodeURIComponent(placeId)}`);
if (!data.success) return; if (!data.success) return;
currentPlaceAccessLevel = data.accessLevel;
document.getElementById('no-place').classList.add('hidden'); document.getElementById('no-place').classList.add('hidden');
document.getElementById('place-view').classList.remove('hidden'); document.getElementById('place-view').classList.remove('hidden');
document.getElementById('place-title').textContent = placeId; document.getElementById('place-title').textContent = placeId;
const canManageOwnership = currentPlaceAccessLevel === 'owner' || currentPlaceAccessLevel === 'bypass';
document.getElementById('delete-place-btn').classList.toggle('hidden', !canManageOwnership);
document.getElementById('shared-access-card').classList.toggle('hidden', !canManageOwnership);
renderReaders(data.accessPoints || []); renderReaders(data.accessPoints || []);
await loadAccessGroups(); await loadAccessGroups();
if (canManageOwnership) {
await loadSharedAccess();
}
} }
function renderReaders(accessPoints) { function renderReaders(accessPoints) {