netx/web/src/i18n/en.ts
oliver 572b0cfd9d Add UME-managed NE sync and batch account tools.
Sync UME inventory into managed NE with source-aware dedupe and cleanup, add one-click account updates for selected or tagged NEs, and expose the new managed NE actions in the web UI while keeping bulk bastion flows compatible with optional target passwords.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 10:52:54 +08:00

540 lines
22 KiB
TypeScript

const en = {
common: {
help: "Help",
refresh: "Refresh",
refreshing: "Refreshing…",
query: "Search",
clearFilters: "Clear filters",
prevPage: "Previous",
nextPage: "Next",
perPage: "{{n}}/page",
pagerMeta: "{{total}} items · page {{page}}/{{pages}}",
opFailed: "Operation failed",
empty: "-",
},
workbench: {
title: "Workbench",
backToWorkbench: "Back to Workbench",
openInNewTab: "Open in new tab",
openModule: "Open or switch to this module tab",
monitoring: "Monitoring",
operations: "Operations",
cards: {
umeSync: "UME Sync",
umeSyncDesc: "UME alarms, subscription & inventory",
managedNe: "NE Management",
managedNeDesc: "Multi-vendor SSH/Telnet NEs & connectivity test",
collect: "Batch Collect",
collectDesc: "Run custom CLI commands on connected NEs and save logs",
},
},
layout: {
title: "UME Integration",
titleUme: "UME Sync",
titleManagedNe: "NE Management",
titleCollect: "Batch Collect",
navUme: "UME",
netxApi: "netx api",
oclawBridge: "oclaw WSS",
language: "Language",
moreMenu: "More",
langZh: "中文",
langEn: "English",
},
collect: {
create: {
title: "New collection job",
hint: "Configure commands and NEs, then create the job. Click Start in the job list to run collection.",
selectedTitle: "Selected NEs",
selectedEmpty: "Filter below and add NEs one by one.",
selectedCount: "{{count}} selected",
clearSelected: "Clear selection",
remove: "Remove",
pickTitle: "Eligible NEs (connectivity passed)",
pickHint: "Only NEs with connect_status=pass. Run connectivity test in NE Management first.",
pickEmpty: "No matching NEs.",
filterKeyword: "Filter",
filterKeywordPh: "Name / IP / vendor / device type",
add: "Add",
addBatch: "Add selected ({{count}})",
added: "Added",
create: "Create job",
creating: "Creating…",
expand: "Expand",
collapse: "Collapse",
meta: "{{ne}} NE(s) selected · {{cmd}} command(s)",
},
eligible: {
title: "Eligible NEs (connectivity passed)",
hint: "Only NEs with connect_status=pass. Run connectivity test in NE Management first.",
empty: "No NEs with passed connectivity test.",
},
form: {
title: "Collection setup",
jobTitle: "Job title",
jobTitlePh: "Auto-generated if empty",
commands: "Commands (one per line, # for comments)",
commandsPh: "display version\ndisplay current-configuration",
commandsHint: "Commands run in order on each device; output is saved as a text log (legacy NetX format).",
meta: "{{ne}} NE(s) selected · {{cmd}} command(s)",
start: "Start collection",
starting: "Submitting…",
},
created: "Collection job created: {{id}}",
started: "Collection started: {{id}}",
paused: "Job paused",
restarted: "Collection restarted",
retryFailedDone: "Retrying failed devices",
deleted: "Job deleted",
nothingToRetry: "No failed devices to retry",
neBusy: "Some NEs are busy in another collection job; wait for it to finish before starting",
jobRunning: "This job is already running",
confirmDelete: "Delete this collection job and its log files?",
jobs: {
title: "Collection jobs",
col: {
title: "Job",
status: "Status",
progress: "Progress",
created: "Created",
lastRun: "Last run",
actions: "Actions",
},
ok: "ok",
fail: "fail",
expand: "Details",
collapse: "Hide",
pause: "Pause",
start: "Start",
starting: "Starting…",
restart: "Restart",
retryFailed: "Retry failed",
downloadResults: "Download results",
delete: "Delete",
autoRefresh: "Auto-refresh every 2s while jobs are running",
runsInProgress: "Some devices are still being collected…",
},
runs: {
status: "Status",
message: "Message",
download: "Log",
downloadFile: "Download",
filterStatus: "Status filter",
filterDevice: "Device filter",
deviceKeywordPh: "Name / IP",
allStatus: "All statuses",
},
},
managedNe: {
title: "Network Elements",
credsNotConfigured:
"NETX_CREDENTIAL_SECRET_KEY is not set. Configure a Fernet key in .env and restart the API to store passwords.",
add: "Add NE",
importBtn: "Import",
downloadTemplate: "Download template",
importing: "Importing…",
edit: "Edit",
delete: "Delete",
confirmDelete: "Delete this network element?",
batchDelete: "Batch delete",
batchDeleting: "Deleting…",
batchDeleteConfirm: "Delete {{n}} selected network element(s)? This cannot be undone.",
batchDeleteDone: "Deleted {{n}} network element(s)",
batchDeleteSelectRequired: "Select network elements to delete",
keywordPh: "name / IP / user / tags",
allVendors: "All vendors",
allConnectStatus: "All connect status",
stats: {
title: "Overview",
total: "{{n}} NEs managed",
pass: "Connected",
fail: "Failed",
unknown: "Untested",
testing: "Testing",
batchProxy: "Batch add proxy",
batchTest: "Batch connect-test",
tagFilter: "Filter by tag",
all: "All",
allTag: "All (no tag filter)",
noTag: "No tags",
tagStats: "Top tags",
confirm: "Apply to {{n}} NE(s). Continue?",
proxyDone: "Proxy applied to {{n}} NE(s)",
testDone: "Connect-test submitted for {{n}} NE(s)",
loadingIds: "Loading…",
},
col: {
name: "Name",
vendor: "Vendor",
deviceType: "Device type",
ip: "Management IP",
port: "Port",
protocol: "Protocol",
user: "Username",
password: "Password",
tags: "Tags",
remark: "Remark",
connect: "Connect",
testedAt: "Tested at",
actions: "Actions",
},
connect: {
run: "Connectivity test",
running: "Testing…",
submitted: "Submitted tests for {{n}} device(s)",
retest: "Test again",
},
connectDetail: "Details",
connectDetailTitle: "Connectivity test log",
connectDetailEmpty:
"No log yet. Run a connectivity test first; failures store full errors and hop context (passwords excluded).",
umeSync: {
sync: "Sync UME NEs",
syncing: "Syncing…",
delete: "Delete UME NEs",
deleting: "Deleting…",
deleteConfirm: "Delete all managed NEs created from UME sync? This cannot be undone.",
done: "UME sync done: {{inserted}} inserted, {{updated}} updated, {{deleted}} deleted, {{total}} inventory total",
deletedDone: "Deleted {{n}} UME-synced NEs",
},
account: {
batchAdd: "Batch add account",
batchByTag: "Batch account by tag",
batchTitle: "Batch add account",
batchHint: "Apply the account info below to {{n}} selected NE(s).",
batchByTagHint: "Apply the account info below to NEs under the selected tag; leave password blank to update only username.",
batchDone: "Account updated for {{n}} NE(s)",
selectRequired: "Select network elements first",
applying: "Applying…",
apply: "Apply to NEs",
usernameOrPasswordRequired: "Enter at least a username or a password",
passwordOptionalBatch: "leave blank to keep unchanged",
},
help:
"[Bulk import]\n" +
"· Required columns: device_type, ip, username, port, protocol, name, vendor. Download the template first.\n" +
"· password may be empty (required for direct login; optional for bastion-managed or batch proxy later).\n" +
"· Recommended flow: import NEs first, select rows, then use Batch add proxy.\n\n" +
"[Jump / bastion]\n" +
"· Bastion SSH username template: {hop_user}@{target_user}@{target_ip} (bastion host is separate); CLI: ssh user@target@ip@bastion-host.\n" +
"· Bastion-managed: set Jump password (Vault); target password optional. Manual mode needs target password.\n" +
"· JumpServer/CBH often use port 2222; some sites use 22.\n\n" +
"[Connectivity / edit]\n" +
"· NETX_CREDENTIAL_SECRET_KEY required to store passwords.\n" +
"· Leave password blank on edit to keep unchanged; open Details after failed connect-test for hop context (no secrets).",
importResult: {
done: "Import done: {{inserted}} inserted, {{updated}} updated, {{failed}} failed row(s)",
},
form: {
requiredHint: "Fields marked with * are required",
nameConnectHint: "After a successful connectivity test, name is replaced with the device hostname",
createTitle: "Add network element",
editTitle: "Edit network element",
save: "Save",
saving: "Saving…",
cancel: "Cancel",
created: "Network element created",
updated: "Network element updated",
deleted: "Network element deleted",
passwordRequired: "Password is required",
passwordOptional: "leave blank to keep unchanged",
},
hop: {
sectionTitle: "Jump host / proxy",
type: "Jump type",
enable: "Connect to target via jump host",
vendor: {
zte: "ZTE device (CLI jump)",
huawei: "Huawei device (CLI jump)",
cisco: "Cisco device (CLI jump)",
linux: "Linux server (SSH tunnel)",
bastion: "Bastion host (SSH protocol proxy)",
},
zteHint: "Run ssh/telnet on the ZTE device to reach the target; target credentials use secondary auth.",
huaweiHint: "Run telnet / stelnet (SSH) on the Huawei hop; stelnet is SSH. Target credentials use secondary auth.",
ciscoHint: "Run Cisco ssh -vrf / telnet /vrf jump commands; target credentials use secondary auth.",
linuxHint: "SSH to the Linux bastion, then direct-tcpip tunnel to target IP:port (ProxyJump-style).",
bastionHint:
"SSH with composite username via bastion protocol proxy. Example: bastion-user@target-user@2.2.2.2@1.1.1.1; password is the bastion/Vault password. JumpServer/CBH often use port 2222.",
targetAuthMode: "Target credentials",
targetAuthBastionManaged: "Bastion-managed (target password optional)",
targetAuthManual: "Manual (secondary auth after connect)",
targetAuthHint: "Bastion-managed needs only bastion password; manual mode requires target NE password.",
usernameTemplate: "SSH username template",
templateHintBastion:
"Default {hop_user}@{target_user}@{target_ip}. Bastion address is the hop host field. CLI example: ssh bastion-user@target-user@2.2.2.2@1.1.1.1.",
host: "Jump host",
port: "Jump port",
protocol: "Jump protocol",
protocolSshStelnet: "ssh (stelnet)",
username: "Jump username",
password: "Jump password",
vrf: "Mgmt VRF (optional)",
vpnInstance: "VPN-Instance (optional)",
vrfCisco: "VRF (optional, e.g. MGMT)",
commandTemplate: "Jump command template",
templateHint:
"ZTE CLI: telnet {target_ip}, telnet {target_ip} vrf {vrf}, ssh {target_ip}, ssh {target_ip} vrf {vrf}. Auto-suggested from jump protocol/VRF; same when left blank. Target credentials via secondary auth prompts.",
templateHintHuawei:
"Huawei CLI: telnet {target_ip}, telnet vpn-instance {vrf} {target_ip}, stelnet {target_ip}, stelnet {target_ip} -vpn-instance {vrf}. SSH protocol maps to stelnet. Auto-suggested when left blank.",
templateHintCisco:
"Cisco CLI: ssh {target_ip}, ssh -vrf {vrf} {target_ip}, telnet {target_ip}, telnet {target_ip} /vrf {vrf}. Auto-suggested when left blank.",
badge: {
zte: "ZTE hop",
huawei: "Huawei hop",
cisco: "Cisco hop",
linux: "Linux hop",
bastion: "Bastion",
},
hostRequired: "Jump host is required",
userRequired: "Jump username is required",
passwordRequired: "Jump password is required",
batchAdd: "Add proxy",
batchTitle: "Batch add jump proxy",
batchHint: "Apply the jump-host settings below to {{n}} selected NE(s) (overwrites existing proxy config).",
batchDone: "Proxy applied to {{n}} NE(s)",
selectRequired: "Select network elements first",
applying: "Applying…",
apply: "Apply to selected",
},
},
ume: {
token: {
title: "UME Token",
disconnected: "disconnected",
connected: "connected",
connectedRenew: "connected (renew required)",
expiresIn: "expires_in",
needsRenew: "renew / 0s",
preview: "preview",
refreshStatus: "Refresh status",
renewLogin: "Renew / login",
renewing: "Renewing…",
disconnect: "Disconnect token",
disconnecting: "Disconnecting…",
renewOkChanged: "Token renewed and updated",
renewOkSame: "Renew completed (unchanged)",
disconnectOk: "UME token disconnected",
renewHint: "Token missing expiry or expired. Use Renew / login or wait for background keepalive.",
},
subscription: {
title: "UME alarm subscription (WebSocket)",
help:
"Subscriptions must be created/cancelled manually. After establish (or on restart if a valid subscription exists in DB), the backend auto-connects WSS for live alarms. Pause/resume on runtime task alarms_current_ws_consumer stops/resumes WSS only (does not cancel the UME subscription).",
sub: "subscription",
subActive: "active",
subInactive: "inactive",
wssPaused: "paused",
wssModeBanner:
"Current alarms are maintained via WSS (mode: {{mode}}); scheduled REST full sync is paused. Use Sync current alarms below for full reconcile.",
serverLostBanner:
"UME server subscription is missing or expired; local state may still show active. Clear local record and re-subscribe.",
establish: "Establish subscription",
establishing: "Establishing…",
reestablish: "Clear local & re-subscribe",
reestablishing: "Re-subscribing…",
cancel: "Cancel subscription",
cancelling: "Cancelling…",
refreshStatus: "Refresh subscription",
clearLocalOnly: "Clear local only",
clearing: "Clearing…",
opFailed: "Subscription operation failed",
confirmClearDefault:
"UME alarm subscription no longer exists or has expired.\n\nClear local subscription record? You can establish again afterwards.",
confirmReestablish: "Clear local record and re-establish subscription on UME. Continue?",
titleLoginFirst: "Log in to UME token first",
titleReestablish: "Clear stale local record and re-establish on UME",
establishInvalid: "Establish did not return a valid id/uri",
establishExists: "Subscription already exists (WSS will stay/connect)",
establishOk: "Subscription established; WSS will connect",
clearLocalOk: "Local subscription cleared; you can establish again",
serverLostMsg: "UME subscription lost. Clear local record and re-subscribe?",
cancelFailed: "Cancel failed: subscription may still exist on UME",
cancelOkMissing: "Local cleared (UME subscription was already missing)",
cancelOk: "Subscription cancelled",
wsLogs: "WSS runtime log",
wsActivity: "Last activity {{time}}",
wsAutoRefresh: "Auto refresh",
wsLogsEmpty: "No logs yet (connect WSS after establishing subscription)",
},
keyAlert: {
title: "AI alarm monitor (OClaw WhatsApp)",
showPanel: "Expand",
hidePanel: "Collapse",
help: "Exact match by notificationId, or substring match on alarm description (case-insensitive; nativeProbableCause, etc.). Optionally restrict to UME inventory ne_type values (multi-select; empty = all devices). Pushed via OClaw WebSocket. Shares NETX_OCLAW_ANALYZE_TOKEN.",
ws: "OClaw WSS",
wsConnected: "connected",
wsDisconnected: "disconnected",
wsDisabled: "disabled",
wsPaused: "paused",
publishedOk: "published ok",
publishedFail: "published fail",
queue: "queue",
matchType: "Match by",
matchNotificationId: "notificationId",
matchKeyword: "description keyword",
matchValuePhNotificationId: "Enter notificationId",
matchValuePhKeyword: "Enter keyword (case-insensitive)",
label: "Rule description",
labelPh: "Required, e.g. BGP Down",
neTypesLabel: "Device types (optional, multi-select)",
neTypesHint: "Leave empty to match all device types. Options come from synced UME Inventory ne_type.",
neTypesEmpty: "No device types yet — sync Inventory first",
neTypesAll: "All",
forwardOnClear: "Push on alarm clear",
forwardOnClearHelp: "Global switch for all monitor rules. By default only new/updated alarms are pushed; when enabled, clear notifications are also sent when UME reports alarms cleared.",
add: "Add rules",
adding: "Adding…",
delete: "Delete",
edit: "Edit",
editTitle: "Edit monitor rule",
save: "Save",
saving: "Saving…",
cancel: "Cancel",
editOk: "Rule updated",
pickFromAlarms: "Load alarm hints",
emptyRules: "No monitor rules yet",
colType: "type",
colMatch: "match",
colLabel: "description",
colNeTypes: "device types",
colForwardClear: "on clear",
colPublished: "published",
colAttempts: "attempts",
colLast: "last push",
colActions: "actions",
colMonitor: "monitor",
monitorOn: "on",
monitorOff: "off",
filterKeywordPh: "Filter match / label",
filterMatchAll: "All types",
filterEnabledAll: "All states",
filterEnabledOn: "Monitoring on",
filterEnabledOff: "Monitoring off",
addOk: "Monitor rule added",
deleteOk: "Deleted",
confirmDelete: "Delete this monitor rule?",
yes: "yes",
no: "no",
},
sync: {
title: "UME sync",
inventory: "Sync inventory",
alarmsCurrent: "Sync current alarms",
full: "Full sync",
failed: "Sync failed",
},
tasks: {
currentTitle: "Running jobs",
running: "running",
noRunning: "No running jobs",
runtimeTitle: "Background tasks",
runtimeOpFailed: "Background task operation failed",
noRuntime: "No background task status",
intervalTitle: "Configured sleep between loop iterations (clamped at process start)",
lastRunTitle: "Last finished sync for scheduled tasks; refreshed at each loop tick",
deletedTitle: "Reconcile deletes: inventory = NE rows; alarms_current = current alarm rows",
lastErrorCol: "last_error",
runtimeError: {
startup_alarm_sync_before_ws: "Starting up: syncing current alarms (WSS connects after completion)…",
startup_gate_waiting: "Startup REST snapshot pending; scheduled REST and WSS on standby",
wss_active_skip_rest: "WSS receiving live alarms; REST sync skipped",
pulling_alarms_current: "Pulling UME current alarms…",
alarms_sync_in_progress_skip: "Another current-alarm REST sync in progress; skipped",
pulling_inventory: "Pulling UME inventory…",
ume_ws_disabled_no_base_url: "Disabled or UME_BASE_URL not configured",
oclaw_fwd_disabled: "Disabled or NETX_OCLAW_ALARM_WS / token / url not configured",
resumed_sync_soon: "Resumed: skipping debounce wait, sync soon",
resumed_wss_reconnect: "Resumed: reconnecting WSS soon",
resumed_oclaw_wss_reconnect: "Resumed: reconnecting OClaw WSS soon",
resumed: "Resumed",
keepalive_failed: "Token keepalive failed",
},
wsState: {
init: "Initializing",
connected: "Connected",
connecting: "Connecting",
disconnected: "Disconnected",
no_subscription: "No subscription",
waiting_token: "Waiting for token",
paused: "Paused",
error: "Connection error",
reconnecting: "Reconnecting",
subscription_lost: "UME subscription lost",
disabled_no_base_url: "Disabled or UME_BASE_URL not configured",
},
fwdState: {
paused: "Paused",
disabled: "Disabled",
connecting: "Connecting",
connected: "Connected",
},
runtimeTask: {
token_keepalive: "UME token keepalive",
alarms_current_auto_sync: "Current alarms auto sync",
alarms_current_ws_consumer: "UME alarm WSS",
oclaw_alarm_forwarder: "OClaw key-alert WSS",
inventory_auto_sync: "Inventory auto sync",
},
},
syncStatus: {
title: "Sync history",
showPanel: "Expand",
hidePanel: "Collapse",
empty: "No sync records",
},
ne: {
title: "Network elements",
showPanel: "Expand",
hidePanel: "Collapse",
keywordPh: "keyword(ne_id/ne_name/user_label/ip/host_name)",
clearTitle: "Clear keyword and reset to page 1",
expand: "Expand details",
collapse: "Collapse details",
cliConnect: "CLI connect",
},
tabs: {
main: "UME sync",
cli: "CLI connect",
},
cli: {
title: "UME CLI connection profile",
showPanel: "Expand",
hidePanel: "Collapse",
hint: "Unified SSH credentials and hop/bastion for UME inventory NEs. OClaw MCP can exec show commands via ume_ne_id without per-device managed_ne entries.",
statusReady: "CLI profile is ready for UME NE command execution.",
statusNotReady: "Set target username and hop/bastion settings (if enabled).",
profileName: "Profile name",
targetUsername: "Target SSH username",
targetPassword: "Target SSH password",
passwordKeep: "Leave blank to keep unchanged",
newProfile: "New profile",
deleteConfirm: "Delete this CLI profile?",
deleted: "Profile deleted",
saved: "CLI profile saved",
connectTestTitle: "Sample NE connectivity test",
sampleNePh: "ume_ne_id (copy from NE list below)",
sampleNeRequired: "ume_ne_id is required",
connectTestSubmitted: "Connectivity test submitted",
connectTestWaiting: "Waiting for test result…",
connectTestRunning: "Connectivity test in progress…",
connectTestResult: "Test result",
existingProfiles: "Existing profiles",
default: "default",
},
alarms: {
title: "Current alarms",
showPanel: "Expand",
hidePanel: "Collapse",
keywordPh: "keyword(alarm key/cause/ne_name/host_name/ip…)",
hostNamePh: "host_name (contains)",
allSeverity: "All severities",
clearedAll: "is_cleared: all",
clearTitle: "Clear filters and reset to page 1",
filterByHost: "Filter by this host",
noHostName: "No host_name (sync inventory first)",
},
},
};
export default en;