mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 15:33:18 +08:00
Bring full managed-NE create onto the canvas (keep placeholders), add single/multi connect test and multi discover links, split topology/managedNe dialogs into modules, and shorten redundant connectivity failure details. Co-authored-by: Cursor <cursoragent@cursor.com>
167 lines
4.9 KiB
TypeScript
167 lines
4.9 KiB
TypeScript
import {
|
|
defaultHopTemplate,
|
|
isAutoHopTemplate,
|
|
type HopVendor,
|
|
} from "../../utils/hopProxy";
|
|
import type { ManagedNeItem } from "../../types";
|
|
|
|
export type ManagedNeFormState = {
|
|
name: string;
|
|
vendor: string;
|
|
device_type: string;
|
|
ip_address: string;
|
|
port: number;
|
|
protocol: string;
|
|
username: string;
|
|
password: string;
|
|
tags: string;
|
|
remark: string;
|
|
hop_enabled: boolean;
|
|
hop_vendor: HopVendor;
|
|
hop_host: string;
|
|
hop_port: number;
|
|
hop_protocol: string;
|
|
hop_username: string;
|
|
hop_password: string;
|
|
hop_command_template: string;
|
|
hop_vrf: string;
|
|
hop_target_auth_mode: "bastion_managed" | "manual";
|
|
hop_enter_system_view: boolean;
|
|
};
|
|
|
|
export function deviceTypeForVendor(vendor: string): string {
|
|
if (vendor === "ZTE") return "zte_zxros";
|
|
if (vendor === "Huawei") return "huawei";
|
|
if (vendor === "Cisco") return "cisco_ios";
|
|
if (vendor === "Juniper") return "juniper_junos";
|
|
if (vendor === "Nokia") return "nokia_sros";
|
|
return "generic";
|
|
}
|
|
|
|
export function emptyManagedNeForm(): ManagedNeFormState {
|
|
return {
|
|
name: "",
|
|
vendor: "ZTE",
|
|
device_type: "zte_zxros",
|
|
ip_address: "",
|
|
port: 22,
|
|
protocol: "ssh",
|
|
username: "",
|
|
password: "",
|
|
tags: "",
|
|
remark: "",
|
|
hop_enabled: false,
|
|
hop_vendor: "zte",
|
|
hop_host: "",
|
|
hop_port: 22,
|
|
hop_protocol: "ssh",
|
|
hop_username: "",
|
|
hop_password: "",
|
|
hop_command_template: defaultHopTemplate("zte", "ssh", ""),
|
|
hop_vrf: "",
|
|
hop_target_auth_mode: "bastion_managed",
|
|
hop_enter_system_view: false,
|
|
};
|
|
}
|
|
|
|
export function applyHopTemplate(
|
|
prev: ManagedNeFormState,
|
|
protocol: string,
|
|
vrf: string,
|
|
force = false,
|
|
): Partial<ManagedNeFormState> {
|
|
if (
|
|
!force &&
|
|
!isAutoHopTemplate(prev.hop_command_template, prev.hop_vendor, prev.hop_protocol, prev.hop_vrf)
|
|
) {
|
|
return {};
|
|
}
|
|
return { hop_command_template: defaultHopTemplate(prev.hop_vendor, protocol, vrf) };
|
|
}
|
|
|
|
export function formFromManagedNe(row: ManagedNeItem): ManagedNeFormState {
|
|
const hopVendor = (["linux", "huawei", "cisco", "zte", "bastion"].includes(row.hop_vendor)
|
|
? row.hop_vendor
|
|
: "zte") as HopVendor;
|
|
return {
|
|
name: row.name,
|
|
vendor: row.vendor,
|
|
device_type: row.device_type,
|
|
ip_address: row.ip_address,
|
|
port: row.port,
|
|
protocol: row.protocol,
|
|
username: row.username,
|
|
password: "",
|
|
tags: row.tags,
|
|
remark: row.remark,
|
|
hop_enabled: row.hop_enabled,
|
|
hop_vendor: hopVendor,
|
|
hop_host: row.hop_host,
|
|
hop_port: row.hop_port,
|
|
hop_protocol: row.hop_protocol,
|
|
hop_username: row.hop_username,
|
|
hop_password: "",
|
|
hop_command_template: isAutoHopTemplate(
|
|
row.hop_command_template,
|
|
row.hop_vendor,
|
|
row.hop_protocol,
|
|
row.hop_vrf,
|
|
)
|
|
? defaultHopTemplate(row.hop_vendor, row.hop_protocol, row.hop_vrf)
|
|
: row.hop_command_template || defaultHopTemplate(row.hop_vendor, row.hop_protocol, row.hop_vrf),
|
|
hop_vrf: row.hop_vrf,
|
|
hop_target_auth_mode: row.hop_target_auth_mode === "manual" ? "manual" : "bastion_managed",
|
|
hop_enter_system_view: Boolean(row.hop_enter_system_view),
|
|
};
|
|
}
|
|
|
|
export function managedSourceKey(
|
|
source: string | undefined,
|
|
): "manual" | "ume_sync" | "webcrt" | "lldp" | "topology" | "" {
|
|
const s = String(source || "").trim().toLowerCase();
|
|
if (!s) return "manual";
|
|
if (s === "ume_sync" || s === "webcrt" || s === "lldp" || s === "topology") return s;
|
|
return "";
|
|
}
|
|
|
|
/** Build API body + hop validation. Throws Error with message key text already translated by caller. */
|
|
export function buildManagedNeSaveBody(
|
|
form: ManagedNeFormState,
|
|
opts: { editing: boolean; hopHostRequired: string; hopUserRequired: string; hopPasswordRequired: string },
|
|
): Record<string, unknown> {
|
|
const body: Record<string, unknown> = {
|
|
name: form.name,
|
|
vendor: form.vendor,
|
|
device_type: form.device_type,
|
|
ip_address: form.ip_address,
|
|
port: form.port,
|
|
protocol: form.protocol,
|
|
username: form.username,
|
|
tags: form.tags,
|
|
remark: form.remark,
|
|
hop_enabled: form.hop_enabled,
|
|
hop_vendor: form.hop_vendor,
|
|
hop_host: form.hop_host,
|
|
hop_port: form.hop_port,
|
|
hop_protocol: form.hop_protocol,
|
|
hop_username: form.hop_username,
|
|
hop_command_template: form.hop_command_template,
|
|
hop_vrf: form.hop_vrf,
|
|
hop_target_auth_mode: form.hop_target_auth_mode,
|
|
hop_enter_system_view: form.hop_enter_system_view,
|
|
...(form.password ? { password: form.password } : {}),
|
|
...(form.hop_password ? { hop_password: form.hop_password } : {}),
|
|
};
|
|
if (form.hop_enabled) {
|
|
if (!form.hop_host.trim()) throw new Error(opts.hopHostRequired);
|
|
if (!form.hop_username.trim()) throw new Error(opts.hopUserRequired);
|
|
if (!opts.editing && !form.hop_password) throw new Error(opts.hopPasswordRequired);
|
|
}
|
|
if (opts.editing) {
|
|
if (!form.password) delete body.password;
|
|
if (!form.hop_password) delete body.hop_password;
|
|
} else {
|
|
body.password = form.password || "";
|
|
}
|
|
return body;
|
|
}
|