Default discover auto-placeholder and canvas neighbor project on.

Sync the canvas auto-add toggle with the shared LLDP collect policy so topology collect and canvas discover stay consistent.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-05 19:09:09 +08:00
parent af91c09d80
commit 51f061032a
4 changed files with 43 additions and 8 deletions

View file

@ -335,7 +335,9 @@ const en = {
policyTitle: "Collect policy",
policySaved: "Policy saved",
enabled: "Enable scheduled collect",
autoAddUnmatched: "Create SSH placeholder NEs for unmatched neighbors",
autoAddUnmatched: "Auto-add unmatched neighbors as placeholders on discover",
autoAddUnmatchedHint:
"Shared by scheduled collect and canvas discover. Off = record unmatched only, no placeholder NE. Default on.",
intervalDays: "Interval (days)",
interval: "Collect interval",
intervalUnitDays: "days",
@ -1444,7 +1446,7 @@ const en = {
alignNeedSelection: "Select at least two nodes",
snapGrid: "Snap to grid",
autoLayoutDiscover: "Auto-layout after discover",
discoverAutoAddUnmatched: "Auto-add unmatched NEs to fabric on discover",
discoverAutoAddUnmatched: "Auto-add unmatched NEs as placeholders on discover",
discoverProjectNeighbors: "Project direct neighbors onto canvas after discover",
undo: "Undo",
redo: "Redo",

View file

@ -332,7 +332,8 @@ const zh = {
policyTitle: "采集策略",
policySaved: "策略已保存",
enabled: "启用周期调度",
autoAddUnmatched: "未纳管邻居建 SSH 占位网元",
autoAddUnmatched: "发现时自动入库未匹配网元(占位)",
autoAddUnmatchedHint: "周期采集与画布单点发现共用;关闭则未匹配邻居只记未匹配、不建占位网元。默认开启。",
intervalDays: "周期(天)",
interval: "采集周期",
intervalUnitDays: "天",
@ -1437,7 +1438,7 @@ const zh = {
alignNeedSelection: "请至少选中两个节点",
snapGrid: "网格吸附",
autoLayoutDiscover: "发现后自动布局",
discoverAutoAddUnmatched: "发现时自动入库未匹配网元",
discoverAutoAddUnmatched: "发现时自动入库未匹配网元(占位)",
discoverProjectNeighbors: "发现后将直连邻居加入画布",
undo: "撤销",
redo: "重做",

View file

@ -40,6 +40,7 @@ import {
createTopologyView,
deleteTopologyFolder,
deleteTopologyMap,
fetchLldpCollectDashboard,
fetchLldpDiscoverJob,
fetchManagedNe,
fetchManagedNeById,
@ -52,6 +53,7 @@ import {
removeTopologyViewNodes,
searchFabricNodes,
startLldpDiscover,
updateLldpCollectPolicy,
updateTopologyFolder,
updateTopologyMap,
} from "../services/api";
@ -458,8 +460,8 @@ type EdgeDefaults = Record<EdgeSourceKind, EdgeDefaultStyle>;
const EDGE_DEFAULTS_KEY = "netx.topology.edgeDefaults";
const AUTO_LAYOUT_DISCOVER_KEY = "netx.topology.autoLayoutAfterDiscover";
const DISCOVER_AUTO_ADD_KEY = "netx.topology.discoverAutoAddUnmatched";
const DISCOVER_PROJECT_NEIGHBORS_KEY = "netx.topology.discoverProjectNeighbors";
const DISCOVER_AUTO_ADD_KEY = "netx.topology.discoverAutoAddUnmatched.v2";
const DISCOVER_PROJECT_NEIGHBORS_KEY = "netx.topology.discoverProjectNeighbors.v2";
const SCALE_BUNDLE_WIDTH_KEY = "netx.topology.scaleBundleWidth";
const CANVAS_BG_KEY = "netx.topology.canvasBg";
const DEFAULT_CANVAS_BG = "#0f172a";
@ -845,10 +847,10 @@ export function TopologyPage() {
const [snapToGrid, setSnapToGrid] = useState(true);
const [autoLayoutAfterDiscover, setAutoLayoutAfterDiscover] = useState(loadAutoLayoutAfterDiscover);
const [discoverAutoAddUnmatched, setDiscoverAutoAddUnmatched] = useState(() =>
loadBoolFlag(DISCOVER_AUTO_ADD_KEY, false),
loadBoolFlag(DISCOVER_AUTO_ADD_KEY, true),
);
const [discoverProjectNeighbors, setDiscoverProjectNeighbors] = useState(() =>
loadBoolFlag(DISCOVER_PROJECT_NEIGHBORS_KEY, false),
loadBoolFlag(DISCOVER_PROJECT_NEIGHBORS_KEY, true),
);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const [addNeOpen, setAddNeOpen] = useState(false);
@ -1049,6 +1051,24 @@ export function TopologyPage() {
}
}, [mapId]);
// Keep canvas "auto placeholder" in sync with topology LLDP collect policy (shared strategy).
useEffect(() => {
let alive = true;
void fetchLldpCollectDashboard()
.then((dash) => {
if (!alive || !dash?.policy) return;
const next = Boolean(dash.policy.auto_add_unmatched);
setDiscoverAutoAddUnmatched(next);
persistBoolFlag(DISCOVER_AUTO_ADD_KEY, next);
})
.catch(() => {
/* keep local default */
});
return () => {
alive = false;
};
}, []);
const neQuery = useQuery({
queryKey: [...queryKeys.managedNeAll, "topology-add-ne", debouncedKeyword],
queryFn: () =>
@ -3097,6 +3117,15 @@ export function TopologyPage() {
const next = e.target.checked;
setDiscoverAutoAddUnmatched(next);
persistBoolFlag(DISCOVER_AUTO_ADD_KEY, next);
void updateLldpCollectPolicy({ auto_add_unmatched: next })
.then(() => {
void queryClient.invalidateQueries({
queryKey: queryKeys.lldpCollectDashboard,
});
})
.catch(() => {
/* local toggle still applies to this canvas discover */
});
}}
/>
{t("topology.discoverAutoAddUnmatched")}

View file

@ -338,6 +338,9 @@ export function LldpLinksPage() {
<input type="checkbox" checked={autoAdd} onChange={(e) => setAutoAdd(e.target.checked)} />
<span>{t("lldpLinks.autoAddUnmatched")}</span>
</label>
<p className="muted" style={{ margin: "0 0 8px", gridColumn: "1 / -1" }}>
{t("lldpLinks.autoAddUnmatchedHint")}
</p>
<label className="config-sync-policy-field">
<span>{t("lldpLinks.interval")}</span>
<input