feat(menu): 日志查询/日志分析拆为独立菜单 + 部署菜单改名「组件部署」

按使用反馈调整信息架构:

=== 1. 日志查询、日志分析保持独立菜单(不折叠)===
上一版把两者并进「日志」分组,实际使用中不方便:
  - 日志查询是最高频入口,不该多点一次 tab 才到
  - 日志分析是管理员专用的聚合视图,与查询的心智模型不同
改为两个独立菜单项,/logs 的菜单名保持「日志查询」不变(用户明确要求),
/analysis 保留 adminOnly(仅管理员可见)。

=== 2. /deployments 菜单改名:部署 Loki → 组件部署 ===
命名评估(三个候选):
  组件部署  ✅ 选中:部署对象是基础设施组件(Loki 实例),
             与本环境大量 cex-* 业务服务明确区分。
             运维在侧栏看到「服务部署」第一反应会是"发布业务服务",容易误点。
  服务部署  ✗ 与业务服务语义冲突
  部署 Loki ✗ 以后支持多组件(Fluent Bit / Grafana)就名不副实
文案改动:菜单 menu.deployments、页面标题、组内 tab 全部统一为「组件部署」,
en 同步为 Component Deploy / Component Deploy 页面标题。

=== 3. 顺带修:启动日志每次都打印「首次部署」===
旧实现无条件打印
    log.Printf("首次部署请查看启动日志或 %s/initial-admin-password.txt ...")
于是每次重启日志里都有「首次部署」,排查时极易被误导成
"平台重新初始化了、数据是不是丢了"(本次就因此自查了一轮)。
改为仅当密码文件存在时才提示(admin 改密后该文件会被删除)。

=== 当前菜单结构(8 项)===
  仪表盘 / 部署向导 / 资源接入(集群·主机·存储) / 日志服务(组件部署·日志采集)
  / 日志查询 / 日志分析(admin) / 日志告警 / 系统管理(用户·审计·设置)

=== 实测 ===
  bundle 文案:组件部署1 日志查询2 日志分析2 资源接入1 日志服务1 系统管理1
  启动日志「首次部署」出现次数:0
  CLI self-check:overall=ok(数据库 54.7 KB,CLI 模式读取)
  CLI backup:记录数 88(修复前为 0)、密钥指纹 d714ebda23908331

镜像:lghost/lokistack:latest + v0.1 = aa6313fee5bb
This commit is contained in:
opsx committed 2026-10-28 21:44:15 +00:00
1 parent b2c82da377
commit 1a4c75e28c
6 files changed
+25 -20

No files matched your search

+13 -2
View File
@@ -26,6 +26,12 @@ import (
// version 由构建注入(-ldflags "-X main.version=..."),未注入时为 dev
var version = "2.0.0"
// fileExists 判断文件是否存在(用于"是否首次部署"这类轻量判断)。
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
// runCLI 提供不依赖 Web 的运维命令(备份 CronJob、恢复、自检都走它)。
//
// lokistack backup --output /app/data/backups/xxx.tar.gz
@@ -154,8 +160,13 @@ func main() {
go func() {
log.Printf("lokistack starting on port %s", cfg.ServerPort)
log.Printf("API: http://localhost:%s/api/v1", cfg.ServerPort)
// 初始密码:首次启动日志中的「已生成管理员账号」,或数据卷 initial-admin-password.txt
log.Printf("首次部署请查看启动日志或 %s/initial-admin-password.txt 获取 admin 初始密码", cfg.DataDir)
// 初始密码只在**真正首次部署**时提示:
// 旧实现无条件打印这句话,于是每次重启日志里都出现"首次部署",
// 排查问题时极易被误导成"平台重新初始化了、数据是不是丢了"。
// 判据用密码文件是否存在(admin 改密后该文件会被删除)。
if pwdFile := filepath.Join(cfg.DataDir, "initial-admin-password.txt"); fileExists(pwdFile) {
log.Printf("首次部署:admin 初始密码见 %s(改密后该文件会自动删除)", pwdFile)
}
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("Server failed: %v", err)
}
+1 -2
View File
@@ -5,7 +5,6 @@ export default {
groups: {
resources: 'Resources',
services: 'Log Service',
logs: 'Logs',
system: 'System',
},
dashboard: 'Dashboard',
@@ -13,7 +12,7 @@ export default {
clusters: 'Clusters',
hosts: 'Hosts',
storage: 'Storage',
deployments: 'Deploy Loki',
deployments: 'Component Deploy',
collectors: 'Log Collectors',
logs: 'Log Query',
alerts: 'Alerts',
+1 -1
View File
@@ -1,7 +1,7 @@
// deployments namespace — Loki deployment page copy (page / card / form / retention / logs dialogs)
export default {
page: {
title: 'Deploy Loki',
title: 'Component Deploy',
description: 'Deploy and manage Loki log aggregation services',
create: 'New Deployment',
emptyTitle: 'No deployments',
+1 -2
View File
@@ -5,7 +5,6 @@ export default {
groups: {
resources: '资源接入',
services: '日志服务',
logs: '日志',
system: '系统管理',
},
dashboard: '仪表盘',
@@ -13,7 +12,7 @@ export default {
clusters: '集群管理',
hosts: '主机管理',
storage: '存储配置',
deployments: '部署 Loki',
deployments: '组件部署',
collectors: '日志采集',
logs: '日志查询',
alerts: '日志告警',
+1 -1
View File
@@ -1,7 +1,7 @@
// deployments 命名空间 — Loki 部署页中文文案(页面/卡片/表单/保留配置/日志弹窗)
export default {
page: {
title: '部署 Loki',
title: '组件部署',
description: '部署与管理 Loki 日志聚合服务',
create: '新建部署',
emptyTitle: '暂无部署',
+8 -12
View File
@@ -55,31 +55,27 @@ export const routes: AppRoute[] = [
{
path: '/deployments', component: Deployments, auth: true,
meta: {
// 组内 tab 名用「组件部署」:部署对象是基础设施组件(Loki 实例),
// 与业务侧大量 cex-* 业务服务明确区分,避免误以为这里是发布业务服务。
title: 'menu.deployments', icon: Rocket, order: 4, adminOnly: true,
group: { key: 'services', label: 'menu.groups.services', icon: Rocket, order: 4 },
},
},
{ path: '/collectors', component: Collectors, auth: true, meta: { title: 'menu.collectors', icon: RadioTower, order: 7, adminOnly: true, groupKey: 'services' } },
// ── 日志(查询 / 分析):同一个数据源的不同视角 ──
{
path: '/logs', component: LogsPage, auth: true,
meta: {
title: 'menu.logs', icon: ScrollText, order: 5,
group: { key: 'logs', label: 'menu.groups.logs', icon: ScrollText, order: 5 },
},
},
{ path: '/analysis', component: AnalysisPage, auth: true, meta: { title: 'menu.analysis', icon: BarChart3, order: 9, adminOnly: true, groupKey: 'logs' } },
// ── 日志查询 / 日志分析:高频入口,保持独立菜单项(不折叠)──
{ path: '/logs', component: LogsPage, auth: true, meta: { title: 'menu.logs', icon: ScrollText, order: 5 } },
{ path: '/analysis', component: AnalysisPage, auth: true, meta: { title: 'menu.analysis', icon: BarChart3, order: 6, adminOnly: true } },
// ── 告警:独立入口(要盯的,不能被折叠) ──
{ path: '/alerts', component: AlertsPage, auth: true, meta: { title: 'menu.alerts', icon: BellRing, order: 6 } },
{ path: '/alerts', component: AlertsPage, auth: true, meta: { title: 'menu.alerts', icon: BellRing, order: 7 } },
// ── 系统管理(用户 / 审计 / 设置):低频管理动作 ──
{
path: '/users', component: UsersPage, auth: true,
meta: {
title: 'menu.users', icon: UsersRound, order: 7, adminOnly: true,
group: { key: 'system', label: 'menu.groups.system', icon: Settings, order: 7 },
title: 'menu.users', icon: UsersRound, order: 8, adminOnly: true,
group: { key: 'system', label: 'menu.groups.system', icon: Settings, order: 8 },
},
},
{ path: '/audit', component: AuditPage, auth: true, meta: { title: 'menu.audit', icon: History, order: 13, adminOnly: true, groupKey: 'system' } },