mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 05:30:46 +08:00
Require vendor when completing unmanaged NEs from topology.
Persist vendor on create/update and refresh the canvas node so icon tone matches inventory. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
57f45fdaaf
commit
bee86eea0d
3 changed files with 56 additions and 4 deletions
|
|
@ -1398,8 +1398,9 @@ const en = {
|
||||||
termConnect: {
|
termConnect: {
|
||||||
title: "Complete login",
|
title: "Complete login",
|
||||||
titleCreate: "Create NE and connect",
|
titleCreate: "Create NE and connect",
|
||||||
hint: "This node is not managed or lacks credentials. Enter IP and protocol to connect (same as creating/completing an NE).",
|
hint: "This node is not managed or lacks credentials. Enter IP, vendor, and protocol to connect (same as creating/completing an NE).",
|
||||||
name: "Name",
|
name: "Name",
|
||||||
|
vendor: "Vendor",
|
||||||
ip: "IP address",
|
ip: "IP address",
|
||||||
port: "Port",
|
port: "Port",
|
||||||
protocol: "Protocol",
|
protocol: "Protocol",
|
||||||
|
|
|
||||||
|
|
@ -1392,8 +1392,9 @@ const zh = {
|
||||||
termConnect: {
|
termConnect: {
|
||||||
title: "补全登录信息",
|
title: "补全登录信息",
|
||||||
titleCreate: "新建网元并登录",
|
titleCreate: "新建网元并登录",
|
||||||
hint: "该网元尚未纳管或缺少登录信息,请填写 IP 与协议后连接(等同新建/补全网元)。",
|
hint: "该网元尚未纳管或缺少登录信息,请填写 IP、厂家与协议后连接(等同新建/补全网元)。",
|
||||||
name: "名称",
|
name: "名称",
|
||||||
|
vendor: "厂家",
|
||||||
ip: "IP 地址",
|
ip: "IP 地址",
|
||||||
port: "端口",
|
port: "端口",
|
||||||
protocol: "协议",
|
protocol: "协议",
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import {
|
||||||
fetchLldpDiscoverJob,
|
fetchLldpDiscoverJob,
|
||||||
fetchManagedNe,
|
fetchManagedNe,
|
||||||
fetchManagedNeById,
|
fetchManagedNeById,
|
||||||
|
fetchManagedNeMeta,
|
||||||
fetchTopologyGraph,
|
fetchTopologyGraph,
|
||||||
fetchTopologyTree,
|
fetchTopologyTree,
|
||||||
fetchUmeNe,
|
fetchUmeNe,
|
||||||
|
|
@ -298,6 +299,7 @@ type CtxMenu =
|
||||||
type TermConnectDialog = {
|
type TermConnectDialog = {
|
||||||
neId: string;
|
neId: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
vendor: string;
|
||||||
ip_address: string;
|
ip_address: string;
|
||||||
port: number;
|
port: number;
|
||||||
protocol: "ssh" | "telnet";
|
protocol: "ssh" | "telnet";
|
||||||
|
|
@ -836,6 +838,16 @@ export function TopologyPage() {
|
||||||
});
|
});
|
||||||
}, [edges, expandPhysicalLinks, hidePorts, edgeFlow, edgeDefaults, selectedEdgeId]);
|
}, [edges, expandPhysicalLinks, hidePorts, edgeFlow, edgeDefaults, selectedEdgeId]);
|
||||||
|
|
||||||
|
const neMetaQuery = useQuery({
|
||||||
|
queryKey: queryKeys.managedNeMeta,
|
||||||
|
queryFn: fetchManagedNeMeta,
|
||||||
|
enabled: Boolean(termDialog),
|
||||||
|
staleTime: 60_000,
|
||||||
|
});
|
||||||
|
const termVendors = neMetaQuery.data?.vendors?.length
|
||||||
|
? neMetaQuery.data.vendors
|
||||||
|
: ["ZTE", "Huawei", "Cisco", "H3C", "Juniper", "Nokia", "Other"];
|
||||||
|
|
||||||
const treeQuery = useQuery({
|
const treeQuery = useQuery({
|
||||||
queryKey: queryKeys.topologyTree,
|
queryKey: queryKeys.topologyTree,
|
||||||
queryFn: fetchTopologyTree,
|
queryFn: fetchTopologyTree,
|
||||||
|
|
@ -1893,6 +1905,7 @@ export function TopologyPage() {
|
||||||
setTermDialog({
|
setTermDialog({
|
||||||
neId: managedId,
|
neId: managedId,
|
||||||
name: String(ne.name || node.data.label || "").trim(),
|
name: String(ne.name || node.data.label || "").trim(),
|
||||||
|
vendor: String(ne.vendor || node.data.vendor || "Other").trim() || "Other",
|
||||||
ip_address: hintIp,
|
ip_address: hintIp,
|
||||||
port: Number(ne.port) || (proto === "telnet" ? 23 : 22),
|
port: Number(ne.port) || (proto === "telnet" ? 23 : 22),
|
||||||
protocol: proto,
|
protocol: proto,
|
||||||
|
|
@ -1918,6 +1931,7 @@ export function TopologyPage() {
|
||||||
setTermDialog({
|
setTermDialog({
|
||||||
neId: "",
|
neId: "",
|
||||||
name: String(node.data.label || "").trim(),
|
name: String(node.data.label || "").trim(),
|
||||||
|
vendor: String(node.data.vendor || "Other").trim() || "Other",
|
||||||
ip_address: String(node.data.ne_ip || "").trim(),
|
ip_address: String(node.data.ne_ip || "").trim(),
|
||||||
port: 22,
|
port: 22,
|
||||||
protocol: "ssh",
|
protocol: "ssh",
|
||||||
|
|
@ -1945,12 +1959,14 @@ export function TopologyPage() {
|
||||||
}
|
}
|
||||||
const port = Number(termDialog.port) || (protocol === "telnet" ? 23 : 22);
|
const port = Number(termDialog.port) || (protocol === "telnet" ? 23 : 22);
|
||||||
const name = termDialog.name.trim() || ip;
|
const name = termDialog.name.trim() || ip;
|
||||||
|
const vendor = String(termDialog.vendor || "Other").trim() || "Other";
|
||||||
setTermBusy(true);
|
setTermBusy(true);
|
||||||
try {
|
try {
|
||||||
let neId = termDialog.neId;
|
let neId = termDialog.neId;
|
||||||
if (neId) {
|
if (neId) {
|
||||||
await updateManagedNe(neId, {
|
await updateManagedNe(neId, {
|
||||||
name,
|
name,
|
||||||
|
vendor,
|
||||||
ip_address: ip,
|
ip_address: ip,
|
||||||
port,
|
port,
|
||||||
protocol,
|
protocol,
|
||||||
|
|
@ -1960,14 +1976,22 @@ export function TopologyPage() {
|
||||||
setNodes((ns) =>
|
setNodes((ns) =>
|
||||||
ns.map((n) =>
|
ns.map((n) =>
|
||||||
String(n.data.managed_ne_id || "") === neId
|
String(n.data.managed_ne_id || "") === neId
|
||||||
? { ...n, data: { ...n.data, ne_ip: ip, label: name || n.data.label } }
|
? {
|
||||||
|
...n,
|
||||||
|
data: {
|
||||||
|
...n.data,
|
||||||
|
ne_ip: ip,
|
||||||
|
vendor,
|
||||||
|
label: name || n.data.label,
|
||||||
|
},
|
||||||
|
}
|
||||||
: n,
|
: n,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const created = await createManagedNe({
|
const created = await createManagedNe({
|
||||||
name,
|
name,
|
||||||
vendor: "Other",
|
vendor,
|
||||||
device_type: "generic",
|
device_type: "generic",
|
||||||
ip_address: ip,
|
ip_address: ip,
|
||||||
port,
|
port,
|
||||||
|
|
@ -1979,6 +2003,7 @@ export function TopologyPage() {
|
||||||
}
|
}
|
||||||
setTermDialog(null);
|
setTermDialog(null);
|
||||||
showOk(t("topology.termConnect.saved"));
|
showOk(t("topology.termConnect.saved"));
|
||||||
|
void queryClient.invalidateQueries({ queryKey: queryKeys.managedNeAll });
|
||||||
openOrFocusModule({
|
openOrFocusModule({
|
||||||
moduleId: "webcrt",
|
moduleId: "webcrt",
|
||||||
path: `/webcrt?ne_id=${encodeURIComponent(neId)}`,
|
path: `/webcrt?ne_id=${encodeURIComponent(neId)}`,
|
||||||
|
|
@ -3909,6 +3934,31 @@ export function TopologyPage() {
|
||||||
onChange={(e) => setTermDialog({ ...termDialog, name: e.target.value })}
|
onChange={(e) => setTermDialog({ ...termDialog, name: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<span className="form-label">
|
||||||
|
{t("topology.termConnect.vendor")}
|
||||||
|
<span className="form-label__required" aria-hidden="true">
|
||||||
|
{" "}
|
||||||
|
*
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<select
|
||||||
|
value={
|
||||||
|
termVendors.includes(termDialog.vendor) ? termDialog.vendor : termDialog.vendor || "Other"
|
||||||
|
}
|
||||||
|
disabled={termBusy}
|
||||||
|
onChange={(e) => setTermDialog({ ...termDialog, vendor: e.target.value })}
|
||||||
|
>
|
||||||
|
{!termVendors.includes(termDialog.vendor) && termDialog.vendor ? (
|
||||||
|
<option value={termDialog.vendor}>{termDialog.vendor}</option>
|
||||||
|
) : null}
|
||||||
|
{termVendors.map((v) => (
|
||||||
|
<option key={v} value={v}>
|
||||||
|
{v}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span className="form-label">
|
<span className="form-label">
|
||||||
{t("topology.termConnect.protocol")}
|
{t("topology.termConnect.protocol")}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue