mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 05:30:46 +08:00
feat(managed-ne): optional password and hop columns in import
Allow creating/importing NEs without target password for bastion-managed workflows, and support optional hop_* columns in bulk import templates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
bac4a609b1
commit
7d74e7b3f4
6 changed files with 167 additions and 53 deletions
|
|
@ -169,6 +169,8 @@ const en = {
|
|||
connectDetailTitle: "Connectivity test log",
|
||||
connectDetailEmpty:
|
||||
"No log yet. Run a connectivity test first; failures store full errors and hop context (passwords excluded).",
|
||||
importHint:
|
||||
"Import template includes optional hop columns (hop_enabled, etc.), or import NEs first then batch-add proxy. Password may be empty for bastion-managed targets.",
|
||||
importResult: {
|
||||
done: "Import done: {{inserted}} inserted, {{updated}} updated, {{failed}} failed row(s)",
|
||||
},
|
||||
|
|
@ -185,6 +187,8 @@ const en = {
|
|||
deleted: "Network element deleted",
|
||||
passwordRequired: "Password is required",
|
||||
passwordOptional: "leave blank to keep unchanged",
|
||||
passwordHint:
|
||||
"Required for direct login; leave empty when bastion manages target credentials. Use batch proxy later.",
|
||||
},
|
||||
hop: {
|
||||
sectionTitle: "Jump host / proxy",
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ const zh = {
|
|||
connectDetail: "详情",
|
||||
connectDetailTitle: "连通性测试日志",
|
||||
connectDetailEmpty: "暂无日志。请先执行连通性测试;失败时会记录完整错误与跳板上下文(不含密码)。",
|
||||
importHint:
|
||||
"导入模板含可选跳板列(hop_enabled 等);也可先导入网元再批量添加代理。密码可留空(堡垒机托管场景)。",
|
||||
importResult: {
|
||||
done: "导入完成:新增 {{inserted}},更新 {{updated}},失败 {{failed}} 行",
|
||||
},
|
||||
|
|
@ -183,6 +185,7 @@ const zh = {
|
|||
deleted: "网元已删除",
|
||||
passwordRequired: "请填写密码",
|
||||
passwordOptional: "留空则不修改",
|
||||
passwordHint: "直连网元需填写;经堡垒机托管时可留空,后续可用「批量添加代理」统一配置跳板。",
|
||||
},
|
||||
hop: {
|
||||
sectionTitle: "跳板 / 代理",
|
||||
|
|
|
|||
|
|
@ -185,10 +185,6 @@ export function NePage() {
|
|||
...(form.password ? { password: form.password } : {}),
|
||||
...(form.hop_password ? { hop_password: form.hop_password } : {}),
|
||||
};
|
||||
const bastionManaged =
|
||||
form.hop_enabled &&
|
||||
form.hop_vendor === "bastion" &&
|
||||
form.hop_target_auth_mode === "bastion_managed";
|
||||
if (form.hop_enabled) {
|
||||
if (!form.hop_host.trim()) throw new Error(t("managedNe.hop.hostRequired"));
|
||||
if (!form.hop_username.trim()) throw new Error(t("managedNe.hop.userRequired"));
|
||||
|
|
@ -199,7 +195,6 @@ export function NePage() {
|
|||
if (!form.hop_password) delete (body as { hop_password?: string }).hop_password;
|
||||
return updateManagedNe(editing.id, body);
|
||||
}
|
||||
if (!form.password && !bastionManaged) throw new Error(t("managedNe.form.passwordRequired"));
|
||||
return createManagedNe({ ...body, password: form.password || "" });
|
||||
},
|
||||
onSuccess: async () => {
|
||||
|
|
@ -372,6 +367,7 @@ export function NePage() {
|
|||
>
|
||||
{importMutation.isPending ? t("managedNe.importing") : t("managedNe.importBtn")}
|
||||
</button>
|
||||
<span className="form-field-hint">{t("managedNe.importHint")}</span>
|
||||
<input
|
||||
ref={importRef}
|
||||
type="file"
|
||||
|
|
@ -638,37 +634,16 @@ export function NePage() {
|
|||
/>
|
||||
</label>
|
||||
<label>
|
||||
<FormLabel
|
||||
required={
|
||||
!editing &&
|
||||
!(
|
||||
form.hop_enabled &&
|
||||
form.hop_vendor === "bastion" &&
|
||||
form.hop_target_auth_mode === "bastion_managed"
|
||||
)
|
||||
}
|
||||
>
|
||||
<FormLabel>
|
||||
{t("managedNe.col.password")}
|
||||
{editing ||
|
||||
(form.hop_enabled &&
|
||||
form.hop_vendor === "bastion" &&
|
||||
form.hop_target_auth_mode === "bastion_managed") ? (
|
||||
<span className="form-label__optional"> ({t("managedNe.form.passwordOptional")})</span>
|
||||
) : null}
|
||||
<span className="form-label__optional"> ({t("managedNe.form.passwordOptional")})</span>
|
||||
</FormLabel>
|
||||
<input
|
||||
type="password"
|
||||
required={
|
||||
!editing &&
|
||||
!(
|
||||
form.hop_enabled &&
|
||||
form.hop_vendor === "bastion" &&
|
||||
form.hop_target_auth_mode === "bastion_managed"
|
||||
)
|
||||
}
|
||||
value={form.password}
|
||||
onChange={(e) => setForm({ ...form, password: e.target.value })}
|
||||
/>
|
||||
<span className="form-field-hint">{t("managedNe.form.passwordHint")}</span>
|
||||
</label>
|
||||
<label>
|
||||
<FormLabel>{t("managedNe.col.tags")}</FormLabel>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue