@allbluecn/admin-app 0.1.0 → 0.2.1

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 (86) hide show
  1. package/package.json +9 -9
  2. package/src/components/admin/admin-user-menu.tsx +12 -6
  3. package/src/components/admin/developer-log.tsx +42 -44
  4. package/src/components/ai-provider/model-list-editor.tsx +5 -4
  5. package/src/components/ai-provider/provider-form.tsx +63 -64
  6. package/src/components/ai-provider/provider-table.tsx +35 -36
  7. package/src/components/auth/admin-login-form.tsx +23 -24
  8. package/src/components/auth/oauth-section.tsx +3 -5
  9. package/src/components/auth/password-input.tsx +2 -3
  10. package/src/components/common/placeholder-page.tsx +2 -4
  11. package/src/components/component/component-form-dialog.tsx +48 -49
  12. package/src/components/component/component-import-dialog.tsx +5 -5
  13. package/src/components/component/component-table.tsx +13 -14
  14. package/src/components/data-table/data-table-pagination.tsx +4 -6
  15. package/src/components/data-table/table-detail-layout.tsx +2 -3
  16. package/src/components/dependency/changelog-dialog.tsx +3 -4
  17. package/src/components/dependency/columns.tsx +32 -24
  18. package/src/components/dependency/dependency-table.tsx +37 -29
  19. package/src/components/dependency/edit-dialog.tsx +24 -25
  20. package/src/components/knowledge-public/bookmark-form-dialog.tsx +7 -7
  21. package/src/components/knowledge-public/compliance-form-dialog.tsx +13 -13
  22. package/src/components/knowledge-public/legal-form-dialog.tsx +51 -46
  23. package/src/components/layout/sidebar-02/app-sidebar.tsx +33 -34
  24. package/src/components/layout/sidebar-02/nav-main.tsx +1 -1
  25. package/src/components/market/columns.tsx +20 -21
  26. package/src/components/market/market-app-form.tsx +45 -38
  27. package/src/components/market/market-app-list.tsx +16 -17
  28. package/src/components/monitoring/error-list.tsx +18 -19
  29. package/src/components/monitoring/health-cards.tsx +11 -13
  30. package/src/components/monitoring/metrics-stats.tsx +11 -12
  31. package/src/components/monitoring/request-log-table.tsx +8 -9
  32. package/src/components/ui/pagination.tsx +0 -2
  33. package/src/components/ui/sidebar.tsx +1 -1
  34. package/src/components/user/columns.tsx +9 -9
  35. package/src/components/user/settings-activity-log.tsx +39 -29
  36. package/src/components/user/settings-profile.tsx +36 -36
  37. package/src/components/user/user-create-dialog.tsx +4 -4
  38. package/src/components/user/user-filters.tsx +16 -18
  39. package/src/lib/i18n/config.ts +0 -32
  40. package/src/providers/index.tsx +6 -16
  41. package/src/routes/__root.tsx +9 -23
  42. package/src/routes/_nav/apps/route.lazy.tsx +2 -3
  43. package/src/routes/_nav/audit/route.lazy.tsx +10 -11
  44. package/src/routes/_nav/billing/invoices/route.lazy.tsx +6 -7
  45. package/src/routes/_nav/billing/route.lazy.tsx +3 -4
  46. package/src/routes/_nav/billing/subscriptions/$subscriptionId/route.lazy.tsx +16 -17
  47. package/src/routes/_nav/billing/subscriptions/route.lazy.tsx +9 -10
  48. package/src/routes/_nav/compliance/route.lazy.tsx +34 -35
  49. package/src/routes/_nav/components/route.lazy.tsx +6 -6
  50. package/src/routes/_nav/dashboard/route.lazy.tsx +3 -5
  51. package/src/routes/_nav/dependencies/route.lazy.tsx +7 -8
  52. package/src/routes/_nav/docs/route.lazy.tsx +2 -3
  53. package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +40 -41
  54. package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +32 -33
  55. package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +32 -33
  56. package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +24 -31
  57. package/src/routes/_nav/licenses/new/route.lazy.tsx +25 -26
  58. package/src/routes/_nav/licenses/route.lazy.tsx +17 -18
  59. package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +26 -27
  60. package/src/routes/_nav/monitoring/errors/route.lazy.tsx +11 -12
  61. package/src/routes/_nav/monitoring/health/route.lazy.tsx +18 -20
  62. package/src/routes/_nav/monitoring/logs/route.lazy.tsx +12 -13
  63. package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +13 -15
  64. package/src/routes/_nav/monitoring/overview/route.lazy.tsx +12 -13
  65. package/src/routes/_nav/monitoring/route.lazy.tsx +8 -9
  66. package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +55 -57
  67. package/src/routes/_nav/permissions/route.lazy.tsx +48 -50
  68. package/src/routes/_nav/settings/route.lazy.tsx +2 -3
  69. package/src/routes/_nav/sso/route.lazy.tsx +20 -18
  70. package/src/routes/_nav/users/$userId/route.lazy.tsx +86 -82
  71. package/src/routes/_nav/users/route.lazy.tsx +4 -5
  72. package/src/routes/setup/route.lazy.tsx +15 -16
  73. package/src/start.ts +2 -2
  74. package/src/lib/i18n/client.ts +0 -32
  75. package/src/lib/i18n/locales/en/admin-ai.json +0 -128
  76. package/src/lib/i18n/locales/en/admin-billing.json +0 -56
  77. package/src/lib/i18n/locales/en/admin-users.json +0 -88
  78. package/src/lib/i18n/locales/en/common.json +0 -877
  79. package/src/lib/i18n/locales/en/enterprise.json +0 -208
  80. package/src/lib/i18n/locales/zh/admin-ai.json +0 -128
  81. package/src/lib/i18n/locales/zh/admin-billing.json +0 -56
  82. package/src/lib/i18n/locales/zh/admin-users.json +0 -88
  83. package/src/lib/i18n/locales/zh/common.json +0 -877
  84. package/src/lib/i18n/locales/zh/enterprise.json +0 -208
  85. package/src/lib/i18n/server.ts +0 -18
  86. package/src/lib/i18n/types.ts +0 -5
@@ -1,6 +1,7 @@
1
1
  import { createLazyFileRoute, Link, useLocation } from '@tanstack/react-router'
2
+ import { m } from '@/paraglide/messages.js'
3
+ import { getLocale } from '@/paraglide/runtime.js'
2
4
  import { useServerFn } from '@tanstack/react-start'
3
- import { useTranslation } from 'react-i18next'
4
5
  import { toast } from 'sonner'
5
6
  import { useCallback, useEffect, useState } from 'react'
6
7
  import type React from 'react'
@@ -112,7 +113,6 @@ function CreateRoleDialog({
112
113
  i18nLang: string
113
114
  onCreated: () => void
114
115
  }): React.ReactElement {
115
- const { t } = useTranslation('enterprise')
116
116
  const createRole = useServerFn(createRoleFn)
117
117
  const [name, setName] = useState('')
118
118
  const [permissions, setPermissions] = useState<ResourcePermission>({})
@@ -132,7 +132,7 @@ function CreateRoleDialog({
132
132
 
133
133
  const handleSubmit = async () => {
134
134
  if (!name.trim()) {
135
- toast.warning(t('permissions.toast.nameRequired'))
135
+ toast.warning(m.enterprise_permissions_toast_nameRequired())
136
136
  return
137
137
  }
138
138
  await createRole({
@@ -142,7 +142,7 @@ function CreateRoleDialog({
142
142
  permissions,
143
143
  },
144
144
  })
145
- toast.success(t('permissions.toast.created', { name: name.trim() }))
145
+ toast.success(m.enterprise_permissions_toast_created({ name: name.trim() }))
146
146
  onOpenChange(false)
147
147
  onCreated()
148
148
  }
@@ -151,24 +151,24 @@ function CreateRoleDialog({
151
151
  <Dialog open={open} onOpenChange={onOpenChange}>
152
152
  <DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
153
153
  <DialogHeader>
154
- <DialogTitle>{t('permissions.createRole')}</DialogTitle>
155
- <DialogDescription>{t('permissions.createRoleDesc')}</DialogDescription>
154
+ <DialogTitle>{m.enterprise_permissions_createRole()}</DialogTitle>
155
+ <DialogDescription>{m.enterprise_permissions_createRoleDesc()}</DialogDescription>
156
156
  </DialogHeader>
157
157
 
158
158
  <div className="space-y-4">
159
159
  <div className="grid gap-2">
160
- <Label htmlFor="role-name">{t('permissions.roleName')}</Label>
160
+ <Label htmlFor="role-name">{m.enterprise_permissions_roleName()}</Label>
161
161
  <Input
162
162
  id="role-name"
163
163
  value={name}
164
- onChange={(e) => setName(e.target.value)}
165
- placeholder={t('permissions.roleNamePlaceholder')}
164
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
165
+ placeholder={m.enterprise_permissions_roleNamePlaceholder()}
166
166
  autoFocus
167
167
  />
168
168
  </div>
169
169
 
170
170
  <div className="space-y-3">
171
- <Label>{t('permissions.permissionsMatrix')}</Label>
171
+ <Label>{m.enterprise_permissions_permissionsMatrix()}</Label>
172
172
  {ALL_RESOURCES.map((resource) => (
173
173
  <div key={resource.key} className="space-y-2">
174
174
  <span className="text-sm font-medium">{isZh ? resource.labelZh : resource.labelEn}</span>
@@ -177,7 +177,7 @@ function CreateRoleDialog({
177
177
  <Select
178
178
  key={action.key}
179
179
  value={permissions[`${resource.key}:${action.key}`] || 'none'}
180
- onValueChange={(value) => handleLevelChange(resource.key, action.key, value)}
180
+ onValueChange={(value: string) => handleLevelChange(resource.key, action.key, value)}
181
181
  >
182
182
  <SelectTrigger className="h-8">
183
183
  <SelectValue>
@@ -201,9 +201,9 @@ function CreateRoleDialog({
201
201
 
202
202
  <DialogFooter>
203
203
  <Button variant="outline" onClick={() => onOpenChange(false)}>
204
- {t('permissions.dialog.cancel')}
204
+ {m.enterprise_permissions_dialog_cancel()}
205
205
  </Button>
206
- <Button onClick={handleSubmit}>{t('permissions.dialog.create')}</Button>
206
+ <Button onClick={handleSubmit}>{m.enterprise_permissions_dialog_create()}</Button>
207
207
  </DialogFooter>
208
208
  </DialogContent>
209
209
  </Dialog>
@@ -223,7 +223,6 @@ function AssignDialog({
223
223
  i18nLang: string
224
224
  onAssigned: () => void
225
225
  }): React.ReactElement {
226
- const { t } = useTranslation('enterprise')
227
226
  const assignRole = useServerFn(assignRoleFn)
228
227
  const unassignRole = useServerFn(unassignRoleFn)
229
228
  const listAssignments = useServerFn(listRoleAssignmentsFn)
@@ -234,7 +233,7 @@ function AssignDialog({
234
233
  useEffect(() => {
235
234
  if (open && role) {
236
235
  listAssignments({ data: { roleId: role.id } })
237
- .then((result) => setAssignments(result))
236
+ .then((result: any) => setAssignments(result))
238
237
  .catch(() => setAssignments([]))
239
238
  }
240
239
  }, [open, role, listAssignments])
@@ -242,14 +241,14 @@ function AssignDialog({
242
241
  const handleAssign = async () => {
243
242
  if (!searchUser.trim() || !role) return
244
243
  await assignRole({ data: { userId: searchUser.trim(), roleId: role.id } })
245
- toast.success(t('permissions.toast.assigned'))
244
+ toast.success(m.enterprise_permissions_toast_assigned())
246
245
  setSearchUser('')
247
246
  onAssigned()
248
247
  }
249
248
 
250
249
  const handleUnassign = async (assignmentId: string) => {
251
250
  await unassignRole({ data: { assignmentId } })
252
- toast.success(t('permissions.toast.unassigned'))
251
+ toast.success(m.enterprise_permissions_toast_unassigned())
253
252
  setAssignments(assignments.filter((a) => a.id !== assignmentId))
254
253
  }
255
254
 
@@ -258,25 +257,25 @@ function AssignDialog({
258
257
  <DialogContent className="max-w-lg">
259
258
  <DialogHeader>
260
259
  <DialogTitle>
261
- {t('permissions.assign', { name: role?.name })}
260
+ {m.enterprise_permissions_assign({ name: role?.name ?? '' })}
262
261
  </DialogTitle>
263
- <DialogDescription>{t('permissions.assignDesc')}</DialogDescription>
262
+ <DialogDescription>{m.enterprise_permissions_assignDesc()}</DialogDescription>
264
263
  </DialogHeader>
265
264
 
266
265
  <div className="space-y-4">
267
266
  <div className="flex gap-2">
268
267
  <Input
269
268
  value={searchUser}
270
- onChange={(e) => setSearchUser(e.target.value)}
271
- placeholder={t('permissions.searchUserPlaceholder')}
269
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchUser(e.target.value)}
270
+ placeholder={m.enterprise_permissions_searchUserPlaceholder()}
272
271
  />
273
272
  <Button onClick={handleAssign} disabled={!searchUser.trim()}>
274
- {t('permissions.assignUser')}
273
+ {m.enterprise_permissions_assignUser()}
275
274
  </Button>
276
275
  </div>
277
276
 
278
277
  {assignments.length === 0 ? (
279
- <p className="text-sm text-muted-foreground">{t('permissions.noAssignments')}</p>
278
+ <p className="text-sm text-muted-foreground">{m.enterprise_permissions_noAssignments()}</p>
280
279
  ) : (
281
280
  <Table>
282
281
  <TableHeader>
@@ -297,7 +296,7 @@ function AssignDialog({
297
296
  className="text-destructive hover:underline"
298
297
  onClick={() => handleUnassign(a.id)}
299
298
  >
300
- {t('permissions.unassign')}
299
+ {m.enterprise_permissions_unassign()}
301
300
  </button>
302
301
  </TableCell>
303
302
  </TableRow>
@@ -309,7 +308,7 @@ function AssignDialog({
309
308
 
310
309
  <DialogFooter>
311
310
  <Button variant="outline" onClick={() => onOpenChange(false)}>
312
- {t('permissions.dialog.close')}
311
+ {m.enterprise_permissions_dialog_close()}
313
312
  </Button>
314
313
  </DialogFooter>
315
314
  </DialogContent>
@@ -318,7 +317,6 @@ function AssignDialog({
318
317
  }
319
318
 
320
319
  function PermissionsPage(): React.ReactElement {
321
- const { t, i18n } = useTranslation('enterprise')
322
320
  const location = useLocation()
323
321
  const selectedWorkspaceId =
324
322
  (location.search as { workspaceId?: string }).workspaceId ??
@@ -337,7 +335,7 @@ function PermissionsPage(): React.ReactElement {
337
335
  useEffect(() => {
338
336
  if (selectedWorkspaceId) {
339
337
  listRoles({ data: { workspaceId: selectedWorkspaceId } })
340
- .then((result) => {
338
+ .then((result: any) => {
341
339
  const data = result as { items: RoleItem[]; total: number; seeded: string }
342
340
  setRoles(data.items)
343
341
  })
@@ -347,11 +345,11 @@ function PermissionsPage(): React.ReactElement {
347
345
 
348
346
  const handleDelete = async (role: RoleItem) => {
349
347
  if (role.isSystem) {
350
- toast.info(t('permissions.toast.systemRole'))
348
+ toast.info(m.enterprise_permissions_toast_systemRole())
351
349
  return
352
350
  }
353
351
  await deleteRole({ data: { roleId: role.id } })
354
- toast.success(t('permissions.toast.deleted', { name: role.name }))
352
+ toast.success(m.enterprise_permissions_toast_deleted({ name: role.name }))
355
353
  setRoles(roles.filter((r) => r.id !== role.id))
356
354
  }
357
355
 
@@ -361,10 +359,10 @@ function PermissionsPage(): React.ReactElement {
361
359
  }
362
360
 
363
361
  const PERMISSION_LEVELS: Record<string, () => string> = {
364
- admin: () => t('permissions.level.admin'),
365
- write: () => t('permissions.level.write'),
366
- read: () => t('permissions.level.read'),
367
- none: () => t('permissions.level.none'),
362
+ admin: () => m.enterprise_permissions_level_admin(),
363
+ write: () => m.enterprise_permissions_level_write(),
364
+ read: () => m.enterprise_permissions_level_read(),
365
+ none: () => m.enterprise_permissions_level_none(),
368
366
  }
369
367
 
370
368
  const workspaces = (Route.useLoaderData() as {
@@ -374,13 +372,13 @@ function PermissionsPage(): React.ReactElement {
374
372
  return (
375
373
  <div className="space-y-4">
376
374
  <div>
377
- <h1 className="text-2xl font-bold">{t('permissions.title')}</h1>
378
- <p className="text-sm text-muted-foreground mt-1">{t('permissions.subtitle')}</p>
375
+ <h1 className="text-2xl font-bold">{m.enterprise_permissions_title()}</h1>
376
+ <p className="text-sm text-muted-foreground mt-1">{m.enterprise_permissions_subtitle()}</p>
379
377
  </div>
380
378
 
381
379
  {workspaces.length > 0 && (
382
380
  <div className="flex items-center gap-2">
383
- <span className="text-sm text-muted-foreground">{t('permissions.workspaceLabel')}</span>
381
+ <span className="text-sm text-muted-foreground">{m.enterprise_permissions_workspaceLabel()}</span>
384
382
  {workspaces.map((ws) => (
385
383
  <Link
386
384
  key={ws.id}
@@ -400,18 +398,18 @@ function PermissionsPage(): React.ReactElement {
400
398
 
401
399
  {roles.length === 0 ? (
402
400
  <div className="rounded-lg border border-border p-8 text-center text-muted-foreground">
403
- {t('permissions.empty')}
401
+ {m.enterprise_permissions_empty()}
404
402
  </div>
405
403
  ) : (
406
404
  <div className="rounded-lg border border-border overflow-hidden">
407
405
  <Table>
408
406
  <TableHeader>
409
407
  <TableRow>
410
- <TableHead>{t('permissions.table.role')}</TableHead>
411
- <TableHead>{t('permissions.table.type')}</TableHead>
412
- <TableHead>{t('permissions.table.members')}</TableHead>
413
- <TableHead>{t('permissions.table.permissions')}</TableHead>
414
- <TableHead>{t('permissions.table.actions')}</TableHead>
408
+ <TableHead>{m.enterprise_permissions_table_role()}</TableHead>
409
+ <TableHead>{m.enterprise_permissions_table_type()}</TableHead>
410
+ <TableHead>{m.enterprise_permissions_table_members()}</TableHead>
411
+ <TableHead>{m.enterprise_permissions_table_permissions()}</TableHead>
412
+ <TableHead>{m.enterprise_permissions_table_actions()}</TableHead>
415
413
  </TableRow>
416
414
  </TableHeader>
417
415
  <TableBody>
@@ -420,7 +418,7 @@ function PermissionsPage(): React.ReactElement {
420
418
  <TableCell className="font-medium">{role.name}</TableCell>
421
419
  <TableCell>
422
420
  <Badge variant={role.isSystem ? 'default' : 'secondary'}>
423
- {role.isSystem ? t('permissions.type.system') : t('permissions.type.custom')}
421
+ {role.isSystem ? m.enterprise_permissions_type_system() : m.enterprise_permissions_type_custom()}
424
422
  </Badge>
425
423
  </TableCell>
426
424
  <TableCell>{role._count?.assignments}</TableCell>
@@ -443,7 +441,7 @@ function PermissionsPage(): React.ReactElement {
443
441
  className="text-primary hover:underline text-sm"
444
442
  onClick={() => handleOpenAssign(role)}
445
443
  >
446
- {t('permissions.action.viewAssignments')}
444
+ {m.enterprise_permissions_action_viewAssignments()}
447
445
  </button>
448
446
  <button
449
447
  type="button"
@@ -451,7 +449,7 @@ function PermissionsPage(): React.ReactElement {
451
449
  onClick={() => handleDelete(role)}
452
450
  disabled={role.isSystem}
453
451
  >
454
- {role.isSystem ? t('permissions.action.notAvailable') : t('permissions.action.delete')}
452
+ {role.isSystem ? m.enterprise_permissions_action_notAvailable() : m.enterprise_permissions_action_delete()}
455
453
  </button>
456
454
  </div>
457
455
  </TableCell>
@@ -464,7 +462,7 @@ function PermissionsPage(): React.ReactElement {
464
462
 
465
463
  {selectedWorkspaceId && (
466
464
  <div className="flex justify-end">
467
- <Button onClick={() => setCreateDialogOpen(true)}>{t('permissions.action.createRole')}</Button>
465
+ <Button onClick={() => setCreateDialogOpen(true)}>{m.enterprise_permissions_action_createRole()}</Button>
468
466
  </div>
469
467
  )}
470
468
 
@@ -472,11 +470,11 @@ function PermissionsPage(): React.ReactElement {
472
470
  open={createDialogOpen}
473
471
  onOpenChange={setCreateDialogOpen}
474
472
  workspaceId={selectedWorkspaceId}
475
- i18nLang={i18n.language}
473
+ i18nLang={getLocale()}
476
474
  onCreated={() => {
477
475
  if (selectedWorkspaceId) {
478
476
  listRoles({ data: { workspaceId: selectedWorkspaceId } })
479
- .then((result) => {
477
+ .then((result: any) => {
480
478
  const data = result as { items: RoleItem[] }
481
479
  setRoles(data.items)
482
480
  })
@@ -488,11 +486,11 @@ function PermissionsPage(): React.ReactElement {
488
486
  open={assignDialogOpen}
489
487
  onOpenChange={setAssignDialogOpen}
490
488
  role={selectedRole}
491
- i18nLang={i18n.language}
489
+ i18nLang={getLocale()}
492
490
  onAssigned={() => {
493
491
  if (selectedWorkspaceId) {
494
492
  listRoles({ data: { workspaceId: selectedWorkspaceId } })
495
- .then((result) => {
493
+ .then((result: any) => {
496
494
  const data = result as { items: RoleItem[] }
497
495
  setRoles(data.items)
498
496
  })
@@ -16,7 +16,7 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createLazyFileRoute } from '@tanstack/react-router'
19
- import { useTranslation } from 'react-i18next'
19
+ import { m } from '@/paraglide/messages.js'
20
20
  import { Settings } from 'lucide-react'
21
21
  import { PlaceholderPage } from '@/components/common/placeholder-page'
22
22
 
@@ -25,6 +25,5 @@ export const Route = createLazyFileRoute('/_nav/settings')({
25
25
  })
26
26
 
27
27
  function SettingsPage() {
28
- const { t } = useTranslation('common')
29
- return <PlaceholderPage title={t('settings.title')} icon={Settings} />
28
+ return <PlaceholderPage title={m.common_settings_title()} icon={Settings} />
30
29
  }
@@ -16,8 +16,8 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createLazyFileRoute } from '@tanstack/react-router'
19
+ import { m } from '@/paraglide/messages.js'
19
20
  import { useServerFn } from '@tanstack/react-start'
20
- import { useTranslation } from 'react-i18next'
21
21
  import { toast } from 'sonner'
22
22
  import type React from 'react'
23
23
  import { deleteSsoProviderFn, toggleSsoProviderFn } from '@/server/serverFns/sso-config'
@@ -33,7 +33,6 @@ export const Route = createLazyFileRoute('/_nav/sso')({
33
33
  })
34
34
 
35
35
  function SsoConfigPage(): React.ReactElement {
36
- const { t } = useTranslation('enterprise')
37
36
  const { items, total } = Route.useLoaderData() as {
38
37
  items: Array<{
39
38
  id: string
@@ -55,13 +54,16 @@ function SsoConfigPage(): React.ReactElement {
55
54
 
56
55
  const handleToggle = async (provider: typeof items[0]) => {
57
56
  await toggleFn({ data: { providerId: provider.id, enabled: !provider.enabled } })
58
- const key = !provider.enabled ? 'enabled' : 'disabled'
59
- toast.success(t('sso.toast.' + key, { name: provider.name }))
57
+ if (!provider.enabled) {
58
+ toast.success(m.enterprise_sso_toastEnabled({ name: provider.name }))
59
+ } else {
60
+ toast.success(m.enterprise_sso_toastDisabled({ name: provider.name }))
61
+ }
60
62
  }
61
63
 
62
64
  const handleDelete = async (provider: typeof items[0]) => {
63
65
  await deleteFn({ data: { providerId: provider.id } })
64
- toast.success(t('sso.toast.deleted', { name: provider.name }))
66
+ toast.success(m.enterprise_sso_toastDeleted({ name: provider.name }))
65
67
  }
66
68
 
67
69
  const TYPE_LABELS: Record<string, string> = {
@@ -75,26 +77,26 @@ function SsoConfigPage(): React.ReactElement {
75
77
  return (
76
78
  <div className="space-y-4">
77
79
  <div>
78
- <h1 className="text-2xl font-bold">{t('sso.title')}</h1>
79
- <p className="text-sm text-muted-foreground mt-1">{t('sso.subtitle', { count: total })}</p>
80
+ <h1 className="text-2xl font-bold">{m.enterprise_sso_title()}</h1>
81
+ <p className="text-sm text-muted-foreground mt-1">{m.enterprise_sso_subtitle({ count: total })}</p>
80
82
  </div>
81
83
 
82
84
  {items.length === 0 ? (
83
85
  <div className="rounded-lg border border-border p-8 text-center text-muted-foreground">
84
- {t('sso.empty')}
86
+ {m.enterprise_sso_empty()}
85
87
  </div>
86
88
  ) : (
87
89
  <div className="rounded-lg border border-border overflow-hidden">
88
90
  <table className="w-full text-sm">
89
91
  <thead>
90
92
  <tr className="border-b border-border bg-muted/50">
91
- <th className="p-3 text-left font-medium">{t('sso.table.name')}</th>
92
- <th className="p-3 text-left font-medium">{t('sso.table.type')}</th>
93
- <th className="p-3 text-left font-medium">{t('sso.table.domain')}</th>
94
- <th className="p-3 text-left font-medium">{t('sso.table.workspace')}</th>
95
- <th className="p-3 text-left font-medium">{t('sso.table.mappings')}</th>
96
- <th className="p-3 text-left font-medium">{t('sso.table.status')}</th>
97
- <th className="p-3 text-left font-medium">{t('sso.table.actions')}</th>
93
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_provider()}</th>
94
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_type()}</th>
95
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_domain()}</th>
96
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_workspace()}</th>
97
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_mappings()}</th>
98
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_statusLabel()}</th>
99
+ <th className="p-3 text-left font-medium">{m.enterprise_sso_actions()}</th>
98
100
  </tr>
99
101
  </thead>
100
102
  <tbody>
@@ -115,7 +117,7 @@ function SsoConfigPage(): React.ReactElement {
115
117
  : 'bg-muted text-muted-foreground'
116
118
  }`}
117
119
  >
118
- {provider.enabled ? t('sso.status.enabled') : t('sso.status.disabled')}
120
+ {provider.enabled ? m.enterprise_sso_enabled() : m.enterprise_sso_disabled()}
119
121
  </span>
120
122
  </td>
121
123
  <td className="p-3 flex items-center gap-2">
@@ -124,14 +126,14 @@ function SsoConfigPage(): React.ReactElement {
124
126
  className="text-primary hover:underline"
125
127
  onClick={() => handleToggle(provider)}
126
128
  >
127
- {provider.enabled ? t('sso.action.disable') : t('sso.action.enable')}
129
+ {provider.enabled ? m.enterprise_sso_actionDisable() : m.enterprise_sso_actionEnable()}
128
130
  </button>
129
131
  <button
130
132
  type="button"
131
133
  className="text-destructive hover:underline"
132
134
  onClick={() => handleDelete(provider)}
133
135
  >
134
- {t('sso.action.delete')}
136
+ {m.enterprise_sso_actionDelete()}
135
137
  </button>
136
138
  </td>
137
139
  </tr>