log namespace so a leaked Token cannot affect other namespaces; do not use cluster-admin.',
rbacScriptIntro:
- 'Creates the log namespace, ServiceAccount, namespace-scoped Role and a long-lived Token in one shot (run it once in the cluster, then paste the Token into the field below):',
+ 'Run once in the cluster to create the namespace / SA / Role / long-lived Token:',
rbacScriptComment1: '# 1) Create in one shot: namespace + SA + namespace-scoped Role + long-lived Token',
rbacScriptComment2: '# 2) Extract the long-lived Token (it does not expire) and paste it into the Token field',
rbacNamespaceNote:
- 'The Namespace above is created by an administrator; the platform Token itself has no cluster-wide permissions. Only grant the namespaces: create/get ClusterRole if the platform really must create its own namespaces — note that namespace creation cannot be restricted by name, so pre-creating log is safer.',
+ 'The token has no cluster-level rights; grant namespaces: create/get only if the platform must create its own namespace.',
rbacTokenNote:
- 'The Token is long-lived but bound to a Role in the log namespace only (it can only touch Pods and workloads there), so a leak is limited to log. The server converts it to a kubeconfig and stores it encrypted with ENCRYPTION_KEY; the database keeps only ENC: ciphertext and the API never returns the plaintext. To rotate it, delete and recreate the Secret — the old Token stops working immediately.',
+ 'Token is scoped to the log namespace with small blast radius; stored encrypted server-side. Rotate by deleting the Secret and recreating.',
contextLabel: 'Context (optional)',
contextPlaceholder: 'Leave blank to use the default context',
submitAdd: 'Add Cluster',
diff --git a/frontend/src/i18n/locales/en/collectors.ts b/frontend/src/i18n/locales/en/collectors.ts
index d69654a..d6cf312 100644
--- a/frontend/src/i18n/locales/en/collectors.ts
+++ b/frontend/src/i18n/locales/en/collectors.ts
@@ -77,7 +77,7 @@ const collectors = {
logPath: 'Log Path',
logPathHostHint: 'Supports glob wildcards (e.g. /var/log/*.log /var/log/syslog); separate multiple paths with commas',
logPathSidecarHint:
- 'Enter the file path your app writes to, e.g. /var/log/app/*.log. Existing log volumes are shared automatically; without one, a shared volume is created only in the dedicated logs directory. Regular paths such as /tmp/test.log are not mounted automatically.',
+ 'Paths the app writes to, e.g. /var/log/app/*.log; only existing log volumes or the dedicated logs directory are shared.',
labels: 'Custom Labels (JSON, optional)',
labelsHint: 'When valid JSON, attached as labels to every log line for filtering in Loki/Grafana; leave empty to skip',
submit: 'Create & Deploy',
@@ -103,11 +103,11 @@ const collectors = {
nsNoMatch: 'No matches',
nsLoadFailed: 'Failed to load namespaces',
nsHint:
- 'Check "All namespaces" to collect cluster-wide; otherwise only the selected namespaces are collected. Generates the kubernetes_sd_configs.namespaces allowlist for Promtail.',
+ '"All namespaces" collects cluster-wide; otherwise only the checked ones.',
appLabelSource: 'app label source',
appSourcePlaceholder: 'Empty = default (controller-name fallback chain)',
appSourceHint:
- 'By default falls back through app.kubernetes.io/name → app → controller name → pod name. If your cluster has its own convention label (e.g. k8s.kuboard.cn/name), enter it here and it takes the highest priority; the rest still serve as fallback.',
+ 'Falls back through app.kubernetes.io/name → app → controller name → pod name; a cluster-specific label (e.g. k8s.kuboard.cn/name) set here takes priority.',
appSourcePreset: {
default: 'Default: app.kubernetes.io/name → app → controller name → pod name',
controllerName: 'controller_name (ReplicaSet name of the Pod, hash stripped = Deployment name)',
@@ -118,8 +118,8 @@ const collectors = {
appInclude: 'Only collect these apps (optional)',
appIncludePlaceholder: 'Empty = no limit; comma-separated, e.g. cex-spot-api, cex-asset-api',
appIncludeHint:
- 'When set, Promtail keeps only logs whose app label matches these values (action: keep) — the most direct way to control log volume. Values must match the app resolved by the "app label source" above.',
- logPathHint: 'The Sidecar requires the app container\'s shared log volume or the dedicated logs directory. Click "Deploy" after saving to apply the new configuration.',
+ 'Keeps only logs whose app matches these values (action: keep) — the most direct way to cap log volume.',
+ logPathHint: 'Sidecar needs a shared log volume or the dedicated logs directory; click Deploy after saving.',
save: 'Save',
saving: 'Saving…',
validation: {
diff --git a/frontend/src/i18n/locales/en/common.ts b/frontend/src/i18n/locales/en/common.ts
index 226e40f..6f3f7d7 100644
--- a/frontend/src/i18n/locales/en/common.ts
+++ b/frontend/src/i18n/locales/en/common.ts
@@ -106,6 +106,14 @@ export default {
apply: 'Apply',
recent: 'Recently used',
},
+ ui: {
+ close: 'Close',
+ prevPage: 'Previous',
+ nextPage: 'Next',
+ goPrevPage: 'Go to previous page',
+ goNextPage: 'Go to next page',
+ morePages: 'More pages',
+ },
password: {
hide: 'Hide password',
show: 'Show password',
diff --git a/frontend/src/i18n/locales/en/deployments.ts b/frontend/src/i18n/locales/en/deployments.ts
index d46cffc..3e058f8 100644
--- a/frontend/src/i18n/locales/en/deployments.ts
+++ b/frontend/src/i18n/locales/en/deployments.ts
@@ -10,7 +10,7 @@ export default {
deleteDockerDesc:
'Delete "{{name}}"? The Loki container on the host will be removed as well. This cannot be undone.',
deleteRecordDesc:
- 'Delete "{{name}}"? Deleting the record does not uninstall the Loki resources already deployed on the cluster/host. This cannot be undone.',
+ 'Deleting "{{name}}" does not uninstall deployed Loki resources; this cannot be undone.',
errLoadRefs: 'Failed to load cluster/host/storage data',
errDeploy: 'Deployment failed',
errStop: 'Failed to stop',
@@ -36,7 +36,7 @@ export default {
ready: 'Loki ready',
notReady: 'Loki not ready',
runningHint:
- 'Tip: link Loki under "Log Query → Data Sources" to start querying; for cross-cluster/public access, configure an Ingress domain for Loki first.',
+ 'Link the Loki source under "Log Query → Data Sources" to query logs.',
configure: 'Configure',
deploy: 'Deploy',
deploying: 'Deploying...',
@@ -103,7 +103,7 @@ export default {
loading: 'Loading…',
templateNote: 'Generated by the deployment template',
yamlLabel: 'Retention Config YAML',
- yamlHint: 'Edit limits_config.retention_period, e.g. 90d or 2160h. Only this setting is accepted here.',
+ yamlHint: 'Edit retention_period, e.g. 90d / 2160h; only this setting is accepted.',
applyHintRunning:
'Save only updates the deployment record; Save & Apply redeploys Loki and queries may be briefly interrupted.',
applyHintIdle: 'Takes effect on the next deployment.',
diff --git a/frontend/src/i18n/locales/en/hosts.ts b/frontend/src/i18n/locales/en/hosts.ts
index 41d231c..9969633 100644
--- a/frontend/src/i18n/locales/en/hosts.ts
+++ b/frontend/src/i18n/locales/en/hosts.ts
@@ -24,7 +24,7 @@ export default {
},
delete: {
warning:
- 'Delete "{{name}}"? Warning: {{dep}} deployments and {{col}} collector policies still reference this host; they will stop working once it is deleted.',
+ 'Delete "{{name}}"? {{dep}} deployment(s) and {{col}} collector policy(ies) still reference it.',
},
toast: {
deleteFailed: 'Failed to delete host',
diff --git a/frontend/src/i18n/locales/en/logs.ts b/frontend/src/i18n/locales/en/logs.ts
index 06aed87..9f3352e 100644
--- a/frontend/src/i18n/locales/en/logs.ts
+++ b/frontend/src/i18n/locales/en/logs.ts
@@ -8,7 +8,7 @@ export default {
query: 'Loki Query',
access: 'Query Access',
sources: 'Data Sources',
- descQuery: 'Search by log stream and time range; drag the timeline to narrow the range, and click a log line to view its context.',
+ descQuery: 'Search by stream selector and time range; drag the timeline or open line context.',
descAccess: 'Reuse log scopes with policy groups and attach multiple users at once.',
descSources: 'Configure Loki connections and authentication.',
},
@@ -20,7 +20,7 @@ export default {
sourceAria: 'Data source',
sourceEmptyOption: 'No data sources available',
limitLabel: 'Per page',
- limitHint: 'Up to 1000 entries per page; paging keeps only the current page. For wide ranges, check the timeline first, then drag to select a peak window.',
+ limitHint: 'Up to 1000 entries per page; paging keeps only the current page.',
rangeInvalid: 'Select a valid start and end time',
queryFailed: 'Query failed',
},
@@ -28,14 +28,28 @@ export default {
loadFailed: 'Failed to load data sources',
missingTitle: 'No Loki data source available',
missingBody:
- 'Link a Loki data source first under "Data Sources": for in-cluster Loki, pick "Cluster Service" (Namespace / Service / port, no Ingress needed); for cross-cluster or public queries, expose Loki via an Ingress domain first, then add it with "Direct URL". Queries are unavailable until a data source is linked.',
+ 'Link a Loki data source first under "Data Sources": use "Cluster Service" in-cluster, or "Direct URL" via an Ingress domain.',
goConfigure: 'Go to data sources',
sectionAria: 'Data source management',
heading: 'Loki Data Sources',
- hint: 'Tip: when Loki runs in the cluster, add a "Cluster Service" data source directly (no Ingress needed); for cross-cluster / public queries, expose Loki via an Ingress domain first, then link it with "Direct URL". Without a linked data source, the query page cannot be used.',
+ hint: 'In-cluster Loki works with "Cluster Service"; cross-cluster / public access needs an Ingress domain plus "Direct URL".',
managedCluster: 'Cluster {{name}}',
managedBadge: 'Platform deployed · managed with the deployment',
- add: '+ Add manually',
+ countLabel: '{{count}} total',
+ create: 'New source',
+ createTitle: 'New data source',
+ editTitle: 'Edit data source',
+ edit: 'Edit',
+ cancel: 'Cancel',
+ testing: 'Testing…',
+ deleteTitle: 'Delete data source',
+ deleteDesc: 'Deleting "{{name}}" breaks queries and access policies based on it. Delete it?',
+ deleteAria: 'Delete {{name}}',
+ defaultBadge: 'Default',
+ emptyTitle: 'No data sources yet',
+ emptyDesc: 'Add a "Cluster Service" or "Direct URL" source, then query logs on the Loki Query tab.',
+ typeLabel: 'Type',
+ namePlaceholder: 'prod-loki',
nameLabel: 'Name',
targetUrl: 'Direct URL',
targetClusterSvc: 'Cluster Service',
@@ -62,17 +76,6 @@ export default {
saveFailed: 'Failed to save',
remove: 'Delete',
},
- range: {
- lastMinutes: 'Last {{count}} minutes',
- lastHours: 'Last {{count}} hours',
- lastHours_one: 'Last {{count}} hour',
- custom: 'Custom time',
- title: 'Select time range',
- start: 'Start time',
- end: 'End time',
- apply: 'Apply',
- recent: 'Recently used',
- },
editor: {
aria: 'LogQL query',
valuesOf: 'Values of {{label}}',
@@ -85,7 +88,7 @@ export default {
templates: {
aria: 'Quick query templates',
title: 'Quick LogQL builder',
- hint: 'Pick a namespace, then an app, then a pod; app candidates come only from the selected namespace.',
+ hint: 'Pick a namespace to narrow down; selecting an app / pod runs the query.',
namespace: 'Namespace',
app: 'App',
appWithKey: 'App ({{key}})',
@@ -95,12 +98,10 @@ export default {
pickNsFirst: 'Pick a namespace first to narrow down',
noPod: 'No pods under this app',
optional: 'Optional',
- scopeLogs: 'Query this scope',
errorLogs: 'Errors (error)',
warnLogs: 'Warnings (warn)',
- podLogs: 'Specific pod logs',
ingressLogs: 'Ingress access logs',
- scopeHint: 'Pick a namespace, then an app or pod — or choose values in the Label browser',
+ scopeHint: 'Selecting an app / pod runs the query — or pick values in the Label browser',
},
labels: {
browser: 'Label Browser',
@@ -115,11 +116,11 @@ export default {
loading: 'Loading…',
noValues: 'No matching values',
useAsValue: 'Use "{{value}}" as value',
- hint: 'Select namespace first to query all replicas in that Namespace; then app / service_name to narrow to a service (workloads without an app label can rely on namespace alone). Candidates come from logs written to Loki within the current time range; the authorized scope is still enforced server-side.',
+ hint: 'Pick namespace, then app / service_name to narrow down; candidates come from logs in the current range.',
},
volume: {
statsLoading: 'Counting logs across the whole time range; you can keep browsing the log page.',
- statsError: 'Log volume statistics timed out or failed; the log page still works. Narrow the time range and query again.',
+ statsError: 'Volume stats failed; narrow the range and retry.',
histogramLoading: 'Counting…',
histogramEmpty: 'No log volume data',
timelineAria: 'Log volume timeline',
@@ -136,16 +137,10 @@ export default {
summary_one: 'Page {{page}} · {{count}} entry',
summaryMore: 'Page {{page}} · {{count}} entries · more available',
summaryMore_one: 'Page {{page}} · {{count}} entry · more available',
- viewAria: 'Log display mode',
- viewRaw: 'Raw',
- viewTable: 'Table',
- viewLine: 'Line',
- viewStream: 'Stream',
- viewPie: 'Pie',
loadingPage: 'Loading log page',
loadingQuery: 'Querying Loki',
loadingWait: 'Waiting for {{seconds}}s. Wide-range queries may take a while.',
- pagingHint: 'Logs are paged newest to oldest; charts show the current page, and the top timeline covers the whole query range.',
+ pagingHint: 'Logs page newest-first; the top timeline covers the whole query range.',
domainAll: 'All domains',
domainFilter: 'Domain filter',
domainPlaceholder: 'Type or pick a domain',
@@ -165,42 +160,6 @@ export default {
idleHint: 'You can also build queries quickly in the Label browser',
retry: 'Query again',
},
- views: {
- noDomain: 'No domain recorded',
- otherDomain: 'Other domains',
- unknown: 'Unknown',
- untagged: 'Untagged',
- other: 'Other',
- tableLoaded: '{{count}} log entries loaded on this page.',
- tableEmpty: 'No logs to display',
- thTime: 'Time',
- thNsPod: 'namespace / pod',
- thLevel: 'Level',
- thLog: 'Log',
- lineByLoaded: 'Based on currently loaded logs; load more for additional results.',
- lineByRange: 'Log volume aggregated over the query time range, from Loki.',
- lineGroupAria: 'Line chart grouping',
- lineByDomain: 'By domain',
- lineByTotal: 'Total',
- lineEmpty: 'No time-series data for this query',
- lineSeriesTotal: 'Log count',
- streamParsed: 'Showing {{count}} parsed entries',
- streamByLevel: 'Showing {{count}} loaded entries by level',
- streamSuffix: ', based on currently loaded results.',
- streamGroupAria: 'Stream chart grouping',
- streamByStatus: 'By HTTP status class',
- streamEmpty: 'No log streams to display',
- pieByAccess: 'Grouping {{count}} parsed entries by access fields',
- pieByLabel: 'Grouping {{count}} loaded entries by label',
- pieGroupAria: 'Pie chart grouping',
- pieDomain: 'Domain (request Host)',
- pieStatus: 'HTTP status',
- pieMethod: 'Method',
- piePath: 'Path',
- pieUpstream: 'Upstream service',
- pieLevel: 'Level',
- pieEmpty: 'No label distribution to display',
- },
ingress: {
modesAria: 'Ingress statistics mode',
modeTraffic: 'Endpoints PV / UV',
@@ -208,7 +167,7 @@ export default {
modeSlow: 'Top 10 slow requests',
modeDetail: 'Request details',
summary:
- 'Based on the {{loaded}} entries loaded on this page, of which {{parsed}} are ingress-nginx access logs. Statistics are recomputed after paging; UV is deduplicated by non-empty client IP.',
+ 'Based on {{loaded}} loaded entries',
statPv: 'PV',
statUv: 'UV (IP)',
statErrors: '4xx / 5xx',
@@ -219,9 +178,9 @@ export default {
error4xx: '4xx only',
slowThreshold: 'Slow request threshold',
seconds: '{{count}}s',
- slowHint: 'Sorted by request_time from the access log; 408 / 499 / 504 are only timeout hints and do not by themselves prove a backend timeout.',
+ slowHint: 'Sorted by request_time; 408 / 499 / 504 are timeout hints.',
slowMissing: '{{count}} entries lack a valid duration.',
- trafficHint: 'Success rate = 2xx / 3xx requests ÷ PV; query strings are stripped from paths.',
+ trafficHint: 'Success rate = 2xx / 3xx ÷ PV',
thHost: 'Request Host',
thPath: 'Path',
thSuccess: 'Success rate',
@@ -257,7 +216,7 @@ export default {
loadFailed: 'Failed to load context',
},
access: {
- labelsUnlimited: 'Unlimited · all namespaces',
+ labelsUnlimited: 'Unrestricted · all namespaces',
loadFailed: 'Failed to load query policies',
validate: 'Fill in the policy group name, choose a data source, and select "Anyone" or at least one user',
saveFailed: 'Failed to save policy group',
@@ -309,19 +268,4 @@ export default {
loading: 'Loading…',
noMatch: 'No matches',
},
- raw: {
- searching: 'Querying…',
- count: '{{count}} logs',
- count_one: '{{count}} log',
- dedupSuffix: ' (deduplicated from {{count}})',
- dedup: 'Dedup',
- empty: 'No matching logs',
- original: 'Raw log',
- labelsTitle: 'Labels (click to filter)',
- filterValue: 'Filter this value',
- excludeValue: 'Exclude this value',
- fields: 'Extracted fields',
- loadMore: 'Load more',
- loadingMore: 'Loading…',
- },
}
diff --git a/frontend/src/i18n/locales/en/settings.ts b/frontend/src/i18n/locales/en/settings.ts
index f389e2d..91b6acf 100644
--- a/frontend/src/i18n/locales/en/settings.ts
+++ b/frontend/src/i18n/locales/en/settings.ts
@@ -45,9 +45,9 @@ export default {
cardTitle: 'Alert Channels — Feishu (Lark)',
create: 'New channel',
// Empty state is assembled as "prefix + link + suffix" (link points to the Alerts page)
- emptyBefore: 'No channels yet — create one per alert group (e.g. "App alerts", "Nginx alerts"), then link rules to it on the ',
+ emptyBefore: 'No channels yet — create one per alert group, ',
emptyLink: 'Alerts',
- emptyAfter: ' page',
+ emptyAfter: 'then link rules to it on the alerts page.',
webhookConfigured: 'Webhook configured',
webhookMissing: 'Not configured',
secretConfigured: ' · Signing secret configured',
@@ -82,7 +82,7 @@ export default {
headerHint: 'Enables LDAP sign-in and bulk user import',
errLoad: 'Failed to load LDAP configuration',
disabledHint:
- 'LDAP is disabled — turn it on and fill in the directory details (server / Bind DN / Base DN). After saving, "Import from LDAP" appears on the Users page.',
+ 'LDAP disabled — enable it and fill in the directory info to show "Import from LDAP" on the Users page.',
hostLabel: 'Server address *',
portLabel: 'Port',
ldapsLabel: 'LDAPS',
@@ -133,7 +133,7 @@ export default {
timezone: 'Timezone',
timezoneAria: 'Theme schedule timezone',
browser: 'Follow browser (local)',
- autoHint: 'Light from {{start}}:00 to {{end}}:00 in the selected timezone, dark otherwise; the sun/moon toggle overrides anytime.',
+ autoHint: 'Light from {{start}}:00–{{end}}:00 in the chosen timezone, dark otherwise; the top bar toggle always works.',
},
prefsCard: {
title: 'Appearance & Language',
diff --git a/frontend/src/i18n/locales/en/storage.ts b/frontend/src/i18n/locales/en/storage.ts
index b871b65..5055277 100644
--- a/frontend/src/i18n/locales/en/storage.ts
+++ b/frontend/src/i18n/locales/en/storage.ts
@@ -10,7 +10,7 @@ export default {
deleteWarning_one:
'Delete "{{name}}"? Warning: {{count}} deployment still uses this storage; its object storage config will stop working.',
deleteWarning_other:
- 'Delete "{{name}}"? Warning: {{count}} deployments still use this storage; their object storage configs will stop working.',
+ 'Delete "{{name}}"? {{count}} deployment(s) still use it; their object storage will break.',
errDelete: 'Failed to delete the storage config',
errSetDefault: 'Failed to set the default storage',
},
diff --git a/frontend/src/i18n/locales/en/users.ts b/frontend/src/i18n/locales/en/users.ts
index 418308b..e2fa855 100644
--- a/frontend/src/i18n/locales/en/users.ts
+++ b/frontend/src/i18n/locales/en/users.ts
@@ -80,7 +80,7 @@ export default {
clear: 'Clear selection',
selectAll: 'Select all',
confirmTitle: 'Confirm Bulk Deletion',
- confirmDesc: 'Delete {{count}} selected users? Protected accounts (your own / the last admin) will be skipped. This cannot be undone.',
+ confirmDesc: 'Delete {{count}} selected users? Protected accounts are skipped; this cannot be undone.',
skippedWarn: '{{count}} skipped: {{reasons}}',
failed: 'Bulk delete failed',
},
diff --git a/frontend/src/i18n/locales/en/wizard.ts b/frontend/src/i18n/locales/en/wizard.ts
index 8f41a2f..7b189dc 100644
--- a/frontend/src/i18n/locales/en/wizard.ts
+++ b/frontend/src/i18n/locales/en/wizard.ts
@@ -32,7 +32,7 @@ const wizard = {
ready: 'Ready',
connected: 'Connected: {{names}}',
nameSep: ', ',
- k8sHint: 'Connect a cluster via kubeconfig or ServiceAccount token; connectivity is verified automatically on creation',
+ k8sHint: 'Connect via kubeconfig or Token; connectivity is verified on create.',
addCluster: 'Add Cluster',
hostHint: 'Connect a host via SSH key or password (used for deployment and later collector installation)',
addHost: 'Add Host',
@@ -44,7 +44,7 @@ const wizard = {
manage: 'Manage Storage',
add: 'Add Storage',
configure: 'Configure Storage',
- hint: 'Object storage (MinIO / RustFS / S3 / OSS) is recommended for more reliable replication and retention. Use "Test Connection" when adding to verify credentials and auto-create missing buckets; skip to use local disk.',
+ hint: 'Object storage (MinIO / RustFS / S3 / OSS) recommended; skip to use local disk.',
},
deploy: {
meta: '{{mode}} · Namespace {{namespace}} · {{endpoint}}',
diff --git a/frontend/src/i18n/locales/zh/alerts.ts b/frontend/src/i18n/locales/zh/alerts.ts
index c621ed5..53763cc 100644
--- a/frontend/src/i18n/locales/zh/alerts.ts
+++ b/frontend/src/i18n/locales/zh/alerts.ts
@@ -34,7 +34,7 @@ export default {
sent: '已发送',
cooldown: '冷却跳过',
failed: '失败',
- hits_other: '{{count}} 条命中',
+ hits: '{{count}} 条命中',
},
tpl: {
nsError: {
@@ -65,7 +65,7 @@ export default {
sourcePlaceholder: '选择数据源',
query: 'LogQL 查询 *',
queryHint:
- '常用:{app="xxx"} |= "FATAL" / {namespace=~".+"} |~ "(?i)error" / {app="x"} |= "OutOfMemoryError"',
+ '常用:{app="xxx"} |= "FATAL"',
channels: '通知通道(可多选,扇出到多个告警群)',
noChannels: '请先在「系统设置 → 告警通知」创建通道',
channelDisabled: '(禁用)',
diff --git a/frontend/src/i18n/locales/zh/analysis.ts b/frontend/src/i18n/locales/zh/analysis.ts
index 61c644f..d823d70 100644
--- a/frontend/src/i18n/locales/zh/analysis.ts
+++ b/frontend/src/i18n/locales/zh/analysis.ts
@@ -1,7 +1,6 @@
// 日志分析页(admin)— 经 i18n/domains.ts 注册,页面入口 import '@/i18n/domains'
export default {
title: '日志分析',
- subtitle: '按应用与命名空间统计日志量、错误量与趋势,定位日志大户',
adminOnly: {
title: '仅管理员可访问',
desc: '日志分析面向管理员提供全量日志统计,请联系管理员开通。',
@@ -24,7 +23,6 @@ export default {
},
trend: {
title: '日志量趋势',
- subtitle: '总量 / 错误 / 告警 按时间分桶',
seriesTotal: '总量',
seriesError: '错误',
seriesWarn: '告警',
@@ -32,25 +30,21 @@ export default {
},
stream: {
title: '应用日志量流图',
- subtitle: '日志量 Top {{count}} 应用随时间的堆叠分布',
empty: '没有应用维度的数据',
},
pie: {
title: '命名空间分布',
- subtitle: '按命名空间统计的日志量占比',
empty: '没有命名空间维度的数据',
other: '其他',
},
daily: {
fixedBadge: '固定近 7 天',
title: '应用每日日志量',
- subtitle: '固定统计近 7 个自然日的 Top 应用分布,不受上方时间范围影响',
empty: '近 7 天没有应用维度的数据',
},
table: {
title: '应用日志量排行',
- subtitle: '按日志量排序的 Top 10 应用,点击「查看日志」跳转查询页',
rank: '#',
app: '应用',
appWithKey: '应用({{key}})',
@@ -64,4 +58,13 @@ export default {
untagged: '(未打标签)',
empty: '没有应用维度的数据',
},
-}
\ No newline at end of file
+ ingress: {
+ title: 'Ingress 访问分析',
+ noIngress: '当前数据源未发现 ingress-nginx / ingress 命名空间的访问日志',
+ empty: '该时间范围内没有可解析的 ingress 访问日志',
+ loading: '加载 ingress 访问日志中…',
+ notDetected: '未检测到 ingress-nginx',
+ toggleAria: '展开 / 折叠 Ingress 访问分析',
+ loadFailed: '加载 ingress 访问日志失败',
+ },
+}
diff --git a/frontend/src/i18n/locales/zh/clusters.ts b/frontend/src/i18n/locales/zh/clusters.ts
index cdd08d3..8dea7e7 100644
--- a/frontend/src/i18n/locales/zh/clusters.ts
+++ b/frontend/src/i18n/locales/zh/clusters.ts
@@ -51,13 +51,13 @@ export default {
rbacScope:
'只授予 log 命名空间权限,Token 泄露也不会影响其他命名空间;不要使用 cluster-admin。',
rbacScriptIntro:
- '一次性创建 log 命名空间、ServiceAccount、命名空间级 Role 和长期 Token(在集群里执行一次,Token 粘贴到下方输入框):',
+ '在集群执行一次,创建命名空间 / SA / Role / 长期 Token:',
rbacScriptComment1: '# 1) 一次创建:命名空间 + SA + 命名空间级 Role + 长期 Token',
rbacScriptComment2: '# 2) 取出长期 Token(不自动过期),粘贴到 Token 输入框',
rbacNamespaceNote:
- '上面的 Namespace 由管理员创建,平台 Token 本身没有任何集群级权限。只有确实需要平台自建命名空间时,才额外授予 namespaces: create/get 的 ClusterRole;注意 namespace 的 create 无法按名称限制,所以预建 log 更安全。',
+ 'Token 无集群级权限;仅当需要平台自建命名空间时才额外授予 namespaces: create/get。',
rbacTokenNote:
- 'Token 长期有效,但只绑定 log 命名空间的 Role(仅能操作该命名空间的 Pod / 工作负载),泄露影响面仅限于 log;服务端会转成 kubeconfig 并用 ENCRYPTION_KEY 加密存储,数据库里只有 ENC: 密文,接口不返回明文。轮换时删除该 Secret 重建即可,旧 Token 立即失效。',
+ 'Token 仅限 log 命名空间,泄露影响面小;服务端加密存储。轮换:删除该 Secret 重建。',
contextLabel: '上下文(可选)',
contextPlaceholder: '留空则使用默认上下文',
submitAdd: '添加集群',
diff --git a/frontend/src/i18n/locales/zh/collectors.ts b/frontend/src/i18n/locales/zh/collectors.ts
index 6717e77..82dd982 100644
--- a/frontend/src/i18n/locales/zh/collectors.ts
+++ b/frontend/src/i18n/locales/zh/collectors.ts
@@ -80,7 +80,7 @@ const collectors = {
logPath: '采集日志路径',
logPathHostHint: '支持 glob 通配(如 /var/log/*.log /var/log/syslog);多个路径用逗号分隔',
logPathSidecarHint:
- '填写业务写入的文件路径,如 /var/log/app/*.log。已有日志卷会自动共享;无日志卷时仅在专用 logs 目录创建共享卷。/tmp/test.log 等普通目录不会自动挂载。',
+ '填业务写入的路径,如 /var/log/app/*.log;仅共享已有日志卷或专用 logs 目录。',
labels: '自定义标签(JSON,可选)',
labelsHint: '合法 JSON 时将附加到每条日志的标签,便于在 Loki/Grafana 中筛选;留空则不加',
submit: '创建并部署',
@@ -107,11 +107,11 @@ const collectors = {
nsLoadFailed: '加载命名空间失败',
// nsHint/appSourceHint/appIncludeHint 含行内 ,渲染处用 Trans 组件
nsHint:
- '勾「所有命名空间」= 采集全集群;否则只采集勾选的命名空间。生成 Promtail 的 kubernetes_sd_configs.namespaces 白名单。',
+ '勾「所有命名空间」= 采集全集群;否则只采勾选项。',
appLabelSource: 'app 标签取值来源',
appSourcePlaceholder: '留空 = 默认(controller 名回退链)',
appSourceHint:
- '默认按 app.kubernetes.io/name → app → controller 名 → pod 名 四级回退。若集群有自己的私有规范标签(如 k8s.kuboard.cn/name),填在这里会作为最高优先级,其余仍兜底。',
+ '默认按 app.kubernetes.io/name → app → controller 名 → pod 名 回退;集群自定义标签(如 k8s.kuboard.cn/name)填此处优先。',
appSourcePreset: {
default: '默认:app.kubernetes.io/name → app → controller 名 → pod 名',
controllerName: 'controller_name(Pod 的 ReplicaSet 名,去 hash = Deployment 名)',
@@ -122,8 +122,8 @@ const collectors = {
appInclude: '只采集这些 app(可选)',
appIncludePlaceholder: '留空 = 不限;多个用逗号分隔,如 cex-spot-api, cex-asset-api',
appIncludeHint:
- '填了之后 Promtail 只保留 app 命中这些值的日志(action: keep),是控制日志量最直接的手段。值需与上面「app 标签取值来源」解析出的 app 一致。',
- logPathHint: 'Sidecar 需使用业务容器的共享日志卷,或专用 logs 目录。保存后点击「部署」应用新配置。',
+ '只保留 app 命中这些值的日志(action: keep),是控制日志量最直接的手段。',
+ logPathHint: 'Sidecar 需共享日志卷或专用 logs 目录;保存后点「部署」生效。',
save: '保存',
saving: '保存中…',
validation: {
diff --git a/frontend/src/i18n/locales/zh/common.ts b/frontend/src/i18n/locales/zh/common.ts
index 756ddcd..298bf98 100644
--- a/frontend/src/i18n/locales/zh/common.ts
+++ b/frontend/src/i18n/locales/zh/common.ts
@@ -105,6 +105,14 @@ export default {
apply: '应用时间',
recent: '最近使用',
},
+ ui: {
+ close: '关闭',
+ prevPage: '上一页',
+ nextPage: '下一页',
+ goPrevPage: '前往上一页',
+ goNextPage: '前往下一页',
+ morePages: '更多页码',
+ },
password: {
hide: '隐藏密码',
show: '显示密码',
diff --git a/frontend/src/i18n/locales/zh/deployments.ts b/frontend/src/i18n/locales/zh/deployments.ts
index 4b056c2..d8b9876 100644
--- a/frontend/src/i18n/locales/zh/deployments.ts
+++ b/frontend/src/i18n/locales/zh/deployments.ts
@@ -9,7 +9,7 @@ export default {
// 删除确认:host-docker 连容器一起删,其余模式仅删记录不卸载资源
deleteDockerDesc: '确定要删除「{{name}}」吗?将同时移除主机上的 Loki 容器,此操作不可恢复。',
deleteRecordDesc:
- '确定要删除「{{name}}」吗?删除记录不会自动卸载集群/主机上已部署的 Loki 资源,此操作不可恢复。',
+ '删除「{{name}}」不会卸载已部署的 Loki 资源,此操作不可恢复。',
errLoadRefs: '加载集群/主机/存储数据失败',
errDeploy: '部署失败',
errStop: '停止失败',
@@ -35,7 +35,7 @@ export default {
ready: 'Loki 就绪',
notReady: 'Loki 未就绪',
runningHint:
- '提示:到「日志查询 → 数据源」关联 Loki 后即可查询;跨集群/公网访问需先为 Loki 配置 Ingress 域名。',
+ '到「日志查询 → 数据源」关联 Loki 后即可查询。',
configure: '配置',
deploy: '部署',
deploying: '部署中...',
@@ -101,7 +101,7 @@ export default {
loading: '读取中…',
templateNote: '由部署模板生成',
yamlLabel: '保留配置 YAML',
- yamlHint: '编辑 limits_config.retention_period,例如 90d 或 2160h。此处只接受这一项配置。',
+ yamlHint: '编辑 retention_period,如 90d / 2160h;仅支持这一项。',
applyHintRunning: '仅保存会更新部署记录;保存并应用会重新部署 Loki,查询可能短暂中断。',
applyHintIdle: '保存后在下次部署时生效。',
cancel: '取消',
diff --git a/frontend/src/i18n/locales/zh/hosts.ts b/frontend/src/i18n/locales/zh/hosts.ts
index 0b71ec1..c550f3c 100644
--- a/frontend/src/i18n/locales/zh/hosts.ts
+++ b/frontend/src/i18n/locales/zh/hosts.ts
@@ -24,7 +24,7 @@ export default {
},
delete: {
warning:
- '确定要删除「{{name}}」吗?警告:仍有 {{dep}} 个部署、{{col}} 个采集策略引用该主机,删除后它们将无法工作。',
+ '确定删除「{{name}}」吗?仍有 {{dep}} 个部署、{{col}} 个采集策略在引用。',
},
toast: {
deleteFailed: '删除主机失败',
diff --git a/frontend/src/i18n/locales/zh/logs.ts b/frontend/src/i18n/locales/zh/logs.ts
index 62978bc..de12649 100644
--- a/frontend/src/i18n/locales/zh/logs.ts
+++ b/frontend/src/i18n/locales/zh/logs.ts
@@ -7,7 +7,7 @@ export default {
query: 'Loki 查询',
access: '查询授权',
sources: '数据源管理',
- descQuery: '按日志流和时间范围检索;拖动时间线缩小范围,点日志查看前后文。',
+ descQuery: '按日志流与时间范围检索,可拖时间线、看前后文。',
descAccess: '用策略组复用日志范围,并一次关联多个用户。',
descSources: '配置 Loki 连接与认证方式。',
},
@@ -19,7 +19,7 @@ export default {
sourceAria: '数据源',
sourceEmptyOption: '暂无可用数据源',
limitLabel: '每页条数',
- limitHint: '每页最多 1000 条;翻页只保留当前页。大范围先看时间线,再拖选高峰时段。',
+ limitHint: '每页最多 1000 条,翻页仅保留当前页。',
rangeInvalid: '请选择有效的起止时间',
queryFailed: '查询失败',
},
@@ -27,14 +27,28 @@ export default {
loadFailed: '加载数据源失败',
missingTitle: '还没有可用的 Loki 数据源',
missingBody:
- '请先到「数据源管理」关联 Loki:集群内可直接选「集群服务」(命名空间 / Service / 端口,无需 Ingress);跨集群或公网查询,请先给 Loki 配置 Ingress 域名,再用「URL 直连」填写该域名。未关联数据源无法查询。',
+ '请先到「数据源管理」关联 Loki:集群内选「集群服务」,跨集群 / 公网用「URL 直连」。',
goConfigure: '去配置数据源',
sectionAria: '数据源管理',
heading: 'Loki 数据源',
- hint: '提示:Loki 部署在集群内时,可直接添加「集群服务」数据源(无需 Ingress);跨集群 / 公网查询需先为 Loki 配置 Ingress 域名,再用「URL 直连」关联。未关联数据源时,查询页无法使用。',
+ hint: '集群内 Loki 选「集群服务」即可;跨集群 / 公网需先配 Ingress 域名,再用「URL 直连」。',
managedCluster: '集群 {{name}}',
managedBadge: '平台部署 · 随部署管理',
- add: '+ 手动添加',
+ countLabel: '共 {{count}} 个',
+ create: '新建数据源',
+ createTitle: '新建数据源',
+ editTitle: '编辑数据源',
+ edit: '编辑',
+ cancel: '取消',
+ testing: '测试中…',
+ deleteTitle: '删除数据源',
+ deleteDesc: '删除「{{name}}」后,基于它的查询与授权策略将失效,确定删除吗?',
+ deleteAria: '删除 {{name}}',
+ defaultBadge: '默认',
+ emptyTitle: '还没有数据源',
+ emptyDesc: '新建「集群服务」或「URL 直连」数据源后,即可在查询页检索日志。',
+ typeLabel: '类型',
+ namePlaceholder: 'prod-loki',
nameLabel: '名称',
targetUrl: 'URL 直连',
targetClusterSvc: '集群服务',
@@ -61,16 +75,6 @@ export default {
saveFailed: '保存失败',
remove: '删除',
},
- range: {
- lastMinutes: '最近 {{count}} 分钟',
- lastHours: '最近 {{count}} 小时',
- custom: '自定义时间',
- title: '选择时间范围',
- start: '开始时间',
- end: '结束时间',
- apply: '应用时间',
- recent: '最近使用',
- },
editor: {
aria: 'LogQL 查询语句',
valuesOf: '{{label}} 的值',
@@ -83,7 +87,7 @@ export default {
templates: {
aria: '快捷查询模板',
title: '快捷生成 LogQL',
- hint: '先选 namespace,再选 app,最后选副本 pod;app 候选只来自所选命名空间。',
+ hint: '先选 namespace 缩小范围;选中 app / pod 自动查询。',
namespace: '命名空间',
app: 'App',
appWithKey: 'App({{key}})',
@@ -93,12 +97,10 @@ export default {
pickNsFirst: '先选命名空间可缩小范围',
noPod: '该 app 下无副本',
optional: '可选',
- scopeLogs: '查询该范围日志',
errorLogs: '错误 error',
warnLogs: '告警 warn',
- podLogs: '指定副本日志',
ingressLogs: 'Ingress 访问日志',
- scopeHint: '先选 namespace,再选 app 或 pod,也可在 Label 浏览器选值',
+ scopeHint: '选 app / pod 即自动查询;也可在 Label 浏览器选值',
},
labels: {
browser: 'Label 浏览器',
@@ -113,11 +115,11 @@ export default {
loading: '加载中…',
noValues: '没有匹配值',
useAsValue: '使用“{{value}}”作为值',
- hint: '先选 namespace 可查该命名空间全部副本;再选 app / service_name 可缩小到某个服务(无 app 标签的工作负载用 namespace 即可)。候选来自当前时间范围内已写入 Loki 的日志;授权范围仍由服务端限制。',
+ hint: '先选 namespace,再选 app / service_name 逐步缩小;候选为当前时间范围内的日志。',
},
volume: {
statsLoading: '正在统计整个时间范围的日志量,日志页可继续浏览。',
- statsError: '日志量统计超时或失败;日志页仍可使用。可缩小时间范围后重新查询。',
+ statsError: '日志量统计失败;可缩小时间范围后重试。',
histogramLoading: '统计中…',
histogramEmpty: '暂无日志量数据',
timelineAria: '日志量时间线',
@@ -131,16 +133,10 @@ export default {
title: '日志结果',
summary: '第 {{page}} 页 · 本页 {{count}} 条',
summaryMore: '第 {{page}} 页 · 本页 {{count}} 条 · 还有更多',
- viewAria: '日志展示方式',
- viewRaw: '原始日志',
- viewTable: '表格',
- viewLine: '折线图',
- viewStream: '流图',
- viewPie: '饼图',
loadingPage: '正在加载日志页',
loadingQuery: '正在查询 Loki',
loadingWait: '已等待 {{seconds}} 秒。大范围查询可能需要较长时间。',
- pagingHint: '日志按时间从新到旧翻页;图表展示当前页,顶部时间线展示整个查询范围。',
+ pagingHint: '日志按时间从新到旧翻页;顶部时间线为整个查询范围。',
domainAll: '全部域名',
domainFilter: '域名筛选',
domainPlaceholder: '输入或选择域名',
@@ -160,42 +156,6 @@ export default {
idleHint: '也可以使用 Label 浏览器快速构建查询',
retry: '重新查询',
},
- views: {
- noDomain: '未记录域名',
- otherDomain: '其他域名',
- unknown: '未知',
- untagged: '未标记',
- other: '其他',
- tableLoaded: '当前页已加载 {{count}} 条日志。',
- tableEmpty: '暂无可展示的日志',
- thTime: '时间',
- thNsPod: 'namespace / pod',
- thLevel: '级别',
- thLog: '日志',
- lineByLoaded: '按当前已加载日志统计;更多结果请继续加载。',
- lineByRange: '按查询时间范围统计的日志量,来自 Loki 时间聚合。',
- lineGroupAria: '折线图分组字段',
- lineByDomain: '按域名',
- lineByTotal: '总量',
- lineEmpty: '当前查询没有可用的时间统计',
- lineSeriesTotal: '日志条数',
- streamParsed: '展示 {{count}} 条已解析日志',
- streamByLevel: '按级别展示当前已加载的 {{count}} 条日志',
- streamSuffix: ',基于当前已加载结果。',
- streamGroupAria: '流图分组字段',
- streamByStatus: '按 HTTP 状态段',
- streamEmpty: '暂无可展示的日志流',
- pieByAccess: '按访问字段统计已解析的 {{count}} 条日志',
- pieByLabel: '按标签统计当前已加载的 {{count}} 条日志',
- pieGroupAria: '饼图分组字段',
- pieDomain: '域名(请求 Host)',
- pieStatus: 'HTTP 状态码',
- pieMethod: '请求方法',
- piePath: '请求路径',
- pieUpstream: '上游服务',
- pieLevel: '级别',
- pieEmpty: '暂无可展示的标签分布',
- },
ingress: {
modesAria: 'Ingress 统计方式',
modeTraffic: '接口 PV / UV',
@@ -203,7 +163,7 @@ export default {
modeSlow: '慢请求 Top 10',
modeDetail: '请求明细',
summary:
- '仅统计当前页已加载的 {{loaded}} 条日志,其中 {{parsed}} 条为 ingress-nginx 访问日志。翻页后重新统计;UV 按非空客户端 IP 去重。',
+ '基于已加载的 {{loaded}} 条日志统计',
statPv: 'PV',
statUv: 'UV(IP)',
statErrors: '4xx / 5xx',
@@ -214,9 +174,9 @@ export default {
error4xx: '只看 4xx',
slowThreshold: '慢请求阈值',
seconds: '{{count}} 秒',
- slowHint: '依据 access log 的 request_time 排序;408 / 499 / 504 仅作超时线索,不能单凭状态码断定后端超时。',
+ slowHint: '按 request_time 排序;408 / 499 / 504 为超时线索。',
slowMissing: '{{count}} 条缺少有效耗时。',
- trafficHint: '访问成功率按 2xx / 3xx 请求数 ÷ PV 计算;路径已去掉查询参数。',
+ trafficHint: '成功率 = 2xx / 3xx ÷ PV',
thHost: '请求 Host',
thPath: '接口路径',
thSuccess: '成功率',
@@ -301,18 +261,4 @@ export default {
loading: '加载中…',
noMatch: '无匹配值',
},
- raw: {
- searching: '查询中…',
- count: '{{count}} 条',
- dedupSuffix: '(去重后,原 {{count}} 条)',
- dedup: '去重',
- empty: '没有匹配的日志',
- original: '日志原文',
- labelsTitle: '标签(点击过滤)',
- filterValue: '过滤此值',
- excludeValue: '排除此值',
- fields: '提取字段',
- loadMore: '加载更多',
- loadingMore: '加载中…',
- },
}
diff --git a/frontend/src/i18n/locales/zh/settings.ts b/frontend/src/i18n/locales/zh/settings.ts
index f571738..39ff24b 100644
--- a/frontend/src/i18n/locales/zh/settings.ts
+++ b/frontend/src/i18n/locales/zh/settings.ts
@@ -45,9 +45,9 @@ export default {
cardTitle: '告警通知通道(飞书/Lark)',
create: '新建通道',
// 空态文案按「前段 + 链接 + 后段」拼接(链接指向日志告警页)
- emptyBefore: '尚无通知通道 —— 每个告警群创建一个通道(如「应用告警群」「Nginx 告警群」),在',
+ emptyBefore: '尚无通知通道 —— 每个告警群建一个通道,',
emptyLink: '日志告警',
- emptyAfter: '页把规则关联到对应通道',
+ emptyAfter: '在告警规则页把规则关联到对应通道。',
webhookConfigured: 'Webhook 已配置',
webhookMissing: '未配置',
secretConfigured: ' · 签名已配置',
@@ -82,7 +82,7 @@ export default {
headerHint: '启用后支持 LDAP 登录与批量导入',
errLoad: '加载 LDAP 配置失败',
disabledHint:
- 'LDAP 未启用 —— 打开开关填写目录服务信息(服务器 / Bind DN / Base DN),保存后用户管理页将出现「从 LDAP 导入」',
+ 'LDAP 未启用 —— 开启并填写目录服务信息后,用户管理页将出现「从 LDAP 导入」。',
hostLabel: '服务器地址 *',
portLabel: '端口',
ldapsLabel: 'LDAPS',
@@ -133,7 +133,7 @@ export default {
timezone: '判定时区',
timezoneAria: '主题定时切换时区',
browser: '跟随浏览器(本地)',
- autoHint: '按所选时区,{{start}}:00–{{end}}:00 使用浅色,其余时段深色;顶栏太阳/月亮可随时手动覆盖。',
+ autoHint: '按所选时区 {{start}}:00–{{end}}:00 浅色,其余深色;顶栏可随时手动切换。',
},
prefsCard: {
title: '外观与语言',
diff --git a/frontend/src/i18n/locales/zh/storage.ts b/frontend/src/i18n/locales/zh/storage.ts
index 4be44b8..2c61d6f 100644
--- a/frontend/src/i18n/locales/zh/storage.ts
+++ b/frontend/src/i18n/locales/zh/storage.ts
@@ -8,7 +8,7 @@ export default {
emptyDescription: '添加第一个 Loki 存储后端',
// 删除确认文案(有部署引用时的警告;count 走中文无复数)
deleteWarning:
- '确定要删除「{{name}}」吗?警告:仍有 {{count}} 个部署使用该存储,删除后这些部署的对象存储配置将失效。',
+ '确定删除「{{name}}」吗?仍有 {{count}} 个部署在使用,删除后其对象存储将失效。',
errDelete: '删除存储配置失败',
errSetDefault: '设置默认存储失败',
},
diff --git a/frontend/src/i18n/locales/zh/users.ts b/frontend/src/i18n/locales/zh/users.ts
index c3c69c2..b91f9ae 100644
--- a/frontend/src/i18n/locales/zh/users.ts
+++ b/frontend/src/i18n/locales/zh/users.ts
@@ -67,7 +67,7 @@ export default {
noEmail: '无邮箱',
empty: '目录下没有用户',
importing: '导入中...',
- importCount_other: '导入 {{count}} 个用户',
+ importCount: '导入 {{count}} 个用户',
importFailed: '导入失败',
loadFailed: '加载 LDAP 用户失败',
},
@@ -78,7 +78,7 @@ export default {
clear: '清除选择',
selectAll: '全选',
confirmTitle: '确认批量删除',
- confirmDesc: '确定要删除选中的 {{count}} 个用户吗?受保护的账号(自己/最后一个管理员)将被跳过,此操作不可恢复。',
+ confirmDesc: '删除选中的 {{count}} 个用户?受保护账号会跳过,操作不可恢复。',
skippedWarn: '{{count}} 项被跳过:{{reasons}}',
failed: '批量删除失败',
},
diff --git a/frontend/src/i18n/locales/zh/wizard.ts b/frontend/src/i18n/locales/zh/wizard.ts
index 78cbcc2..1e578ca 100644
--- a/frontend/src/i18n/locales/zh/wizard.ts
+++ b/frontend/src/i18n/locales/zh/wizard.ts
@@ -33,7 +33,7 @@ const wizard = {
ready: '已就绪',
connected: '已接入:{{names}}',
nameSep: '、',
- k8sHint: '通过 kubeconfig 或 ServiceAccount Token 接入集群,创建后自动验证连通性',
+ k8sHint: 'kubeconfig 或 Token 接入,创建后自动验证连通性。',
addCluster: '添加集群',
hostHint: 'SSH 密钥或密码接入主机(用于部署与后续采集器安装)',
addHost: '添加主机',
@@ -45,7 +45,7 @@ const wizard = {
manage: '管理存储',
add: '添加存储',
configure: '配置存储',
- hint: '推荐对象存储(MinIO / RustFS / S3 / OSS):多副本与数据保留更可靠。添加时可用「测试连接」验证凭证,并自动创建不存在的桶;跳过则使用本地磁盘。',
+ hint: '推荐对象存储(MinIO / RustFS / S3 / OSS),更可靠;跳过则使用本地磁盘。',
},
deploy: {
meta: '{{mode}} · 命名空间 {{namespace}} · {{endpoint}}',
diff --git a/frontend/src/pages/alerts/index.tsx b/frontend/src/pages/alerts/index.tsx
index be738ee..26ac0cf 100644
--- a/frontend/src/pages/alerts/index.tsx
+++ b/frontend/src/pages/alerts/index.tsx
@@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useState } from 'react'
import { Link } from 'react-router'
import { BellRing, Plus, Play, Pencil, Trash2 } from 'lucide-react'
import { Button } from '@/components/ui/button'
+import { Checkbox } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input'
import { Switch } from '@/components/ui/switch'
import { Card, CardContent } from '@/components/ui/card'
@@ -380,14 +381,12 @@ const AlertsPage = memo(function AlertsPage() {
const checked = field.value.includes(String(ch.id))
return (