Commit Graph
100 Commits
Author SHA1 Message Date
Logan.Li 738498fea3 feat(k8s): align install.sh with latest opsx-loki version
- cloud auto-detection (ACK/TKE/EKS/CCE/GKE/AKS/K3s/self-hosted) via
  node providerID, used for deployment banner and failure diagnostics
- storage class resolution chain: explicit STORAGE_CLASS > default
  annotation > sole SC; self-hosted clusters without any SC now get a
  zero-dependency static local PV (hostPath DirectoryOrCreate +
  nodeAffinity pin + WaitForFirstConsumer + Retain), LOCAL_STORAGE
  auto/off/force tri-state
- PVC rendered with resolved storageClassName + PVC_SIZE; image
  rendered into deployment via IMAGE env
- rollout failure diagnostics per waiting-reason: ImagePullBackOff
  lists per-cloud registry suggestions, CreateContainerConfigError
  points to secret, PVC Pending suggests per-cloud SC
- colored info/ok/warn/die helpers, /dev/urandom key fallback,
  completion banner with pod/node/ip, port-forward and backup hints
- kubernetes/examples/: alibaba ALB + tencent qcloud (CLB health
  check annotations, NodePort backend) ingress templates, secret
  example moved here (opsx-loki layout)
- README updated with env-var table and local-storage notes
2026-10-26 22:09:33 +08:00
Logan.Li 0b16488029 feat(deploy): single-image docker-compose and kubernetes install.sh
- multi-stage root Dockerfile (opsx-loki pattern): frontend dist +
  go binary + gh-ost in one alpine image, non-root user, HEALTHCHECK,
  entrypoint warning for missing SECRET_KEY; gin now serves the SPA
  from DIST_DIR (asset/db-logos/favicon passthrough, /api returns JSON
  404, SPA fallback to index.html) - one origin, no CORS surface
- docker-compose.yml rewritten: single service, named data volume,
  no-new-privileges + cap_drop ALL, /health healthcheck, resource
  limits, log rotation; SECRET_KEY required (openssl rand -hex 32),
  JWT_SECRET optional (auto-generated and persisted in prod)
- kubernetes/: install.sh one-command deploy (idempotent secret
  reuse, --nodeport/--ingress flags, rollout wait, backup tips) plus
  namespace/secret/pvc/deployment(single replica + Recreate, probes,
  resource limits, non-root)/service/nodeport/ingress manifests and
  README (sqlite single-writer constraints, snapshot backup)
- docs: README quick-start now has 3 deployment paths; ARCHITECTURE
  ch.14 expanded

single-image runtime verified locally (SPA/assets/api/login coexist
on :9002); full image build left to server (docker hub unreachable
from this machine)
2026-10-26 20:33:26 +08:00
Logan.Li 13fb3aceb3 feat(ldap): ad/openldap dual compat and config gating
- multi-round user filters (config filter first, then
  objectClass=inetOrgPerson, then AD sAMAccountName/userPrincipalName
  fallback) applied to login search, user listing and batch import;
  previously pure-AD directories found no users
- attribute fallback chains (uid/sAMAccountName/userPrincipalName,
  cn/displayName, telephoneNumber/mobile) via ldapEntryAttr
- import errors explain likely cause instead of empty result
- AES-encrypted admin password kept (aiops stores plaintext)
- frontend gating per aiops pattern: LDAP account management panel
  hidden with hint until a config is actually saved (was gated on
  unsaved form values); batch-import modal hides to/from-LDAP tabs
  when unconfigured, local CSV always available
2026-10-26 20:08:46 +08:00
Logan.Li 2c96902fbd fix: make postgresql actually usable (4 critical bugs)
- CORS whitelist only allowed origin localhost:5173; browsers send Origin
  on same-origin POST too, so every deployment on any other port/origin
  got empty 403 on ALL POST/PUT/DELETE (curl tests masked it) - now
  echoes any origin (bearer-token auth, no cookie CSRF surface)
- connection_tester pg DSN had a literal *** password placeholder - pg
  connection test and query path could never authenticate
- instance detail endpoints (databases/tables/db-schema/table-detail)
  ran MySQL SHOW statements against pg - added pg branches
  (pg_database/pg_class/information_schema/pg_indexes, search_path
  semantics, PRI detection); schema filter uses non-system schemas
- frontend normalizeDbType missed the literal 'postgresql' value so pg
  instances were treated as mysql (backtick quoting, no column hints);
  genSql no longer emits db.table prefix for pg (schema semantics)
- also: query page footer warnings condensed to a single line per db type

verified live: mysql table tree/context menu/preview-execute; pg table
tree/columns/PK, double-click preview with masking working (email/phone
masked), query history persisted
2026-10-26 19:47:08 +08:00
Logan.Li c8155e2d33 fix(ticket): implicit executor for default-flow tickets
- list is_executor and ExecuteTicket both required an execute-step
  approval record; tickets created without a workflow (default flow)
  had none, so the execute button never appeared and the API returned
  403 for everyone - admin/dba are now implicit executors (approved
  status only, consistent in both list enrichment and execution check)
- status labels: pending/reviewing/approved were all shown as 审核中;
  now 待初审/审批中/待执行 so the ready-to-execute state is visible
- verified end-to-end on test backend: create -> quick review dialog
  with comment -> impact-summary execute confirm -> success, detail
  page stage steps reach 完成 with execute result visible
2026-10-26 19:14:35 +08:00
Logan.Li a4090123ba feat(ticket): stage steps and approval flow conveniences
- TicketStageSteps: status-driven stepper (opsx-sec pattern, active
  derived from ticket status incl. rejected/failed/cancelled/rollback
  terminal states) at top of ticket detail page
- QuickReviewDialog: inline approve/reject with optional comment for
  list rows and detail dialog (reject prompts reason, notes terminal
  semantics); replaces fixed-comment direct calls and alert() usage
- execute now requires impact-summary confirm (instance + database +
  statement count) in both list and detail dialog
- DetailTimeline action keys aligned with backend values (created/
  pending_review/approve/reject/executed/execution_failed) - icons and
  colors were silently falling back before
- create page: removed dead scheduled_at field (backend never accepted
  it), added rollback SQL collection (backend-supported), real priority
  select, approval-flow preview showing bound workflow steps and
  approvers once instance selected
- empty tickets state now embeds create CTA button
- RedisDetailPage split: key detail panel extracted to feature
  component (996 -> 658 lines after formatter reflow; panel 377 lines)
2026-10-26 19:06:09 +08:00
Logan.Li f6d636fa44 feat(query): sql workspace conveniences per opsxdb patterns
- generic ContextMenu component (viewport flip, esc/outside close)
- SchemaSidebar table right-click menu: preview data, generate
  SELECT/INSERT/UPDATE/DELETE templates with pk-aware WHERE, copy table
  name; double-click table runs preview SELECT; column right-click
  copy/insert; dialect-aware quoting; preview SELECT carries no LIMIT
- SqlEditor selection-first execution (Mod-Enter runs selection else
  statement at cursor via quote/comment-aware splitter); pagination
  replays last executed statement
- query history persisted server-side: drawer fetches query-histories
  with keyword/mine/favorites filters, star toggle (new PUT favorite +
  mine filter endpoints), insert and insert-and-run
- custom templates in localStorage alongside built-ins
- unit tests: genSql + statement splitter (28 tests green)
2026-10-26 18:53:02 +08:00
Logan.Li ff539b47e0 feat(redis): shared key browser with grouped tree + cursor pagination
New src/features/redis/keyBrowser/ shared by RedisDetailPage keys tab and
SchemaSidebar redis branch (both previously flat one-shot lists):
- keyTree: ':'-separated folder tree with recursive key counts, numeric
  sort, exact-hit pinned at root, local key removal (no full refetch),
  type color dots, readable TTL (45s/5m30s/2d5h)
- useRedisKeyBrowser: cursor state machine + request-sequence guard +
  Map merge on load-more; setter-synced args (Enter right after typing
  no longer races stale render), auto-search on db/instance change
- RedisKeyBrowser: enter-to-scan search bar (SCAN has cost - no debounce,
  opsxdb-style) with clear button, effective type filter, load-more
  button with cursor hint, '已全部加载' end state
- useRedisDbs: real db list from /redis/:id/dbs (cluster -> DB0 banner)
- RedisDetailPage: hash row edits now use field-level HSET/HDEL endpoint
  (preserves other fields + TTL); delete/add update tree locally; CLI
  output renders arrays/objects/errors properly
- SchemaSidebar: redis branch swaps to shared browser (compact mode,
  inline detail preview + insert-command preserved), auto-switches to
  Keys tab for redis instances
- vite dev proxy target overridable via API_PROXY_TARGET (local testing)

Browser-verified: 200/page with load-more (200->400->600), exact hit
badge, keyword auto-expand, key detail panel, queries sidebar
2026-10-26 18:39:38 +08:00
Logan.Li 6604fdf48e feat(backend): redis key scan service - cursor pagination + cluster + CLI fix
Modeled on opsxdb's redis scan design:
- opaque base64 scan cursor {pattern,db,type,nodes,index,cursor}; server
  validates search conditions match, rejects stale cursors (400)
- soft page cap 200 keys (whole scan batches returned, no key loss),
  max 20 SCAN calls per page; next_cursor until all shards exhausted
- pattern rule: no glob chars -> *kw* contains match; non-glob input
  also probed with TYPE for exact hit (returned as exact, slot-routed
  so cluster/NAT safe)
- pipeline batch TYPE/TTL replaces per-key serial N+1; type filter now
  effective server-side
- cluster: per-master direct SCAN merged across shards (MasterAddrs on
  wrapper), DB0-only, MOVED errors hint at switching deploy mode;
  SlowLog/ClientList aggregate across masters (were cluster-broken)
- GET /redis/:id/dbs (0-15, cluster -> [0])
- POST /redis/:id/keys/:key/field: hash row-level HSET/HDEL (no whole-
  key rewrite)
- RedisExecuteCommand fixed (was always-403): accepts {db, command}
  full-string, quote-aware tokenizer, whitelist on first word, expanded
  read-only set
- RedisUpdateKey preserves previous TTL unless explicitly set/cleared
  (was silently dropping TTL); string type skips the DEL

Verified live against local redis: 200/page no overlap across pages,
cursor 400 on condition change, exact hit, type filter, hash field
edit round-trip, CLI DBSIZE/HGET ok, SET rejected
2026-10-26 18:27:11 +08:00
Logan.Li 6945c53879 fix(frontend): eliminate boot race between role restore and route guard
Root cause (pre-existing): user state initialized with default role
'developer' while JWT role restoration happened via render-phase setState
~1 render later; first guard pass evaluated tickets/workflow against the
developer writable-datasource gate and bounced admins to dashboard on
direct load.

Fix: initialize user state lazily from the JWT in one pass
(restoreUserFromToken) - first render already carries the correct role.
Verified in browser: direct loads of /tickets and /workflow stay put;
URL query state survives refresh; expired session redirects to
/login?redirect=<path> and login returns to the original page.
2026-10-26 18:06:22 +08:00
Logan.Li d867c276d4 chore(frontend): engineering baseline per guide ch.8
- toolchain: vitest+jsdom (15 tests green: permission pure functions
  exhaustive, storage migration), prettier (printWidth 120 to fit the
  dense existing style + 700-line page budget), commitlint conventional
- npm scripts: typecheck / format / test / lint:fix; build fingerprint
  __APP_VERSION__ (version+git hash+build time) shown in Settings > about
- git hooks via core.hooksPath=frontend/.husky: pre-commit lint-staged
  (prettier + eslint --fix best-effort), commit-msg commitlint
- permission pure functions extracted to lib/permissions.ts (single
  source consumed by useAuth/useLogin); AuditLogsPage filters on URL
- backend: resp package unit tests; health version constant aligned
  with frontend package.json
2026-10-26 17:58:59 +08:00
Logan.Li ac498c7ba2 refactor(frontend): split 7 oversized pages into feature co-location
Per guide ch.7 page split pattern (skeleton orchestrates, private
components live in features/<domain>/):
- InstancePage 1716->328, UsersPage 1309->240, TicketsPage 1076->195,
  TicketDetailPage 911->287, QueriesPage 883->479, LdapConfigPage 860->393,
  WorkflowPage 852->194
- new feature modules: datasource/ rbac/ ticket/ query/ system/ldap/
  governance/workflow/ (components + hooks + types + utils)
- stable keys replace index keys in dynamic lists; polling intervals
  and toast call sites preserved 1:1 (verified by agents)
- filter/pagination state moved to URL query via new useQueryState hook
  (Instance/Users/Tickets/AuditLogs pages): refresh/share/back-button
  restore state; composite updates applied atomically
- permission pure functions extracted to lib/permissions.ts (used by
  useAuth + useLogin); page-size audit: 0 pages over 700-line budget
2026-10-26 17:54:15 +08:00
Logan.Li ac563d1c5e refactor(frontend): unify theme tokens to single --dg-* source
- remove shadcn HSL dual-track vars (523->416->~300 lines index.css);
  tailwind semantic colors (border/background/card/primary/destructive/
  popover/muted/accent) now bridge directly to var(--dg-*) tokens
- drop dead darkMode:['class'] config and inert dark: variants in kept
  ui components; theme switching is data-theme based (4 themes intact)
- first-frame inline theme script in index.html (reads namespaced key
  with legacy fallback, resolves system, sets color-scheme) - no flash
- consolidate duplicated db-type brand colors into lib/constants.ts
  single source (dbTypeColorMap + dbTypeBrandColorMap, with pg/mongodb
  aliases); instance health stroke now uses theme tokens
- verified via browser: dark #0d1117 / light #f5f6f8 both resolve,
  tokens cascade correctly
2026-10-26 17:38:27 +08:00
Logan.Li a213d08e31 chore(frontend): purge dead code per guide red line
- delete 4 dead pages (~2300 lines): Home, ConfigPlatformPage,
  DataDictionaryPage, NotificationsPage (kept the live NotificationPage)
- delete 52 unused shadcn ui components (keep button/card/dialog in use;
  re-generate via shadcn CLI when needed)
- delete App.css, SkeletonCard, empty shared/ and features engine dirs
- remove dead theme blocks (midnight-purple / orange-vitality) from index.css
- uninstall ~40 dead deps (echarts, sonner, next-themes, zod,
  react-hook-form, unused radix packages, cmdk, vaul, ...)
- fix DEVELOPMENT.md drift: mock layer section rewritten to real API layer,
  permission docs now point to menu.ts single source
2026-10-26 17:23:24 +08:00
Logan.Li 16f1f7d65f feat(backend): unified response helpers, refresh token, security hardening
- new resp package (OK/Page/Fail/BadRequest/.../InternalErr): unified error
  envelope {detail, code?}, sanitized 500s (full error logged server-side,
  generic message to client - stops DB error leakage), pagination envelope
  {items,total,page,page_size}; migrate 200+ inline c.JSON error sites
- refresh token: 7d rotation tokens (SHA-256 hashed at rest), public
  POST /auth/refresh with single-use rotation, POST /auth/logout revokes
  all user refresh tokens (endpoint previously missing - frontend 404)
- security: gh-ost command line password masked in task status payload;
  Instance.MarshalJSON guarantees encrypted passwords never leave the API
  (removes reliance on per-handler manual masking); production (DEBUG=false)
  with default JWT secret now auto-generates and persists a random secret
- safe.Go recover wrapper for background goroutines (instance probe,
  gh-ost async)
- delete dead service layer (zero callers)
- fix pre-existing go vet unkeyed bson.E literals
2026-10-26 17:21:00 +08:00
Logan.Li d5b8b8116c fix(frontend): harden auth request layer per web guide
- fix double-unwrap bug in useLogin prefs sync (theme sync silently broken)
- request layer: 401 single-flight refresh queue + debounced single redirect
  with return-url, cancel-aware silent passthrough, skipErrorHandler opt-out,
  typed blob download (replace bare fetch export in QueriesPage)
- useFetchList: AbortController + version guard + error state (three states)
- ErrorBoundary with chunk-load auto recovery (reload once)
- permission single source: derive route guard from menu constants, drop
  hand-maintained routePermissionMap; TicketDetailPage uses unified
  hasActionPermission instead of inline role string comparison
- namespaced localStorage keys (opsxsql.*) with read-old-write-new migration
- fix pre-existing tsc errors (InstancePage/WorkflowPage/QueriesPage/
  PlatformConfigPage/RedisDetailPage) - typecheck now passes clean
2026-10-26 17:12:29 +08:00
Logan.Li f5cf3f4440 fix: prevent query execute event state leak 2026-07-07 17:52:44 +08:00
Logan.Li 617c15dbfe feat: harden query read-only workflow 2026-07-07 17:20:44 +08:00
Logan.Li 58bbc394e9 feat: enhance redis and production IA 2026-07-07 10:39:33 +08:00
Logan 644981eef4 feat: improve datasource query audit workflows 2026-07-06 23:01:04 +08:00
logan 74748e4914 fix: 审批流程三个bug修复
1. 点通过不再重复创建审批记录(后端无NULL记录时返回400而非自动创建)
2. 非提交人不再显示撤销按钮(列表页增加applicant_id校验)
3. 已审批工单不再显示通过/拒绝按钮(is_approver只计算pending记录)
4. 前端审批失败时弹出错误提示而非静默忽略
2026-06-03 17:17:12 +08:00
logan 3a6dd99633 feat: 审核规则驱动SQL检查 + db_type过滤 + Redis只读拦截 + 配置文档
1. 审核规则改为从audit_rules表动态匹配(去硬编码)
   - CreateTicket提交时查audit_rules WHERE db_type=? AND is_enabled=true
   - 正则匹配SQL,value=reject拦截,warn/review放行
   - UPDATE/DELETE无WHERE: Go RE2不支持(?!...)负向前瞻
     → 用value=where_check特殊标记+strings.Contains WHERE检测
   - 修复UPDATE/DELETE无WHERE正则(Go兼容)

2. ListAuditRules按db_type过滤
   - ghost.go: 添加c.Query('db_type') WHERE过滤
   - MySQL不显示KEYS规则,Redis不显示DROP规则

3. Redis只读命令拦截(工单提交)
   - 新增Redis只读命令白名单: GET/HGET/MGET/HGETALL/KEYS/SCAN等28个
   - 只读命令走工单→直接拦截,引导用户用查询功能

4. 补充audit_rules规则
   - Redis新增7条: DEBUG/SHUTDOWN/SCRIPT/SAVE/BGSAVE/BGREWRITEAOF/SLAVEOF/CLUSTER
   - MySQL新增1条: DROP SCHEMA
   - 总计34条规则(MySQL12/Redis11/PG7/MongoDB4)

5. docs/CONFIGURATION.md 配置系统文档
   - 三套配置体系: system_settings/audit_rules/ldap_configs
   - 每项配置: key/默认值/作用/代码引用位置
   - 未引用配置标注: executor_batch_size/executor_backup/query_max_rows_examined(待实现)
   - LDAP冗余配置: system_settings中7项ldap_*无代码引用(LDAP用独立表)

验证: 5/5审批流通过, 36/36安全测试通过, 27/27审核规则匹配正确
2026-06-03 03:17:22 +08:00
logan 8fbcb8647d feat: SQL安全防护体系 — 危险SQL黑名单 + 事务回滚 + LIMIT修复
🔴 P0 安全漏洞修复:
- MySQL: 黑名单拦截 DROP DATABASE/DROP SCHEMA
- MySQL: 拦截无WHERE的UPDATE/DELETE(全表操作)
- MySQL: 多语句中含危险SQL也会被检测
- Redis: 拦截 FLUSHALL/FLUSHDB/CONFIG/DEBUG/SHUTDOWN/SCRIPT/SAVE/BGSAVE/KEYS/CLUSTER/REPLICAOF

🔄 事务支持:
- MySQL多语句执行包裹在事务中
- 任一SQL失败自动回滚全部已执行语句
- 验证通过: INSERT成功+UNIQUE冲突=全部回滚

🔧 Bug修复:
- query.go: LIMIT只追加SELECT语句(SHOW/CREATE等不再追加LIMIT报错)
- SHOW VARIABLES/STATUS 恢复正常

📊 测试验证:
- 29/29 安全拦截测试全部通过
- MySQL 8项危险操作全部拦截
- Redis 11项危险命令全部拦截
- 10项正常SQL全部放行
- 事务回滚验证通过
- 类型错误/参数错误正确报告
2026-06-03 02:49:07 +08:00
logan 8ceb249274 fix: MySQL DDL+DML同批EXPLAIN预检bug + Redis集群MOVED重定向 + 清晰错误提示
MySQL修复:
- 批次含DDL时跳过整个EXPLAIN预检(避免CREATE TABLE未执行时INSERT的EXPLAIN失败)
- 纯DML批次仍正常做EXPLAIN预检

Redis集群修复:
- 单节点客户端遇到MOVED时自动映射外部IP+端口重试
- 重试失败给出清晰提示(Docker端口未暴露)
- 新增 isClusterInstance/parseMovedTarget 辅助函数

测试验证通过:
- MySQL 5条DDL+DML ✅ (建表+INSERT+UPDATE+加索引)
- MySQL 纯DML+EXPLAIN预检 ✅
- MySQL dba(logan)执行 ✅
- Redis单机 SET写入 ✅
- Redis集群 ⚠️ Docker内部端口未暴露(基础设施限制)
2026-06-03 02:40:15 +08:00
logan 2984f11181 refactor: tests目录精简重构 + 脏数据清理脚本
- 删除16个旧Python测试文件(970行→400行)
- 重写conftest.py适配真实种子用户(admin/test123/test234/testtest/logan)
- 5个精简测试文件覆盖核心API:
  - test_auth.py: 登录/鉴权/种子用户验证 (6 tests)
  - test_instances.py: 实例列表/详情/连接测试 (6 tests)
  - test_tickets.py: 工单CRUD/只读SQL拦截/auditor权限 (7 tests)
  - test_workflow.py: E2E完整审批流/拒绝/撤销 (3 tests)
  - test_permissions.py: 角色权限/执行权限/workflow权限 (6 tests)
- 新增 cleanup_test_data.py 清理测试脏数据(支持--dry-run)
- 全量29测试3.27s通过
2026-06-03 02:24:40 +08:00
logan bec2cafec2 feat: 执行结果结构化-每条SQL记录status/affected_rows/duration_ms + 去掉工单详情优先级字段
后端:
- 新增 SqlExecItem/SqlExecResult 结构体
- MySQL/Redis/gh-ost 三条执行路径全部改为 JSON 结构化结果
- 每条 SQL 记录完整语句、状态、影响行数、耗时(ms)、错误信息
- 总耗时/开始结束时间一并记录

前端:
- ExecuteResult 接口匹配后端 SqlExecResult
- 表格展示每条 SQL 执行结果(序号/SQL/状态/影响行数/耗时/错误)
- 汇总卡片: 状态/总耗时/SQL数量
- 去掉工单详情中的优先级和变更原因字段
- 保留 plain text fallback 兼容旧数据

E2E验证: INSERT+UPDATE+ALTER 三语句全部成功, 结构化结果正确
2026-06-03 02:15:37 +08:00
logan 1364c737ef fix: 工单列表权限过滤-developer/auditor也能看到待审工单
- developer之前只能看applicant_id=自己的工单,导致审批人看不到待审工单
- 改为admin看全部,其他角色(包括developer/dba/auditor)都能看到自己提交+自己作为审批人的工单
- E2E全流程验证通过: testtest提交→test123初审→test234复审→admin执行→success
2026-06-03 02:06:20 +08:00
logan bd8100bfe0 fix: 撤销工单支持approved状态 + DDL跳过EXPLAIN预检 + 审批菜单仅admin/dba + 审批状态流转修复 + 权限组实例绑定修复 2026-06-03 01:53:21 +08:00
logan b1a3d74661 feat: 角色权限体系改造 — developer可审批, auditor纯只读
角色权限矩阵:
- admin: 全部权限
- dba: 数据源管理+工单全流程+审批+执行
- developer: 查询+提交工单+审批(不能执行)
- auditor: 只读(审计日志+审核规则+审批流程查看)

后端改动:
- ticket.go: 修复GetCurrentUser返回值顺序bug(userID,username,role)
- ticket.go: CreateTicket拦截auditor提交工单
- ticket.go: ApproveTicket允许admin/dba/developer
- ticket.go: ExecuteTicket仅允许admin/dba
- router.go: query执行限制admin/dba/developer
- router.go: workflow写操作限制admin/dba
- router.go: audit-rules写操作限制admin/dba

前端改动:
- menu.ts: tickets去掉auditor, workflow加developer+auditor, audit-logs加auditor
- useAuth.tsx: routePermissionMap和actionPermissionMap同步更新
- TicketDetailPage: canApprove加developer角色

DB迁移: test123/test234从auditor→developer
2026-06-03 01:19:24 +08:00
logan 97fd4ff069 fix: 数据变更工单拦截只读SQL — 前端提交/检测+后端创建三层拦截SELECT/SHOW/DESC/EXPLAIN 2026-06-03 00:48:09 +08:00
logan 70da8a8a8b fix: 工单执行按钮仅在审核通过(approved)状态显示,审核中不再显示执行按钮 2026-06-03 00:38:12 +08:00
logan bbf9522710 fix: 消息推送添加渠道placeholder改为数据变更消息机器人 2026-06-01 21:33:33 +08:00
logan 7564d92c69 fix: NotificationPage 添加渠道弹框 X 图标未 import 导致报错 2026-06-01 21:11:36 +08:00
logan 132b2db2d2 fix: 平台配置页面修复 - 隐藏LDAP重复分组、敏感字段列表textarea多行展示、分组排序优化
- 过滤ldap分组(有独立LDAP页面不重复展示)
- 敏感字段列表从单行input改为textarea每行一个字段名(key修正data_masking_sensitive_fields)
- 添加GROUP_ORDER固定展示顺序:查询控制→安全策略→数据脱敏→日志清理→执行器→Ghost/OSC
- 所有分组输入框均有默认值,cleanup组retention天数输入框正常显示
2026-06-01 21:07:44 +08:00
logan 9c457eb599 chore: Dockerfile gh-ost 版本更新 v1.1.9(macOS本地验证通过)
- gh-ost v1.1.9 真实执行验证通过(macOS arm64 + 远程MySQL)
- ALTER TABLE ADD COLUMN → gh-ost OK (6行表,~8秒完成)
- ALTER TABLE ADD INDEX → gh-ost OK
- ghost_enabled 默认 false,本地开发: ~/bin/gh-ost
2026-06-01 01:55:29 +08:00
logan b2b689f791 feat: 工单执行集成gh-ost通道 + Dockerfile安装gh-ost + 密码解密修复
- ExecuteTicket: 检测 ghost_enabled + ALTER TABLE → 走 gh-ost 同步执行
- parseAlterTable: 解析 ALTER TABLE 提取表名和 alter 子句(支持反引号/db.table)
- buildGhOstTask: 修复密码传递(加密→解密后传给 gh-ost 命令行)
- Dockerfile: 运行阶段下载 gh-ost v1.1.6 Linux amd64 二进制
- ghost_enabled=false 默认关闭,工单流程正常走普通通道
- 端到端验证: ALTER TABLE+ghost_enabled=true → gh-ost; INSERT/关闭 → 普通
2026-06-01 01:47:08 +08:00
logan bc2092a980 feat: 平台配置全面生效 — 配置策略接入实际逻辑
- query组: ExecuteQuery读取query_limit_max/query_timeout/query_dangerous_pattern
  - 查询超时通过context.WithTimeout生效,db.QueryContext/QueryRowContext
  - 危险模式检测拦截无WHERE的DELETE/UPDATE/DROP/TRUNCATE
  - LIMIT上限从settings读取,不再硬编码1000

- security组: Login读取login_max_attempts/login_lockout_minutes
  - 新增User字段: failed_login_attempts + locked_until
  - 登录失败达到阈值自动锁定,成功时清除计数
  - JWT Token过期时间读取session_timeout_hours设置

- executor组: ExecuteTicket读取executor_timeout/executor_dry_run
  - 执行超时通过context.WithTimeout控制
  - 开启dry_run时先EXPLAIN预检查SQL语法
  - db.ExecContext替代db.Exec

- cleanup组: SettingsCleanupPreview/Run从占位改为真实实现
  - 预览统计4类数据(工单/查询历史/慢日志/审计日志)待清理数量
  - 执行清理按retention_days配置删除过期数据

- ghost组: 13项gh-ost配置加入seedDefaultSettings
  - enabled/path/mode/osc_priority/env/cloud/trigger/chunk/load/lag等
  - 已被ghost.go中getGhostConfig等函数读取

- 前端: PlatformConfigPage新增Ghost/OSC分组显示
2026-06-01 01:00:23 +08:00
logan 8af868b3ca fix: 数据源编辑密码保留 + Redis ACL 认证支持
后端:
- UpdateInstance: 空密码和'******'都不更新密码字段,防止编辑后丢失密码
- testRedis/getRedisClient/getRedisMetrics: 增加 Username 参数支持 Redis 6.0+ ACL 认证
- username 为 'default' 或空时走传统密码认证模式

前端:
- EditInstanceDialog: Redis 用户名字段提示'6.0+ ACL 可选',密码 placeholder 改为'不修改请留空'
- CreateInstanceForm: Redis 类型也显示用户名输入框(可选),创建/测试连接时 Redis username 为空则不传
- Redis 提示文案从'无需用户名'改为'6.0+ ACL 支持用户名+密码认证'
2026-05-31 23:55:18 +08:00
logan bfb64d4dce fix: WorkflowEditor 下拉过滤禁用用户 — getEligibleUsers 增加 is_active 条件
- 审核阶段: 只显示 is_active=true 且角色为 admin/dba/auditor 的用户
- 执行阶段: 只显示 is_active=true 且角色为 admin/dba 的用户
- 禁用用户不再出现在审批流程编辑器下拉列表中
2026-05-31 23:35:58 +08:00
logan 1f9d373c08 fix: 审批流程编辑器按步骤类型过滤可选用户
- 审核阶段: 只显示 admin/superadmin/dba/auditor 角色用户
- 执行阶段: 只显示 admin/superadmin/dba 角色用户
- 全选按钮也基于过滤后的用户列表
- UserDropdown 改用 fixed 定位避免 overflow 裁剪
2026-05-31 23:22:08 +08:00
logan aaa7666d66 fix: 统一所有弹框组件 padding + 主题风格
- ModalOverlay: 内容容器加 p-6 + border + shadow-xl
- alert-dialog: 统一主题变量 bg-[var(--dg-bg-secondary)] + rounded-xl
- sheet: SheetContent 加 p-6,移除 Header/Footer 重复 p-4
- drawer: DrawerContent 加 p-6,移除 Header/Footer 重复 p-4
- 所有弹框统一: p-6 padding + dg-border + shadow-xl + z-[101]
2026-05-31 23:08:08 +08:00
logan 363753653e fix: DialogContent 添加默认 padding p-6,修复确认弹框布局压缩问题
- dialog.tsx: DialogContent 基础样式加 p-6 (24px padding)
- ConfirmDialog.tsx: 按钮区域间距 pt-2 → pt-4
- 修复所有使用 Radix Dialog 的弹框内容紧贴边缘的问题
2026-05-31 23:05:51 +08:00
logan dce6b8cc28 refactor: LdapConfigPage 删除确认弹框统一使用 ConfirmDialog 公共组件
- 移除 LdapConfigPage 自定义 ModalOverlay 确认弹框
- 替换为 ConfirmDialog(variant=danger) 保持风格统一
- 清理未使用的 AlertTriangle import
- 全站确认弹框现已全部统一使用 ConfirmDialog 组件
2026-05-31 22:58:10 +08:00
logan bef2f98f28 feat: 审批/执行角色权限校验 + LDAP用户禁止重置密码
- ticket.go: ApproveTicket 前置角色检查(admin/dba/auditor),ExecuteTicket 前置角色检查(admin/dba)
- ticket.go: 创建工单时自动从 instance.workflow_id 读取关联审批流程
- UsersPage.tsx: LDAP 用户重置密码按钮置灰(disabled+opacity-30+提示文案)
- 权限模型: 审核=管理员/DBA/审核员, 执行=管理员/DBA, 提交=所有角色
2026-05-31 22:20:24 +08:00
logan b4c982d565 feat: 工单执行人直接执行(自动通过) + 审批时间线 + 执行结果展示
后端:
- 创建工单时检测是否有审核步骤,无审核步骤直接设为 reviewing
- ExecuteTicket 允许 reviewing 状态,自动通过 execute 审批记录再执行
- 验证执行人权限(非执行人返回 403)
- 列表 API 返回 has_audit_step/is_executor/is_approver 元信息
- 详情 API 返回 approvals 带 approver_name/actual_approver_name

前端:
- 按钮权限精确化:通过/拒绝只对审核人显示,执行只对执行人显示
- 详情弹框加载完整审批数据,展示操作时间线
- 时间线:提交人→每个步骤的指派人+实际操作人+操作时间+备注
- 执行结果文本格式 fallback 显示
- 失败工单显示失败原因
2026-05-31 21:58:52 +08:00
logan cdb52aa4a9 feat: 工单审批流程支持 workflow 指定用户审批 + Redis 命令执行
1. 工单创建时读取 workflow_steps 的 approver_ids 创建审批记录
   - 有指定用户:为每个用户创建审批记录(任一通过即可)
   - 无指定用户:按 approver_role 角色匹配 fallback
   - 无 workflow:默认 admin 审批
2. Redis 工单执行:复用 getRedisClient + parseCommandParts 执行写命令
   - 支持 SET/DEL/HSET 等所有写操作
   - 解析 db0/db1 格式的目标库
   - 返回 [OK] 命令 → 结果
2026-05-31 21:40:30 +08:00
logan c5270f82c1 fix: 批量删除用户改用 ConfirmDialog 替代浏览器原生 confirm()
- handleBatchAction 删除分支改为 setDeleteConfirm 弹 ConfirmDialog
- 确认后执行删除,取消则关闭弹框
2026-05-31 14:34:21 +08:00
logan 6a53eb8bdf fix: Redis sidebar点击key直接替换编辑器内容而非追加拼凑
- Redis类型: 点击sidebar key直接 setSql(text) 替换,避免多条命令堆叠
- SQL类型(MySQL/PG): 保持追加行为,用空格连接
- 修复 \n 转义字符问题(双反斜杠→单反斜杠)
2026-05-31 02:36:01 +08:00
logan 24c633d9f0 feat: ZRANGE WITHSCORES JSON自动解析为结构化表格 + Redis审计规则 + 前端安全检查
- ZRANGE WITHSCORES 自动检测JSON member,展开为 open/close/high/low/volume 等独立列
- Redis 审计: 只读命令安全,写命令warning,FLUSHALL等危险命令error
- TicketCreatePage: auditResult.findings 添加 undefined 安全检查
- 审计API支持 instance_id 自动解析 db_type
2026-05-31 02:07:10 +08:00
logan 9c5cb04cfa fix: Redis集群查询+metrics修复 — 单节点连接替代ClusterClient
- crypto.go: decryptPassword 自动处理 enc: 前缀,避免调用方遗漏
- redis.go: getRedisClient 统一使用 redis.NewClient 单节点连接
  ClusterClient 拓扑发现(CLUSTER SLOTS)在Docker内网IP不可达时超时
  redisClientWrapper 全部方法改为使用 Client (不再走 ClusterClient)
  ScanAllKeys 简化为单节点 SCAN
- connection_tester.go: getRedisMetrics 统一单节点连接采集metrics
  删除 isCluster 分支的 ClusterClient 代码,避免5秒超时
2026-05-31 01:30:10 +08:00
logan e9a700b9d9 fix: Redis 查询格式修复
- rows nil → 空数组: rowsOrDefault() 确保 HGETALL/LRANGE 空集合返回 [] 而非 null
- 扩展只读白名单: PING/CONFIG/CLIENT/SLOWLOG/CLUSTER/MEMORY/OBJECT/DEBUG 等
- 前端 sortedResult: Array.isArray() 检查防止 raw_text 模式报 not iterable
2026-05-31 00:34:38 +08:00
logan e8fd5f6b63 fix: LDAP导入用户 auth_source 修复
- BatchImportLdapUsers: 设置 AuthSource='ldap' + HashedPassword='-' + IsActive=true
- 修正已有 zhangsan/lisi/wangwu 用户 auth_source 从 local 改为 ldap
2026-05-31 00:18:43 +08:00
logan 31db229d70 feat: MySQL/PG 实时指标采集 + 版本检测修复 + 密码加密存储
- 新增 getMySQLMetrics(): SHOW GLOBAL STATUS 采集连接数/QPS/延迟/运行时间
- 新增 getPostgresMetrics(): pg_stat_activity 采集活跃连接+运行时间
- 修复 extractVersion(): 支持 Redis 'version: 7.4.9, mode: standalone' 格式(逗号截断)
- CreateInstance/UpdateInstance: 创建/更新时自动加密密码(enc: 前缀)
- InstanceMetrics handler: MySQL/PG 分别调用专属 metrics 函数
2026-05-31 00:15:18 +08:00
logan 433e7e2909 feat: ARDM风格查询页优化 — 可拖拽Sidebar + Redis差异化结果展示 + KeyHeader\n\n1. Sidebar可拖拽宽度(200-600px, localStorage持久化)\n2. Redis raw_text展示加ARDM KeyHeader: key名+类型标签+TTL+格式标签+复制按钮\n3. HGETALL结果用field/value紧凑双列展示替代通用表格\n4. 后端raw_text模式自动查询key TYPE和TTL返回raw_type/raw_ttl 2026-05-30 18:20:22 +08:00
logan 4e6f9eb8fd fix: Redis集群SCAN遍历所有master节点 + 查询结果布局调整\n\n1. ScanAllKeys(): 集群模式用ForEachMaster遍历所有master节点SCAN合并去重\n2. RedisScanKeys/KEYS命令均改用ScanAllKeys,确保集群不遗漏key\n3. QueriesPage布局: sidebar独立左侧,查询结果只在编辑器下方不被sidebar占据宽度 2026-05-30 15:28:38 +08:00
logan 430a667455 fix: Redis命令解析支持引号参数(parseCommandParts替代strings.Fields)\n\nstrings.Fields()会将引号当作参数的一部分,导致HGET带引号查询失败\n新增parseCommandParts()函数支持双引号和单引号包裹的参数 2026-05-30 14:47:21 +08:00
logan c51f619a7d feat: 实现LDAP创建OU和用户(LDAP Add)+弹框风格统一 2026-05-30 10:24:29 +08:00
logan 7b5f95e702 fix: LDAP批量导入用户auth_source设为ldap而非默认local 2026-05-30 02:34:29 +08:00
logan 0afc9947fb fix: 查询结果固定布局 - 编辑器/sidebar不被结果挤走 + 结果区可折叠 2026-05-30 02:16:34 +08:00
logan 471221fc47 style: Redis查询结果展示优化 — 列宽加大/字体12px/raw区500px 2026-05-30 01:56:17 +08:00
logan c18fc9bd70 feat: Redis cluster UI - SchemaSidebar 集群db0锁定 + InstanceItem cluster_mode 字段 2026-05-30 01:51:48 +08:00
logan 3af65f2350 feat: Redis cluster support + version auto-detect + metrics API 2026-05-30 01:44:58 +08:00
logan d66ce3d5c9 docs: 添加 README.md 项目文档 2026-05-29 23:26:11 +08:00
logan 5212aaac54 chore: 清理残留空文件 + 备份seed前DB 2026-05-29 23:19:43 +08:00
logan 889cce140b refactor: 弹框架构重构 + 审核规则seed API + LDAP默认配置 + 全量初始数据
弹框架构:
- Layout header/sidebar z-[200] 隔离弹框层,弹框不再遮挡面包屑
- dialog.tsx 简化: 去掉 border/backdrop-blur,统一暗色主题变量
- ModalOverlay z-[100] 对齐 Radix Dialog overlay 层级
- EditInstanceDialog 同步 z-index 修复
- 修复 InstanceGroupPage/InstancePage/LdapConfigPage 缺失 import
- 修复 InstanceGroupPage 缺失 X icon import
- RedisDetailPage ModalOverlay 迁移为 FormDialog

审核规则:
- POST /audit-rules/seed/:dbType 初始化默认规则 (mysql 11/pg 7/redis 4/mongo 4)
- POST /audit-rules/:id/toggle 开关规则
- PUT /audit-rules/:id 编辑规则
- seed.go 启动时自动创建 26 条默认审核规则

LDAP 默认配置:
- seed.go 自动写入 9 条 LDAP 配置 (8.217.205.92:389, dc=opsx,dc=vip)
- 全新 DB 启动即就位,无需手动配置
2026-05-29 22:48:45 +08:00
logan 47431f127c fix: DB_PATH 从 backend-python/ 改为 backend/sqlite3.db
- .env: DB_PATH=../backend/sqlite3.db
- config.go default: ../backend/sqlite3.db
- 删除根目录和 backend/ 下 0 字节残留空 db 文件
- 全新初始化验证: 4用户 + 1审批流程 + 4登录均通过
2026-05-29 22:04:21 +08:00
logan ad12f30355 feat: 添加 seed.go 初始化文件 — 默认用户+审批流程+系统设置
- seedDefaultUsers: 4个默认用户(admin/dba/auditor/developer, 密码admin123)
- seedDefaultWorkflow: 默认审批流程(提交→DBA审核→执行)
- seedDefaultSettings: 数据脱敏默认配置
- 所有操作幂等,已有数据不覆盖
- main.go调用seedAll()统一初始化
2026-05-29 21:31:25 +08:00
logan 86eea25031 fix: 审批接口自动补全缺失的approval记录
旧ticket可能没有关联approval记录(创建时代码不同),
导致approve/reject报400 No pending approval。
现在admin/dba角色会自动创建approval记录再审批。
2026-05-29 18:46:51 +08:00
logan efd22b9c15 fix: 全局替换剩余7个手写弹框为ModalOverlay
- LdapConfigPage: 3个弹框(创建OU/添加用户/账号测试)
- AnnouncementPage: 2个弹框(查看/编辑公告)
- NotificationPage: 1个弹框(编辑通知)
- InstancePage: 1个弹框(批量导入)
所有弹框统一使用ModalOverlay组件,行为与EditInstanceDialog一致
tsc --noEmit 通过
2026-05-29 17:35:18 +08:00
logan 3c5e1c1f7d fix: 统一弹框组件 — ModalOverlay对齐EditInstanceDialog行为
- ModalOverlay移除遮罩层onClick(不响应外部点击关闭)
- 移除body.style.overflow=hidden(修复白条问题)
- max-h从90vh改为85vh(与EditInstanceDialog一致)
- 10个页面手写fixed弹框替换为ModalOverlay组件
- InstanceGroupPage/WorkflowPage/UsersPage/RedisDetailPage/TicketsPage已替换
- dialog.tsx添加onPointerDownOutside/onInteractOutside阻止外部点击
- index.css添加body[data-scroll-locked]覆盖Radix滚动锁定
- Layout.tsx main添加relative定位上下文
2026-05-29 17:16:08 +08:00
logan 5366d5c963 refactor: 重写测试套件对齐Go后端API + 修复superadmin权限
- 删除 29 个旧 Python 后端单元测试 (from app.* 导入已不适用)
- 重写 19 个集成测试文件对齐 Go/Gin 后端实际 API 行为:
  - 创建端点返回 201 (非 200)
  - Settings PUT 需要数组格式
  - SQL 审核 field 是 sql_content (非 sql)
  - 实例/审核规则列表不支持服务端过滤, 改为客户端过滤
  - 实例详情 MySQL 不可达时返回 500 (容错断言)
- 修复 RequireRole 中间件: superadmin 等同 admin 权限
- 测试结果: 81 passed, 4 skipped, 0 failed
2026-05-29 16:12:32 +08:00
logan 557d88d3ed feat: 数据脱敏体系重构 — 全局设置+masked_columns+前端去硬编码
后端:
- applyDataMasking 新增 masked_columns 返回字段,告诉前端哪些列被脱敏
- seedDefaultSettings 添加 data_masking 分组(启用开关+敏感字段列表)
- 脱敏逻辑: 全局敏感字段 + 实例级 mask_fields 合并,开关关闭则跳过

前端:
- QueriesPage 去掉硬编码 sensitiveKeywords 和 maskData()
- 改用后端返回的 masked_columns 显示'敏'标签
- 脱敏值由后端统一处理(替换为*)
- PlatformConfigPage 数据脱敏分组独立显示
- EditInstanceDialog 脱敏字段简化为逗号分隔输入

验证:
- 设置页开关可正常开关/保存
- 查询 ghost_test: email列被脱敏为*,列头显示'敏'标签
- 非敏感列(name, id, status)正常显示
2026-05-28 23:26:10 +08:00
logan e81eed288c feat: SchemaSidebar字段/索引tab切换+选库自动展开+singleDb过滤+表单击展开
- SchemaSidebar: 展开表后显示字段/索引两个tab,可切换查看
- 新增 tableIndexes state + IndexInfo import
- 选库后自动调用 handleExpandDb 加载表(修复之前无表bug)
- singleDb 模式下只显示当前选中库
- 表按钮交互改为: 单击展开/折叠, Alt+点击插入表名
- 菜单重组为工作台/管理/系统三段式
- TicketCreatePage 数据库必选(非Redis不自动选)
2026-05-28 22:31:40 +08:00
logan a95a341370 fix: 修复TicketCreatePage浏览按钮缺少<button>标签+补Sparkles import 2026-05-28 21:43:12 +08:00
logan 795a5afd72 fix: 删除TicketCreatePage遗留的broken代码行 2026-05-28 21:41:37 +08:00
logan 7e26837c5f refactor: TicketCreatePage用SchemaSidebar替换手写浏览器+SqlEditor暴露insertText光标定位
- SqlEditor: 添加 forwardRef + useImperativeHandle 暴露 insertText 方法
  - 支持在光标位置插入文本并移动光标
- TicketCreatePage: 删除300+行手写表结构/Redis/索引浏览代码
  - 统一使用 SchemaSidebar 组件(与查询页一致)
  - handleSchemaInsert: 已选库插table名,未选库插db.table名
  - 清理未用 imports/icons/types/helpers (RedisKeyItem, formatBytes等)
  - 848行 → 435行
2026-05-28 21:34:59 +08:00
logan c6ef67adba fix: 修复权限组用户看不到实例的bug — AccessibleInstances第二次Pluck覆盖第一次结果,改为单条OR查询 2026-05-28 20:50:57 +08:00
logan ed43f6f398 feat: 实现用户批量导入(LDAP+本地+CSV模板)
- BatchImportLdapUsers: 从LDAP导入用户到本地DB
  解析 dn/cn/uid/mail 字段,默认密码 admin123,角色 developer
  重复用户自动跳过
- BatchImportUsers: 本地CSV批量导入
  支持 username/display_name/email/role/password
  skip_existing 选项控制重复行为
- ImportTemplate: 真实CSV模板下载(UTF-8 BOM)
- 3个endpoint从placeholder改为真实实现
2026-05-28 16:26:53 +08:00
logan add9416c0e fix: 查询结果单元格不再截断,完整显示内容
去掉 max-w-[200px] truncate 限制,改为 whitespace-pre-wrap break-words
自然换行,LRANGE 等长文本完整展示
2026-05-28 16:17:31 +08:00
logan 7f09ef8e1a fix: Redis侧边栏扫描也自动补通配符
RedisScanKeys 端点的 pattern 参数无通配符时自动追加 *,
与查询页 KEYS 命令行为一致,输入 match 即匹配 match*
2026-05-28 16:13:50 +08:00
logan b8df2c0027 fix: Redis KEYS命令自动补通配符(*)
输入 KEYS match 自动变为 match* 模糊匹配,
无需手动加 *,同时匹配 ? [] 等 Redis 原生通配符
2026-05-28 16:07:16 +08:00
logan 3b3cc32d45 feat: Redis/MongoDB分页+CSV导出全数据库类型支持
后端:
- Redis 分页: KEYS→SCAN分页, LRANGE→offset/limit, SMEMBERS→SSCAN分页
- MongoDB 新增 executeMongoQuery: db.collection.find/aggregate 解析
  - find: skip/limit分页 + CountDocuments总数
  - aggregate: $facet并行取count+data
  - bson.M扁平化处理嵌套文档
- ExportQueryCSV 改为多分支: exportSQLCSV/exportRedisCSV/exportMongoCSV
  - Redis: 复用executeRedisQuery取数据写CSV
  - MongoDB: 复用executeMongoQuery取数据写CSV
- 新增 mongo-driver v2 依赖
- 前端: Redis也显示导出CSV按钮(去掉dbType过滤)
2026-05-28 15:58:42 +08:00
logan 5ea86fe334 feat: 查询分页(limit/offset)+流式CSV导出+去复制按钮
后端:
- ExecuteQuery 添加 limit/offset 参数,MySQL 自动注入 LIMIT/OFFSET
- 首页自动 COUNT 查总数(total),翻页页不再重复 count
- 新增 POST /query/export 流式 CSV 导出端点,游标分批写不占内存
- 默认 limit=100, max=1000,防止大数据量 OOM

前端:
- 查询结果加分页控件(首页/上一页/下一页/末页 + 每页条数选择)
- CSV 导出改走流式端点(全量数据),不限于当前页
- 去掉复制按钮(Copy/Check/coped state),Redis 单值也不显示复制
- 工具栏显示 总行数/行每页/列数
2026-05-28 15:51:22 +08:00
logan 03ff845485 feat: Redis单值结果直接展示+JSON中文格式化+悬浮复制
1. GET/HGET/TTL等单值命令: 直接展示raw值, 不再套table
2. JSON自动检测+格式化(中文正常显示, 2空格缩进)
3. 非JSON值(如false/数字)直接文本展示
4. 代码块右上角悬浮复制按钮(hover显示)
5. 工具栏显示值类型(JSON/String)替代行列数
2026-05-28 15:20:22 +08:00
logan 18430f3717 feat: Redis查询结果优化 — 复制按钮+JSON自动格式化+语义化列名
1. GET/HGET/TTL等单值命令: columns改为[key,value]替代[command,result]
2. DBSIZE等无key命令保持[command,result]格式
3. 前端添加复制按钮(Clipboard API), 2秒反馈
4. JSON值自动检测并格式化显示(whitespace-pre-wrap)
5. 结果区最大高度350px→500px
6. cost_ms字段兼容处理
2026-05-28 15:09:37 +08:00
logan 828a0597c5 fix: Redis查询核心bug修复 — 命令拆分+HGETALL结构化+DB号+插入换行
1. executeRedisQuery: client.Do()没传命令名导致ERR unknown command
2. HGETALL结果用reflect处理map类型,结构化输出field/value表格
3. 支持指定Redis DB号(之前固定DB=0)
4. 前端Redis命令插入用换行分隔,MySQL保持空格
5. cost_ms到execution_time_ms字段映射修复
2026-05-28 14:53:12 +08:00
logan 6b5d8bede4 fix: 查询页两个细节修复
1. 点击侧边栏表名插入 db.table 格式(如 log_analytics.access_logs)
   - SchemaSidebar 表名: onInsert(t.name) → onInsert(`${dbName}.${t.name}`)
   - SchemaSidebar 字段名: onInsert(col.Field) → onInsert(`${t.name}.${col.Field}`)
2. 查询不存在的表应显示错误而非'无结果数据'
   - QueriesPage handleExecute: 检查 res.error 字段,有错误则 setError + 不设 result
2026-05-28 14:41:46 +08:00
logan 9dda75efdb fix: LDAP导入弹框OU列表和用户列表解析失败
根因: 后端 ou-list/user-list API 直接返回数组, 前端错误地从 res.ous/res.users 取值
- loadLdapOus: Array.isArray(res) 兼容处理
- loadLdapUsers: Array.isArray(res) 兼容处理
- LDAP用户显示字段: cn/uid/mail 替代 nickname/username/email
2026-05-28 14:30:23 +08:00
logan 3a07432032 fix: BatchImportModal LDAP弹框3处bug修复
- backdrop onClick冒泡关闭弹框移除(L1036)
- useEffect getConfig/loadLdapOus串行化防时序竞争(L906-919)
- to-ldap/from-ldap条件渲染顺序修正(loading→未配置→正常)
2026-05-27 23:41:19 +08:00
logan 4351421848 fix: ConfirmDialog确认后弹框不关闭(9页面) + 登录页顶部渐变线移除
- 9个页面 onConfirm 回调添加 setDeleteConfirm(null) 关闭弹框
  - InstancePage/InstanceDetailPage/InstanceGroupPage/RedisDetailPage
  - UsersPage/AnnouncementPage/NotificationPage/NotificationsPage/WorkflowPage
- 白日梦境(NeonCityView) + 云石纹理(GradientMeshView) 移除顶部蓝色渐变线
2026-05-27 22:10:50 +08:00
logan 5a61babd33 feat: 霓虹都市→白日梦境 + 渐变网格→云石纹理 — 两个白色浅色主题登录页重写 2026-05-27 21:53:27 +08:00
logan b5739ba955 fix: 权限策略弹窗输入框失焦 — FormModal从内联函数组件改为直接JSX内联,避免state更新导致DOM重建 2026-05-27 21:42:40 +08:00
logan 7f6a4bb6df fix: 全部页面 confirm() 替换为 ConfirmDialog 组件 — 9个页面统一回调模式 2026-05-27 21:25:14 +08:00
logan 41dab3deab feat: 10个登录页图标统一 — 蓝紫渐变(#3b82f6→#8b5cf6)+白色盾牌勾选,与favicon一致 2026-05-27 21:04:45 +08:00
logan e6b421574d fix: 登录页功能卡片文案对齐实际功能 — 自助查询/变更审批/规则引擎/审计追踪/角色权限 2026-05-27 20:36:15 +08:00
logan d8b9e81635 feat: 品牌重命名 SQL-Platform → OpsxSQL — 12个文件18处替换,覆盖所有登录组件+Layout+index.html 2026-05-27 20:27:57 +08:00
logan 18ed0c1faf feat: 浏览器图标 — 蓝紫渐变圆角方块+白色盾牌勾选 2026-05-27 18:31:49 +08:00
logan 492bf7f8e3 fix: 功能展示风格提到第一位+比例优化 — 右侧400px更紧凑,左侧间距缩减,默认登录页改为sidepanel 2026-05-27 18:21:22 +08:00
logan f8b2266542 fix: 侧边面板恢复 commit 35a014e 原始设计 — 左品牌+6功能卡片,右登录表单,白色主题友好 2026-05-27 18:15:18 +08:00
logan b4fa60bc68 fix: 侧边面板恢复更早版本 (commit 8aaf227) — 左40%渐变+装饰圆圈+Database图标+主题切换按钮 2026-05-27 18:10:27 +08:00