This commit is contained in:
Martino Ferrari
2026-04-25 22:56:09 +02:00
parent 8b548ba1c2
commit 986f6cd6d8
85 changed files with 11479 additions and 5050 deletions
+91
View File
@@ -0,0 +1,91 @@
import { h } from 'preact';
import { useState } from 'preact/hooks';
import InterfaceList from './InterfaceList';
import Canvas from './Canvas';
import { wsClient } from './lib/ws';
import { parseInterface } from './lib/xml';
import type { Interface } from './lib/types';
import { useEffect } from 'preact/hooks';
interface Props {
onEdit?: (iface?: Interface) => void;
}
export default function ViewMode({ onEdit }: Props) {
const [currentInterface, setCurrentInterface] = useState<Interface | null>(null);
const [parseError, setParseError] = useState<string | null>(null);
const [wsStatus, setWsStatus] = useState('connecting');
useEffect(() => {
const unsub = wsClient.status.subscribe(setWsStatus);
return unsub;
}, []);
function handleLoad(xml: string) {
try {
setParseError(null);
setCurrentInterface(parseInterface(xml));
} catch (err) {
setParseError(err instanceof Error ? err.message : 'Failed to parse interface file.');
}
}
async function handleNavigate(interfaceId: string) {
try {
const res = await fetch(`/api/v1/interfaces/${encodeURIComponent(interfaceId)}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const xml = await res.text();
handleLoad(xml);
} catch (err) {
setParseError(`Failed to load interface "${interfaceId}": ${err instanceof Error ? err.message : err}`);
}
}
return (
<div class="view-mode">
<header class="toolbar">
<div class="toolbar-left">
<span class="app-name">uopi</span>
{currentInterface && (
<span class="iface-name">{currentInterface.name}</span>
)}
</div>
<div class="toolbar-center">
{parseError && (
<span class="parse-error" title={parseError}>Parse error check console</span>
)}
</div>
<div class="toolbar-right">
<div class={`status-chip ${wsStatus}`}>
<span class="status-dot"></span>
{wsStatus}
</div>
<button
class="btn-edit"
onClick={() => onEdit?.(currentInterface ?? undefined)}
title="Switch to Edit mode"
>
Edit
</button>
</div>
</header>
<div class="content">
<InterfaceList
onLoad={handleLoad}
onEdit={onEdit}
onSelect={async (id) => {
try {
const res = await fetch(`/api/v1/interfaces/${encodeURIComponent(id)}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
handleLoad(await res.text());
} catch (err) {
setParseError(`Failed to load interface "${id}": ${err instanceof Error ? err.message : err}`);
}
}}
/>
<Canvas iface={currentInterface} onNavigate={handleNavigate} />
</div>
</div>
);
}