Major changes: logic add to panel, local variables, panel histor, users management...
This commit is contained in:
+35
-16
@@ -5,7 +5,8 @@ import ViewMode from './ViewMode';
|
||||
import EditMode from './EditMode';
|
||||
import FullscreenMode from './FullscreenMode';
|
||||
import { applyZoom, getStoredZoom } from './ZoomControl';
|
||||
import type { Interface } from './lib/types';
|
||||
import { AuthContext, DEFAULT_ME, fetchMe, canRead } from './lib/auth';
|
||||
import type { Interface, Me } from './lib/types';
|
||||
|
||||
type AppMode = 'view' | 'edit';
|
||||
|
||||
@@ -18,6 +19,8 @@ export default function App() {
|
||||
const [editTarget, setEditTarget] = useState<Interface | null>(null);
|
||||
// Interface to show when returning to view mode after editing
|
||||
const [viewTarget, setViewTarget] = useState<Interface | null>(null);
|
||||
// Resolved identity + global access level for the current user.
|
||||
const [me, setMe] = useState<Me>(DEFAULT_ME);
|
||||
|
||||
useEffect(() => {
|
||||
const unsub = wsClient.status.subscribe(setWsStatus);
|
||||
@@ -29,6 +32,7 @@ export default function App() {
|
||||
document.documentElement.style.setProperty('--dpr', String(dpr));
|
||||
applyZoom(getStoredZoom());
|
||||
if (!fsParam) wsClient.connect('/ws');
|
||||
fetchMe().then(setMe);
|
||||
}, []);
|
||||
|
||||
if (fsParam) {
|
||||
@@ -40,25 +44,40 @@ export default function App() {
|
||||
setMode('edit');
|
||||
}
|
||||
|
||||
function exitEdit(iface: Interface) {
|
||||
setViewTarget(iface);
|
||||
// `iface === null` means the editor discarded an unsaved/new panel; keep
|
||||
// showing whatever was previously open (held in viewTarget).
|
||||
function exitEdit(iface: Interface | null) {
|
||||
if (iface) setViewTarget(iface);
|
||||
setMode('view');
|
||||
setEditTarget(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{wsStatus === 'disconnected' && (
|
||||
<div class="connection-banner">WebSocket disconnected — reconnecting…</div>
|
||||
)}
|
||||
{/* ViewMode is always mounted so PlotPanel ring-buffers are never destroyed.
|
||||
EditMode is conditionally rendered; it resets from props each time anyway. */}
|
||||
<div style={`display:${mode === 'view' ? 'contents' : 'none'}`}>
|
||||
<ViewMode onEdit={enterEdit} initialInterface={viewTarget} />
|
||||
if (!canRead(me.level)) {
|
||||
return (
|
||||
<div class="app-root">
|
||||
<div class="access-denied">
|
||||
<h1>Access denied</h1>
|
||||
<p>
|
||||
Your account{me.user ? ` (${me.user})` : ''} does not have permission
|
||||
to access this application. Contact an administrator.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{mode === 'edit' && (
|
||||
<EditMode initial={editTarget} onDone={exitEdit} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={me}>
|
||||
<div class="app-root">
|
||||
{wsStatus === 'disconnected' && (
|
||||
<div class="connection-banner">WebSocket disconnected — reconnecting…</div>
|
||||
)}
|
||||
{mode === 'view' ? (
|
||||
<ViewMode onEdit={enterEdit} initialInterface={viewTarget} onView={setViewTarget} />
|
||||
) : (
|
||||
<EditMode key={editTarget?.id || 'new'} initial={editTarget} onDone={exitEdit} />
|
||||
)}
|
||||
</div>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user