Implemented admin pane + user permission
This commit is contained in:
@@ -15,6 +15,30 @@ interface Props {
|
||||
onToggleCollapse: () => void;
|
||||
}
|
||||
|
||||
// Monochrome (currentColor) panel-kind glyph. Inline SVG avoids font-dependent
|
||||
// emoji that may render in colour or as a missing-glyph box.
|
||||
function KindIcon({ kind }: { kind?: 'panel' | 'plot' }) {
|
||||
const plot = kind === 'plot';
|
||||
return (
|
||||
<span class="iface-item-icon" title={plot ? 'Plot panel' : 'HMI panel'}>
|
||||
{plot ? (
|
||||
<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M2.5 2.5 v11 h11" />
|
||||
<path d="M4.5 11 L7 7.5 L9 9.5 L13 4.5" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<rect x="2" y="2.5" width="12" height="11" rx="1.5" />
|
||||
<path d="M4.5 6 h7" />
|
||||
<circle cx="6" cy="6" r="1.2" fill="currentColor" stroke="none" />
|
||||
<path d="M4.5 10 h7" />
|
||||
<circle cx="10" cy="10" r="1.2" fill="currentColor" stroke="none" />
|
||||
</svg>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onEditId, width, collapsed, onToggleCollapse }: Props) {
|
||||
const [interfaces, setInterfaces] = useState<InterfaceListItem[]>([]);
|
||||
const [folders, setFolders] = useState<Folder[]>([]);
|
||||
@@ -87,6 +111,7 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
|
||||
id: String(item.id || item.ID || ''),
|
||||
name: String(item.name || item.Name || ''),
|
||||
version: Number(item.version || item.Version || 0),
|
||||
kind: item.kind === 'plot' ? ('plot' as const) : undefined,
|
||||
owner: item.owner ? String(item.owner) : '',
|
||||
folder: item.folder ? String(item.folder) : '',
|
||||
order: Number(item.order || 0),
|
||||
@@ -171,19 +196,21 @@ export default function InterfaceList({ onLoad, onSelect, onEdit, onNewPlot, onE
|
||||
return (
|
||||
<li
|
||||
key={item.id}
|
||||
class={`iface-item${dropTarget === `p:${item.id}` ? ' drop-target' : ''}`}
|
||||
class={`iface-item iface-item-clickable${dropTarget === `p:${item.id}` ? ' drop-target' : ''}`}
|
||||
draggable={drag}
|
||||
onClick={() => onSelect?.(item.id)}
|
||||
onDragStart={drag ? (e) => { dragId.current = item.id; e.dataTransfer!.effectAllowed = 'move'; } : undefined}
|
||||
onDragEnd={endDrag}
|
||||
onDragOver={(e) => { if (dragId.current) { e.preventDefault(); e.stopPropagation(); setDropTarget(`p:${item.id}`); } }}
|
||||
onDragLeave={() => setDropTarget(t => t === `p:${item.id}` ? null : t)}
|
||||
onDrop={(e) => dropOnPanel(item, e)}
|
||||
>
|
||||
<span class="iface-item-name" onClick={() => onSelect?.(item.id)} title={item.owner ? `Owner: ${item.owner}` : undefined}>
|
||||
<span class="iface-item-name" title={item.owner ? `Owner: ${item.owner}` : undefined}>
|
||||
<KindIcon kind={item.kind} />
|
||||
{item.name || item.id}
|
||||
{item.perm === 'read' && <span class="iface-badge" title="Read-only">ro</span>}
|
||||
</span>
|
||||
<div class="iface-item-actions">
|
||||
<div class="iface-item-actions" onClick={(e) => e.stopPropagation()}>
|
||||
{item.perm === 'write' && <button class="icon-btn" title="Edit" onClick={() => onEditId?.(item.id)}>✎</button>}
|
||||
<button class="icon-btn" title="Open fullscreen in new tab" onClick={() => handleFullscreen(item.id)}>⛶</button>
|
||||
{writable && <button class="icon-btn" title="Clone" onClick={() => handleClone(item.id)}>⎘</button>}
|
||||
|
||||
Reference in New Issue
Block a user