@allbluecn/admin-app 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/allblue-ui/package.json +6 -0
  2. package/allblue-ui/src/components/confirm-dialog.tsx +94 -0
  3. package/allblue-ui/src/components/infinite-scroll-sentinel.tsx +37 -0
  4. package/allblue-ui/src/components/notion-avatar.tsx +126 -0
  5. package/allblue-ui/src/components/user-avatar.tsx +82 -0
  6. package/{src/components → allblue-ui/src}/data-table/data-table-pagination.tsx +14 -5
  7. package/{src/components → allblue-ui/src}/data-table/data-table.tsx +1 -1
  8. package/{src/components → allblue-ui/src}/data-table/table-detail-layout.tsx +5 -6
  9. package/allblue-ui/src/hooks/use-load-more.ts +57 -0
  10. package/allblue-ui/src/index.ts +31 -0
  11. package/allblue-ui/src/lib/datetime.ts +226 -0
  12. package/allblue-ui/src/lib/sanitize.ts +18 -0
  13. package/allblue-ui/src/lib/utils.ts +1 -0
  14. package/{src/components → allblue-ui/src}/ui/alert-dialog.tsx +1 -3
  15. package/{src/components → allblue-ui/src}/ui/checkbox.tsx +0 -1
  16. package/{src/components → allblue-ui/src}/ui/dialog.tsx +1 -1
  17. package/{src/components → allblue-ui/src}/ui/dropdown-menu.tsx +0 -2
  18. package/{src/components → allblue-ui/src}/ui/field.tsx +2 -2
  19. package/{src/components → allblue-ui/src}/ui/input-group.tsx +3 -4
  20. package/allblue-ui/src/ui/input.tsx +19 -0
  21. package/{src/components → allblue-ui/src}/ui/pagination.tsx +1 -1
  22. package/{src/components → allblue-ui/src}/ui/select.tsx +0 -2
  23. package/{src/components → allblue-ui/src}/ui/separator.tsx +1 -0
  24. package/{src/components → allblue-ui/src}/ui/sheet.tsx +1 -2
  25. package/{src/components → allblue-ui/src}/ui/sidebar.tsx +7 -7
  26. package/{src/components → allblue-ui/src}/ui/switch.tsx +1 -0
  27. package/{src/components → allblue-ui/src}/ui/table.tsx +0 -2
  28. package/{src/components → allblue-ui/src}/ui/toast.tsx +44 -18
  29. package/{src/components → allblue-ui/src}/ui/tooltip.tsx +1 -0
  30. package/package.json +21 -18
  31. package/src/components/admin/admin-user-menu.tsx +4 -4
  32. package/src/components/admin/developer-log.tsx +16 -32
  33. package/src/components/ai-memory/memory-facts-panel.tsx +30 -70
  34. package/src/components/ai-prompts/preview-panel.tsx +1 -1
  35. package/src/components/ai-prompts/prompt-editor.tsx +8 -9
  36. package/src/components/ai-prompts/prompt-table.tsx +6 -6
  37. package/src/components/ai-prompts/section-editor.tsx +3 -3
  38. package/src/components/ai-prompts/variable-panel.tsx +2 -2
  39. package/src/components/ai-prompts/version-history.tsx +21 -41
  40. package/src/components/ai-provider/model-list-editor.tsx +2 -3
  41. package/src/components/ai-provider/provider-form.tsx +7 -7
  42. package/src/components/ai-provider/provider-table.tsx +17 -40
  43. package/src/components/auth/admin-login-form.tsx +7 -7
  44. package/src/components/auth/icon-input.tsx +2 -2
  45. package/src/components/auth/password-input.tsx +2 -2
  46. package/src/components/component/component-form-dialog.tsx +10 -18
  47. package/src/components/component/component-import-dialog.tsx +6 -6
  48. package/src/components/component/component-preview.tsx +311 -0
  49. package/src/components/component/component-table.tsx +3 -3
  50. package/src/components/dependency/changelog-dialog.tsx +2 -2
  51. package/src/components/dependency/columns.tsx +3 -3
  52. package/src/components/dependency/dependency-table.tsx +7 -7
  53. package/src/components/dependency/edit-dialog.tsx +8 -8
  54. package/src/components/invitations/invitations-page.tsx +26 -49
  55. package/src/components/knowledge-public/bookmark-form-dialog.tsx +6 -6
  56. package/src/components/knowledge-public/compliance-form-dialog.tsx +6 -6
  57. package/src/components/knowledge-public/legal-form-dialog.tsx +7 -7
  58. package/src/components/layout/sidebar-02/app-sidebar.tsx +1 -2
  59. package/src/components/layout/sidebar-02/index.tsx +1 -1
  60. package/src/components/layout/sidebar-02/nav-main.tsx +2 -3
  61. package/src/components/layout/sidebar-02/nav-notifications.tsx +3 -3
  62. package/src/components/market/columns.tsx +4 -4
  63. package/src/components/market/market-app-form.tsx +6 -7
  64. package/src/components/market/market-app-list.tsx +14 -29
  65. package/src/components/monitoring/error-list.tsx +2 -2
  66. package/src/components/monitoring/metrics-stats.tsx +1 -1
  67. package/src/components/monitoring/request-log-table.tsx +2 -2
  68. package/src/components/oauth-providers/provider-page.tsx +20 -38
  69. package/src/components/permissions/assign-dialog.tsx +135 -0
  70. package/src/components/permissions/create-role-dialog.tsx +135 -0
  71. package/src/components/permissions/types.ts +49 -0
  72. package/src/components/user/columns.tsx +6 -6
  73. package/src/components/user/settings-activity-log.tsx +7 -7
  74. package/src/components/user/settings-profile/avatar-uploader.tsx +118 -0
  75. package/src/components/user/settings-profile/social-links.tsx +63 -0
  76. package/src/components/user/settings-profile.tsx +26 -125
  77. package/src/components/user/user-create-dialog.tsx +6 -6
  78. package/src/components/user/user-detail/error-boundary.tsx +19 -0
  79. package/src/components/user/user-detail/user-detail-dialogs.tsx +203 -0
  80. package/src/components/user/user-filters.tsx +4 -4
  81. package/src/lib/auth/page-gate.ts +28 -0
  82. package/src/lib/auth.config.ts +25 -9
  83. package/src/lib/i18n/detect.ts +1 -1
  84. package/src/lib/loader-serial.ts +14 -0
  85. package/src/providers/index.tsx +1 -1
  86. package/src/routeTree.gen.ts +67 -78
  87. package/src/routes/__root.tsx +4 -4
  88. package/src/routes/_nav/audit/route.lazy.tsx +1 -2
  89. package/src/routes/_nav/compliance/route.lazy.tsx +5 -3
  90. package/src/routes/_nav/components/route.lazy.tsx +14 -34
  91. package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +18 -38
  92. package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +18 -38
  93. package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +6 -6
  94. package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +3 -3
  95. package/src/routes/_nav/licenses/new/route.lazy.tsx +5 -5
  96. package/src/routes/_nav/licenses/route.lazy.tsx +1 -1
  97. package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +2 -2
  98. package/src/routes/_nav/monitoring/errors/route.lazy.tsx +10 -10
  99. package/src/routes/_nav/monitoring/errors/route.tsx +7 -0
  100. package/src/routes/_nav/monitoring/health/route.lazy.tsx +13 -15
  101. package/src/routes/_nav/monitoring/health/route.tsx +14 -0
  102. package/src/routes/_nav/monitoring/logs/route.lazy.tsx +24 -9
  103. package/src/routes/_nav/monitoring/logs/route.tsx +13 -0
  104. package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +12 -14
  105. package/src/routes/_nav/monitoring/metrics/route.tsx +7 -0
  106. package/src/routes/_nav/monitoring/overview/route.lazy.tsx +14 -13
  107. package/src/routes/_nav/monitoring/overview/route.tsx +17 -0
  108. package/src/routes/_nav/monitoring/route.lazy.tsx +6 -6
  109. package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +2 -2
  110. package/src/routes/_nav/permissions/route.lazy.tsx +21 -311
  111. package/src/routes/_nav/permissions/route.tsx +1 -1
  112. package/src/routes/_nav/route.tsx +5 -13
  113. package/src/routes/_nav/sso/route.lazy.tsx +2 -3
  114. package/src/routes/_nav/users/$userId/route.lazy.tsx +91 -156
  115. package/src/routes/_nav/users/-components/users-table.tsx +1 -1
  116. package/src/routes/_nav/users/route.lazy.tsx +1 -1
  117. package/src/routes/login/route.lazy.tsx +1 -1
  118. package/src/routes/setup/route.lazy.tsx +2 -2
  119. package/src/server/__tests__/admin-billing.test.ts +191 -16
  120. package/src/server/__tests__/compliance.test.ts +44 -7
  121. package/src/server/__tests__/permissions.test.ts +10 -5
  122. package/src/server/__tests__/prompt-defaults.test.ts +3 -3
  123. package/src/server/admin-ai-alerts.ts +2 -1
  124. package/src/server/admin-ai-usage.ts +2 -1
  125. package/src/server/ai-memory/store.ts +6 -2
  126. package/src/server/{serverFns/ai-prompts → ai-prompts}/prompt-defaults.ts +5 -3
  127. package/src/server/{serverFns/dependency → dependency}/helpers.ts +4 -3
  128. package/src/server/knowledge-public/github-sync.ts +2 -1
  129. package/src/server/license-issue.ts +2 -1
  130. package/src/server/middlewares/auth-rate-limit.ts +117 -0
  131. package/src/server/observability/health-check.ts +4 -1
  132. package/src/server/observability/metrics.ts +17 -15
  133. package/src/server/observability/request-middleware.ts +2 -1
  134. package/src/server/observability/timing.ts +14 -16
  135. package/src/server/serverFns/admin-billing.ts +107 -12
  136. package/src/server/serverFns/ai-memory/list-users.ts +2 -1
  137. package/src/server/serverFns/ai-prompts/activate.ts +2 -1
  138. package/src/server/serverFns/ai-prompts/get.ts +3 -2
  139. package/src/server/serverFns/ai-prompts/list.ts +3 -2
  140. package/src/server/serverFns/ai-prompts/rollback.ts +3 -1
  141. package/src/server/serverFns/ai-prompts/save.ts +5 -3
  142. package/src/server/serverFns/ai-provider/create.ts +4 -1
  143. package/src/server/serverFns/ai-provider/delete.ts +4 -1
  144. package/src/server/serverFns/ai-provider/get.ts +4 -1
  145. package/src/server/serverFns/ai-provider/list.ts +28 -1
  146. package/src/server/serverFns/ai-provider/seed-from-seed.ts +2 -1
  147. package/src/server/serverFns/ai-provider/update.ts +4 -1
  148. package/src/server/serverFns/anyhub/market.ts +8 -1
  149. package/src/server/serverFns/audit.ts +14 -1
  150. package/src/server/serverFns/auth/setup.ts +3 -1
  151. package/src/server/serverFns/compliance.ts +32 -3
  152. package/src/server/serverFns/components/import.ts +69 -14
  153. package/src/server/serverFns/components/list.ts +4 -1
  154. package/src/server/serverFns/components/mutations.ts +9 -1
  155. package/src/server/serverFns/dependency/list.ts +28 -5
  156. package/src/server/serverFns/dependency/sync.ts +7 -2
  157. package/src/server/serverFns/dependency/update.ts +4 -1
  158. package/src/server/serverFns/developer-log-auto-generate.ts +63 -32
  159. package/src/server/serverFns/developer-logs.ts +5 -1
  160. package/src/server/serverFns/invitations.ts +7 -1
  161. package/src/server/serverFns/knowledge-public/bookmarks/create.ts +2 -1
  162. package/src/server/serverFns/knowledge-public/bookmarks/delete.ts +2 -1
  163. package/src/server/serverFns/knowledge-public/bookmarks/detail.ts +2 -1
  164. package/src/server/serverFns/knowledge-public/bookmarks/list.ts +2 -1
  165. package/src/server/serverFns/knowledge-public/bookmarks/sync-all-github.ts +2 -1
  166. package/src/server/serverFns/knowledge-public/bookmarks/update.ts +2 -1
  167. package/src/server/serverFns/knowledge-public/compliance/create.ts +2 -1
  168. package/src/server/serverFns/knowledge-public/compliance/delete.ts +2 -1
  169. package/src/server/serverFns/knowledge-public/compliance/detail.ts +2 -1
  170. package/src/server/serverFns/knowledge-public/compliance/list.ts +2 -1
  171. package/src/server/serverFns/knowledge-public/compliance/update.ts +2 -1
  172. package/src/server/serverFns/knowledge-public/legal/create.ts +2 -1
  173. package/src/server/serverFns/knowledge-public/legal/delete.ts +2 -1
  174. package/src/server/serverFns/knowledge-public/legal/detail.ts +2 -1
  175. package/src/server/serverFns/knowledge-public/legal/list.ts +2 -1
  176. package/src/server/serverFns/knowledge-public/legal/update.ts +2 -1
  177. package/src/server/serverFns/licenses.ts +8 -2
  178. package/src/server/serverFns/monitoring/get-errors.ts +2 -1
  179. package/src/server/serverFns/monitoring/get-health.ts +2 -1
  180. package/src/server/serverFns/monitoring/get-metrics.ts +2 -1
  181. package/src/server/serverFns/monitoring/get-request-logs.ts +2 -1
  182. package/src/server/serverFns/monitoring/report-error.ts +2 -1
  183. package/src/server/serverFns/monitoring/reset.ts +2 -1
  184. package/src/server/serverFns/oauth-providers.ts +4 -1
  185. package/src/server/serverFns/permissions.ts +18 -11
  186. package/src/server/serverFns/sentry/config.ts +11 -8
  187. package/src/server/serverFns/sso-config.ts +17 -2
  188. package/src/server/serverFns/user/create.ts +6 -1
  189. package/src/server/serverFns/user/delete.ts +6 -1
  190. package/src/server/serverFns/user/detail.ts +5 -2
  191. package/src/server/serverFns/user/list.ts +19 -4
  192. package/src/server/serverFns/user/reset-password.ts +10 -2
  193. package/src/server/serverFns/user/update-role.ts +10 -2
  194. package/src/server/serverFns/user/update-status.ts +10 -2
  195. package/src/styles/globals.css +4 -0
  196. package/src/components/ui/input.tsx +0 -19
  197. /package/{src → allblue-ui/src}/hooks/use-mobile.ts +0 -0
  198. /package/{src → allblue-ui/src}/lib/avatar.ts +0 -0
  199. /package/{src/components → allblue-ui/src}/ui/alert.tsx +0 -0
  200. /package/{src/components → allblue-ui/src}/ui/avatar.tsx +0 -0
  201. /package/{src/components → allblue-ui/src}/ui/badge.tsx +0 -0
  202. /package/{src/components → allblue-ui/src}/ui/button.tsx +0 -0
  203. /package/{src/components → allblue-ui/src}/ui/card.tsx +0 -0
  204. /package/{src/components → allblue-ui/src}/ui/collapsible.tsx +0 -0
  205. /package/{src/components → allblue-ui/src}/ui/label.tsx +0 -0
  206. /package/{src/components → allblue-ui/src}/ui/skeleton.tsx +0 -0
  207. /package/{src/components → allblue-ui/src}/ui/textarea.tsx +0 -0
  208. /package/src/routes/{api.auth.$.ts → api/auth/$.ts} +0 -0
  209. /package/src/routes/{api.sentry-test.ts → api/sentry-test.ts} +0 -0
@@ -0,0 +1,28 @@
1
+ import { redirect } from '@tanstack/react-router'
2
+
3
+ interface SessionLike {
4
+ user?: { id?: string; role?: string | null } | null
5
+ }
6
+
7
+ /**
8
+ * admin「需登录页面」beforeLoad gate:未登录跳登录并携带回跳;
9
+ * 已登录但非管理员(ADMIN/SUPER_ADMIN)拒绝回登录页。
10
+ * session 取自 __root beforeLoad 注入的 context.session(勿在此重复调 getSessionFn)。
11
+ */
12
+ export function requireAdminPage(args: {
13
+ context: { session: SessionLike | null }
14
+ location: { pathname: string; searchStr: string }
15
+ }): void {
16
+ if (!args.context.session?.user?.id) {
17
+ throw redirect({
18
+ to: '/login',
19
+ search: { redirect: args.location.pathname + args.location.searchStr },
20
+ })
21
+ }
22
+ if (
23
+ args.context.session.user.role !== 'ADMIN' &&
24
+ args.context.session.user.role !== 'SUPER_ADMIN'
25
+ ) {
26
+ throw redirect({ to: '/login' })
27
+ }
28
+ }
@@ -22,6 +22,7 @@ import type { PrismaClient } from '@allbluecn/database'
22
22
  import bcrypt from 'bcryptjs'
23
23
  import { getRandomConfig, presetBgColors } from '@/components/settings/avatar/avatar-config'
24
24
  import { resolveIpLocation, getClientIp } from '@allbluecn/kernel'
25
+ import { isLoginBlocked, recordLoginFailure, clearLoginFailures } from '@/server/middlewares/auth-rate-limit'
25
26
 
26
27
  let _prisma: PrismaClient | null = null
27
28
  async function getDb(): Promise<PrismaClient> {
@@ -66,13 +67,7 @@ export const authConfig: StartAuthJSConfig = {
66
67
  const creds = credentials as { email: string; password: string; remember?: string; stayLoggedIn?: string }
67
68
  if (!creds.email || !creds.password) return null
68
69
 
69
- const user = await getDb().then(db => db.user.findUnique({
70
- where: { email: creds.email },
71
- select: { id: true, email: true, username: true, password: true, role: true, status: true },
72
- }))
73
-
74
- // 用户不存在:userId 为外键,无法记录日志(保持现状)
75
- if (!user) return null
70
+ const loginEmail = creds.email.toLowerCase().trim()
76
71
 
77
72
  // 安全提取 IP/UA(start-authjs 传递的 request 类型可能不标准,失败不阻塞登录)
78
73
  let ip: string | null = null
@@ -84,7 +79,26 @@ export const authConfig: StartAuthJSConfig = {
84
79
  userAgent = headers.get('user-agent') || null
85
80
  }
86
81
  } catch {
87
- // 忽略:IP/UA 仅用于日志,获取失败不影响登录
82
+ // 忽略:IP/UA 仅用于限流与日志,获取失败不影响登录
83
+ }
84
+
85
+ // SEC-09:登录失败限流(email+IP 维度,仅失败计数,成功清零)。
86
+ // 被限流返回 null——与密码错误不可区分,不暴露「被限流」细节(防枚举)。
87
+ // 测试环境豁免(NODE_ENV=test)在限流器内部处理,e2e 成功登录不受影响。
88
+ if (isLoginBlocked(loginEmail, ip)) return null
89
+
90
+ const user = await getDb().then(db => db.user.findUnique({
91
+ // 邮箱按原样查询:admin 建号/初始 setup 均原样大小写入库(zod .email() 不转
92
+ // 小写),归一化查询会静默锁死存量混合大小写账号。限流 key 的归一在
93
+ // auth-rate-limit 的 loginKey() 内部完成,与 DB 查询口径无关。
94
+ where: { email: creds.email },
95
+ select: { id: true, email: true, username: true, password: true, role: true, status: true },
96
+ }))
97
+
98
+ // 用户不存在:userId 为外键,无法记录日志(保持现状)
99
+ if (!user) {
100
+ recordLoginFailure(loginEmail, ip)
101
+ return null
88
102
  }
89
103
 
90
104
  // 安全记录登录日志(DB 异常不阻塞登录流程)
@@ -128,11 +142,13 @@ export const authConfig: StartAuthJSConfig = {
128
142
  // 密码校验
129
143
  const isValid = await bcrypt.compare(creds.password, user.password)
130
144
  if (!isValid) {
145
+ recordLoginFailure(loginEmail, ip)
131
146
  await recordLog(false, '密码错误')
132
147
  return null
133
148
  }
134
149
 
135
- // 登录成功:记录 IP/UA/地理位置
150
+ // 登录成功:清零失败计数 + 记录 IP/UA/地理位置
151
+ clearLoginFailures(loginEmail, ip)
136
152
  const location = await resolveIpLocation(ip)
137
153
  await recordLog(true, undefined, location)
138
154
  await getDb().then(db => db.user.update({ where: { id: user.id }, data: { lastLoginAt: new Date() } }))
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- import { supportedLngs, fallbackLng, isSupportedLocale, type AppLocale } from './config'
2
+ import { fallbackLng, isSupportedLocale, type AppLocale } from './config'
3
3
 
4
4
  export function detectLocale(request: Request, userLocale: string | null): AppLocale {
5
5
  const url = new URL(request.url)
@@ -0,0 +1,14 @@
1
+ // loader 预取数据的 JSON 归一化:客户端 RPC 路径返回纯 JSON(Date → ISO 字符串),
2
+ // SSR loader 路径若保留 Date 会让同组件在两条路径下收到不同形态。
3
+ // 统一在 loader 出口归一为 JSON 形态,保证与既有 useState + 客户端 fetch 行为一致。
4
+ export type Jsonified<T> = T extends (infer U)[]
5
+ ? Jsonified<U>[]
6
+ : T extends Date
7
+ ? string
8
+ : T extends object
9
+ ? { [K in keyof T]: Jsonified<T[K]> }
10
+ : T
11
+
12
+ export function jsonify<T>(value: T): Jsonified<T> {
13
+ return JSON.parse(JSON.stringify(value)) as Jsonified<T>
14
+ }
@@ -18,7 +18,7 @@
18
18
 
19
19
  import { ThemeProvider } from "next-themes";
20
20
  import { type ReactNode } from "react";
21
- import { TooltipProvider } from "@/components/ui/tooltip";
21
+ import { TooltipProvider } from "@allbluecn/ui/tooltip";
22
22
 
23
23
  export function Providers({
24
24
  children,
@@ -37,7 +37,7 @@ import { Route as NavPermissionsRouteRouteImport } from './routes/_nav/permissio
37
37
  import { Route as NavSettingsRouteRouteImport } from './routes/_nav/settings/route'
38
38
  import { Route as NavSsoRouteRouteImport } from './routes/_nav/sso/route'
39
39
  import { Route as NavUsersRouteRouteImport } from './routes/_nav/users/route'
40
- import { Route as ApiSentryTestRouteImport } from './routes/api.sentry-test'
40
+ import { Route as ApiSentryTestRouteImport } from './routes/api/sentry-test'
41
41
  import { Route as NavAiPromptsKeyRouteRouteImport } from './routes/_nav/ai-prompts/$key/route'
42
42
  import { Route as NavAiProvidersNewRouteRouteImport } from './routes/_nav/ai-providers/new/route'
43
43
  import { Route as NavBillingInvoicesRouteRouteImport } from './routes/_nav/billing/invoices/route'
@@ -47,9 +47,14 @@ import { Route as NavKnowledgePublicComplianceRouteRouteImport } from './routes/
47
47
  import { Route as NavKnowledgePublicLegalRouteRouteImport } from './routes/_nav/knowledge-public/legal/route'
48
48
  import { Route as NavLicensesLicenseIdRouteRouteImport } from './routes/_nav/licenses/$licenseId/route'
49
49
  import { Route as NavMonitoringAiUsageRouteRouteImport } from './routes/_nav/monitoring/ai-usage/route'
50
+ import { Route as NavMonitoringErrorsRouteRouteImport } from './routes/_nav/monitoring/errors/route'
51
+ import { Route as NavMonitoringHealthRouteRouteImport } from './routes/_nav/monitoring/health/route'
52
+ import { Route as NavMonitoringLogsRouteRouteImport } from './routes/_nav/monitoring/logs/route'
53
+ import { Route as NavMonitoringMetricsRouteRouteImport } from './routes/_nav/monitoring/metrics/route'
54
+ import { Route as NavMonitoringOverviewRouteRouteImport } from './routes/_nav/monitoring/overview/route'
50
55
  import { Route as NavMonitoringSentryRouteRouteImport } from './routes/_nav/monitoring/sentry/route'
51
56
  import { Route as NavUsersUserIdRouteRouteImport } from './routes/_nav/users/$userId/route'
52
- import { Route as ApiAuthSplatRouteImport } from './routes/api.auth.$'
57
+ import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$'
53
58
  import { Route as ApiComplianceDownloadJobIdRouteImport } from './routes/api/compliance-download/$jobId'
54
59
  import { Route as ApiObservabilityErrorsRouteImport } from './routes/api/observability/errors'
55
60
  import { Route as ApiObservabilityHealthRouteImport } from './routes/api/observability/health'
@@ -63,21 +68,6 @@ const NavAiProvidersIndexRouteLazyRouteImport = createFileRoute(
63
68
  )()
64
69
  const NavLicensesNewRouteLazyRouteImport =
65
70
  createFileRoute('/_nav/licenses/new')()
66
- const NavMonitoringErrorsRouteLazyRouteImport = createFileRoute(
67
- '/_nav/monitoring/errors',
68
- )()
69
- const NavMonitoringHealthRouteLazyRouteImport = createFileRoute(
70
- '/_nav/monitoring/health',
71
- )()
72
- const NavMonitoringLogsRouteLazyRouteImport = createFileRoute(
73
- '/_nav/monitoring/logs',
74
- )()
75
- const NavMonitoringMetricsRouteLazyRouteImport = createFileRoute(
76
- '/_nav/monitoring/metrics',
77
- )()
78
- const NavMonitoringOverviewRouteLazyRouteImport = createFileRoute(
79
- '/_nav/monitoring/overview',
80
- )()
81
71
 
82
72
  const IndexRouteRoute = IndexRouteRouteImport.update({
83
73
  id: '/',
@@ -355,40 +345,39 @@ const NavMonitoringAiUsageRouteRoute =
355
345
  } as any).lazy(() =>
356
346
  import('./routes/_nav/monitoring/ai-usage/route.lazy').then((d) => d.Route),
357
347
  )
358
- const NavMonitoringErrorsRouteLazyRoute =
359
- NavMonitoringErrorsRouteLazyRouteImport.update({
348
+ const NavMonitoringErrorsRouteRoute =
349
+ NavMonitoringErrorsRouteRouteImport.update({
360
350
  id: '/errors',
361
351
  path: '/errors',
362
352
  getParentRoute: () => NavMonitoringRouteRoute,
363
353
  } as any).lazy(() =>
364
354
  import('./routes/_nav/monitoring/errors/route.lazy').then((d) => d.Route),
365
355
  )
366
- const NavMonitoringHealthRouteLazyRoute =
367
- NavMonitoringHealthRouteLazyRouteImport.update({
356
+ const NavMonitoringHealthRouteRoute =
357
+ NavMonitoringHealthRouteRouteImport.update({
368
358
  id: '/health',
369
359
  path: '/health',
370
360
  getParentRoute: () => NavMonitoringRouteRoute,
371
361
  } as any).lazy(() =>
372
362
  import('./routes/_nav/monitoring/health/route.lazy').then((d) => d.Route),
373
363
  )
374
- const NavMonitoringLogsRouteLazyRoute =
375
- NavMonitoringLogsRouteLazyRouteImport.update({
376
- id: '/logs',
377
- path: '/logs',
378
- getParentRoute: () => NavMonitoringRouteRoute,
379
- } as any).lazy(() =>
380
- import('./routes/_nav/monitoring/logs/route.lazy').then((d) => d.Route),
381
- )
382
- const NavMonitoringMetricsRouteLazyRoute =
383
- NavMonitoringMetricsRouteLazyRouteImport.update({
364
+ const NavMonitoringLogsRouteRoute = NavMonitoringLogsRouteRouteImport.update({
365
+ id: '/logs',
366
+ path: '/logs',
367
+ getParentRoute: () => NavMonitoringRouteRoute,
368
+ } as any).lazy(() =>
369
+ import('./routes/_nav/monitoring/logs/route.lazy').then((d) => d.Route),
370
+ )
371
+ const NavMonitoringMetricsRouteRoute =
372
+ NavMonitoringMetricsRouteRouteImport.update({
384
373
  id: '/metrics',
385
374
  path: '/metrics',
386
375
  getParentRoute: () => NavMonitoringRouteRoute,
387
376
  } as any).lazy(() =>
388
377
  import('./routes/_nav/monitoring/metrics/route.lazy').then((d) => d.Route),
389
378
  )
390
- const NavMonitoringOverviewRouteLazyRoute =
391
- NavMonitoringOverviewRouteLazyRouteImport.update({
379
+ const NavMonitoringOverviewRouteRoute =
380
+ NavMonitoringOverviewRouteRouteImport.update({
392
381
  id: '/overview',
393
382
  path: '/overview',
394
383
  getParentRoute: () => NavMonitoringRouteRoute,
@@ -488,6 +477,11 @@ export interface FileRoutesByFullPath {
488
477
  '/knowledge-public/legal': typeof NavKnowledgePublicLegalRouteRoute
489
478
  '/licenses/$licenseId': typeof NavLicensesLicenseIdRouteRoute
490
479
  '/monitoring/ai-usage': typeof NavMonitoringAiUsageRouteRoute
480
+ '/monitoring/errors': typeof NavMonitoringErrorsRouteRoute
481
+ '/monitoring/health': typeof NavMonitoringHealthRouteRoute
482
+ '/monitoring/logs': typeof NavMonitoringLogsRouteRoute
483
+ '/monitoring/metrics': typeof NavMonitoringMetricsRouteRoute
484
+ '/monitoring/overview': typeof NavMonitoringOverviewRouteRoute
491
485
  '/monitoring/sentry': typeof NavMonitoringSentryRouteRoute
492
486
  '/users/$userId': typeof NavUsersUserIdRouteRoute
493
487
  '/api/auth/$': typeof ApiAuthSplatRoute
@@ -497,11 +491,6 @@ export interface FileRoutesByFullPath {
497
491
  '/ai-prompts/': typeof NavAiPromptsIndexRouteLazyRoute
498
492
  '/ai-providers/': typeof NavAiProvidersIndexRouteLazyRoute
499
493
  '/licenses/new': typeof NavLicensesNewRouteLazyRoute
500
- '/monitoring/errors': typeof NavMonitoringErrorsRouteLazyRoute
501
- '/monitoring/health': typeof NavMonitoringHealthRouteLazyRoute
502
- '/monitoring/logs': typeof NavMonitoringLogsRouteLazyRoute
503
- '/monitoring/metrics': typeof NavMonitoringMetricsRouteLazyRoute
504
- '/monitoring/overview': typeof NavMonitoringOverviewRouteLazyRoute
505
494
  '/ai-providers/$id/edit': typeof NavAiProvidersIdEditRouteRoute
506
495
  '/billing/subscriptions/$subscriptionId': typeof NavBillingSubscriptionsSubscriptionIdRouteRoute
507
496
  }
@@ -539,6 +528,11 @@ export interface FileRoutesByTo {
539
528
  '/knowledge-public/legal': typeof NavKnowledgePublicLegalRouteRoute
540
529
  '/licenses/$licenseId': typeof NavLicensesLicenseIdRouteRoute
541
530
  '/monitoring/ai-usage': typeof NavMonitoringAiUsageRouteRoute
531
+ '/monitoring/errors': typeof NavMonitoringErrorsRouteRoute
532
+ '/monitoring/health': typeof NavMonitoringHealthRouteRoute
533
+ '/monitoring/logs': typeof NavMonitoringLogsRouteRoute
534
+ '/monitoring/metrics': typeof NavMonitoringMetricsRouteRoute
535
+ '/monitoring/overview': typeof NavMonitoringOverviewRouteRoute
542
536
  '/monitoring/sentry': typeof NavMonitoringSentryRouteRoute
543
537
  '/users/$userId': typeof NavUsersUserIdRouteRoute
544
538
  '/api/auth/$': typeof ApiAuthSplatRoute
@@ -548,11 +542,6 @@ export interface FileRoutesByTo {
548
542
  '/ai-prompts': typeof NavAiPromptsIndexRouteLazyRoute
549
543
  '/ai-providers': typeof NavAiProvidersIndexRouteLazyRoute
550
544
  '/licenses/new': typeof NavLicensesNewRouteLazyRoute
551
- '/monitoring/errors': typeof NavMonitoringErrorsRouteLazyRoute
552
- '/monitoring/health': typeof NavMonitoringHealthRouteLazyRoute
553
- '/monitoring/logs': typeof NavMonitoringLogsRouteLazyRoute
554
- '/monitoring/metrics': typeof NavMonitoringMetricsRouteLazyRoute
555
- '/monitoring/overview': typeof NavMonitoringOverviewRouteLazyRoute
556
545
  '/ai-providers/$id/edit': typeof NavAiProvidersIdEditRouteRoute
557
546
  '/billing/subscriptions/$subscriptionId': typeof NavBillingSubscriptionsSubscriptionIdRouteRoute
558
547
  }
@@ -594,6 +583,11 @@ export interface FileRoutesById {
594
583
  '/_nav/knowledge-public/legal': typeof NavKnowledgePublicLegalRouteRoute
595
584
  '/_nav/licenses/$licenseId': typeof NavLicensesLicenseIdRouteRoute
596
585
  '/_nav/monitoring/ai-usage': typeof NavMonitoringAiUsageRouteRoute
586
+ '/_nav/monitoring/errors': typeof NavMonitoringErrorsRouteRoute
587
+ '/_nav/monitoring/health': typeof NavMonitoringHealthRouteRoute
588
+ '/_nav/monitoring/logs': typeof NavMonitoringLogsRouteRoute
589
+ '/_nav/monitoring/metrics': typeof NavMonitoringMetricsRouteRoute
590
+ '/_nav/monitoring/overview': typeof NavMonitoringOverviewRouteRoute
597
591
  '/_nav/monitoring/sentry': typeof NavMonitoringSentryRouteRoute
598
592
  '/_nav/users/$userId': typeof NavUsersUserIdRouteRoute
599
593
  '/api/auth/$': typeof ApiAuthSplatRoute
@@ -603,11 +597,6 @@ export interface FileRoutesById {
603
597
  '/_nav/ai-prompts/': typeof NavAiPromptsIndexRouteLazyRoute
604
598
  '/_nav/ai-providers/': typeof NavAiProvidersIndexRouteLazyRoute
605
599
  '/_nav/licenses/new': typeof NavLicensesNewRouteLazyRoute
606
- '/_nav/monitoring/errors': typeof NavMonitoringErrorsRouteLazyRoute
607
- '/_nav/monitoring/health': typeof NavMonitoringHealthRouteLazyRoute
608
- '/_nav/monitoring/logs': typeof NavMonitoringLogsRouteLazyRoute
609
- '/_nav/monitoring/metrics': typeof NavMonitoringMetricsRouteLazyRoute
610
- '/_nav/monitoring/overview': typeof NavMonitoringOverviewRouteLazyRoute
611
600
  '/_nav/ai-providers/$id/edit': typeof NavAiProvidersIdEditRouteRoute
612
601
  '/_nav/billing/subscriptions/$subscriptionId': typeof NavBillingSubscriptionsSubscriptionIdRouteRoute
613
602
  }
@@ -649,6 +638,11 @@ export interface FileRouteTypes {
649
638
  | '/knowledge-public/legal'
650
639
  | '/licenses/$licenseId'
651
640
  | '/monitoring/ai-usage'
641
+ | '/monitoring/errors'
642
+ | '/monitoring/health'
643
+ | '/monitoring/logs'
644
+ | '/monitoring/metrics'
645
+ | '/monitoring/overview'
652
646
  | '/monitoring/sentry'
653
647
  | '/users/$userId'
654
648
  | '/api/auth/$'
@@ -658,11 +652,6 @@ export interface FileRouteTypes {
658
652
  | '/ai-prompts/'
659
653
  | '/ai-providers/'
660
654
  | '/licenses/new'
661
- | '/monitoring/errors'
662
- | '/monitoring/health'
663
- | '/monitoring/logs'
664
- | '/monitoring/metrics'
665
- | '/monitoring/overview'
666
655
  | '/ai-providers/$id/edit'
667
656
  | '/billing/subscriptions/$subscriptionId'
668
657
  fileRoutesByTo: FileRoutesByTo
@@ -700,6 +689,11 @@ export interface FileRouteTypes {
700
689
  | '/knowledge-public/legal'
701
690
  | '/licenses/$licenseId'
702
691
  | '/monitoring/ai-usage'
692
+ | '/monitoring/errors'
693
+ | '/monitoring/health'
694
+ | '/monitoring/logs'
695
+ | '/monitoring/metrics'
696
+ | '/monitoring/overview'
703
697
  | '/monitoring/sentry'
704
698
  | '/users/$userId'
705
699
  | '/api/auth/$'
@@ -709,11 +703,6 @@ export interface FileRouteTypes {
709
703
  | '/ai-prompts'
710
704
  | '/ai-providers'
711
705
  | '/licenses/new'
712
- | '/monitoring/errors'
713
- | '/monitoring/health'
714
- | '/monitoring/logs'
715
- | '/monitoring/metrics'
716
- | '/monitoring/overview'
717
706
  | '/ai-providers/$id/edit'
718
707
  | '/billing/subscriptions/$subscriptionId'
719
708
  id:
@@ -754,6 +743,11 @@ export interface FileRouteTypes {
754
743
  | '/_nav/knowledge-public/legal'
755
744
  | '/_nav/licenses/$licenseId'
756
745
  | '/_nav/monitoring/ai-usage'
746
+ | '/_nav/monitoring/errors'
747
+ | '/_nav/monitoring/health'
748
+ | '/_nav/monitoring/logs'
749
+ | '/_nav/monitoring/metrics'
750
+ | '/_nav/monitoring/overview'
757
751
  | '/_nav/monitoring/sentry'
758
752
  | '/_nav/users/$userId'
759
753
  | '/api/auth/$'
@@ -763,11 +757,6 @@ export interface FileRouteTypes {
763
757
  | '/_nav/ai-prompts/'
764
758
  | '/_nav/ai-providers/'
765
759
  | '/_nav/licenses/new'
766
- | '/_nav/monitoring/errors'
767
- | '/_nav/monitoring/health'
768
- | '/_nav/monitoring/logs'
769
- | '/_nav/monitoring/metrics'
770
- | '/_nav/monitoring/overview'
771
760
  | '/_nav/ai-providers/$id/edit'
772
761
  | '/_nav/billing/subscriptions/$subscriptionId'
773
762
  fileRoutesById: FileRoutesById
@@ -1064,35 +1053,35 @@ declare module '@tanstack/react-router' {
1064
1053
  id: '/_nav/monitoring/errors'
1065
1054
  path: '/errors'
1066
1055
  fullPath: '/monitoring/errors'
1067
- preLoaderRoute: typeof NavMonitoringErrorsRouteLazyRouteImport
1056
+ preLoaderRoute: typeof NavMonitoringErrorsRouteRouteImport
1068
1057
  parentRoute: typeof NavMonitoringRouteRoute
1069
1058
  }
1070
1059
  '/_nav/monitoring/health': {
1071
1060
  id: '/_nav/monitoring/health'
1072
1061
  path: '/health'
1073
1062
  fullPath: '/monitoring/health'
1074
- preLoaderRoute: typeof NavMonitoringHealthRouteLazyRouteImport
1063
+ preLoaderRoute: typeof NavMonitoringHealthRouteRouteImport
1075
1064
  parentRoute: typeof NavMonitoringRouteRoute
1076
1065
  }
1077
1066
  '/_nav/monitoring/logs': {
1078
1067
  id: '/_nav/monitoring/logs'
1079
1068
  path: '/logs'
1080
1069
  fullPath: '/monitoring/logs'
1081
- preLoaderRoute: typeof NavMonitoringLogsRouteLazyRouteImport
1070
+ preLoaderRoute: typeof NavMonitoringLogsRouteRouteImport
1082
1071
  parentRoute: typeof NavMonitoringRouteRoute
1083
1072
  }
1084
1073
  '/_nav/monitoring/metrics': {
1085
1074
  id: '/_nav/monitoring/metrics'
1086
1075
  path: '/metrics'
1087
1076
  fullPath: '/monitoring/metrics'
1088
- preLoaderRoute: typeof NavMonitoringMetricsRouteLazyRouteImport
1077
+ preLoaderRoute: typeof NavMonitoringMetricsRouteRouteImport
1089
1078
  parentRoute: typeof NavMonitoringRouteRoute
1090
1079
  }
1091
1080
  '/_nav/monitoring/overview': {
1092
1081
  id: '/_nav/monitoring/overview'
1093
1082
  path: '/overview'
1094
1083
  fullPath: '/monitoring/overview'
1095
- preLoaderRoute: typeof NavMonitoringOverviewRouteLazyRouteImport
1084
+ preLoaderRoute: typeof NavMonitoringOverviewRouteRouteImport
1096
1085
  parentRoute: typeof NavMonitoringRouteRoute
1097
1086
  }
1098
1087
  '/_nav/monitoring/sentry': {
@@ -1227,22 +1216,22 @@ const NavLicensesRouteRouteWithChildren =
1227
1216
 
1228
1217
  interface NavMonitoringRouteRouteChildren {
1229
1218
  NavMonitoringAiUsageRouteRoute: typeof NavMonitoringAiUsageRouteRoute
1219
+ NavMonitoringErrorsRouteRoute: typeof NavMonitoringErrorsRouteRoute
1220
+ NavMonitoringHealthRouteRoute: typeof NavMonitoringHealthRouteRoute
1221
+ NavMonitoringLogsRouteRoute: typeof NavMonitoringLogsRouteRoute
1222
+ NavMonitoringMetricsRouteRoute: typeof NavMonitoringMetricsRouteRoute
1223
+ NavMonitoringOverviewRouteRoute: typeof NavMonitoringOverviewRouteRoute
1230
1224
  NavMonitoringSentryRouteRoute: typeof NavMonitoringSentryRouteRoute
1231
- NavMonitoringErrorsRouteLazyRoute: typeof NavMonitoringErrorsRouteLazyRoute
1232
- NavMonitoringHealthRouteLazyRoute: typeof NavMonitoringHealthRouteLazyRoute
1233
- NavMonitoringLogsRouteLazyRoute: typeof NavMonitoringLogsRouteLazyRoute
1234
- NavMonitoringMetricsRouteLazyRoute: typeof NavMonitoringMetricsRouteLazyRoute
1235
- NavMonitoringOverviewRouteLazyRoute: typeof NavMonitoringOverviewRouteLazyRoute
1236
1225
  }
1237
1226
 
1238
1227
  const NavMonitoringRouteRouteChildren: NavMonitoringRouteRouteChildren = {
1239
1228
  NavMonitoringAiUsageRouteRoute: NavMonitoringAiUsageRouteRoute,
1229
+ NavMonitoringErrorsRouteRoute: NavMonitoringErrorsRouteRoute,
1230
+ NavMonitoringHealthRouteRoute: NavMonitoringHealthRouteRoute,
1231
+ NavMonitoringLogsRouteRoute: NavMonitoringLogsRouteRoute,
1232
+ NavMonitoringMetricsRouteRoute: NavMonitoringMetricsRouteRoute,
1233
+ NavMonitoringOverviewRouteRoute: NavMonitoringOverviewRouteRoute,
1240
1234
  NavMonitoringSentryRouteRoute: NavMonitoringSentryRouteRoute,
1241
- NavMonitoringErrorsRouteLazyRoute: NavMonitoringErrorsRouteLazyRoute,
1242
- NavMonitoringHealthRouteLazyRoute: NavMonitoringHealthRouteLazyRoute,
1243
- NavMonitoringLogsRouteLazyRoute: NavMonitoringLogsRouteLazyRoute,
1244
- NavMonitoringMetricsRouteLazyRoute: NavMonitoringMetricsRouteLazyRoute,
1245
- NavMonitoringOverviewRouteLazyRoute: NavMonitoringOverviewRouteLazyRoute,
1246
1235
  }
1247
1236
 
1248
1237
  const NavMonitoringRouteRouteWithChildren =
@@ -21,7 +21,7 @@ import globalsCss from '../styles/globals.css?url'
21
21
  import type { RouterContext } from '@/lib/router-context'
22
22
  import type { AppLocale } from '@/lib/i18n/config'
23
23
  import { Providers } from '@/providers'
24
- import { Toaster } from '@/components/ui/toast'
24
+ import { Toaster } from '@allbluecn/ui/toast'
25
25
  import { getSessionFn } from '@/server/serverFns/auth/session'
26
26
  import { getLocaleFn } from '@/server/serverFns/locale'
27
27
  import { reportClientError } from '@/server/serverFns/monitoring/report-error'
@@ -103,7 +103,7 @@ function RootComponent() {
103
103
  <body className="w-full h-full min-h-screen antialiased">
104
104
  <Providers>
105
105
  <Outlet />
106
- <Toaster />
106
+ <Toaster position="bottom-right" />
107
107
  </Providers>
108
108
  <Scripts />
109
109
  </body>
@@ -127,8 +127,8 @@ function NotFoundPageInner() {
127
127
  )
128
128
  }
129
129
 
130
- function ErrorBoundary({ error }: { error: Error }) {
131
- return <ErrorBoundaryInner error={error} />
130
+ function ErrorBoundary({ error }: { error: unknown }) {
131
+ return <ErrorBoundaryInner error={error instanceof Error ? error : new Error(String(error))} />
132
132
  }
133
133
 
134
134
  function ErrorBoundaryInner({ error }: { error: Error }) {
@@ -18,7 +18,7 @@
18
18
  import { createLazyFileRoute } from '@tanstack/react-router'
19
19
  import { m } from '@/paraglide/messages.js'
20
20
  import type React from 'react'
21
- import { Badge } from '@/components/ui/badge'
21
+ import { Badge } from '@allbluecn/ui/badge'
22
22
 
23
23
  export const Route = createLazyFileRoute('/_nav/audit')({
24
24
  pendingComponent: () => (
@@ -38,7 +38,6 @@ function AuditLogPage(): React.ReactElement {
38
38
  resourceId: string | null
39
39
  userId: string | null
40
40
  workspaceId: string | null
41
- metadata: Record<string, unknown>
42
41
  ip: string | null
43
42
  userAgent: string | null
44
43
  createdAt: string
@@ -19,11 +19,11 @@ import { createLazyFileRoute } from '@tanstack/react-router'
19
19
  import { m } from '@/paraglide/messages.js'
20
20
  import { useQuery, useQueryClient } from '@tanstack/react-query'
21
21
  import { useServerFn } from '@tanstack/react-start'
22
- import { toast } from '@/components/ui/toast'
22
+ import { toast } from '@allbluecn/ui/toast'
23
23
  import type React from 'react'
24
24
  import { listComplianceExportsFn, executeComplianceJobFn } from '@/server/serverFns/compliance'
25
- import { Badge } from '@/components/ui/badge'
26
- import { Button } from '@/components/ui/button'
25
+ import { Badge } from '@allbluecn/ui/badge'
26
+ import { Button } from '@allbluecn/ui/button'
27
27
  import { Loader2 } from 'lucide-react'
28
28
 
29
29
  export const Route = createLazyFileRoute('/_nav/compliance')({
@@ -156,6 +156,8 @@ function CompliancePage(): React.ReactElement {
156
156
  </span>
157
157
  )}
158
158
  {item.status === 'completed' && !isExpired(item) && (
159
+ // 豁免原生 <a>:文件下载语义(download 属性触发浏览器下载而非路由导航),
160
+ // TanStack <Link> 不支持 download,替换会丢失下载行为
159
161
  <a
160
162
  href={`/api/compliance-download/${item.id}`}
161
163
  download={`allblue-export-${item.id}.json`}
@@ -15,28 +15,18 @@
15
15
  // You should have received a copy of the GNU Affero General Public License
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
- import { useState, useEffect } from 'react'
18
+ import { useState } from 'react'
19
19
  import { createLazyFileRoute, useNavigate, useRouter } from '@tanstack/react-router'
20
- import { BUILTIN_COMPONENTS, registerComponents, unregisterComponent } from '@allbluecn/web-app/prototype'
21
20
  import { Plus, Search, Download } from 'lucide-react'
22
- import { Button } from '@/components/ui/button'
23
- import { Input } from '@/components/ui/input'
24
- import {
25
- AlertDialog,
26
- AlertDialogAction,
27
- AlertDialogCancel,
28
- AlertDialogContent,
29
- AlertDialogDescription,
30
- AlertDialogFooter,
31
- AlertDialogHeader,
32
- AlertDialogTitle,
33
- } from '@/components/ui/alert-dialog'
21
+ import { Button } from '@allbluecn/ui/button'
22
+ import { Input } from '@allbluecn/ui/input'
23
+ import { ConfirmDialog } from '@allbluecn/ui/components/confirm-dialog'
34
24
  import { cn } from '@/lib/utils'
35
25
  import { ComponentTable, type ComponentItem } from '@/components/component/component-table'
36
26
  import { ComponentFormDialog } from '@/components/component/component-form-dialog'
37
27
  import { ComponentImportDialog } from '@/components/component/component-import-dialog'
38
28
  import { deleteComponentFn } from '@/server/serverFns/components/mutations'
39
- import { toast } from '@/components/ui/toast'
29
+ import { toast } from '@allbluecn/ui/toast'
40
30
 
41
31
  const CATEGORY_TABS = [
42
32
  { key: 'all', label: '全部' },
@@ -60,11 +50,6 @@ function ComponentsPage() {
60
50
  const navigate = useNavigate({ from: '/components' })
61
51
  const router = useRouter()
62
52
 
63
- useEffect(() => {
64
- registerComponents(BUILTIN_COMPONENTS)
65
- return () => { BUILTIN_COMPONENTS.forEach((c) => unregisterComponent(c.type)) }
66
- }, [])
67
-
68
53
  const [searchInput, setSearchInput] = useState(urlSearch ?? '')
69
54
  const [createOpen, setCreateOpen] = useState(false)
70
55
  const [editing, setEditing] = useState<ComponentItem | null>(null)
@@ -165,20 +150,15 @@ function ComponentsPage() {
165
150
  onSuccess={() => router.invalidate()}
166
151
  />
167
152
 
168
- <AlertDialog open={!!deleting} onOpenChange={(o: boolean) => !o && setDeleting(null)}>
169
- <AlertDialogContent>
170
- <AlertDialogHeader>
171
- <AlertDialogTitle>删除组件「{deleting?.name}」?</AlertDialogTitle>
172
- <AlertDialogDescription>
173
- 组件将被标记为已删除(软删除),不影响已使用该组件的原型页面。可在数据库中恢复。
174
- </AlertDialogDescription>
175
- </AlertDialogHeader>
176
- <AlertDialogFooter>
177
- <AlertDialogCancel>取消</AlertDialogCancel>
178
- <AlertDialogAction onClick={handleDelete}>删除</AlertDialogAction>
179
- </AlertDialogFooter>
180
- </AlertDialogContent>
181
- </AlertDialog>
153
+ <ConfirmDialog
154
+ open={!!deleting}
155
+ onOpenChange={(o: boolean) => !o && setDeleting(null)}
156
+ title={<>删除组件「{deleting?.name}」?</>}
157
+ description="组件将被标记为已删除(软删除),不影响已使用该组件的原型页面。可在数据库中恢复。"
158
+ cancelLabel="取消"
159
+ confirmLabel="删除"
160
+ onConfirm={handleDelete}
161
+ />
182
162
  </div>
183
163
  )
184
164
  }