diff --git a/web/src/Canvas.tsx b/web/src/Canvas.tsx index 375bb9d..47933cd 100644 --- a/web/src/Canvas.tsx +++ b/web/src/Canvas.tsx @@ -1,7 +1,8 @@ -import { h } from 'preact'; +import { h, Fragment } from 'preact'; import { useState, useEffect } from 'preact/hooks'; import { initLocalState } from './lib/localstate'; import { logicEngine } from './lib/logic'; +import { getWidgetCmdStore, type WidgetCmd } from './lib/widgetCommands'; import type { Interface, Widget, SignalRef } from './lib/types'; import TextView from './widgets/TextView'; import TextLabel from './widgets/TextLabel'; @@ -42,6 +43,32 @@ interface CtxState { signal: SignalRef | null; } +// Wraps a single view-mode widget so panel logic (action.widget) can drive it: +// `hidden` removes it from the view, `disabled` dims it and blocks interaction +// via a transparent overlay (which still surfaces the right-click menu). Plot +// pause/clear are handled inside PlotWidget itself. +function WidgetView({ widget, children, onContextMenu }: { + widget: Widget; + children: any; + onContextMenu: (e: MouseEvent) => void; + key?: string; +}) { + const [cmd, setCmd] = useState(() => getWidgetCmdStore(widget.id).get()); + useEffect(() => getWidgetCmdStore(widget.id).subscribe(setCmd), [widget.id]); + if (cmd.hidden) return null; + if (!cmd.disabled) return children; + return ( + + {children} +
+ + ); +} + interface Props { iface: Interface | null; onNavigate?: (interfaceId: string) => void; @@ -131,9 +158,8 @@ export default function Canvas({ iface, onNavigate, timeRange }: Props) {
{iface.widgets.map(widget => { const Comp = COMPONENTS[widget.type]; - return Comp + const inner = Comp ? onCtxMenu(e, widget)} onNavigate={onNavigate} @@ -141,7 +167,6 @@ export default function Canvas({ iface, onNavigate, timeRange }: Props) { /> : (
{widget.type}
); + return ( + onCtxMenu(e, widget)} + > + {inner} + + ); })}
diff --git a/web/src/EditMode.tsx b/web/src/EditMode.tsx index 992ea73..4f9fc82 100644 --- a/web/src/EditMode.tsx +++ b/web/src/EditMode.tsx @@ -682,6 +682,7 @@ export default function EditMode({ initial, onDone }: Props) { diff --git a/web/src/LogicDialogs.tsx b/web/src/LogicDialogs.tsx index f902b95..0392c1f 100644 --- a/web/src/LogicDialogs.tsx +++ b/web/src/LogicDialogs.tsx @@ -13,10 +13,18 @@ export default function LogicDialogs() { } function DialogModal({ req }: { req: DialogRequest; key?: string }) { - const [val, setVal] = useState(req.defaultValue ?? ''); const isSetpoint = req.kind === 'setpoint'; + const inputIdx = req.fields + .map((f, i) => (f.type === 'input' ? i : -1)) + .filter(i => i >= 0); + // Per-input editable values, keyed by field index, seeded from the prefill. + const [vals, setVals] = useState>( + () => Object.fromEntries(inputIdx.map(i => [i, req.fields[i].value])) + ); - function ok() { req.resolve(isSetpoint ? val : ''); } + function ok() { + req.resolve(inputIdx.map(i => vals[i] ?? '')); + } function cancel() { req.resolve(null); } function onKey(e: KeyboardEvent) { @@ -29,12 +37,20 @@ function DialogModal({ req }: { req: DialogRequest; key?: string }) {