This commit is contained in:
Martino Ferrari
2026-06-24 01:39:15 +02:00
parent 11120bedca
commit c0f7e662be
76 changed files with 4368 additions and 210 deletions
+26 -1
View File
@@ -1,6 +1,6 @@
import { h, Fragment } from 'preact';
import { useState, useCallback, useRef, useEffect } from 'preact/hooks';
import type { Interface, Widget, PlotLayout, StateVar, LogicGraph } from './lib/types';
import type { Interface, Widget, PlotLayout, StateVar, LogicGraph, Folder } from './lib/types';
import { serializeInterface, parseInterface } from './lib/xml';
import { initLocalState } from './lib/localstate';
import SignalTree from './SignalTree';
@@ -8,6 +8,7 @@ import EditCanvas, { genWidgetId, DEFAULT_SIZES } from './EditCanvas';
import PlotPanelCanvas from './PlotPanelCanvas';
import LogicEditor from './LogicEditor';
import PropertiesPane from './PropertiesPane';
import ShareDialog from './ShareDialog';
import HelpModal from './HelpModal';
import ZoomControl from './ZoomControl';
import { useAuth, canWrite } from './lib/auth';
@@ -121,6 +122,10 @@ export default function EditMode({ initial, onDone }: Props) {
const [showGroupMenu, setShowGroupMenu] = useState(false);
const [showHelp, setShowHelp] = useState(false);
const [helpSection, setHelpSection] = useState('edit');
// Panel sharing (folder, public visibility, grants). The folders list feeds
// ShareDialog's folder picker; fetched lazily the first time Share is opened.
const [showShare, setShowShare] = useState(false);
const [folders, setFolders] = useState<Folder[]>([]);
const [leftW, setLeftW] = useState(220);
const [rightW, setRightW] = useState(260);
// Center column tab: the drag-and-drop layout editor, or the panel-logic editor.
@@ -163,6 +168,15 @@ export default function EditMode({ initial, onDone }: Props) {
setShowHelp(true);
}, []);
// Open the panel-sharing dialog, refreshing the folder list it offers first.
const openShare = useCallback(() => {
fetch('/api/v1/folders')
.then(r => r.ok ? r.json() : [])
.then(data => setFolders(Array.isArray(data) ? data : []))
.catch(() => {})
.finally(() => setShowShare(true));
}, []);
// Undo / redo. Snapshots capture both widgets and (for plot panels) the split
// layout, so split/close/resize operations are undone atomically.
type Snapshot = { widgets: Widget[]; layout?: PlotLayout };
@@ -748,6 +762,7 @@ export default function EditMode({ initial, onDone }: Props) {
onChange={handleWidgetChange}
onRenameId={handleWidgetRename}
onIfaceChange={handleIfaceChange}
onShare={writable && iface.id ? openShare : undefined}
width={rightW}
/>
</Fragment>
@@ -797,6 +812,16 @@ export default function EditMode({ initial, onDone }: Props) {
{showHelp && (
<HelpModal initialSection={helpSection} onClose={() => setShowHelp(false)} />
)}
{showShare && iface.id && (
<ShareDialog
ifaceId={iface.id}
ifaceName={iface.name}
folders={folders}
onClose={() => setShowShare(false)}
onSaved={() => window.dispatchEvent(new CustomEvent('uopi:refresh-interfaces'))}
/>
)}
</div>
);
}
+9 -1
View File
@@ -10,6 +10,9 @@ interface Props {
onChange: (updated: Widget) => void;
onRenameId: (oldId: string, newId: string) => void;
onIfaceChange: (updated: Interface) => void;
// When provided, a "Share…" button is shown in the canvas-level section that
// opens the panel's sharing settings (folder, public visibility, grants).
onShare?: () => void;
width?: number;
}
@@ -86,7 +89,7 @@ const LABEL_WIDGETS = new Set(['textview', 'gauge', 'barh', 'barv', 'setvalue',
// Widgets with multiple signals
const MULTI_SIGNAL_WIDGETS = new Set(['plot', 'multiled', 'table']);
export default function PropertiesPane({ selected, multiCount, iface, onChange, onRenameId, onIfaceChange, width }: Props) {
export default function PropertiesPane({ selected, multiCount, iface, onChange, onRenameId, onIfaceChange, onShare, width }: Props) {
const [collapsed, setCollapsed] = useState(false);
const [configSets, setConfigSets] = useState<{ id: string; name: string }[]>([]);
@@ -173,6 +176,11 @@ export default function PropertiesPane({ selected, multiCount, iface, onChange,
</Field>
</div>
)}
{onShare && (
<button class="panel-btn props-share-btn" onClick={onShare} title="Manage folder, public visibility and per-user/group sharing">
Share
</button>
)}
</div>
{w && (
+5
View File
@@ -3016,6 +3016,11 @@ body {
.props-section:last-child { border-bottom: none; }
.props-share-btn {
margin: 0.4rem 0.6rem 0;
width: calc(100% - 1.2rem);
}
.props-section-title {
font-size: 0.7rem;
font-weight: 700;