Added ldap and pam authentication

This commit is contained in:
Martino Ferrari
2026-06-23 17:59:40 +02:00
parent ac24011487
commit 11120bedca
36 changed files with 1935 additions and 66 deletions
+35 -2
View File
@@ -2,6 +2,7 @@ import { h } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks';
import { useAuth, canWrite } from './lib/auth';
import type { Interface, InterfaceListItem, Folder } from './lib/types';
import { ScopeFilter, bucketOf, type Bucket } from './lib/scope';
import ShareDialog from './ShareDialog';
interface Props {
@@ -50,6 +51,11 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
const dragId = useRef<string | null>(null);
const me = useAuth();
const writable = canWrite(me.level);
// Mine/Group/Global visibility filter. Default to Global so the primary
// navigation list isn't empty for users who own no panels; legacy/public
// panels live there.
const [bucket, setBucket] = useState<Bucket>('global');
const [scopeGroup, setScopeGroup] = useState('');
// Panels in a folder ('' = root), sorted by their stored order then name.
function panelsIn(folder: string): InterfaceListItem[] {
@@ -58,6 +64,26 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || (a.name || a.id).localeCompare(b.name || b.id));
}
// Whether a panel falls in the active visibility bucket. In group mode a
// chosen group narrows to panels shared with that specific group.
function inScope(item: InterfaceListItem): boolean {
if (bucketOf(item, me) !== bucket) return false;
if (bucket === 'group' && scopeGroup) return (item.groups ?? []).includes(scopeGroup);
return true;
}
// Panels in a folder that pass the active visibility filter.
function visiblePanelsIn(folder: string): InterfaceListItem[] {
return panelsIn(folder).filter(inScope);
}
// A folder is shown when it (recursively) contains any in-scope panel, so
// empty branches collapse out under the active filter.
function folderHasVisible(id: string): boolean {
if (visiblePanelsIn(id).length > 0) return true;
return folders.some(f => f.parent === id && folderHasVisible(f.id));
}
// Persist a new ordering for a folder's panels (also moves panels between folders).
async function reorder(folder: string, ids: string[]) {
const res = await fetch('/api/v1/interfaces/reorder', {
@@ -116,6 +142,8 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
folder: item.folder ? String(item.folder) : '',
order: Number(item.order || 0),
perm: (item.perm as InterfaceListItem['perm']) || 'write',
scope: item.scope ? String(item.scope) : '',
groups: Array.isArray(item.groups) ? item.groups.map(String) : [],
})).filter((item: InterfaceListItem) => item.id);
setInterfaces(normalized);
setFolders(Array.isArray(folderData) ? folderData : []);
@@ -222,9 +250,11 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
}
// Render a folder and everything beneath it (subfolders first, then panels).
// Folders with no in-scope descendant panels are hidden under the filter.
function renderFolder(folder: Folder) {
if (!folderHasVisible(folder.id)) return null;
const children = folders.filter(f => f.parent === folder.id);
const panels = panelsIn(folder.id);
const panels = visiblePanelsIn(folder.id);
const open = expanded[folder.id] !== false; // default expanded
const canDrop = folder.perm === 'write';
return (
@@ -256,7 +286,7 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
}
const rootFolders = folders.filter(f => !f.parent);
const rootPanels = panelsIn('');
const rootPanels = visiblePanelsIn('');
return (
<aside class={`panel${collapsed ? ' collapsed' : ''}`} style={!collapsed && width ? `width:${width}px;min-width:${width}px;` : undefined}>
@@ -289,6 +319,9 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
</div>
)}
<ScopeFilter me={me} value={bucket} onChange={setBucket}
group={scopeGroup} onGroupChange={setScopeGroup} />
<div class="panel-list">
{loading ? (
<p class="hint">Loading</p>