mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 02:00:46 +08:00
Filter peers by AFI (and VRF pairs for CE), support zip/pair bindings in discover UI, and tag FIB rows with address_families. Co-authored-by: Cursor <cursoragent@cursor.com>
2695 lines
103 KiB
TypeScript
2695 lines
103 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",
|
||
copy: "Copy",
|
||
copied: "Copied",
|
||
},
|
||
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: "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: "OK",
|
||
healthWarn: "CHECK",
|
||
healthUnknown: "N/A",
|
||
},
|
||
statusTitle: "Runtime status",
|
||
hostHealth: "HOST",
|
||
platformCapacity: "Platform capacity",
|
||
channels: "CHANNELS",
|
||
fleet: "FLEET",
|
||
fleetNe: "NE",
|
||
fleetNeUnit: "units",
|
||
fleetNeKnown: "Known",
|
||
fleetNePass: "Pass",
|
||
fleetNeFail: "Fail",
|
||
fleetNeTesting: "Testing",
|
||
fleetNeUnknown: "Untested",
|
||
fleetNeNoTag: "No tag",
|
||
fleetNeTags: "Top tags",
|
||
fleetTopo: "Topology",
|
||
fleetTopoNodes: "nodes",
|
||
fleetTopoEdges: "edges",
|
||
fleetTopoOther: "Other regions",
|
||
fleetTopoUnassigned: "Unassigned",
|
||
fleetTopoNoRegion: "No regions",
|
||
fleetTopoDiscover: "Last discover",
|
||
fleetTopoUpdated: "Summary updated",
|
||
fleetSched: "Schedulers",
|
||
fleetSchedConfig: "Config sync",
|
||
fleetSchedLldp: "LLDP",
|
||
fleetSchedPort: "Port traffic",
|
||
fleetSchedNeCollect: "NE collect",
|
||
fleetSchedFabric: "Fabric reconcile",
|
||
fleetSchedOn: "ON",
|
||
fleetSchedOff: "OFF",
|
||
fleetSchedMode: "Mode",
|
||
fleetSchedHeartbeat: "Heartbeat",
|
||
fleetSchedFresh: "Fresh",
|
||
fleetSchedStale: "Stale",
|
||
|
||
sidePanel: "Console side panel",
|
||
consoleId: "OPS CONSOLE",
|
||
refreshedAt: "Updated {{time}}",
|
||
taskRail: "ACTIVE TASKS",
|
||
taskRailAll: "ALL",
|
||
taskRailEmpty: "No active tasks",
|
||
taskTotal: "POOL {{count}}",
|
||
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",
|
||
cutoverCompare: "Cutover compare",
|
||
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",
|
||
bizState: "Business monitor",
|
||
bizCompare: "Business compare",
|
||
bizMigration: "Cutover monitor",
|
||
compareTemplates: "Compare templates",
|
||
monitorTemplates: "Monitor templates",
|
||
},
|
||
collapseNav: "Collapse sidebar",
|
||
expandNav: "Expand sidebar",
|
||
placeholder: {
|
||
title: "Coming soon",
|
||
body: "This capability is not available yet.",
|
||
},
|
||
},
|
||
bizState: {
|
||
title: "Business monitor",
|
||
create: "Create task",
|
||
createHint: "Pick any valid NE (managed / UME); search supported",
|
||
created: "Task created",
|
||
createFailed: "Create failed",
|
||
empty: "No business-state tasks yet.",
|
||
pickNe: "Select NE…",
|
||
neKeywordPh: "Name / IP / ID",
|
||
allSource: "All sources",
|
||
selectedNe: "Selected",
|
||
neEmpty: "No matching NEs.",
|
||
colSource: "Source",
|
||
colVendor: "Vendor",
|
||
colConnect: "Connect",
|
||
start: "Start schedule",
|
||
pause: "Pause",
|
||
statusPaused: "Paused",
|
||
scheduleEnabled: "Enable schedule",
|
||
scheduleOn: "Scheduled",
|
||
scheduleOff: "Manual",
|
||
scheduleHint: "When checked, collect on interval; otherwise only Collect now.",
|
||
collectNow: "Collect now",
|
||
delete: "Delete",
|
||
confirmDelete: "Delete this task and all batches?",
|
||
deleted: "Deleted",
|
||
started: "Schedule enabled",
|
||
paused: "Schedule paused (manual only)",
|
||
collecting: "Collecting",
|
||
detail: "Details",
|
||
interval: "Interval",
|
||
intervalUnitDays: "days",
|
||
intervalUnitHours: "hours",
|
||
intervalUnitSeconds: "seconds",
|
||
retention: "Retention days",
|
||
retentionHint: "Batches older than this are purged; baselines and compare/cutover refs are kept.",
|
||
dailyKeepEnabled: "Daily keep policy",
|
||
dailyKeepCount: "Keep per day",
|
||
dailyKeepHint: "When on: keep only the newest N batches per past day; extras purge next day (off by default).",
|
||
markBaseline: "Mark baseline",
|
||
unmarkBaseline: "Unmark baseline",
|
||
baseline: "Baseline",
|
||
protected: "Protected",
|
||
deleteBatch: "Delete",
|
||
bulkDelete: "Bulk delete",
|
||
confirmDeleteBatch: "Delete this batch? Protected batches cannot be deleted.",
|
||
confirmBulkDelete: "Delete {{count}} selected batches? Protected ones are skipped.",
|
||
batchDeleted: "Batch deleted",
|
||
bulkDeleted: "Deleted {{deleted}}, skipped {{skipped}}",
|
||
purgeNow: "Purge now",
|
||
purgeOk: "Purge done: dropped {{dropped}}",
|
||
selectAll: "Select deletable",
|
||
colProtect: "Protect",
|
||
saveSchedule: "Save schedule",
|
||
scheduleSaved: "Schedule saved",
|
||
colInterval: "Interval",
|
||
profiles: "Monitor items",
|
||
enable: "On",
|
||
command: "Command template",
|
||
params: "Bindings",
|
||
discoverVrf: "Discover VRFs",
|
||
discoverBind: "Discover / Bind",
|
||
saveBindings: "Save bindings",
|
||
cancel: "Close",
|
||
bindTitle: "Select bindings",
|
||
unbound: "Not bound",
|
||
bindHintRequired: "Bind params before collect",
|
||
discoverLoading: "Discovering…",
|
||
discoverEmpty: "No candidates discovered",
|
||
selectAllVrfs: "Select all",
|
||
deselectAllVrfs: "Deselect all",
|
||
batches: "Batches",
|
||
viewBatch: "Open",
|
||
export: "Export",
|
||
noBatches: "No batches yet",
|
||
batchDetail: "Batch detail",
|
||
batchWorkbook: "Batch workbook",
|
||
batchId: "Batch ID",
|
||
copyBatchId: "Copy batch ID",
|
||
sheetCommands: "Commands",
|
||
sheetLldp: "LLDP neighbors",
|
||
sheetVrfRoute: "VRF route summary",
|
||
sheetIsis: "ISIS adjacency",
|
||
sheetIfaceBrief: "Interface brief",
|
||
sheetArp: "ARP",
|
||
sheetNd6: "ND6 cache",
|
||
sheetBgpPeer: "BGP peers",
|
||
sheetConfigIface: "Interface intent",
|
||
sheetConfigVrf: "VRF intent",
|
||
sheetConfigBgp: "BGP intent",
|
||
sheetFilterPh: "Filter this sheet…",
|
||
sheetEmpty: "No rows in this sheet",
|
||
sheetLoading: "Loading…",
|
||
collectCommand: "Collect command",
|
||
viewRawLog: "Raw log",
|
||
rawLogTitle: "Raw collect log",
|
||
rawLogEmpty: "No raw output",
|
||
filterColumn: "Column",
|
||
filterAllCols: "All columns",
|
||
listFilterPh: "Filter NE / IP / vendor / status",
|
||
purposeFilter: "Task purpose",
|
||
purposeAll: "All purposes",
|
||
purposePortrait: "Portrait",
|
||
purposeCutoverHf: "Cutover HF",
|
||
colPurpose: "Purpose",
|
||
colNe: "NE",
|
||
colStatus: "Status",
|
||
colLast: "Last collect",
|
||
colTime: "Time",
|
||
colRows: "Rows",
|
||
colActions: "Actions",
|
||
colCommand: "Command",
|
||
colMessage: "Message",
|
||
pickTask: "Open details to manage a task",
|
||
noNeedBind: "This item needs no parameter bindings",
|
||
discoverFailed: "Discover failed",
|
||
bindingsSaved: "Bindings saved",
|
||
},
|
||
bizCompare: {
|
||
title: "Business compare",
|
||
templates: "Compare templates",
|
||
newTemplate: "New template",
|
||
editTemplate: "Edit template",
|
||
saveTemplate: "Save template",
|
||
templateSaved: "Template saved",
|
||
templateDeleted: "Template deleted",
|
||
confirmDeleteTemplate: "Delete this compare template?",
|
||
confirmDeleteJob: "Delete this compare job and all runs?",
|
||
confirmDeleteRun: "Delete this compare run? Job config is kept.",
|
||
deleteJob: "Delete job",
|
||
deleteRun: "Delete run",
|
||
runDeleted: "Compare run deleted",
|
||
emptyTemplates: "No templates yet. Create one or import a JSON file.",
|
||
exportTemplate: "Export",
|
||
importTemplate: "Import",
|
||
templateExported: "Template exported",
|
||
templateImported: "Template imported",
|
||
templateImportInvalid: "Invalid file: need name and metrics",
|
||
templateImportHint: "Import/export JSON to share templates privately (no job/batch data)",
|
||
templateHint:
|
||
"Pick metrics, then set Key / interface / compare / display. Compare modes: exact, abs delta, or relative %. Display can include context-only columns. Empty compare = presence-only.",
|
||
stepPickMetrics: "① Pick metrics",
|
||
stepConfigRules: "② Configure compare rules",
|
||
pickMetricsHint: "Check metrics to add. Then configure each sheet below.",
|
||
pickMetricsHintShort: "Click to add/remove; switch sheets in the left list below.",
|
||
showMetrics: "Show metric picker",
|
||
hideMetrics: "Hide metric picker",
|
||
noMetricsYet: "Select at least one metric first",
|
||
selectedCount: "{{n}} selected",
|
||
tabFields: "Field rules",
|
||
tabFilters: "Row filters",
|
||
fieldsHintShort:
|
||
"Key aligns rows; Compare fields take part in value diff; empty compare = presence-only.",
|
||
tagCompareN: "{{n}} cmp",
|
||
colFields: "Fields",
|
||
keyFields: "Key",
|
||
ifaceFields: "Interface",
|
||
compareFields: "Compare",
|
||
compareMode: "Mode",
|
||
tolerance: "Tolerance",
|
||
displayField: "Display",
|
||
keyAlwaysDisplay: "Key columns are always shown",
|
||
modeEq: "Exact equal",
|
||
modeNumeric: "Abs delta",
|
||
modePercent: "Relative %",
|
||
normalizeField: "Norm",
|
||
ignoreFields: "Ignore",
|
||
field: "Field",
|
||
note: "Note",
|
||
keyRequired: "Select at least one key field",
|
||
keyIsIdentity: "Key aligns rows; not used as a value-compare field",
|
||
metricsRequired: "Add at least one metric sheet",
|
||
noMetricFields: "No fields for this metric",
|
||
rowFilters: "Row filter rules",
|
||
rowFiltersHint:
|
||
"Filter rows before compare. Conditions in a group are AND; groups are OR. Selecting ARP seeds editable default rules you can change.",
|
||
rowFiltersHintShort: "AND in group · OR across groups · empty = all rows",
|
||
rowFiltersEmpty: "No filters → compare all rows.",
|
||
filterClear: "Clear",
|
||
filterAddOr: "Add group (OR)",
|
||
filterAddAnd: "Add condition (AND)",
|
||
filterAddOrShort: "+ OR group",
|
||
filterAddAndShort: "+ AND",
|
||
filterRemoveGroup: "Remove group",
|
||
filterGroupN: "Group {{n}}",
|
||
filterOr: "OR",
|
||
filterAnd: "AND",
|
||
filterField: "Field",
|
||
filterOp: "Op",
|
||
filterValue: "Value",
|
||
normalizeNone: "None",
|
||
normalizeLower: "lower",
|
||
normalizeUpper: "upper",
|
||
normalizeMac: "MAC",
|
||
normalizeEmpty: "empty→blank",
|
||
templateFilterPh: "Filter template / metric",
|
||
jobFilterPh: "Filter job / template / status",
|
||
addMetric: "Add metric",
|
||
pickMetric: "Pick metric…",
|
||
addSheet: "Add to template",
|
||
removeSheet: "Remove sheet",
|
||
sheetIdRequired: "sheet_id is required (unique per split)",
|
||
duplicateSheetId: "sheet_id must be unique",
|
||
sheetTitle: "Sheet title",
|
||
sheetId: "sheet_id",
|
||
splitSheet: "Split / duplicate",
|
||
colSheets: "Sheets",
|
||
sheetsUnit: "sheets",
|
||
presenceShort: "presence",
|
||
modeFields: "Mode: compare selected field values",
|
||
modeFieldsShort: "fields",
|
||
modePresence: "Mode: presence-only (entry set match)",
|
||
mapping: "Port mapping (optional)",
|
||
newMapping: "New mapping…",
|
||
mapName: "Mapping name",
|
||
saveMapping: "Save mapping",
|
||
validateMapping: "Validate",
|
||
validateNeed: "Select mapping and before/after batches first",
|
||
mapHint:
|
||
"One pair per line: before_if,after_if (comma / tab / pipe). Example:\ngei-0/1/1,gei-0/1/2\nxgei-0/1/0,xgei-0/2/0\n# comments start with #. Not slash-grouped A,B/C,D.",
|
||
mappingSaved: "Mapping saved",
|
||
mappingOptionalHint:
|
||
"Optional. Empty = ignore local port renames (match on non-interface keys). Fill to apply port map. Main-port pairs also cover .subinterfaces (suffix kept).",
|
||
ifaceNormalize: "Interface normalize",
|
||
ifaceNormalizeHint:
|
||
"Template rules, one per line: alias,canonical. Applied before port mapping. Example:\nGE,gei\nSG,smartgroup\nXGE,xgei",
|
||
createJob: "Create compare job",
|
||
defaultJobName: "Cutover compare",
|
||
jobName: "Name",
|
||
template: "Template",
|
||
mode: "Mode",
|
||
modeManual: "Manual batches",
|
||
modeAuto: "Auto (pin before; latest after batch)",
|
||
beforeTask: "Before task",
|
||
beforeBatch: "Before batch",
|
||
afterTask: "After task",
|
||
afterBatch: "After batch",
|
||
sideBefore: "Before",
|
||
sideAfter: "After",
|
||
sidesVs: "vs",
|
||
sidesTitle: "Compare sides",
|
||
pick: "Select…",
|
||
sameAsBefore: "Same as before / select…",
|
||
autoHint: "auto: new after-task batches trigger compare",
|
||
createCompare: "Create job",
|
||
createSteps: "Create steps",
|
||
stepBasics: "Basics",
|
||
stepSheets: "Sheets",
|
||
stepBatches: "Batches",
|
||
stepMapping: "Port mapping",
|
||
next: "Next",
|
||
back: "Back",
|
||
enabledSheets: "Compare sheets",
|
||
enabledSheetsHint: "Toggle sheets; all on by default. Off sheets are skipped.",
|
||
noTemplateSheets: "This template has no sheets",
|
||
needJobName: "Enter a job name",
|
||
needTemplate: "Select a compare template",
|
||
needSheets: "Enable at least one sheet",
|
||
needBeforeBatch: "Select before task and batch",
|
||
needAfterBatch: "Select after batch",
|
||
runNow: "Run now",
|
||
saveJob: "Save config",
|
||
jobSaved: "Job config saved",
|
||
jobDeleted: "Compare job deleted",
|
||
jobList: "Compare jobs",
|
||
detail: "Details",
|
||
edit: "Edit",
|
||
delete: "Delete",
|
||
tabConfig: "Job config",
|
||
tabResult: "Result",
|
||
runs: "Run history",
|
||
noRuns: "No runs yet — run a compare first",
|
||
result: "Result",
|
||
pickBatchRun: "Select compare run",
|
||
pickRun: "Select run…",
|
||
runCount: "{{n}} runs",
|
||
resultEmpty: "No matching diff rows",
|
||
resultFilterPh: "Filter key / values…",
|
||
kindAll: "All",
|
||
kindDiff: "Fail",
|
||
kindAdded: "Added",
|
||
kindRemoved: "Missing only",
|
||
kindChanged: "Mismatch only",
|
||
kindUnchanged: "Pass",
|
||
kindAddedShort: "Added",
|
||
kindRemovedShort: "Missing",
|
||
kindChangedShort: "Mismatch",
|
||
kindUnchangedShort: "Pass",
|
||
kindFail: "Fail",
|
||
kindPass: "Pass",
|
||
kindSuccess: "Pass",
|
||
successCount: "Pass",
|
||
passRateShort: "Pass %",
|
||
verdictPass: "Pass",
|
||
verdictFail: "Fail",
|
||
failCount: "Failed rows",
|
||
missCount: "Missing",
|
||
extraCount: "Extra",
|
||
mismatchCount: "Mismatch",
|
||
matchCount: "Match",
|
||
failFields: "Failed fields",
|
||
failFieldsEmpty: "—",
|
||
failWholeRow: "Whole row",
|
||
pairBefore: "pre",
|
||
pairAfter: "post",
|
||
sheetAllPass: "All match",
|
||
filterFailField: "Failed compare field",
|
||
filterFailFieldAll: "Any failed field",
|
||
resultEmpty: "No matching rows",
|
||
resultFilterPh: "Filter identity / values…",
|
||
diffCount: "{{n}} failed",
|
||
passRate: "Pass rate",
|
||
passOk: "All passed",
|
||
passWarn: "Has failures",
|
||
runOverview: "Verdict",
|
||
sheetCurrent: "Current check",
|
||
diffCountLabel: "Failed rows",
|
||
diffRate: "Fail rate",
|
||
beforeCount: "Before rows",
|
||
afterCount: "After rows",
|
||
matchedRows: "Matched",
|
||
totalRows: "Total rows",
|
||
sheetCount: "Sheets",
|
||
sheetNavTitle: "Checks",
|
||
sheetNavHint: "{{n}} checks · click to switch",
|
||
collapseSheetNav: "Collapse checks",
|
||
expandSheetNav: "Expand checks",
|
||
sheetFailCount: "{{n}} failed",
|
||
topChangedFields: "Top failed fields",
|
||
exportTables: "Download tables",
|
||
exportOk: "Compare tables exported",
|
||
fullscreen: "Fullscreen board",
|
||
exitFullscreen: "Exit fullscreen",
|
||
emptyJobs: "No compare jobs yet",
|
||
created: "Compare job created",
|
||
ran: "Compare finished",
|
||
colName: "Name",
|
||
colMode: "Mode",
|
||
colStatus: "Status",
|
||
colKind: "Verdict",
|
||
colResult: "Result",
|
||
colDetail: "Detail",
|
||
colFailFields: "Failed fields",
|
||
colActions: "Actions",
|
||
colKey: "Identity",
|
||
colChange: "Changes",
|
||
},
|
||
bizMigration: {
|
||
title: "Cutover monitor",
|
||
hint: "Separate from business compare: baseline drift, expect set, dual-device verdict. Reuses collect tasks and port mappings.",
|
||
hintPort:
|
||
"Metric focus: port status (interface_brief / admin·phy·prot). Baseline → pick ports → evaluate board.",
|
||
hintShort: "Monitor template sets rules; bind collect + dual baselines → expect → evaluate board.",
|
||
create: "Create task",
|
||
createHint:
|
||
"Except portrait baselines, the full cutover flow runs on this page; create auto-spawns HF biz-monitor tasks on schedule.",
|
||
createHintShort:
|
||
"Pick old/new NEs → monitor template & metrics → interval/window → baselines → port map → create. HF tasks are auto-created.",
|
||
pickOldNe: "Old NE",
|
||
pickNewNe: "New NE",
|
||
pickNe: "Pick NE",
|
||
pickNeHint: "Click to pick a device",
|
||
hideNePicker: "Hide list",
|
||
nePairReady: "Both NEs selected — continue, or click a card to re-pick.",
|
||
needNePair: "Enter a name and select old/new NEs",
|
||
needProjectName: "Enter a task name",
|
||
needMonitorTemplate: "Select a monitor template",
|
||
needMetrics: "Select at least one metric",
|
||
noPortraitBaseline:
|
||
"No portrait task/batches for this NE yet — run portrait collect in business monitor first (baselines can be set later).",
|
||
baselineOptionalHint: "Baselines can be set later in detail; pick from portrait batches when available.",
|
||
metricInterval: "Per-metric interval (sec)",
|
||
metricIntervalOptional: "Per-metric interval (optional)",
|
||
metricIntervalHint: "Leave blank to use the global interval; a filled value creates a separate HF task.",
|
||
scheduleHint:
|
||
"Enter the window in your local time; stored as UTC. Scheduler pauses HF outside the window.",
|
||
sectionSchedule: "Collect interval & window",
|
||
sectionBaseline: "Baselines & mapping",
|
||
sectionDevices: "Old / new NEs",
|
||
sectionMetrics: "Collect metrics",
|
||
createSteps: "Create steps",
|
||
stepDevices: "Devices",
|
||
stepTemplate: "Template",
|
||
stepSchedule: "Schedule",
|
||
stepBaseline: "Baselines",
|
||
next: "Next",
|
||
back: "Back",
|
||
colHf: "HF",
|
||
hfReady: "Ready",
|
||
hfMissing: "Missing",
|
||
showCreateMore: "More: template / mapping / baselines",
|
||
hideCreateMore: "Hide more",
|
||
setupHintShort: "Portrait tasks feed baselines; HF tasks feed cutover collect. Configure template, metrics, window and dual baselines here.",
|
||
createProject: "Create task",
|
||
projectName: "Task name",
|
||
projectNamePh: "e.g. PE-A / PE-B cutover-1",
|
||
sectionName: "1. Task name",
|
||
sectionTasks: "2. Bind collect tasks (required)",
|
||
sectionTasksHint: "Pick the old-device and new-device business-monitor tasks.",
|
||
sectionOptional: "3. Monitor template, mapping & baselines (optional)",
|
||
sectionOptionalHint:
|
||
"Skip for now if needed; set later under Baseline. Defaults to the system monitor template when omitted.",
|
||
sectionPair: "Bound collect tasks",
|
||
sectionPairHint: "Collect tasks are fixed at create time; adjust monitor template, mapping and baselines here.",
|
||
sectionBaselineHint: "Both old and new baselines are required; old lists expect objects, new feeds dual-side verdict.",
|
||
optionalNone: "None",
|
||
monitorTemplate: "Monitor template",
|
||
monitorTemplateHint: "Chooses which metrics to compare and dual-side success semantics. Defaults to the system monitor template.",
|
||
compareTemplate: "Compare template",
|
||
compareTemplateBound: "Bound compare template: {{name}}",
|
||
portMappingHint:
|
||
"With a mapping, iface metrics compare only mapped ports (they must appear after cutover). Same-name ports outside the map are not a migration; old down + new up is an anomaly. No mapping means same-name compare. BGP/PW still use the batch expect set.",
|
||
baselineNeedTask: "Select the matching collect task first",
|
||
baselinePickHint: "Choose from that task’s collect batches",
|
||
oldTask: "Old-device portrait task",
|
||
newTask: "New-device portrait task",
|
||
portMapping: "Port mapping",
|
||
oldBaseline: "Old baseline batch",
|
||
newBaseline: "New baseline batch",
|
||
needProjectFields: "Enter a name and pick old/new portrait tasks",
|
||
needExpectPorts: "Select at least one expected object for this batch",
|
||
needBaselineFirst: "Save an old baseline batch first to list expect objects",
|
||
needBothBaselines: "Save both old and new baseline batches before evaluating",
|
||
errOldBaselineRequired: "Old baseline batch is required",
|
||
errNewBaselineRequired: "New baseline batch is required",
|
||
needBizStateTasks: "No portrait business-monitor tasks yet. Create one first:",
|
||
projectCreated: "Task created",
|
||
projects: "Tasks",
|
||
empty: "No cutover tasks yet.",
|
||
emptyProjects: "No cutover tasks yet",
|
||
listFilterPh: "Filter name / NE / IP / status",
|
||
kpiProjects: "Tasks",
|
||
kpiActive: "Active",
|
||
detail: "Detail",
|
||
cancel: "Close",
|
||
colName: "Task",
|
||
colPair: "Old → New",
|
||
colBaseline: "Baseline",
|
||
colCreated: "Created",
|
||
colActions: "Actions",
|
||
baselineSet: "Set",
|
||
baselineUnset: "Unset",
|
||
statusActive: "Active",
|
||
statusDone: "Done",
|
||
statusPaused: "Paused",
|
||
statusPending: "Pending",
|
||
statusReview: "Review",
|
||
tabSetup: "Baseline",
|
||
tabBatches: "Batches",
|
||
tabBoard: "Board",
|
||
saveBaseline: "Save",
|
||
baselineSaved: "Baseline saved",
|
||
pickExpectPorts: "Expect",
|
||
portFilterPh: "Filter",
|
||
emptyBaselinePorts: "No baseline data",
|
||
batchLabel: "Batch label",
|
||
batchId: "Batch ID",
|
||
copyBatchId: "Copy batch ID",
|
||
defaultBatchLabel: "Night N",
|
||
expectPorts: "Expected ports (old side)",
|
||
expectPortsPh: "Comma or newline separated",
|
||
createBatch: "New",
|
||
batchCreated: "Batch created",
|
||
batches: "Batches",
|
||
startBatch: "Start",
|
||
finishBatch: "Finish",
|
||
evaluate: "Evaluate",
|
||
evaluated: "Done",
|
||
statusUpdated: "Status updated",
|
||
board: "Board",
|
||
metricPort: "Port status",
|
||
progress: "Progress",
|
||
anomaly: "Anomaly",
|
||
onlyExpect: "Expect only",
|
||
onlyExpectHint: "Shows all drift by default; check to filter to this batch's expect set",
|
||
pinCurrentBatches: "Current collect batches",
|
||
pinOldBatch: "Old current",
|
||
pinNewBatch: "New current",
|
||
pinLatest: "Latest",
|
||
runHistory: "Runs",
|
||
runLatest: "Latest",
|
||
colRuleHit: "Rule hit",
|
||
colCommand: "Collect command",
|
||
mappingBound: "Mapping saved and bound to this project",
|
||
allMetrics: "All metrics",
|
||
colMetric: "Metric",
|
||
colKey: "Object",
|
||
colPort: "Old port",
|
||
openRedChip: "Red {{n}}",
|
||
metaPortrait: "Portrait",
|
||
metaHf: "HF",
|
||
metaBaseline: "Baseline",
|
||
baselineOk: "set",
|
||
baselineMissing: "missing",
|
||
needBaselineFirst: "Set baseline first",
|
||
enableHighfreq: "Enable HF",
|
||
highfreqReady: "HF ready",
|
||
collectNow: "Collect now",
|
||
collectTriggered: "Collect triggered",
|
||
openBizState: "Biz monitor",
|
||
hfNotBound: "Unbound",
|
||
projectCollectMetrics: "Metrics",
|
||
hfInterval: "Interval(s)",
|
||
hfStart: "Start",
|
||
hfEnd: "End",
|
||
markProjectDone: "Done / stop HF",
|
||
confirmProjectDone: "Complete project and pause all HF?",
|
||
projectMarkedDone: "Done; HF paused",
|
||
deleteProject: "Delete",
|
||
confirmDeleteProject: "Delete project? HF will pause and batches removed.",
|
||
projectDeleted: "Deleted",
|
||
acceptPassedShort: "Pass",
|
||
acceptFailedShort: "Fail",
|
||
colMapped: "Mapped new",
|
||
colDesc: "Description",
|
||
colOldPort: "Old port",
|
||
colNewPort: "New port",
|
||
colOldStatus: "Old admin/phy/prot",
|
||
colNewStatus: "New admin/phy/prot",
|
||
colOld: "Old",
|
||
colNew: "New",
|
||
colVerdict: "Verdict",
|
||
emptyDiffs: "No rows yet — run Evaluate",
|
||
emptyRed: "No red tickets",
|
||
verdictMigrated: "Migrated",
|
||
verdictMigrating: "Migrating",
|
||
verdictLost: "Lost",
|
||
verdictAnomaly: "Anomaly",
|
||
verdictNotInvolved: "Not involved",
|
||
verdictUnexpected: "Unexpected new",
|
||
verdictOk: "OK",
|
||
highfreqHint: "",
|
||
boundTasks: "Bound tasks",
|
||
oldPortraitTask: "Old portrait",
|
||
newPortraitTask: "New portrait",
|
||
oldHfTask: "Old HF",
|
||
newHfTask: "New HF",
|
||
projectCollectHint: "",
|
||
hfWindowInactive: "HF window inactive or project done",
|
||
baselinePortraitOnly: "",
|
||
collectSkipped: "skipped",
|
||
collectSkippedBanner: "Skipped: {{metrics}}",
|
||
currentMissing: "no current",
|
||
currentMissingBanner: "No current: {{metrics}}",
|
||
highfreqReadyInactive: "HF bound (window inactive, no collect)",
|
||
collectPartial: "Partial fail (ok {{ok}} / fail {{fail}})",
|
||
errMetricNeedsBindings: "Metric \"{{metric}}\" needs bindings ({{params}}); not supported for cutover HF — remove it",
|
||
errNoProfileForMetric: "Metric \"{{metric}}\" has no collect profile for this vendor",
|
||
acceptTitle: "Acceptance",
|
||
acceptPassed: "Passed",
|
||
acceptFailed: "Failed ({{n}} red)",
|
||
newBaselineMissingBanner: "Missing new baseline: {{metrics}}",
|
||
acceptCarryHint: "May continue with red",
|
||
openRedHint: "Red {{n}}",
|
||
redTitle: "Red tickets",
|
||
redOpen: "open",
|
||
resolveRed: "Resolve",
|
||
redResolved: "Resolved",
|
||
batchCreatedWithRed: "Batch created ({{n}} red)",
|
||
colStatus: "Status",
|
||
verdictUnfinished: "Unfinished",
|
||
},
|
||
bizMonitorTpl: {
|
||
title: "Monitor templates",
|
||
hint: "Compare templates define HOW to align/diff; monitor templates define WHEN dual-device migrate succeeds — one sheet tab per compare sheet.",
|
||
create: "New monitor template",
|
||
edit: "Edit",
|
||
save: "Save",
|
||
cancel: "Close",
|
||
created: "Created",
|
||
saved: "Saved",
|
||
deleted: "Deleted",
|
||
confirmDelete: "Delete this monitor template?",
|
||
delete: "Delete",
|
||
empty: "No monitor templates yet.",
|
||
listFilterPh: "Filter name / compare template / note",
|
||
kpiTotal: "Templates",
|
||
colName: "Name",
|
||
namePh: "e.g. Status cutover monitor",
|
||
colCompare: "Compare template",
|
||
colCollect: "HF collect metrics",
|
||
colNote: "Note",
|
||
colActions: "Actions",
|
||
needName: "Name is required",
|
||
defaultsInvalid: "Invalid defaults JSON",
|
||
overridesInvalid: "Invalid sheet_overrides JSON",
|
||
exportTemplate: "Export",
|
||
importTemplate: "Import",
|
||
templateExported: "Template exported",
|
||
templateImported: "Template imported",
|
||
templateImportInvalid:
|
||
"Invalid import file: need name and compare_template_id (or compare_template_name)",
|
||
templateImportHint: "Import/export JSON to share monitor templates (no job/batch data)",
|
||
templateImportCompareMissing:
|
||
"Matching compare template not found — import or create it first",
|
||
formHint: "Pick a compare template → same sheet tabs appear → set success conditions per sheet.",
|
||
compareHint: "Owns which sheets and Key/compare fields; here you only set dual verdict rules.",
|
||
pickCompare: "Pick compare template…",
|
||
openCompare: "Manage compare templates",
|
||
collectAll: "All sheets",
|
||
collectPh: "interface_brief, bgp_peer (empty = all)",
|
||
collectHint: "HF collect metrics; empty / “All sheets” uses every compare-template sheet.",
|
||
collectTitle: "High-freq collect subset",
|
||
defaults: "defaults (JSON)",
|
||
overrides: "sheet_overrides (JSON)",
|
||
overridesHint: "Optional per-metric status_fields / success patterns.",
|
||
globalPolicy: "Global policy",
|
||
outOfExpect: "Out-of-expect objects",
|
||
outOfExpectHint: "How to treat drift outside the batch expect set.",
|
||
ooeStrict: "Strict (red anomaly)",
|
||
ooeWarn: "Warn (yellow only, no red tickets)",
|
||
ooeIgnore: "Ignore (always not involved)",
|
||
sheetRules: "Per-sheet migrate rules",
|
||
applyAllPresets: "Apply recommended presets to all",
|
||
applyAllPresetsShort: "All presets",
|
||
sheetsUnit: " sheets",
|
||
sheetHowReadonly: "Compare template (read-only)",
|
||
iface: "Interface",
|
||
compare: "Compare",
|
||
presenceOnly: "presence only",
|
||
editInCompare: "Edit HOW",
|
||
presetAuto: "Recommended",
|
||
presetSkip: "Skip sheet",
|
||
skipDual: "Skip dual for this sheet",
|
||
skipDualHint: "Skipped in cutover evaluate (use a compare job for counters).",
|
||
statusFields: "Fields used for up/down",
|
||
statusFieldsHint: "Ports: admin/phy/prot; BGP: state; ARP: leave empty (presence only).",
|
||
statusOptionalHint: "With no status fields, only presence (gone/added) is used.",
|
||
downValues: "Down values",
|
||
upValues: "Up values",
|
||
noFields: "No fields (pick metrics on the compare template first)",
|
||
successPatterns: "Success rules (old OR-groups × new OR-groups)",
|
||
successPatternsShort: "Success",
|
||
successPatternsHint:
|
||
"Presence is whether the row exists. Value change binds a field and a strategy. AND inside a group, OR between groups.",
|
||
successPatternsHintShort: "AND in group · OR across groups · old+new both match ⇒ success",
|
||
successPatternsHintFree:
|
||
"Each side has two condition kinds: presence (no field) or value change (must bind a field). Inside a group everything must match (AND). Between groups, any group is enough (OR).",
|
||
anomalyPatternsShort: "Anomaly",
|
||
anomalyPatternsHint:
|
||
"Same shape as success. Match ⇒ red. Check “don’t care” on one side to watch only the other (e.g. new-side gone/down). Not-yet-success is still migrating, not anomaly.",
|
||
anomalyPatternsHintShort: "Success first; then anomaly. Don’t-care watches one side. Mid-state ≠ anomaly.",
|
||
successRow: "Success {{n}}",
|
||
anomalyRow: "Anomaly {{n}}",
|
||
removeRow: "Remove",
|
||
oldSideAny: "Old",
|
||
newSideAny: "New",
|
||
groupLogicHint: "AND inside a group, OR between groups",
|
||
sideDontCare: "Don’t care this side",
|
||
sideDontCareHint: "Judged by the other side only.",
|
||
groupN: "Group {{n}}",
|
||
addAnd: "Add to this group (AND)",
|
||
addOr: "Add another group (OR)",
|
||
addAndShort: "+ AND",
|
||
addOrShort: "+ OR group",
|
||
addSuccessRow: "+ Success rule",
|
||
addAnomalyRow: "+ Anomaly rule",
|
||
modeAny: "Match any",
|
||
modeAll: "Match all",
|
||
addCond: "Add condition",
|
||
pickField: "Pick field…",
|
||
condValue: "Value",
|
||
opEmpty: "empty",
|
||
opNotEmpty: "not empty",
|
||
opChanged: "changed vs baseline",
|
||
opUnchanged: "same as baseline",
|
||
op_eq: "equals",
|
||
op_ne: "not equals",
|
||
op_in: "in",
|
||
op_not_in: "not in",
|
||
op_empty: "empty",
|
||
op_not_empty: "not empty",
|
||
op_changed: "changed vs baseline",
|
||
op_unchanged: "same as baseline",
|
||
and: "and",
|
||
groupPresence: "Presence",
|
||
groupValue: "Value change",
|
||
groupStatus: "Status class",
|
||
groupField: "Field condition",
|
||
tokRemoved: "Gone",
|
||
tokAdded: "Added",
|
||
tokUnchanged: "Unchanged",
|
||
tokChanged: "Changed",
|
||
tokUp: "up",
|
||
tokDown: "down",
|
||
tokOther: "other",
|
||
or: "or",
|
||
tagSkip: "skip",
|
||
tagRules: "{{n}}",
|
||
tagEmpty: "empty",
|
||
needCompareFirst: "Pick a compare template that has sheets first.",
|
||
showMore: "More: note / HF collect / JSON",
|
||
hideMore: "Hide more",
|
||
showJson: "Advanced: edit JSON",
|
||
hideJson: "Back to visual editor",
|
||
},
|
||
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. Uplink group",
|
||
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. Behind a reverse proxy, IP is taken from trusted forwarded headers; use the Client column to tell browsers apart on the same public IP. 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",
|
||
colClient: "Client",
|
||
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 and netxops. Defaults on create: alarms:read + ne:read + ne:write + ne:exec + biz-monitor:read; 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. System-wide cap: {{max}} non-revoked keys (revoke to free a slot).",
|
||
tokenQuota: "Active {{active}} / {{max}}",
|
||
tokenLimitReached: "API key limit reached ({{max}}). Revoke unused keys first.",
|
||
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)",
|
||
scopeBizMonitorRead: "biz-monitor:read — Biz monitor / cutover read (netxops)",
|
||
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.",
|
||
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)",
|
||
enterSystemView: "Huawei system-view before jump",
|
||
enterSystemViewNo: "Stay in user-view (default)",
|
||
enterSystemViewYes: "Enter system-view first",
|
||
enterSystemViewHint:
|
||
"Some Huawei hops only accept stelnet/telnet in system-view. Choose explicitly; NetX will not auto-retry.",
|
||
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). Matched alerts are broadcast by NetX (server) to subscribed Netx Ops (DSH) clients.",
|
||
hub: "DSH subscribers",
|
||
hubConnected: "subscribed",
|
||
hubEmpty: "no subscribers",
|
||
hubSubscribers: "subscribers",
|
||
hubPublished: "published",
|
||
hubDeliverOk: "deliver ok",
|
||
hubDeliverFail: "deliver fail",
|
||
hubConnections: "Active connections",
|
||
hubColId: "id",
|
||
hubColUser: "user",
|
||
hubColRemote: "remote",
|
||
hubColClient: "client",
|
||
hubColConnected: "connected",
|
||
hubColLastSeen: "last seen",
|
||
hubEmptyConnections: "No Netx Ops clients are connected to the alarm hub",
|
||
hubPath: "path",
|
||
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 to subscribed Netx Ops clients.",
|
||
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",
|
||
resumed_sync_soon: "Resumed: skipping debounce wait, sync soon",
|
||
resumed_wss_reconnect: "Resumed: reconnecting 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",
|
||
},
|
||
runtimeTask: {
|
||
token_keepalive: "UME token keepalive",
|
||
alarms_current_auto_sync: "Current alarms auto sync",
|
||
alarms_current_ws_consumer: "UME alarm 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: "Filter UME NEs (name / IP / ID)",
|
||
sampleNeRequired: "Select a UME NE first",
|
||
sampleNeEmpty: "No matching NE",
|
||
sampleNeLoading: "Loading…",
|
||
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: "Login progress streams into the terminal; slow devices may take >10s",
|
||
},
|
||
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",
|
||
more: "More",
|
||
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 links ({{count}})",
|
||
removeSelected: "Remove selected ({{count}})",
|
||
openWebcrt: "Open terminal",
|
||
openNe: "NE details",
|
||
openAlarms: "View alarms",
|
||
noAlarmLink: "Cannot build an alarm filter for this node",
|
||
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",
|
||
createNeModeHint:
|
||
"Create a full managed NE, or a topology placeholder (credentials can be filled later).",
|
||
createNeManaged: "Managed NE",
|
||
createNeManagedHint: "Same full form as NE management; placed on the canvas after create.",
|
||
createNePlaceholder: "Placeholder NE",
|
||
createNePlaceholderHint: "Name/IP only; topology placeholder for sketching first.",
|
||
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}}",
|
||
createManagedNeDone: "Created and placed {{name}}",
|
||
createManagedNePlaceFailed:
|
||
"{{name}} was created in inventory, but placing on the map failed: {{error}}. Add it again from NE management or the sidebar.",
|
||
createManagedNePosFailed:
|
||
"{{name}} is on the map, but could not move to the click position (kept default layout coords)",
|
||
createNeBusy: "Creating…",
|
||
connectTest: "Connectivity test",
|
||
connectTestSelected: "Connectivity test ({{count}})",
|
||
connectTestNeedManaged: "Node is not linked to a managed NE; cannot run connectivity test",
|
||
connectTestSkipped: "skipped {{count}} without managed link",
|
||
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)",
|
||
showConnectStatus: "Show connect-status dots",
|
||
showAlarmOverlay: "Show alarm overlay",
|
||
showLevelColors: "Color by classify level",
|
||
levelUnmatched: "Unclassified",
|
||
level: {
|
||
external: "External",
|
||
core: "Core",
|
||
aggregation: "Aggregation",
|
||
access: "Access",
|
||
edge: "Edge",
|
||
},
|
||
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 -EDGE-",
|
||
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",
|
||
colSummary: "Summary",
|
||
colDetail: "Detail",
|
||
showDetail: "Expand",
|
||
hideDetail: "Collapse",
|
||
filterBusiness: "Business",
|
||
filterAll: "All",
|
||
filterWebcrt: "Device terminal",
|
||
filterNeExec: "Device exec",
|
||
filterAuth: "Auth",
|
||
filterHttp: "HTTP",
|
||
summary: {
|
||
connecting: "Connecting to {{device}}",
|
||
loginOk: "Logged in to {{device}}",
|
||
loginFail: "Login failed {{device}}: {{error}}",
|
||
logout: "Disconnected {{device}}",
|
||
logoutReason: "Disconnected {{device}} ({{reason}})",
|
||
command: "{{device}} · cmd: {{command}}",
|
||
neExec: "{{device}} · exec: {{commands}}",
|
||
neExecBatch: "Batch exec {{n}} NE(s) (ok {{ok}} / fail {{fail}})",
|
||
},
|
||
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;
|