Restore topology and WebCRT as workbench modules.

Also tighten config-sync policy form alignment and make the network nav collapse control icon-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-07-31 10:55:51 +08:00
parent f5b4a14c0f
commit abb5172a8f
11 changed files with 97 additions and 37 deletions

View file

@ -235,46 +235,43 @@ export function ConfigSyncPage() {
<div className="panel" style={{ marginBottom: 16 }}>
<h3>{t("configSync.policyTitle")}</h3>
<div className="filter-inline" style={{ flexWrap: "wrap", gap: 12 }}>
<label>
<input type="checkbox" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />{" "}
{t("configSync.enabled")}
<div className="config-sync-policy-row">
<label className="config-sync-policy-check">
<input type="checkbox" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />
<span>{t("configSync.enabled")}</span>
</label>
<label>
{t("configSync.intervalDays")}{" "}
<label className="config-sync-policy-field">
<span>{t("configSync.intervalDays")}</span>
<input
type="number"
min={1}
max={365}
value={intervalDays}
onChange={(e) => setIntervalDays(Math.max(1, Number(e.target.value) || 1))}
style={{ width: 72 }}
/>
</label>
<label>
{t("configSync.concurrency")}{" "}
<label className="config-sync-policy-field">
<span>{t("configSync.concurrency")}</span>
<input
type="number"
min={1}
max={30}
value={concurrency}
onChange={(e) => setConcurrency(Math.max(1, Math.min(30, Number(e.target.value) || 1)))}
style={{ width: 72 }}
/>
</label>
<label>
{t("configSync.historyKeep")}{" "}
<label className="config-sync-policy-field">
<span>{t("configSync.historyKeep")}</span>
<input
type="number"
min={0}
max={30}
value={historyKeep}
onChange={(e) => setHistoryKeep(Math.max(0, Math.min(30, Number(e.target.value) || 0)))}
style={{ width: 72 }}
/>
</label>
<label>
{t("configSync.scope")}{" "}
<label className="config-sync-policy-field">
<span>{t("configSync.scope")}</span>
<select
value={scopeMode}
onChange={(e) => setScopeMode(e.target.value === "selected" ? "selected" : "all")}

View file

@ -781,7 +781,7 @@ export function NePage() {
onClick={() =>
openOrFocusModule({
moduleId: "network",
path: `/network/webcrt?ne_id=${encodeURIComponent(row.id)}`,
path: `/webcrt?ne_id=${encodeURIComponent(row.id)}`,
})
}
title={t("managedNe.openTerminal")}

View file

@ -677,14 +677,14 @@ export function TopologyPage() {
if (managedId) {
openOrFocusModule({
moduleId: "network",
path: `/network/webcrt?ne_id=${encodeURIComponent(managedId)}`,
path: `/webcrt?ne_id=${encodeURIComponent(managedId)}`,
});
return;
}
if (umeId) {
openOrFocusModule({
moduleId: "network",
path: `/network/webcrt?ne_id=${encodeURIComponent(umeId)}&source=ume`,
path: `/webcrt?ne_id=${encodeURIComponent(umeId)}&source=ume`,
});
return;
}

View file

@ -125,7 +125,7 @@ export function NetworkConfigsPage() {
{t("networkConfigs.view")}
</button>
<Link
to={`/network/webcrt?${row.source === "ume" ? "ume_ne_id" : "ne_id"}=${encodeURIComponent(row.target_id)}`}
to={`/webcrt?${row.source === "ume" ? "ume_ne_id" : "ne_id"}=${encodeURIComponent(row.target_id)}`}
style={{ marginLeft: 8 }}
>
WebCRT