mirror of
https://github.com/hansjone/netx.git
synced 2026-10-08 23:33:21 +08:00
Topology MCP adds pull/compact/bundle/suggest-hubs with a no-template skill path; API gains fabric level and NE collection policy; web list pages get paging and denser collect/network workflows. Co-authored-by: Cursor <cursoragent@cursor.com>
1894 lines
72 KiB
TypeScript
1894 lines
72 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}}",
|
||
jumpPage: "Go to page",
|
||
pageSize: "Page size",
|
||
exportCsv: "Export CSV",
|
||
exporting: "Exporting…",
|
||
exportOk: "Exported {{count}} rows",
|
||
exportTruncated: "Exported first {{count}} of {{total}} rows (truncated)",
|
||
exportFailed: "Export failed",
|
||
opFailed: "Operation failed",
|
||
empty: "-",
|
||
cancel: "Cancel",
|
||
},
|
||
workbench: {
|
||
title: "Workbench",
|
||
modules: "Modules",
|
||
sections: "Sections",
|
||
moduleCount: "{{count}} modules",
|
||
backToWorkbench: "Back to Workbench",
|
||
openInNewTab: "Open in new tab",
|
||
openModule: "Open or switch to this module tab",
|
||
monitoring: "System integration",
|
||
operations: "Operations",
|
||
system: "System",
|
||
welcomeEyebrow: "Workbench",
|
||
welcomeTitle: "Welcome back, {{name}}",
|
||
welcomeSub: "Monitor sync, topology, and ops tasks from one place.",
|
||
today: "Today · {{date}}",
|
||
kpi: {
|
||
uptime: "API uptime",
|
||
health: "System health",
|
||
tasks: "Active tasks",
|
||
healthOk: "Schedulers healthy",
|
||
healthWarn: "Check schedulers",
|
||
healthUnknown: "Metrics unavailable",
|
||
},
|
||
statusTitle: "Runtime status",
|
||
announceTitle: "Announcements",
|
||
recentTitle: "Recent operations",
|
||
recentMore: "View all",
|
||
quickTitle: "Quick actions",
|
||
emptyRecent: "No recent audit entries.",
|
||
gauge: {
|
||
cpu: "CPU",
|
||
mem: "Memory",
|
||
storage: "Storage",
|
||
storageUsed: "Used",
|
||
storageUnavailable: "Unavailable",
|
||
cli: "CLI budget",
|
||
db: "DB pool",
|
||
webcrt: "WebCRT",
|
||
tasks: "Active tasks",
|
||
low: "Low load",
|
||
normal: "Normal",
|
||
high: "Busy",
|
||
},
|
||
quick: {
|
||
tasks: "Task overview",
|
||
logs: "Audit logs",
|
||
users: "User admin",
|
||
apiKeys: "API keys",
|
||
sessions: "Sessions",
|
||
},
|
||
announce: {
|
||
a1: "Dark workbench shell is live — other modules follow the same palette.",
|
||
a1Date: "2026-08-04",
|
||
a2: "LLDP collect supports pause / resume / stop; interrupted jobs resume after restart.",
|
||
a2Date: "2026-08-04",
|
||
a3: "Config sync and LLDP KPI boards refresh while jobs are running.",
|
||
a3Date: "2026-08-03",
|
||
},
|
||
recentCols: {
|
||
action: "Action",
|
||
module: "Module",
|
||
time: "Time",
|
||
user: "User",
|
||
},
|
||
cards: {
|
||
umeSync: "UME Sync",
|
||
network: "Network Management",
|
||
managedNe: "NE Management",
|
||
collect: "Batch Collect",
|
||
webcrt: "WebCRT",
|
||
topology: "Topology",
|
||
portTrafficWall: "Traffic wall",
|
||
users: "Users",
|
||
audit: "Audit",
|
||
apiKeys: "API Keys",
|
||
sessions: "Login sessions",
|
||
},
|
||
},
|
||
network: {
|
||
title: "Network Management",
|
||
nav: {
|
||
detail: "Network details",
|
||
tasks: "Monitoring tasks",
|
||
topologyMgmt: "Topology management",
|
||
devices: "Device list",
|
||
topology: "Topology",
|
||
lldpLinks: "LLDP",
|
||
topoClassify: "Classify",
|
||
alarms: "Alarms",
|
||
configs: "Configurations",
|
||
webcrt: "WebCRT",
|
||
collectTasks: "Collection tasks",
|
||
configSync: "Config sync",
|
||
portTraffic: "Port traffic",
|
||
portTrafficWall: "Traffic wall",
|
||
},
|
||
collapseNav: "Collapse sidebar",
|
||
expandNav: "Expand sidebar",
|
||
placeholder: {
|
||
title: "Coming soon",
|
||
body: "This capability is not available yet.",
|
||
},
|
||
},
|
||
portTraffic: {
|
||
title: "Port traffic",
|
||
create: "Monitor device",
|
||
backList: "Back to list",
|
||
created: "Device monitoring added",
|
||
createFailed: "Create failed",
|
||
updated: "Saved",
|
||
interfacesSaved: "Interfaces updated",
|
||
started: "Started",
|
||
paused: "Paused",
|
||
stopped: "Stopped",
|
||
statusRunning: "Running",
|
||
statusPaused: "Paused",
|
||
statusStopped: "Stopped",
|
||
statusDraft: "Draft",
|
||
collecting: "Collecting",
|
||
deleted: "Deleted",
|
||
confirmDelete: "Delete this device monitoring and its samples?",
|
||
empty: "No devices monitored yet. Pick a NE and interfaces to start.",
|
||
keywordPh: "Name / IP / note / ID",
|
||
allStatus: "All statuses",
|
||
exportDevicesName: "port-traffic-devices",
|
||
exportEventsName: "port-traffic-events",
|
||
wall: "Ops wall",
|
||
wallTitle: "Port traffic wall",
|
||
toDevices: "Manage devices",
|
||
wallEmpty: "No monitored devices yet. Add a device and pick interfaces first.",
|
||
fullscreen: "Fullscreen",
|
||
exitFullscreen: "Exit fullscreen",
|
||
board: "Board",
|
||
boardPick: "Select board",
|
||
boardPickHint: "Select or create a traffic wall board.",
|
||
boardEmpty: "No boards yet. Create one for cutover or duty monitoring.",
|
||
boardDefaultName: "Untitled board",
|
||
boardName: "Name",
|
||
boardCols: "Columns",
|
||
boardCreate: "New board",
|
||
boardEdit: "Edit layout",
|
||
boardSave: "Save",
|
||
boardCancel: "Cancel",
|
||
boardSaved: "Board saved",
|
||
boardCreated: "Board created",
|
||
boardDeleted: "Board deleted",
|
||
boardConfirmDelete: "Delete this board and its panels?",
|
||
boardUnsavedLeave: "You have unsaved changes. Leave anyway?",
|
||
boardOpenTab: "Open in new tab",
|
||
boardOpen: "Open wall",
|
||
boardListHint: "Open a board in its own browser tab; launching Network from the workbench will not refresh open walls.",
|
||
boardPanelCount: "Panels",
|
||
boardUpdated: "Updated",
|
||
boardClosedHint: "You can close this tab, or reopen from Network → Traffic wall list.",
|
||
boardAddPanel: "Add panel",
|
||
boardNoPanels: "No panels yet. Edit the board and add interfaces.",
|
||
boardPickDevice: "Select device",
|
||
boardPanelSettings: "Panel settings",
|
||
boardPanelTitle: "Title (optional)",
|
||
boardColSpan: "Column span",
|
||
boardPanelStale: "Interface missing or inactive. Please reselect.",
|
||
boardRetarget: "Reselect port",
|
||
edit: "Edit",
|
||
save: "Save",
|
||
start: "Start",
|
||
pause: "Pause",
|
||
stop: "Stop",
|
||
delete: "Delete",
|
||
wizStep1: "Device",
|
||
wizStep2: "Interfaces",
|
||
wizStep3: "Params",
|
||
step1: "Params",
|
||
step2: "NEs",
|
||
step3: "Interfaces",
|
||
step4: "Confirm",
|
||
prev: "Back",
|
||
next: "Next",
|
||
fieldTitle: "Task name",
|
||
titlePh: "e.g. Access uplinks",
|
||
titleRequired: "Task name is required",
|
||
portsRequired: "Select at least one interface",
|
||
interval: "Interval (sec)",
|
||
retention: "Retention (days)",
|
||
retentionHintWizard: "Use ≥8 days for week-over-week compare",
|
||
concurrency: "Concurrency",
|
||
note: "Note",
|
||
notePh: "Optional",
|
||
startNow: "Start after create",
|
||
neKeywordPh: "Name / IP / vendor",
|
||
deepLinkHint: "Opened from topology: NE {{ne}}{{ifname}}. Confirm selection, then continue.",
|
||
deepLinkIfname: ", interface {{ifname}}",
|
||
selectedNe: "{{count}} NE(s) selected",
|
||
selectedOneNe: "Selected",
|
||
selectedPorts: "{{count}} interface(s) selected",
|
||
pickNeFirst: "Select one NE first",
|
||
discover: "Discover interfaces",
|
||
discoverDetail: "Discover detail",
|
||
discoverCommand: "Command",
|
||
discoverRaw: "Raw log",
|
||
discoverOk: "Discover succeeded",
|
||
discoverFail: "Discover failed",
|
||
confirmCreate: "Start monitoring",
|
||
wallTask: "Task",
|
||
wallPort: "Interface",
|
||
wallDevice: "Device",
|
||
wallDeviceLabel: "Device",
|
||
pickPort: "Select interface",
|
||
range: "Range",
|
||
compare: "Compare",
|
||
compareOff: "Off",
|
||
compareDay: "Yesterday (same TOD)",
|
||
compareWeek: "Last week (same weekday)",
|
||
compareShift: "Previous window",
|
||
compareCustom: "Custom offset",
|
||
offsetHours: "Offset (hours)",
|
||
aheadHours: "Extend past now (hours)",
|
||
aheadHoursHint:
|
||
"Push the chart end past now. With period compare enabled, the overlay can show trend after the current clock; 0 ends at now.",
|
||
mapBaselineHint:
|
||
"Mapped baseline can be combined with period compare; turn on Yesterday yourself when you need that contrast.",
|
||
baseline: "Baseline",
|
||
baselineAt: "Baseline time",
|
||
baselineDevice: "Baseline device",
|
||
baselinePort: "Baseline interface",
|
||
seriesCurrentIn: "Current In",
|
||
seriesCurrentOut: "Current Out",
|
||
seriesBaselineIn: "Baseline In",
|
||
seriesBaselineOut: "Baseline Out",
|
||
mapBaselinePort: "Mapped baseline interface",
|
||
mapBaselineTask: "Mapped baseline task",
|
||
mapBaselineNone: "None",
|
||
retentionHint: "Week compare needs retention_days ≥ 8 or the baseline may be empty.",
|
||
collectNow: "Collect now",
|
||
collectStarted: "Collect triggered",
|
||
collectBusy: "Collect already running",
|
||
targetError: "Last interface error",
|
||
waitSamples: "Samples appear after the device runs; or click Collect now. Chart auto-refreshes.",
|
||
waitAfterError: "Collect failed — open Logs under Traffic monitoring for details, then Collect now.",
|
||
log: "Logs",
|
||
logTitle: "Collect logs",
|
||
logEmpty: "No log entries yet.",
|
||
logDevice: "Device",
|
||
logLevel: "Level",
|
||
logTime: "Time",
|
||
logMessage: "Message",
|
||
logClose: "Close",
|
||
logHasError: "Has error",
|
||
rebind: "Rebind NE",
|
||
rebindTitle: "Rebind network element",
|
||
rebindOk: "Rebound to selected NE; collect can resume",
|
||
rebindFailed: "Rebind failed",
|
||
rebindHint:
|
||
"Pick the correct NE and confirm. IPs may not be unique, and a matching IP does not mean the same device. History is kept.",
|
||
rebindCurrent: "Current binding",
|
||
rebindEmpty: "No NEs found — add the device back under inventory first.",
|
||
rebindSameIp: "Same IP",
|
||
rebindSameIpHint: "IP matches current monitor — still verify name and ID",
|
||
rebindSubmit: "Confirm rebind",
|
||
rebindConfirm: "Bind monitoring to {{ne}}? History samples are kept.",
|
||
err: {
|
||
managedNeNotFound:
|
||
"Managed NE not found (often deleted then re-created with a new id). Use Rebind NE and pick manually.",
|
||
targetErrors: "{{count}} interface(s) failed",
|
||
unsupportedVendor: "Unsupported vendor / device type",
|
||
invalidSource: "Invalid NE source",
|
||
rebindPickFirst: "Select an NE first",
|
||
rebindNeMissing: "Selected NE not found — refresh and try again",
|
||
rebindSourceMismatch: "NE source does not match this monitor device",
|
||
alreadyMonitored: "That NE is already monitored by another device entry",
|
||
},
|
||
kpiLatest: "latest",
|
||
kpiBw: "Bandwidth",
|
||
latestAt: "Latest sample",
|
||
hoverPoint: "Cursor",
|
||
wallLiveTitle: "Live traffic",
|
||
filterView: "View",
|
||
filterMap: "Mapped baseline",
|
||
yMode: "Y axis",
|
||
yModeAuto: "Auto (incl. baseline)",
|
||
yModeCurrent: "Fit current",
|
||
yModeUtil: "Utilization %",
|
||
kpi: {
|
||
tasks: "Tasks",
|
||
devices: "Devices",
|
||
running: "Running",
|
||
ports: "Interfaces",
|
||
samples24h: "Samples 24h",
|
||
},
|
||
col: {
|
||
title: "Task",
|
||
device: "Device",
|
||
status: "Status",
|
||
ports: "Interfaces",
|
||
interval: "Interval",
|
||
last: "Last collect",
|
||
actions: "Actions",
|
||
source: "Source",
|
||
name: "Device",
|
||
vendor: "Vendor",
|
||
ifname: "Interface",
|
||
bw: "BW",
|
||
upDown: "Admin / Phy / Prot",
|
||
admin: "Admin",
|
||
phy: "Phy",
|
||
prot: "Prot",
|
||
description: "Description",
|
||
},
|
||
},
|
||
lldpLinks: {
|
||
title: "LLDP links",
|
||
collectNow: "Collect now",
|
||
retryFailed: "Retry failed",
|
||
started: "LLDP collect started",
|
||
pause: "Pause",
|
||
resume: "Resume",
|
||
stop: "Stop",
|
||
confirmStop: "Stop this job and skip remaining NEs?",
|
||
paused: "Paused",
|
||
resumed: "Resumed",
|
||
stopped: "Collect stopped",
|
||
policyTitle: "Collect policy",
|
||
policySaved: "Policy saved",
|
||
enabled: "Enable scheduled collect",
|
||
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",
|
||
intervalUnitHours: "hours",
|
||
concurrency: "Concurrency",
|
||
historyKeep: "Jobs to keep",
|
||
scope: "Scope",
|
||
scopeAll: "All NEs (managed + UME)",
|
||
scopeSelected: "Selected NEs",
|
||
savePolicy: "Save policy",
|
||
selectedCount: "{{count}} selected",
|
||
targetKeywordPh: "Name / IP / vendor",
|
||
jobsTitle: "Collect jobs",
|
||
jobDetailTitle: "Job details",
|
||
expand: "Details",
|
||
edgesTitle: "Fabric links",
|
||
edgeKeywordPh: "Endpoint name or IP",
|
||
edgeStatusAll: "All statuses",
|
||
edgeStatusActive: "Active",
|
||
edgeStatusMissing: "Missing",
|
||
edgeSourceAll: "All sources",
|
||
exportEdgesName: "lldp-fabric-edges",
|
||
exportJobsName: "lldp-collect-jobs",
|
||
exportItemsName: "lldp-job-items",
|
||
statusAll: "All statuses",
|
||
jobKeywordPh: "Job ID / error / scope",
|
||
itemKeywordPh: "NE name / IP / error",
|
||
itemResultAll: "All results",
|
||
missCount: "Miss cycles",
|
||
replacedBy: "Replaced",
|
||
kpi: {
|
||
nodes: "Fabric nodes",
|
||
edges: "Active links",
|
||
missing: "Missing",
|
||
running: "In progress",
|
||
idle: "Idle",
|
||
last: "Last job",
|
||
nextDue: "Next due",
|
||
},
|
||
col: {
|
||
source: "Source",
|
||
name: "Device",
|
||
vendor: "Vendor",
|
||
trigger: "Trigger",
|
||
scope: "Scope",
|
||
status: "Status",
|
||
progress: "Progress",
|
||
edges: "Edges",
|
||
missingDelta: "Missing/purged",
|
||
started: "Started",
|
||
ended: "Ended",
|
||
neighbors: "Neighbors",
|
||
error: "Error",
|
||
aSide: "Side A",
|
||
bSide: "Side B",
|
||
aPort: "Port A",
|
||
bPort: "Port B",
|
||
lastSeen: "Last seen",
|
||
},
|
||
jobStatus: {
|
||
running: "Running",
|
||
pending: "Pending",
|
||
paused: "Paused",
|
||
done: "Done",
|
||
failed: "Failed",
|
||
cancelled: "Cancelled",
|
||
stopped: "Stopped",
|
||
},
|
||
triggerMode: {
|
||
manual: "Manual",
|
||
schedule: "Scheduled",
|
||
topology: "Topology canvas",
|
||
retry_failed: "Retry failed",
|
||
},
|
||
jobScope: {
|
||
all: "All NEs",
|
||
ne_ids: "Selected NEs",
|
||
selected: "Selected NEs",
|
||
},
|
||
itemResult: {
|
||
ok: "OK",
|
||
warn: "Warn",
|
||
fail: "Fail",
|
||
},
|
||
edgeSource: {
|
||
lldp: "LLDP",
|
||
manual: "Manual",
|
||
stale: "Stale",
|
||
},
|
||
},
|
||
configSync: {
|
||
title: "Config sync",
|
||
syncNow: "Sync now",
|
||
retryFailed: "Retry failed",
|
||
pause: "Pause",
|
||
resume: "Resume",
|
||
stop: "Stop",
|
||
confirmStop: "Stop this cycle and cancel remaining NE tasks?",
|
||
started: "Sync cycle started",
|
||
paused: "Paused",
|
||
resumed: "Resumed",
|
||
stopped: "Sync cycle stopped",
|
||
policyTitle: "Sync policy",
|
||
policySaved: "Policy saved",
|
||
enabled: "Enable scheduled sync",
|
||
intervalDays: "Interval (days)",
|
||
concurrency: "Concurrency",
|
||
historyKeep: "Config versions to keep",
|
||
cycleKeep: "Jobs to keep",
|
||
scope: "Scope",
|
||
scopeAll: "All NEs",
|
||
scopeSelected: "Selected NEs",
|
||
savePolicy: "Save policy",
|
||
selectedCount: "{{count}} selected",
|
||
targetKeywordPh: "Name / IP / vendor",
|
||
cyclesTitle: "Sync cycles",
|
||
cyclesEmpty: "No sync cycles yet",
|
||
tasksTitle: "Cycle tasks",
|
||
taskKeywordPh: "Name / IP / message",
|
||
keywordPh: "ID / trigger / message",
|
||
statusAll: "All statuses",
|
||
allStatus: "All statuses",
|
||
exportCyclesName: "config-sync-cycles",
|
||
exportTasksName: "config-sync-tasks",
|
||
expand: "Details",
|
||
collapse: "Collapse",
|
||
kpi: {
|
||
snapshots: "Snapshots",
|
||
running: "In progress",
|
||
idle: "Idle",
|
||
last: "Last cycle",
|
||
nextDue: "Next due",
|
||
},
|
||
col: {
|
||
source: "Source",
|
||
name: "Device",
|
||
vendor: "Vendor",
|
||
trigger: "Trigger",
|
||
status: "Status",
|
||
progress: "Progress",
|
||
started: "Started",
|
||
ended: "Ended",
|
||
message: "Message",
|
||
actions: "Actions",
|
||
},
|
||
},
|
||
networkDevices: {
|
||
title: "Device list",
|
||
keywordPh: "Name / IP / ID",
|
||
allSource: "All sources",
|
||
empty: "No network elements.",
|
||
exportName: "network-devices",
|
||
col: {
|
||
source: "Source",
|
||
name: "Name",
|
||
vendor: "Vendor",
|
||
deviceType: "Device type",
|
||
connect: "Connect",
|
||
actions: "Actions",
|
||
},
|
||
},
|
||
networkConfigs: {
|
||
title: "Configurations",
|
||
keywordPh: "Name / IP / ID",
|
||
vendorPh: "Vendor",
|
||
allSource: "All sources",
|
||
empty: "No synced configs yet. Run Config sync first.",
|
||
view: "View",
|
||
export: "Export",
|
||
exportBoth: "Export all",
|
||
exportOk: "Config exported",
|
||
exportListName: "network-configs",
|
||
close: "Close",
|
||
tabSet: "Set format",
|
||
tabHier: "Hierarchical",
|
||
col: {
|
||
name: "Device",
|
||
vendor: "Vendor",
|
||
source: "Source",
|
||
size: "Size",
|
||
collected: "Collected",
|
||
},
|
||
},
|
||
layout: {
|
||
title: "UME Integration",
|
||
titleUme: "UME Sync",
|
||
titleNetwork: "Network Management",
|
||
titleManagedNe: "NE Management",
|
||
titleCollect: "Batch Collect",
|
||
titleWebcrt: "WebCRT",
|
||
titleTopology: "Topology",
|
||
titlePortTrafficWall: "Traffic wall",
|
||
titleUsers: "Users",
|
||
titleAudit: "Audit",
|
||
titleApiKeys: "API Keys",
|
||
titleSessions: "Login sessions",
|
||
navUme: "UME",
|
||
netxApi: "netx api",
|
||
oclawBridge: "oclaw WSS",
|
||
activeTasks: "Active {{count}}",
|
||
activeTasksHint: "Open Audit · Task overview",
|
||
language: "Language",
|
||
switchLanguage: "Switch language / 切换语言",
|
||
moreMenu: "More",
|
||
langZh: "中文",
|
||
langEn: "English",
|
||
},
|
||
auth: {
|
||
loginTitle: "Sign in",
|
||
username: "Username",
|
||
password: "Password",
|
||
login: "Sign in",
|
||
loggingIn: "Signing in…",
|
||
loginFailed: "Login failed",
|
||
logout: "Sign out",
|
||
sessionsTitle: "Login sessions",
|
||
sessionsHint: "Manage browser/device logins for this account. Revoked sessions must sign in again.",
|
||
sessionsEmpty: "No active sessions.",
|
||
revokeOtherSessions: "Revoke other sessions",
|
||
revokeSession: "Revoke",
|
||
sessionCurrent: "Current",
|
||
sessionRevoked: "Session revoked",
|
||
sessionsRevokedOthers: "Revoked {{count}} other session(s)",
|
||
revokeCurrentConfirm: "This is your current session; revoking it requires signing in again. Continue?",
|
||
colSession: "Session",
|
||
colLastSeen: "Last seen",
|
||
colCreated: "Created",
|
||
usersTitle: "User management",
|
||
usersHint: "Only admins can create and manage local accounts.",
|
||
addUser: "Add user",
|
||
role: "Role",
|
||
roleAdmin: "Admin",
|
||
roleUser: "User",
|
||
status: "Status",
|
||
active: "Active",
|
||
disabled: "Disabled",
|
||
enable: "Enable",
|
||
disable: "Disable",
|
||
actions: "Actions",
|
||
newPassword: "New password",
|
||
resetPassword: "Reset password",
|
||
userCreated: "User created",
|
||
userUpdated: "User updated",
|
||
auditTitle: "Audit log",
|
||
auditHintAdmin: "View login and operation records for all users.",
|
||
auditHintUser: "View your own operation records.",
|
||
filterUsername: "Filter username",
|
||
filterAction: "Filter action",
|
||
colTime: "Time",
|
||
colUser: "User",
|
||
colAction: "Action",
|
||
colMethod: "Method",
|
||
colPath: "Path",
|
||
colStatus: "Status",
|
||
colIp: "IP",
|
||
apiKeysTitle: "API Key management",
|
||
apiKeysHelp:
|
||
"The web UI uses login sessions, not API keys — keys are for MCP/scripts. Defaults on create: alarms:read + ne:read + ne:write + ne:exec; refine later with Edit scopes (takes effect immediately, no need to regenerate). Secret is shown once. Admins may issue for other users; scopes cannot exceed the owner's. Unused scopes are reserved for future MCP tools.",
|
||
tokenName: "Name",
|
||
expiresIn: "Expiry",
|
||
expire7d: "7 days",
|
||
expire30d: "30 days",
|
||
expire90d: "90 days",
|
||
expire365d: "1 year",
|
||
expireNever: "Never",
|
||
tokenOwner: "Owner",
|
||
tokenOwnerSelf: "Myself ({{user}})",
|
||
createToken: "Create key",
|
||
tokenCreated: "API key created",
|
||
tokenUpdated: "Scopes updated",
|
||
tokenRevoked: "Revoked",
|
||
tokenOnceHint: "Copy and store this secret now; it will not be shown again:",
|
||
copyToken: "Copy",
|
||
tokenCopied: "Copied",
|
||
tokenCopyFailed: "Copy failed",
|
||
expiresAt: "Expires",
|
||
lastUsed: "Last used",
|
||
tokenStatusActive: "Active",
|
||
tokenStatusExpired: "Expired",
|
||
tokenStatusRevoked: "Revoked",
|
||
revokeToken: "Revoke",
|
||
revokeConfirm: "Revoke this API key?",
|
||
editScopes: "Edit scopes",
|
||
saveScopes: "Save scopes",
|
||
scopesUnsetLegacy: "Unrestricted (same as owner)",
|
||
scopesCol: "Scopes",
|
||
scopesRequired: "Select at least one scope",
|
||
scopesNoneAvailable: "This owner has no grantable scopes",
|
||
scopeAlarmsRead: "alarms:read — Alarms read (netx MCP)",
|
||
scopeNeRead: "ne:read — NE / topology read (MCP)",
|
||
scopeNeWrite: "ne:write — NE / topology write / draw (MCP)",
|
||
scopeNeExec: "ne:exec — Managed NE CLI (netx MCP)",
|
||
scopeSql: "sql:query — UME SQL (netx MCP)",
|
||
scopeWebcrt: "webcrt:session — WebCRT (reserved MCP)",
|
||
scopeAdminUsers: "admin:users — User admin (reserved MCP)",
|
||
scopeOpsWrite: "ops:write — Ops write / subscriptions (reserved MCP)",
|
||
|
||
forceChangeTitle: "Change initial password",
|
||
forceChangeHint: "Account {{user}} is still using the default password. You must change it before continuing.",
|
||
oldPassword: "Current password",
|
||
confirmPassword: "Confirm new password",
|
||
savePassword: "Save new password",
|
||
savingPassword: "Saving…",
|
||
passwordTooShort: "New password must be at least 8 characters",
|
||
passwordMismatch: "New passwords do not match",
|
||
passwordMustChange: "New password must differ from the default/old password",
|
||
},
|
||
collect: {
|
||
statusAll: "All statuses",
|
||
keywordPh: "Job title / ID",
|
||
exportJobsName: "collect-jobs",
|
||
exportRunsName: "collect-runs",
|
||
policyTitle: "Collect policy",
|
||
policyHint:
|
||
"Periodic schedule is off by default (one-shot / manual). Enable it to auto-create and run jobs on an interval. Keeps the last 3 finished jobs by default.",
|
||
policySaved: "Policy saved",
|
||
enabled: "Enable scheduled collect",
|
||
interval: "Collect interval",
|
||
intervalUnitDays: "days",
|
||
intervalUnitHours: "hours",
|
||
historyKeep: "Jobs to keep",
|
||
scope: "Scope",
|
||
scopeAll: "All NEs (managed + UME)",
|
||
scopeSelected: "Selected NEs only",
|
||
savePolicy: "Save policy",
|
||
collectNow: "Collect now",
|
||
selectedCount: "{{count}} selected",
|
||
colSource: "Source",
|
||
policyCommandsRequired: "Add commands and save the policy before enabling schedule or collecting now",
|
||
policyTargetsRequired: "No eligible NEs in scope; adjust scope or select NEs",
|
||
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",
|
||
pickHint: "All managed and UME inventory NEs are selectable (any connect status). UME uses CLI connect profile credentials.",
|
||
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: "New",
|
||
collapse: "Close",
|
||
meta: "{{ne}} NE(s) selected · {{cmd}} command(s)",
|
||
},
|
||
eligible: {
|
||
title: "Eligible NEs",
|
||
hint: "All managed and UME inventory NEs are selectable (any connect status).",
|
||
empty: "No NEs.",
|
||
},
|
||
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",
|
||
listTitle: "Job list",
|
||
col: {
|
||
title: "Job",
|
||
status: "Status",
|
||
progress: "Progress",
|
||
created: "Created",
|
||
lastRun: "Last run",
|
||
actions: "Actions",
|
||
},
|
||
ok: "ok",
|
||
fail: "fail",
|
||
expand: "Details",
|
||
collapse: "Hide",
|
||
detailTitle: "Job details",
|
||
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…",
|
||
},
|
||
kpi: {
|
||
jobs: "Jobs",
|
||
running: "In progress",
|
||
idle: "Idle",
|
||
last: "Last job",
|
||
active: "Active jobs",
|
||
nextDue: "Next due",
|
||
},
|
||
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",
|
||
openTerminal: "Terminal",
|
||
confirmDelete:
|
||
"Delete this network element? If its Fabric node is managed-only (no UME binding), that node and its direct links will also be removed.",
|
||
batchDelete: "Batch delete",
|
||
batchDeleting: "Deleting…",
|
||
batchDeleteConfirm:
|
||
"Delete {{n}} selected network element(s)? Cannot be undone. Managed-only Fabric nodes cascade (node + direct links); nodes still bound to UME keep topology.",
|
||
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",
|
||
source: "Source",
|
||
ip: "Management IP",
|
||
port: "Port",
|
||
protocol: "Protocol",
|
||
user: "Username",
|
||
password: "Password",
|
||
tags: "Tags",
|
||
remark: "Remark",
|
||
connect: "Connect",
|
||
testedAt: "Tested at",
|
||
actions: "Actions",
|
||
},
|
||
source: {
|
||
manual: "Manual",
|
||
ume_sync: "UME sync",
|
||
webcrt: "WebCRT",
|
||
lldp: "LLDP placeholder",
|
||
topology: "Topology placeholder",
|
||
},
|
||
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? Cannot be undone. Fabric nodes that become fully orphaned (no UME left) are removed with their direct links.",
|
||
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 IP or FQDN); CLI: ssh user@target@ip@bastion-host.\n" +
|
||
"· Bastion-managed: set Jump password (Vault); target password optional. Manual mode needs target password.\n" +
|
||
"· Jump host accepts IP (192.0.2.10) or domain (ssh-bastion.example.com). 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. Hop host may be an IP or FQDN. Examples: bastion-user@target-user@198.51.100.20@192.0.2.10 or bastion-user@target-user@198.51.100.20@ssh-bastion.example.com; 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 (IP or FQDN) goes in Jump host. CLI example: ssh bastion-user@target-user@198.51.100.20@ssh-bastion.example.com.",
|
||
host: "Jump host",
|
||
hostPlaceholderBastion: "192.0.2.10 or ssh-bastion.example.com",
|
||
hostHintBastion:
|
||
"IP or FQDN. You can paste a full SSH destination (e.g. bastion-user@target-user@198.51.100.20@ssh-bastion.example.com); on blur it splits into jump username + 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",
|
||
showPanel: "Details",
|
||
hidePanel: "Close",
|
||
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…",
|
||
pulling_topology: "Pulling UME topology (nodes/links)…",
|
||
topology_sync_busy: "Topology sync already running; skipped",
|
||
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",
|
||
connect_refused: "OClaw gateway down or port 8787 refused",
|
||
connect_timeout: "Timed out connecting to OClaw gateway",
|
||
auth_failed: "OClaw netx-bridge auth failed (check shared token)",
|
||
disconnected: "OClaw WSS disconnected",
|
||
},
|
||
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",
|
||
topology_auto_sync: "Topology auto sync",
|
||
},
|
||
},
|
||
syncStatus: {
|
||
title: "Sync history",
|
||
showPanel: "Details",
|
||
hidePanel: "Close",
|
||
empty: "No sync records",
|
||
summary: "{{total}} record(s), {{running}} running",
|
||
fabricGapTitle: "Topology dock is newer than Fabric / UME World",
|
||
fabricGapHint:
|
||
"Dock ME {{dock}}, Fabric UME {{fabric}}. Apply without pulling UME. Last status: {{status}}",
|
||
applyFabric: "Apply to topology",
|
||
applyingFabric: "Applying…",
|
||
applyFabricOk: "Applied to topology",
|
||
},
|
||
ne: {
|
||
title: "Network elements",
|
||
showPanel: "Details",
|
||
hidePanel: "Close",
|
||
keywordPh: "keyword(ne_id/ne_name/user_label/ip/host_name)",
|
||
clearTitle: "Clear keyword and reset to page 1",
|
||
expand: "Details",
|
||
collapse: "Close",
|
||
cliConnect: "CLI connect",
|
||
summary: "{{total}} inventory NE(s)",
|
||
},
|
||
tabs: {
|
||
main: "UME sync",
|
||
cli: "CLI connect",
|
||
},
|
||
cli: {
|
||
title: "UME CLI connection profile",
|
||
showPanel: "Details",
|
||
hidePanel: "Close",
|
||
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",
|
||
movedHint: "Current alarm query moved to Network Management →",
|
||
showPanel: "Expand",
|
||
hidePanel: "Collapse",
|
||
keywordPh: "keyword(alarm key/cause/ne_name/host_name/ip…)",
|
||
hostNamePh: "host_name (contains)",
|
||
allSeverity: "All severities",
|
||
clearedAll: "Cleared: all",
|
||
clearedYes: "Cleared",
|
||
clearedNo: "Active",
|
||
clearTitle: "Clear filters and reset to page 1",
|
||
filterByHost: "Filter by this host",
|
||
noHostName: "No host_name (sync inventory first)",
|
||
col: {
|
||
time: "Time",
|
||
severity: "Severity",
|
||
neId: "NE ID",
|
||
hostName: "Host",
|
||
neType: "NE type",
|
||
cause: "Cause",
|
||
},
|
||
},
|
||
},
|
||
webcrt: {
|
||
title: "WebCRT",
|
||
deviceList: "Device list",
|
||
sessionManager: "Device list",
|
||
connect: "Connect",
|
||
hint: "Pick an NE and open an interactive terminal in the browser. Credentials stay on the server.",
|
||
hintCrt: "Click an NE on the left to open a terminal. Includes managed, Sessions, and UME; or use New Session for a quick login.",
|
||
filterKeyword: "Filter",
|
||
filterKeywordPh: "Filter by name / IP / tag",
|
||
empty: "No matching NEs. Switch source or refine the search.",
|
||
open: "Open terminal",
|
||
opening: "Connecting…",
|
||
opened: "Opened {{name}}",
|
||
disconnect: "Disconnect",
|
||
closed: "Session closed",
|
||
termPlaceholder: "No terminal session open",
|
||
sessionMeta: "{{name}} · {{ip}}",
|
||
source: {
|
||
all: "All",
|
||
managed: "Managed",
|
||
webcrt: "Sessions",
|
||
ume: "UME",
|
||
},
|
||
newSession: {
|
||
title: "New Session",
|
||
claimTitle: "Complete placeholder session",
|
||
claimHint:
|
||
"Enter a reachable host. Session name defaults to the placeholder name. On success, source becomes WebCRT.",
|
||
connect: "Connect",
|
||
connecting: "Connecting…",
|
||
protocol: "Protocol",
|
||
host: "Hostname",
|
||
port: "Port",
|
||
sessionName: "Session name",
|
||
sessionNamePh: "Optional; defaults to IP",
|
||
authTitle: "SSH Authentication",
|
||
savePassword: "Save password",
|
||
ipRequired: "Hostname is required",
|
||
userRequired: "Username is required",
|
||
passwordRequired: "Password is required",
|
||
},
|
||
status: {
|
||
idle: "Idle",
|
||
connecting: "Connecting",
|
||
connected: "Connected",
|
||
error: "Error",
|
||
closed: "Closed",
|
||
},
|
||
phase: {
|
||
creating: "Creating session",
|
||
authenticating: "Authenticating",
|
||
waitingPrompt: "Waiting for device prompt",
|
||
hint: "Slow devices may take more than 10 seconds",
|
||
},
|
||
tabMenu: {
|
||
close: "Close",
|
||
closeOthers: "Close others",
|
||
closeAll: "Close all",
|
||
copyIp: "Copy IP",
|
||
copyIpOk: "Copied {{ip}}",
|
||
copyIpEmpty: "No IP on this tab",
|
||
},
|
||
treeMenu: {
|
||
rename: "Rename",
|
||
renameLabel: "Session name",
|
||
renameSave: "Save",
|
||
renameRequired: "Session name is required",
|
||
renamed: "Session renamed",
|
||
delete: "Delete session",
|
||
deleteConfirm: "Delete session \"{{name}}\"? This cannot be undone.",
|
||
deleted: "Session deleted",
|
||
},
|
||
keywordHl: {
|
||
title: "Keyword Highlighting",
|
||
enabled: "Enabled",
|
||
newKeyword: "New keyword",
|
||
newKeywordPh: "Keyword or regex",
|
||
regex: "Regular expression",
|
||
add: "Add",
|
||
colKeyword: "Keyword",
|
||
colRegex: "Regex",
|
||
empty: "No keywords yet",
|
||
moveUp: "Move up",
|
||
moveDown: "Move down",
|
||
remove: "Remove",
|
||
caseSensitive: "Case sensitive",
|
||
color: "Text color",
|
||
saved: "Keyword highlighting saved",
|
||
},
|
||
actions: {
|
||
reconnect: "Reconnect",
|
||
recordLog: "Record log",
|
||
clear: "Clear",
|
||
copy: "Copy",
|
||
recording: "Recording",
|
||
recordingOn: "Log recording started",
|
||
recordingSaved: "Log saved",
|
||
copied: "Copied to clipboard",
|
||
copyEmpty: "Terminal is empty",
|
||
copyFailed: "Copy failed",
|
||
break: "Break",
|
||
breakSent: "Break sent",
|
||
broadcast: "Broadcast",
|
||
broadcastSent: "Sent to all sessions",
|
||
postLogin: "Post-login cmds",
|
||
},
|
||
favorites: "Favorites",
|
||
recent: "Recent",
|
||
favorite: "Toggle favorite",
|
||
encoding: "Encoding",
|
||
fontSize: "Font size",
|
||
theme: "Theme",
|
||
themeDark: "Dark",
|
||
themeLight: "Light",
|
||
colorScheme: "Color scheme",
|
||
backgroundColor: "Background",
|
||
foregroundColor: "Font color",
|
||
scheme: {
|
||
dark: "Deep blue (default)",
|
||
blackWhite: "Black on white",
|
||
whiteBlack: "White on black",
|
||
greenBlack: "Green on black",
|
||
amberBlack: "Amber on black",
|
||
custom: "Custom",
|
||
},
|
||
copyOnSelect: "Copy on select",
|
||
pasteDelay: "Paste max line wait",
|
||
pasteDelayOff: "No delay (bulk send)",
|
||
keepalive: "SSH keepalive",
|
||
keepaliveOff: "Off",
|
||
keepaliveSec: "{{n}} sec",
|
||
options: "Options",
|
||
globalSessionOptions: "Global Session Options",
|
||
sessionOptionsSave: "Save",
|
||
sessionOptionsCancel: "Cancel",
|
||
sessionOptionsSaved: "Global session options saved",
|
||
disconnectBanner: "Session disconnected",
|
||
disconnectBannerError: "Session error or connection lost",
|
||
broadcastPh: "Send to all tabs…",
|
||
buttonBarHint: "One per line: label|command",
|
||
postLoginPrompt: "Post-login commands (one per line, this device)",
|
||
postLoginSaved: "Post-login commands saved",
|
||
sftp: {
|
||
title: "SFTP",
|
||
refresh: "Refresh",
|
||
up: "Up",
|
||
upload: "Upload",
|
||
uploaded: "Upload complete",
|
||
uploading: "Upload {{done}}/{{total}} · {{name}} {{pct}}",
|
||
downloading: "Download {{done}}/{{total}} · {{name}} {{pct}}",
|
||
downloaded: "Downloaded {{count}} file(s)",
|
||
downloadPartial: "Downloaded {{ok}}, failed {{failed}}",
|
||
uploadPartial: "Uploaded {{ok}}, failed {{failed}}",
|
||
retrying: "Retrying {{name}} ({{attempt}}/{{max}})…",
|
||
cancel: "Cancel",
|
||
dropHint: "Drop to upload into current folder",
|
||
dropEmpty: "No uploadable files found",
|
||
mkdir: "New",
|
||
mkdirPrompt: "New folder name",
|
||
mkdirInvalid: "Invalid folder name (no / or ..)",
|
||
mkdirOk: "Folder created",
|
||
rename: "Rename",
|
||
renamePrompt: "New name",
|
||
renameInvalid: "Invalid name (no / or ..)",
|
||
renamed: "Renamed",
|
||
download: "Download",
|
||
chmod: "chmod",
|
||
chmodPrompt: "Mode (e.g. 755 or rwxr-xr-x)",
|
||
chmodOk: "Permissions updated",
|
||
chmodPartial: "chmod ok {{ok}}, failed {{failed}}",
|
||
delete: "Delete",
|
||
deleteConfirm: "Delete {{name}}?",
|
||
deleteRecursiveConfirm: "{{name}} includes folders; non-empty folders will be removed recursively. Continue?",
|
||
deletePartial: "Deleted {{ok}}, failed {{failed}}",
|
||
deleted: "Deleted",
|
||
selectedCount: "{{count}} selected",
|
||
empty: "This folder is empty",
|
||
listTruncated: "Folder is large; showing first {{count}} entries (limit {{max}})",
|
||
dir: "dir",
|
||
loading: "Loading…",
|
||
enterHint: "Click to select; Ctrl/Shift multi-select; double-click to open",
|
||
downloadHint: "Click to select; Ctrl/Shift multi-select; double-click to download",
|
||
colName: "Name",
|
||
colSize: "Size",
|
||
colMtime: "Modified",
|
||
colOwner: "Owner",
|
||
colGroup: "Group",
|
||
colMode: "Access",
|
||
resizeHint: "Drag to resize SFTP / terminal",
|
||
colResizeHint: "Drag to resize column",
|
||
},
|
||
term: {
|
||
findPh: "Find…",
|
||
findPrev: "Previous",
|
||
findNext: "Next",
|
||
findClose: "Close find",
|
||
copy: "Copy",
|
||
paste: "Paste",
|
||
pasteEmpty: "Clipboard is empty",
|
||
pasteFailed: "Cannot read clipboard (on HTTP use the paste box, or Ctrl+V)",
|
||
pasteBridgeHint:
|
||
"This page is not HTTPS, so the browser blocks clipboard reads. Press Ctrl+V in this box to send text to the terminal.",
|
||
pasteBridgePh: "Press Ctrl+V here…",
|
||
pasteBridgeCancel: "Cancel",
|
||
clear: "Clear",
|
||
pasting: "Pasting {{done}}/{{total}} lines…",
|
||
wsError: "[WebSocket error]",
|
||
wsClosed: "[WebSocket closed code={{code}}]",
|
||
sessionStatus: "[session {{state}}{{detail}}]",
|
||
outputTruncated: "[output truncated: {{count}} chunk(s) dropped]",
|
||
},
|
||
err: {
|
||
deviceType: "Unsupported device type",
|
||
ipConflictRestart: "Database still enforces unique IP; restart the netx API and retry",
|
||
sessionLimit: "Session limit reached; close other terminals first",
|
||
neNotFound: "Network element not found",
|
||
credsIncomplete: "Incomplete username/password on this NE",
|
||
authRejected: "Wrong username or password. Please try again.",
|
||
cliProfile: "UME NEs require a CLI connect profile (default account / hop)",
|
||
connectFailed: "Device login failed: {{detail}}",
|
||
sftpHop: "SFTP does not support hop devices yet (direct SSH only)",
|
||
sftpSsh: "SFTP requires SSH",
|
||
sftpNeedPassword: "SFTP needs a saved SSH password (one-shot dialog passwords are not reused for files)",
|
||
sftpUnsupported: "This SSH session has no SFTP channel (device may not offer it)",
|
||
sftpTooLarge: "File exceeds size limit (default 512MB)",
|
||
sftpChmodInvalid: "Invalid mode (use 755 or rwxr-xr-x)",
|
||
sftpAborted: "Transfer cancelled",
|
||
queueDropped: "Terminal output too fast; about {{count}} chunk(s) dropped — transcript may be incomplete",
|
||
websocket: "WebSocket connection failed",
|
||
},
|
||
},
|
||
topology: {
|
||
title: "Topology",
|
||
maps: "Maps",
|
||
tree: "Topology tree",
|
||
treeLoading: "Loading tree…",
|
||
treeLoadFailed: "Failed to load topology tree",
|
||
treeRetry: "Retry",
|
||
graphLoading: "Loading topology…",
|
||
graphLoadFailed: "Failed to load topology",
|
||
graphRefreshing: "Refreshing…",
|
||
canvasEmpty: "No NEs on this map yet",
|
||
canvasEmptyHint: "Use Add NE, or pick a region that already has devices.",
|
||
treeHint: "Top level is a Root (nav only); its unique Root Map is the canvas. Open the root map or a sub-region to edit devices.",
|
||
treeSearch: "Search NEs across maps",
|
||
treeSearchPh: "Name / IP",
|
||
treeSearchEmpty: "No matching NEs",
|
||
treeSearchNoViews: "Not on any map",
|
||
treeSearchNotOnMap: "This NE is not placed on any topology map yet",
|
||
locateNotOnCanvas:
|
||
"This NE is missing from the world-map sample and has no world coordinates. Open a region map instead.",
|
||
treeSearchViewCount: "{{count}} map(s)",
|
||
treeSearchTruncated: "Showing first 30 of {{total}}",
|
||
rootName: "Roots",
|
||
selectRegion: "Select a root or region",
|
||
openMap: "Open map",
|
||
openRegion: "Open",
|
||
kindPhysical: "Physical",
|
||
kindCustom: "Custom",
|
||
layerNodeHint: "{{count}} NE(s)",
|
||
layerNodeEmpty: "Click to create & open",
|
||
rootCanvasHint: "Pick a root from the left tree.",
|
||
regionCanvasHint: "Open the root map to edit devices; create sub-regions on that canvas.",
|
||
regionBrowseHint: "Root folder: unique root map below. Click to open.",
|
||
browserTitle: "Topology folder",
|
||
browserRegionSub: "{{count}} map(s)",
|
||
browserRegionsSub: "{{count}} item(s)",
|
||
browserEmptyMaps: "No root map under this root yet.",
|
||
addNe: "Add NE",
|
||
backUp: "Back",
|
||
newRegion: "New root",
|
||
newRegionName: "New root",
|
||
newRegionPrompt: "Root name",
|
||
newSubRegion: "New sub-region",
|
||
newSubRegionName: "New sub-region",
|
||
newSubRegionPrompt: "Sub-region name",
|
||
subRegionNotOnFlat: "The world map has no regions. Create sub-regions on World or a lower-level canvas.",
|
||
worldMapNoDirectNes: "Cannot add NEs on the world map — add them on a sub-region canvas.",
|
||
worldMapName: "World map",
|
||
worldMapOffline: "World map is temporarily offline",
|
||
rootMapName: "Root map",
|
||
worldHud: "World {{total}} · close-up {{cached}} · z{{zoom}} · {{lod}}",
|
||
worldEmptyCoords: "World map has no coordinates yet",
|
||
worldEmptyCoordsHint:
|
||
"Dock has {{dock}} NEs, but Fabric / world coords are empty. Apply without pulling UME.",
|
||
worldApply: "Apply to world map",
|
||
worldApplying: "Applying…",
|
||
worldApplyOk: "Applied to world map",
|
||
subRegionNeedParent: "Open a root map or region canvas first, then create a sub-region.",
|
||
regionCreated: "Created",
|
||
regionDeleted: "Deleted",
|
||
deleteRegion: "Delete",
|
||
deleteRegionConfirm: "Delete \"{{name}}\"? Its maps will also be deleted.",
|
||
deleteUmeWorldConfirm:
|
||
"Delete \"{{name}}\"? This cascades all UME regions and maps under it. A later UME topology apply may recreate it.",
|
||
renameRegion: "Rename",
|
||
renameRegionPrompt: "Name",
|
||
regionRenamed: "Renamed",
|
||
collapseRegion: "Collapse",
|
||
expandRegion: "Expand",
|
||
newCustom: "Custom map",
|
||
newCustomName: "Custom topology",
|
||
newCustomPrompt: "Custom map name",
|
||
folderHint: "Creating a root auto-creates its unique root map. Add sub-regions on that canvas.",
|
||
folderHintShort: "Root folder",
|
||
outsidePeers: "{{count}} outside peer(s) linked but not on this map",
|
||
outsidePeersView: "Off-map NEs {{count}}",
|
||
outsidePeersTitle: "Outside peers",
|
||
outsidePeersHint: "Linked to this map but not placed. Select and add only what you need.",
|
||
outsidePeersVia: "via {{name}}",
|
||
outsidePeersFilterPh: "Filter: name / IP / via",
|
||
outsidePeersEmpty: "No matching outside peers",
|
||
projectNeighbors: "Project neighbors",
|
||
projectedNeighbors: "Projected {{count}} neighbor(s) onto the map",
|
||
localBrowserOnly: "this browser only",
|
||
deleteEdgeConfirm:
|
||
"Remove selected link(s) from the canvas? They are deleted from Fabric only when you Save. LLDP may recreate them on the next collect.",
|
||
edgeDeleted: "Queued {{count}} link delete(s) — Save to apply",
|
||
discoverCancelled: "Discovery cancelled",
|
||
truncatedMembership: "Membership cap reached; some neighbors were not placed. Use classify or a new map.",
|
||
truncatedFrozen: "This map membership is frozen; neighbors cannot be projected. Unfreeze via classify workflow or create a new map.",
|
||
truncatedNodes: "Too many view nodes; display truncated. Narrow membership or create another map.",
|
||
truncatedEdges: "Too many edges; display truncated. Filter status or create another map.",
|
||
truncatedGeneric: "Graph data truncated. Narrow scope or create another map.",
|
||
deleteSelectionConfirm:
|
||
"Remove {{nodes}} NE(s) from this map and {{edges}} link(s)? Link deletes apply on Save; NE remove from map applies on Save.",
|
||
selectionDeleted: "Queued: remove {{nodes}} NE(s), delete {{edges}} link(s) — Save to apply",
|
||
newMap: "New",
|
||
newMapName: "New topology",
|
||
rename: "Rename",
|
||
renamePrompt: "Topology map name",
|
||
renameHint: "Double-click to rename",
|
||
renamed: "Topology map renamed",
|
||
deleteMap: "Delete map",
|
||
deleteMapConfirm: "Delete map \"{{name}}\"? Nodes and edges will be removed.",
|
||
emptyMaps: "No roots yet. Create a root first.",
|
||
palette: "NE library",
|
||
paletteHint: "Select multiple to add in batch, or drag one onto the canvas",
|
||
paletteDragHint: "Drag onto canvas to add",
|
||
selectAllVisible: "Select all visible",
|
||
addSelected: "Add selected ({{count}})",
|
||
addSelectedDone: "Added {{count}} NE(s)",
|
||
addingNe: "Adding…",
|
||
filterPh: "Type to filter: name / IP / vendor",
|
||
save: "Save",
|
||
saveDirty: "Save *",
|
||
unsavedConfirm: "You have unsaved changes. Discard and switch maps?",
|
||
saving: "Saving…",
|
||
saved: "Topology saved",
|
||
saveFailed: "Save failed: {{detail}}",
|
||
readOnlyBanner: "Read-only (ne:write scope required to edit)",
|
||
readOnlyHint: "Read-only — no write permission",
|
||
discoverTimeout: "Discovery timed out; check LLDP tasks for progress",
|
||
policySyncFailed: "Failed to sync LLDP policy; local toggle still applies to canvas discovery",
|
||
discover: "Discover links",
|
||
discovering: "Discovering…",
|
||
discoverOne: "Discover links",
|
||
discovered: "Discovery done: +{{added}} updated {{updated}} missing {{stale}}",
|
||
discoverFail: "Discovery failed: {{detail}}",
|
||
discoverOneNeedNe: "This node is not linked to a scannable NE",
|
||
selectMap: "Select or create a topology map",
|
||
renameNode: "Rename",
|
||
renameNodePrompt: "Node display name",
|
||
sourcePort: "Local port",
|
||
targetPort: "Remote port",
|
||
endpointA: "Endpoint A",
|
||
endpointB: "Endpoint B",
|
||
port: "port",
|
||
expandPhysicalLinks: "Expand physical links",
|
||
scaleBundleWidth: "Thicken bundles by link count",
|
||
linkMembers: "Physical members ({{count}})",
|
||
canvasHint:
|
||
"Left tree lists regions; add maps yourself, then open a map to edit devices with Add NE and save positions.",
|
||
selected: "Selected",
|
||
selectedEdge: "Selected edge",
|
||
selectedCount: "{{count}} selected",
|
||
toolModes: "Edit modes",
|
||
toolSelect: "Select",
|
||
toolPan: "Pan",
|
||
toolDrag: "Drag",
|
||
toolConnect: "Connect",
|
||
layout: "Layout",
|
||
layoutHierarchicalTb: "Hierarchical · top-bottom",
|
||
layoutHierarchicalLr: "Hierarchical · left-right",
|
||
layoutForce: "Force-directed",
|
||
layoutGrid: "Grid",
|
||
layoutRadial: "Radial",
|
||
layoutSelected: "Selected only (hierarchical)",
|
||
layoutNeedSelection: "Select nodes to lay out first",
|
||
align: "Align",
|
||
alignLeft: "Align left",
|
||
alignRight: "Align right",
|
||
alignTop: "Align top",
|
||
alignBottom: "Align bottom",
|
||
alignHCenter: "Align center X",
|
||
alignVCenter: "Align center Y",
|
||
alignHDistribute: "Distribute horizontally",
|
||
alignVDistribute: "Distribute vertically",
|
||
alignNeedSelection: "Select at least two nodes",
|
||
snapGrid: "Snap to grid",
|
||
autoLayoutDiscover: "Auto-layout after discover",
|
||
discoverAutoAddUnmatched: "Auto-add unmatched NEs as placeholders on discover",
|
||
discoverProjectNeighbors:
|
||
"After discover, project neighbors of scanned NEs onto the canvas (Save to keep permanently)",
|
||
undo: "Undo",
|
||
redo: "Redo",
|
||
discoverSelected: "Discover selected ({{count}})",
|
||
removeSelected: "Remove selected ({{count}})",
|
||
openWebcrt: "Open terminal",
|
||
openNe: "NE details",
|
||
removeNode: "Remove from canvas",
|
||
deletePlaceholder: "Delete placeholder",
|
||
deletePlaceholderConfirm:
|
||
"Permanently delete this placeholder NE (inventory + Fabric links)? This cannot be undone with canvas Undo.",
|
||
deletePlaceholderDone: "Placeholder deleted",
|
||
removeEdge: "Delete edge",
|
||
nodeMenu: "Node",
|
||
paneMenu: "Canvas",
|
||
edgeMenu: "Edge",
|
||
createNe: "New NE",
|
||
createNeTitle: "New topology placeholder NE",
|
||
createNeHint:
|
||
"Source is topology placeholder. Complete login via WebCRT, or promote in NE management.",
|
||
createNeName: "Name",
|
||
createNeNamePh: "e.g. SW-CORE-01",
|
||
createNeNameRequired: "NE name is required",
|
||
createNeIp: "IP (optional)",
|
||
createNeIpPh: "Can fill later during setup",
|
||
createNeDone: "Created placeholder {{name}}",
|
||
createNeBusy: "Creating…",
|
||
selectionMenu: "Selection",
|
||
edgeStyle: "Edge style",
|
||
edgeColor: "Color",
|
||
edgeLineStyle: "Line",
|
||
edgeLineSolid: "Solid",
|
||
edgeLineDashed: "Dashed",
|
||
edgeLineDotted: "Dotted",
|
||
edgeWidth: "Width",
|
||
edgeStyleReset: "Reset style",
|
||
edgeDefaults: "Default edge styles",
|
||
edgeDefaultsReset: "Factory reset",
|
||
noNeLink: "Not linked to a managed NE",
|
||
completeNeFirst:
|
||
"Login details are incomplete (vendor, hop/proxy, etc. belong in NE inventory). Complete the NE first, then open the terminal.",
|
||
edgeManual: "Manual",
|
||
edgeUme: "UME",
|
||
edgeDiscovered: "LLDP",
|
||
edgeStale: "Missing",
|
||
fit: "Fit view",
|
||
export: "Export",
|
||
exportSvg: "SVG vector",
|
||
exportXml: "XML data",
|
||
exporting: "Exporting…",
|
||
exportEmpty: "Nothing on the canvas to export",
|
||
exportedSvg: "SVG exported",
|
||
exportedXml: "XML exported",
|
||
exportFailed: "Export failed: {{detail}}",
|
||
liveSync: "Live sync",
|
||
liveSyncOn: "Syncing…",
|
||
liveSyncHint: "Poll the tree about every 5s and the open map every 3s (watch MCP create/draw). Off by default",
|
||
fullscreen: "Fullscreen",
|
||
exitFullscreen: "Exit fullscreen",
|
||
display: "Display",
|
||
canvasBg: "Canvas background",
|
||
canvasBgColor: "Background color",
|
||
canvasBgReset: "Reset default",
|
||
textColors: "Text colors",
|
||
textColorsReset: "Reset default",
|
||
labelColor: "NE name",
|
||
edgeLabelColor: "Link numbers",
|
||
vendorColors: "Vendor icon colors",
|
||
vendorColorsReset: "Reset default",
|
||
vendorTone: {
|
||
cisco: "Cisco",
|
||
huawei: "Huawei",
|
||
zte: "ZTE",
|
||
juniper: "Juniper",
|
||
nokia: "Nokia",
|
||
ericsson: "Ericsson",
|
||
h3c: "H3C",
|
||
ruijie: "Ruijie",
|
||
mikrotik: "MikroTik",
|
||
gray: "Unknown / unmanaged",
|
||
},
|
||
hideIp: "Hide IP",
|
||
hideVendor: "Hide vendor",
|
||
showPlaceholderBadge: "Show placeholder badge (TOPO/LLDP)",
|
||
hidePorts: "Hide ports",
|
||
edgeFlow: "Edge flow",
|
||
collapseSidebar: "Collapse sidebar",
|
||
expandSidebar: "Expand sidebar",
|
||
resizeSidebar: "Drag to resize sidebar",
|
||
hideAdded: "Hide added",
|
||
paletteEmpty: "No matching NEs.",
|
||
paletteHiddenAll: "Added NEs are hidden; uncheck to show them again.",
|
||
paletteSource: "NE source",
|
||
paletteManaged: "Managed",
|
||
paletteUme: "UME",
|
||
paletteLoading: "Loading…",
|
||
discoverReport: "Discovery progress",
|
||
discoverClose: "Close",
|
||
discoverCancel: "Cancel discovery",
|
||
discoverProgress: "Scanning {{count}} managed NE(s) on the map (serial LLDP; please wait)…",
|
||
discoverProgressLive: "Scanning {{index}}/{{total}}: {{name}}",
|
||
discoverSummary: "Scanned {{scanned}} · added {{added}} · updated {{updated}} · missing {{stale}} · failed {{failed}}",
|
||
discoverNeOk: "neighbors {{neighbors}} · added {{added}} · updated {{updated}}",
|
||
discoverNeFail: "Collect failed",
|
||
discoverUnmatched: "unmatched {{count}}",
|
||
discoverUnmatchedMore: "{{count}} more not listed",
|
||
discoverVendorRequired: "Vendor/device type missing; skipped LLDP command",
|
||
discoverParserStub: "Parser \"{{parser}}\" is still a stub; output was collected but neighbors were not parsed",
|
||
discoverNoTargets:
|
||
"No scannable NEs on the map. Add managed NEs, or UME NEs with a CLI connect profile.",
|
||
discoverViewDetail: "Detail",
|
||
discoverLinkCount: "{{count}} link(s)",
|
||
discoverLinksTitle: "Matched links ({{count}})",
|
||
discoverLinksEmpty: "No on-map peer links matched in this scan.",
|
||
discoverUnmatchedTitle: "Unmatched neighbors ({{count}})",
|
||
discoverUnmatchedEmpty: "No unmatched neighbors.",
|
||
discoverColPeer: "Peer NE",
|
||
discoverColRemote: "Neighbor",
|
||
discoverColLocalPort: "Local port",
|
||
discoverColRemotePort: "Remote port",
|
||
discoverColProtocol: "Protocol",
|
||
discoverColAction: "Result",
|
||
discoverLinkAdded: "Added",
|
||
discoverLinkUpdated: "Updated",
|
||
discoverLinkKeptManual: "Kept manual",
|
||
discoverLocatePeer: "Locate peer",
|
||
discoverLocateNe: "Locate NE",
|
||
discoverRawPreview: "Raw output preview (truncated when long; parsing uses full output)",
|
||
discoverGoLldp: "Details → LLDP links",
|
||
findNode: "Find",
|
||
findNodePh: "Type to search: name / IP / vendor",
|
||
findNoMatch: "No matching node on the canvas",
|
||
findMore: "{{count}} more matches…",
|
||
locateOnCanvas: "Click to locate on canvas",
|
||
openPortTraffic: "Open port traffic",
|
||
removeStale: "Clear missing ({{count}})",
|
||
removeStaleHint:
|
||
"Queue delete of red missing edges (applies on Save); scheduled collect also purges after 4 consecutive misses",
|
||
staleRemoved: "Queued {{count}} missing edge delete(s) — Save to apply",
|
||
connectHint: "Connect mode: drag from the NE center anchor to the target (Esc or Select to exit)",
|
||
},
|
||
topoClassify: {
|
||
title: "Classify",
|
||
openTopo: "Topology",
|
||
inventory: "NE inventory",
|
||
keywordPh: "Filter by name/IP",
|
||
filterLevelAll: "All levels",
|
||
filterRegionAll: "All regions",
|
||
filterUnmatchedOff: "No unmatched filter",
|
||
kindAny: "Missing level or region",
|
||
kindLevel: "Missing level",
|
||
kindRegion: "Missing region",
|
||
filterLinkAll: "All link states",
|
||
filterLinkLinked: "Linked inventory",
|
||
filterLinkOrphaned: "Detached",
|
||
colLink: "Link",
|
||
linkManaged: "Managed",
|
||
linkUme: "UME",
|
||
linkBoth: "Managed+UME",
|
||
linkOrphaned: "Detached",
|
||
levelExternal: "L0 external",
|
||
levelCore: "L1 core",
|
||
levelCoreSub: "L1.1 core′",
|
||
levelAgg: "L2 aggregation",
|
||
levelAggSub: "L2.1 agg′",
|
||
levelAccess: "L3 access",
|
||
levelAccessSub: "L3.1 deeper access",
|
||
levelInvalid: "Invalid level (0–99.9, one decimal)",
|
||
sourceManual: "Manual",
|
||
sourceUmeSync: "UME sync",
|
||
sourceLldp: "LLDP placeholder",
|
||
sourceTopology: "Topology placeholder",
|
||
sourceWebcrt: "WebCRT",
|
||
regexTitle: "Regex find",
|
||
patternPh: "Regex, e.g. ^CORE- or -BJ-",
|
||
fieldName: "Name",
|
||
fieldNameIp: "Name+IP",
|
||
findMatches: "Find matches",
|
||
matchOk: "Matched {{count}}; selected",
|
||
matchHint: "{{count}} matched",
|
||
assignLevel: "Level only",
|
||
assignRegion: "Region only",
|
||
assignBoth: "Level + region",
|
||
clearRegion: "Clear region",
|
||
confirmAssign: "Confirm assign",
|
||
bulkConfirm: "Write tags to {{count}} selected/matched NE(s)?",
|
||
bulkOk: "Updated {{count}}",
|
||
selectedCount: "{{count}} selected",
|
||
selectPage: "Select page",
|
||
colNe: "NE",
|
||
colLevel: "Level",
|
||
colRegion: "Region",
|
||
colActions: "Actions",
|
||
edit: "Edit",
|
||
save: "Save",
|
||
cancel: "Cancel",
|
||
delete: "Delete",
|
||
deleteSelected: "Delete nodes ({{count}})",
|
||
deleteConfirm:
|
||
"Delete {{count}} fabric node(s) (placements and edges)? Managed/UME inventory is not touched.",
|
||
deleteOk: "Deleted {{count}} node(s)",
|
||
deleteHint:
|
||
"Only orphaned or LLDP/WebCRT placeholder fabric nodes can be deleted; UME-only and real managed NEs cannot",
|
||
deleteBlocked: "UME-only or still linked to real managed inventory — cannot delete here",
|
||
rowSaved: "Saved",
|
||
loading: "Loading…",
|
||
empty: "No NEs.",
|
||
},
|
||
audit: {
|
||
title: "Audit & ops",
|
||
logsTitle: "Operation logs",
|
||
nav: {
|
||
tasks: "Task overview",
|
||
logs: "Operation logs",
|
||
},
|
||
tasks: {
|
||
title: "Task overview",
|
||
hint: "Live view of running or pending background work. Actor prefers recent audit entries; scheduled work shows as scheduler/system.",
|
||
empty: "No tasks to show right now.",
|
||
open: "Open",
|
||
inflight: "running {{n}}",
|
||
kpiActive: "Active / in-flight",
|
||
kpiTotal: "Total rows",
|
||
kpiKinds: "By kind",
|
||
kpiStatuses: "By status",
|
||
colKind: "Kind",
|
||
colTitle: "Task",
|
||
colStatus: "Status",
|
||
colActor: "Actor",
|
||
colTrigger: "Trigger",
|
||
colProgress: "Progress",
|
||
colStarted: "Started",
|
||
colUpdated: "Updated",
|
||
colLink: "Open",
|
||
kind: {
|
||
port_traffic: "Port traffic",
|
||
config_sync: "Config sync",
|
||
ne_collect: "Batch collect",
|
||
lldp_discover: "LLDP discover",
|
||
ume_sync: "UME sync",
|
||
ne_connect: "Connect test",
|
||
ume_runtime: "UME runtime",
|
||
webcrt: "WebCRT",
|
||
},
|
||
trigger: {
|
||
manual: "Manual",
|
||
schedule: "Schedule",
|
||
topology: "Topology",
|
||
system: "System",
|
||
retry_failed: "Retry failed",
|
||
},
|
||
status: {
|
||
collecting: "Collecting",
|
||
running: "Running",
|
||
testing: "Testing",
|
||
connecting: "Logging in",
|
||
ready: "Connected",
|
||
detached: "Detached (grace)",
|
||
pending: "Pending",
|
||
paused: "Paused",
|
||
idle: "Idle",
|
||
error: "Error",
|
||
failed: "Failed",
|
||
},
|
||
},
|
||
},
|
||
};
|
||
|
||
export default en;
|