@h-ai/cli 1.0.0-beta.2 → 1.0.0-beta.20

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 (254) hide show
  1. package/README.en.md +74 -154
  2. package/README.ja.md +74 -154
  3. package/README.md +74 -154
  4. package/dist/{chunk-AKV2CQZV.js → chunk-2ZL5ORQ2.js} +316 -97
  5. package/dist/chunk-2ZL5ORQ2.js.map +1 -0
  6. package/dist/{chunk-EF7WOFWZ.js → chunk-L53P43B2.js} +1312 -163
  7. package/dist/chunk-L53P43B2.js.map +1 -0
  8. package/dist/cli-config-templates-LWMD2I6V.js +5 -0
  9. package/dist/{cli-config-templates-HHFHNXBN.js.map → cli-config-templates-LWMD2I6V.js.map} +1 -1
  10. package/dist/{cli-skill-templates-PN4FLGBC.js → cli-skill-templates-D6S2OQ6X.js} +3 -3
  11. package/dist/{cli-skill-templates-PN4FLGBC.js.map → cli-skill-templates-D6S2OQ6X.js.map} +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +30118 -3253
  14. package/dist/index.js.map +1 -1
  15. package/dist/metafile-esm.json +1 -1
  16. package/package.json +22 -18
  17. package/templates/README.md +45 -30
  18. package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -10
  19. package/templates/apps/admin/src/routes/+page.svelte.hbs +4 -4
  20. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +17 -7
  21. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +26 -6
  22. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +2 -2
  23. package/templates/apps/api/.dockerignore.hbs +10 -0
  24. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +8 -0
  25. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +6 -1
  26. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +13 -5
  27. package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +13 -5
  28. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
  29. package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +6 -2
  30. package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +24 -2
  31. package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +4 -4
  32. package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +74 -24
  33. package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
  34. package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +153 -37
  35. package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +39 -13
  36. package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +106 -33
  37. package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +3 -1
  38. package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
  39. package/templates/apps/api/e2e/api-serv.spec.ts.hbs +20 -3
  40. package/templates/apps/api/e2e/capture-evidence.ts.hbs +4 -1
  41. package/templates/apps/api/eslint.config.js.hbs +3 -1
  42. package/templates/apps/api/images/serv.Dockerfile.hbs +15 -10
  43. package/templates/apps/api/playwright.config.ts.hbs +23 -19
  44. package/templates/apps/api/pnpm-workspace.yaml.hbs +27 -16
  45. package/templates/apps/fullstack/.dockerignore.hbs +10 -0
  46. package/templates/apps/fullstack/.gitignore.hbs +7 -2
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +14 -12
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +5 -3
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +10 -2
  50. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +1 -1
  51. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +10 -2
  52. package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +0 -1
  53. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +0 -1
  54. package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +4 -1
  55. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +16 -4
  56. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +10 -8
  57. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +3 -3
  58. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +8 -2
  59. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +0 -1
  60. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +0 -2
  61. package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +4 -1
  62. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +16 -4
  63. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +2 -0
  64. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +9 -9
  65. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +10 -2
  66. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +1 -0
  67. package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +0 -1
  68. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +0 -2
  69. package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +4 -1
  70. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +19 -5
  71. package/templates/apps/fullstack/docs/security-configuration.md.hbs +4 -1
  72. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +140 -28
  73. package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +19 -5
  74. package/templates/apps/fullstack/eslint.config.js.hbs +3 -1
  75. package/templates/apps/fullstack/images/serv.Dockerfile.hbs +19 -11
  76. package/templates/apps/fullstack/images/web.Dockerfile.hbs +17 -8
  77. package/templates/apps/fullstack/package.json.hbs +2 -1
  78. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +7 -5
  79. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +114 -23
  80. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +57 -11
  81. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
  82. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +17 -7
  83. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +13 -7
  84. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +17 -7
  85. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +10 -4
  86. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +65 -30
  87. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
  88. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +1 -2
  89. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +69 -21
  90. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +21 -5
  91. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +63 -11
  92. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -1
  93. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -1
  94. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +147 -33
  95. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +43 -12
  96. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +146 -30
  97. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +33 -10
  98. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +142 -26
  99. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +6 -2
  100. package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
  101. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +48 -66
  102. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +1 -0
  103. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +1 -0
  104. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +1 -0
  105. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +9 -2
  106. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +0 -3
  107. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +15 -3
  108. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +33 -7
  109. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +16 -2
  110. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +104 -13
  111. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +37 -7
  112. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +9 -3
  113. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +25 -3
  114. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +133 -19
  115. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +14 -2
  116. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +66 -34
  117. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +132 -30
  118. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +8 -2
  119. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +23 -5
  120. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +143 -21
  121. package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -2
  122. package/templates/apps/fullstack/playwright.config.ts.hbs +25 -3
  123. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +30 -14
  124. package/templates/apps/h5/src/routes/+layout.svelte.hbs +74 -30
  125. package/templates/apps/h5/src/routes/+page.svelte.hbs +2 -2
  126. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +2 -2
  127. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +2 -2
  128. package/templates/apps/mobile-app/capacitor.config.ts.hbs +5 -2
  129. package/templates/apps/mobile-app/messages/en-US.json +2 -2
  130. package/templates/apps/mobile-app/messages/ja-JP.json +2 -2
  131. package/templates/apps/mobile-app/messages/zh-CN.json +2 -2
  132. package/templates/apps/mobile-app/src/App.svelte.hbs +17 -5
  133. package/templates/apps/mobile-app/src/lib/api.ts.hbs +20 -6
  134. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +8 -1
  135. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +6 -2
  136. package/templates/apps/mobile-app/src/lib/pages/profile.svelte.hbs +13 -1
  137. package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +5 -1
  138. package/templates/apps/website/scripts/static-website.mjs.hbs +19 -6
  139. package/templates/apps/website/src/routes/+layout.svelte.hbs +56 -29
  140. package/templates/apps/website/src/routes/+page.svelte.hbs +4 -4
  141. package/templates/apps/website/src/routes/about/+page.svelte.hbs +2 -2
  142. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +2 -2
  143. package/templates/apps/website/src/routes/services/+page.svelte.hbs +20 -5
  144. package/templates/base/.dockerignore.hbs +10 -0
  145. package/templates/base/.gitignore.hbs +7 -2
  146. package/templates/base/e2e/app.spec.ts.hbs +130 -36
  147. package/templates/base/eslint-rules.js +44 -25
  148. package/templates/base/eslint.config.js.hbs +3 -1
  149. package/templates/base/images/web.Dockerfile.hbs +25 -14
  150. package/templates/base/package.json.hbs +13 -7
  151. package/templates/base/patches/daisyui-5.7.50.patch +8 -0
  152. package/templates/base/patches/deepmerge-4.3.1.patch +51 -0
  153. package/templates/base/playwright.config.ts +3 -1
  154. package/templates/base/pnpm-workspace.yaml.hbs +33 -16
  155. package/templates/base/src/app.d.ts.hbs +1 -1
  156. package/templates/base/src/app.html.hbs +1 -0
  157. package/templates/base/src/hooks.server.ts.hbs +44 -33
  158. package/templates/base/src/lib/build-metadata.ts.hbs +0 -1
  159. package/templates/base/src/lib/server/init.ts.hbs +146 -35
  160. package/templates/base/src/lib/server/kit-config.ts.hbs +7 -4
  161. package/templates/base/src/routes/+layout.server.ts.hbs +2 -2
  162. package/templates/base/svelte.config.js.hbs +10 -100
  163. package/templates/base/tests/scaffold.test.ts.hbs +12 -3
  164. package/templates/base/tsconfig.json.hbs +7 -4
  165. package/templates/base/vite.config.ts.hbs +108 -14
  166. package/templates/base/vitest.config.ts.hbs +6 -2
  167. package/templates/features/ai/routes/api/chat/+server.ts +3 -1
  168. package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +3 -3
  169. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +3 -3
  170. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +3 -3
  171. package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +3 -3
  172. package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +3 -3
  173. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +3 -3
  174. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +3 -3
  175. package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +3 -3
  176. package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +3 -3
  177. package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +3 -3
  178. package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +3 -3
  179. package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +3 -3
  180. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +14 -3
  181. package/templates/shared/browser-check/startup.js +115 -0
  182. package/templates/shared/browser-check/update.css +37 -0
  183. package/templates/shared/browser-check/update.html +19 -0
  184. package/templates/shared/browser-startup.spec.ts +23 -0
  185. package/templates/shared/build-metadata.ts +18 -4
  186. package/templates/shared/e2e-env.ts +22 -6
  187. package/templates/shared/native-name.d.mts +5 -0
  188. package/templates/shared/native-name.mjs +94 -0
  189. package/templates/shared/public-base-path.mjs +17 -4
  190. package/templates/shared/run-e2e.mjs +46 -12
  191. package/templates/shared/run-node.mjs +56 -0
  192. package/templates/shared/run-tauri.mjs +74 -0
  193. package/templates/shared/vite-runtime-config.ts +9 -3
  194. package/templates/skills/AGENTS.md +10 -73
  195. package/templates/skills/bridges/admin/AGENTS.md +9 -65
  196. package/templates/skills/bridges/api/AGENTS.md +8 -59
  197. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +9 -54
  198. package/templates/skills/bridges/h5/AGENTS.md +8 -63
  199. package/templates/skills/bridges/mobile-app/AGENTS.md +8 -62
  200. package/templates/skills/bridges/website/AGENTS.md +8 -63
  201. package/templates/skills/hai-ai/SKILL.md +6 -2
  202. package/templates/skills/hai-ai/acp.md +153 -0
  203. package/templates/skills/hai-ai/guide.md +27 -12
  204. package/templates/skills/hai-ai/reference.md +24 -15
  205. package/templates/skills/hai-ai/resources.md +69 -0
  206. package/templates/skills/hai-api-client/SKILL.md +1 -1
  207. package/templates/skills/hai-api-client/reference.md +3 -1
  208. package/templates/skills/hai-app-create/collaboration.md +7 -0
  209. package/templates/skills/hai-app-create/development.md +19 -10
  210. package/templates/skills/hai-app-create/project.md +33 -0
  211. package/templates/skills/hai-app-create/reference.md +10 -10
  212. package/templates/skills/hai-app-tests/reference.md +1 -1
  213. package/templates/skills/hai-app-tests/validation.md +1 -0
  214. package/templates/skills/hai-build/SKILL.md +19 -9
  215. package/templates/skills/hai-build/paths.md +4 -2
  216. package/templates/skills/hai-build/reference.md +26 -8
  217. package/templates/skills/hai-cache/reference.md +6 -2
  218. package/templates/skills/hai-capacitor/SKILL.md +1 -0
  219. package/templates/skills/hai-capacitor/reference.md +24 -0
  220. package/templates/skills/hai-ci/SKILL.md +3 -0
  221. package/templates/skills/hai-core/SKILL.md +9 -4
  222. package/templates/skills/hai-core/reference.md +40 -10
  223. package/templates/skills/hai-core/request-access.md +2 -2
  224. package/templates/skills/hai-crypto/SKILL.md +2 -2
  225. package/templates/skills/hai-crypto/reference.md +7 -3
  226. package/templates/skills/hai-deploy/SKILL.md +41 -5
  227. package/templates/skills/hai-deploy/middleware.md +26 -14
  228. package/templates/skills/hai-framework-sync/SKILL.md +13 -9
  229. package/templates/skills/hai-framework-sync/sync.md +2 -0
  230. package/templates/skills/hai-iam/reference.md +2 -2
  231. package/templates/skills/hai-kit/SKILL.md +1 -1
  232. package/templates/skills/hai-kit/reference.md +19 -5
  233. package/templates/skills/hai-payment/reference.md +41 -17
  234. package/templates/skills/hai-reach/SKILL.md +3 -1
  235. package/templates/skills/hai-reach/reference.md +29 -9
  236. package/templates/skills/hai-reldb/SKILL.md +1 -1
  237. package/templates/skills/hai-reldb/reference.md +9 -2
  238. package/templates/skills/hai-scheduler/reference.md +1 -1
  239. package/templates/skills/hai-serv/SKILL.md +2 -1
  240. package/templates/skills/hai-serv/reference.md +26 -15
  241. package/templates/skills/hai-storage/reference.md +23 -6
  242. package/templates/skills/hai-ui/SKILL.md +8 -5
  243. package/templates/skills/hai-ui/charts.md +51 -0
  244. package/templates/skills/hai-ui/guide.md +1 -1
  245. package/templates/skills/hai-ui/reference.md +29 -38
  246. package/templates/skills/hai-vecdb/reference.md +8 -3
  247. package/dist/chunk-AKV2CQZV.js.map +0 -1
  248. package/dist/chunk-EF7WOFWZ.js.map +0 -1
  249. package/dist/chunk-MUHRBJSW.js +0 -29272
  250. package/dist/chunk-MUHRBJSW.js.map +0 -1
  251. package/dist/cli-config-templates-HHFHNXBN.js +0 -5
  252. package/dist/src-TEBHR5I5.js +0 -5
  253. package/dist/src-TEBHR5I5.js.map +0 -1
  254. package/templates/apps/fullstack/playwright.session-close.config.ts.hbs +0 -18
@@ -9,14 +9,44 @@
9
9
  const { store }: Props = $props()
10
10
  let selected = $state<AdminAuditLog | null>(null)
11
11
  const columns = $derived([
12
- { key: 'createdAt', sortable: true, label: m.created_at() },
13
- { key: 'username', label: m.audit_actor() },
14
- { key: 'action', sortable: true, label: m.audit_action() },
15
- { key: 'category', sortable: true, label: m.audit_category() },
16
- { key: 'outcome', sortable: true, label: m.audit_outcome() },
17
- { key: 'severity', sortable: true, label: m.audit_severity() },
18
- { key: 'resource', sortable: true, label: m.audit_resource() },
19
- { key: 'ipAddress', label: m.audit_ip() },
12
+ {
13
+ key: 'createdAt',
14
+ sortable: true,
15
+ label: m.created_at(),
16
+ },
17
+ {
18
+ key: 'username',
19
+ label: m.audit_actor(),
20
+ },
21
+ {
22
+ key: 'action',
23
+ sortable: true,
24
+ label: m.audit_action(),
25
+ },
26
+ {
27
+ key: 'category',
28
+ sortable: true,
29
+ label: m.audit_category(),
30
+ },
31
+ {
32
+ key: 'outcome',
33
+ sortable: true,
34
+ label: m.audit_outcome(),
35
+ },
36
+ {
37
+ key: 'severity',
38
+ sortable: true,
39
+ label: m.audit_severity(),
40
+ },
41
+ {
42
+ key: 'resource',
43
+ sortable: true,
44
+ label: m.audit_resource(),
45
+ },
46
+ {
47
+ key: 'ipAddress',
48
+ label: m.audit_ip(),
49
+ },
20
50
  ])
21
51
  </script>
22
52
 
@@ -30,7 +60,15 @@
30
60
  event.preventDefault()
31
61
  void store.queryAudit()
32
62
  }}>
33
- <FilterBar data-testid='audit-filters' activeCount={[store.auditAction, store.auditResource, store.auditStartDate, store.auditEndDate, store.auditCategory, store.auditOutcome, store.auditSeverity].filter(Boolean).length} onreset={() => {
63
+ <FilterBar data-testid='audit-filters' activeCount={[
64
+ store.auditAction,
65
+ store.auditResource,
66
+ store.auditStartDate,
67
+ store.auditEndDate,
68
+ store.auditCategory,
69
+ store.auditOutcome,
70
+ store.auditSeverity,
71
+ ].filter(Boolean).length} onreset={() => {
34
72
  store.auditAction = ''
35
73
  store.auditResource = ''
36
74
  store.auditStartDate = ''
@@ -48,9 +86,60 @@
48
86
  <FormField label={m.audit_resource()}><Input size='sm' id="audit-resource" bind:value={store.auditResource} placeholder={m.audit_resource_placeholder()} data-testid="audit-resource" /></FormField>
49
87
  <FormField label={m.audit_start()} for="audit-start"><input id="audit-start" type="date" class="input block h-9 min-w-0 w-full" bind:value={store.auditStartDate} /></FormField>
50
88
  <FormField label={m.audit_end()} for="audit-end"><input id="audit-end" type="date" class="input block h-9 min-w-0 w-full" bind:value={store.auditEndDate} /></FormField>
51
- <FormField label={m.audit_category()}><Select size='sm' bind:value={store.auditCategory} options={[{ value: '', label: m.audit_all() }, { value: 'system', label: m.audit_category_system() }, { value: 'business', label: m.audit_category_business() }]} data-testid='audit-category' /></FormField>
52
- <FormField label={m.audit_outcome()}><Select size='sm' bind:value={store.auditOutcome} options={[{ value: '', label: m.audit_all() }, { value: 'success', label: m.audit_success() }, { value: 'failure', label: m.audit_failure() }, { value: 'denied', label: m.audit_denied() }]} data-testid='audit-outcome' /></FormField>
53
- <FormField label={m.audit_severity()}><Select size='sm' bind:value={store.auditSeverity} options={[{ value: '', label: m.audit_all() }, { value: 'info', label: m.audit_info() }, { value: 'warning', label: m.audit_warning() }, { value: 'error', label: m.audit_error() }, { value: 'critical', label: m.audit_critical() }]} data-testid='audit-severity' /></FormField>
89
+ <FormField label={m.audit_category()}><Select size='sm' bind:value={store.auditCategory} options={[
90
+ {
91
+ value: '',
92
+ label: m.audit_all(),
93
+ },
94
+ {
95
+ value: 'system',
96
+ label: m.audit_category_system(),
97
+ },
98
+ {
99
+ value: 'business',
100
+ label: m.audit_category_business(),
101
+ },
102
+ ]} data-testid='audit-category' /></FormField>
103
+ <FormField label={m.audit_outcome()}><Select size='sm' bind:value={store.auditOutcome} options={[
104
+ {
105
+ value: '',
106
+ label: m.audit_all(),
107
+ },
108
+ {
109
+ value: 'success',
110
+ label: m.audit_success(),
111
+ },
112
+ {
113
+ value: 'failure',
114
+ label: m.audit_failure(),
115
+ },
116
+ {
117
+ value: 'denied',
118
+ label: m.audit_denied(),
119
+ },
120
+ ]} data-testid='audit-outcome' /></FormField>
121
+ <FormField label={m.audit_severity()}><Select size='sm' bind:value={store.auditSeverity} options={[
122
+ {
123
+ value: '',
124
+ label: m.audit_all(),
125
+ },
126
+ {
127
+ value: 'info',
128
+ label: m.audit_info(),
129
+ },
130
+ {
131
+ value: 'warning',
132
+ label: m.audit_warning(),
133
+ },
134
+ {
135
+ value: 'error',
136
+ label: m.audit_error(),
137
+ },
138
+ {
139
+ value: 'critical',
140
+ label: m.audit_critical(),
141
+ },
142
+ ]} data-testid='audit-severity' /></FormField>
54
143
  </FormLayout>
55
144
  <div class='w-full space-y-2'>
56
145
  <p class='text-xs text-base-content/60'>{m.audit_stats_hint()}</p>
@@ -81,7 +170,9 @@
81
170
  <dt>{m.audit_request_id()}</dt><dd class='break-all'>{selected.requestId ?? '—'}</dd>
82
171
  <dt>{m.audit_trace_id()}</dt><dd class='break-all'>{selected.traceId ?? '—'}</dd>
83
172
  <dt>{m.audit_scope()}</dt><dd class='break-all'>{selected.scopeId ?? '—'}</dd>
84
- <dt>{m.audit_actor_snapshot()}</dt><dd class='break-all'>{selected.actorSnapshot ? JSON.stringify(selected.actorSnapshot) : '—'}</dd>
173
+ <dt>{m.audit_actor_snapshot()}</dt><dd class='break-all'>{selected.actorSnapshot
174
+ ? JSON.stringify(selected.actorSnapshot)
175
+ : '—'}</dd>
85
176
  <dt class="text-base-content/50">{m.created_at()}</dt><dd>{store.formatDate(selected.createdAt)}</dd>
86
177
  <dt class="text-base-content/50">{m.audit_actor()}</dt><dd class="break-all">{selected.username || m.audit_system()}</dd>
87
178
  <dt class="text-base-content/50">{m.audit_action()}</dt><dd>{selected.action}</dd>
@@ -13,16 +13,32 @@
13
13
  import * as m from '../paraglide/messages.js'
14
14
 
15
15
  const { store }: { store: ManagementStore } = $props()
16
- let page = $state({ items: [] as FeedbackReportView[], total: 0, page: 1, pageSize: 20 })
16
+ let page = $state({
17
+ items: [] as FeedbackReportView[],
18
+ total: 0,
19
+ page: 1,
20
+ pageSize: 20,
21
+ })
17
22
  let query = $state<FeedbackListQuery>({ page: 1, pageSize: 20 })
18
23
  let selected = $state<Detail>()
19
- let evidence = $state({ items: [] as FeedbackEvidenceInput[], total: 0, page: 1, pageSize: 20 })
24
+ let evidence = $state({
25
+ items: [] as FeedbackEvidenceInput[],
26
+ total: 0,
27
+ page: 1,
28
+ pageSize: 20,
29
+ })
20
30
  let loading = $state(false)
21
31
  let error = $state('')
22
32
  let requestVersion = 0
23
33
  let detailVersion = 0
24
34
  let imageUrls = $state<Record<string, string>>({})
25
- const permissions = $derived({ read: store.hasPermission('feedback:read'), process: store.hasPermission('feedback:process'), reopen: store.hasPermission('feedback:reopen'), export: store.hasPermission('feedback:export'), retry: store.hasPermission('feedback:process') })
35
+ const permissions = $derived({
36
+ read: store.hasPermission('feedback:read'),
37
+ process: store.hasPermission('feedback:process'),
38
+ reopen: store.hasPermission('feedback:reopen'),
39
+ export: store.hasPermission('feedback:export'),
40
+ retry: store.hasPermission('feedback:process'),
41
+ })
26
42
  function view(report: FeedbackReport): FeedbackReportView {
27
43
  return { ...report, description: report.description || report.summary || '', appVersion: report.appVersion || '' }
28
44
  }
@@ -35,8 +51,12 @@
35
51
  const result = await managementApi.feedback.reports.list(next)
36
52
  if (!result.success)
37
53
  throw new Error(result.error.message, { cause: result.error })
38
- if (version === requestVersion)
39
- page = { ...result.data, items: result.data.items.map(view) }
54
+ if (version === requestVersion) {
55
+ page = {
56
+ ...result.data,
57
+ items: result.data.items.map(view),
58
+ }
59
+ }
40
60
  }
41
61
  catch (cause) {
42
62
  if (version === requestVersion)
@@ -114,7 +134,10 @@
114
134
  if (result.data.contentType.startsWith('image/') || result.data.contentType.startsWith('video/')) {
115
135
  if (imageUrls[id])
116
136
  URL.revokeObjectURL(imageUrls[id])
117
- imageUrls = { ...imageUrls, [id]: URL.createObjectURL(new Blob([new Uint8Array(feedbackDataBytes(result.data)).buffer], { type: result.data.contentType })) }
137
+ imageUrls = {
138
+ ...imageUrls,
139
+ [id]: URL.createObjectURL(new Blob([new Uint8Array(feedbackDataBytes(result.data)).buffer], { type: result.data.contentType })),
140
+ }
118
141
  }
119
142
  else {
120
143
  await downloadFeedback(feedbackDataBytes(result.data), result.data.name, result.data.contentType)
@@ -146,7 +169,14 @@
146
169
  <section data-testid='feedback-page' class='flex min-h-0 flex-1 flex-col gap-3'>
147
170
  <PageHeader title={m.nav_feedback()} class='mb-0' />
148
171
  {#if selected}
149
- <FeedbackDetail report={view(selected.report)} webhook={selected.jobs.find(job => job.type === 'webhook')} {evidence} history={selected.history.map(item => ({ id: item.id, actorId: item.userId, fromStatus: item.from, toStatus: item.to, createdAt: item.timestamp, note: item.note }))} {permissions}
172
+ <FeedbackDetail report={view(selected.report)} webhook={selected.jobs.find(job => job.type === 'webhook')} {evidence} history={selected.history.map(item => ({
173
+ id: item.id,
174
+ actorId: item.userId,
175
+ fromStatus: item.from,
176
+ toStatus: item.to,
177
+ createdAt: item.timestamp,
178
+ note: item.note,
179
+ }))} {permissions}
150
180
  attachments={selected.attachments.map(item => ({ ...item, mimeType: item.contentType, url: imageUrls[item.id] }))}
151
181
  onevidencequery={loadEvidence} onreplay={loadReplay} onstatus={status} onexport={exportBundle} onretry={retry}
152
182
  onattachment={item => attachment(item.id)} onclose={closeDetail} />
@@ -14,7 +14,9 @@
14
14
  let description = $state('')
15
15
  let permission = $state<AdminPermissionPolicy | null>(null)
16
16
  async function savePolicy(operations: string[]) {
17
- return permission ? store.savePermissionPolicy(permission.id, operations) : err(HaiCommonError.CONFLICT, m.home_error())
17
+ return permission
18
+ ? store.savePermissionPolicy(permission.id, operations)
19
+ : err(HaiCommonError.CONFLICT, m.home_error())
18
20
  }
19
21
  function edit(role: AdminRole) {
20
22
  editing = role
@@ -35,9 +37,13 @@
35
37
  <div class="grid gap-3 md:grid-cols-2">
36
38
  {#each store.roles as role (role.id)}
37
39
  <Card bordered shadow={false}>
38
- <div class="flex items-center justify-between gap-3"><h2 class="text-lg font-semibold">{roleLabel(role.code)}</h2><Badge variant={role.code === 'admin' ? 'primary' : 'ghost'}>{role.code}</Badge></div>
40
+ <div class="flex items-center justify-between gap-3"><h2 class="text-lg font-semibold">{roleLabel(role.code)}</h2><Badge variant={role.code === 'admin'
41
+ ? 'primary'
42
+ : 'ghost'}>{role.code}</Badge></div>
39
43
  <p class="mt-3 text-sm leading-6 text-base-content/60">{roleCapabilities(role.code)}</p>
40
- <p class="mt-4 text-xs text-base-content/45">{m.role_members({ count: String(role.userCount) })}</p>
44
+ <p class="mt-4 text-xs text-base-content/45">{m.role_members({
45
+ count: String(role.userCount),
46
+ })}</p>
41
47
  {#if role.description}<p class="mt-3 text-sm text-base-content/70">{role.description}</p>{/if}
42
48
  {#if role.code === 'admin' || role.code === 'user'}<div class="mt-5"><Button variant="outline" size="sm" onclick={() => edit(role)}>{m.role_edit()}</Button></div>{/if}
43
49
  </Card>
@@ -11,8 +11,24 @@
11
11
 
12
12
  interface Props { store: ManagementStore }
13
13
  const { store }: Props = $props()
14
- const languageOptions = $derived(locales.filter(locale => store.info?.supportedLocales.includes(locale)).map(locale => ({ value: locale, label: locale === 'zh-CN' ? '简体中文' : locale === 'ja-JP' ? '日本語' : 'English' })))
15
- const themeOptions = $derived(AVAILABLE_THEMES.map(theme => ({ value: theme, label: theme === 'high-contrast' ? m.theme_high_contrast() : theme === 'formal' ? m.theme_formal() : getThemeInfo(theme)?.name ?? theme })))
14
+ const languageOptions = $derived(locales.filter(locale => store.info?.supportedLocales.includes(locale)).map(locale => ({
15
+ value: locale,
16
+ label: locale === 'zh-CN'
17
+ ? '简体中文'
18
+ : locale === 'ja-JP'
19
+ ? '日本語'
20
+ : 'English',
21
+ })))
22
+ const themeOptions = $derived(AVAILABLE_THEMES.map(theme => ({
23
+ value: theme,
24
+ label: theme === 'high-contrast'
25
+ ? m.theme_high_contrast()
26
+ : theme === 'formal'
27
+ ? m.theme_formal()
28
+ : theme === 'eye-care'
29
+ ? m.theme_eye_care()
30
+ : getThemeInfo(theme)?.name ?? theme,
31
+ })))
16
32
  </script>
17
33
 
18
34
  <section class='grid w-full min-w-0 gap-4 xl:grid-cols-2' data-testid='settings-page'>
@@ -21,7 +37,13 @@
21
37
  <Card class='xl:row-span-2' title={m.profile_title()} bordered shadow={false} data-guide='admin-profile-form'>
22
38
  <div class='mb-5 flex flex-wrap items-center gap-3 border-b border-base-content/8 pb-4'>
23
39
  <p class='min-w-0 break-all text-sm text-base-content/55'>@{store.user.username}</p>
24
- <Badge size='sm' variant='ghost'>{store.user.roles.filter((code): code is import('{{fullstack.contractPackageName}}').AdminRoleCode => ['admin', 'audit_admin', 'config_admin', 'business_operator', 'user'].includes(code)).map(roleLabel).join(', ')}</Badge>
40
+ <Badge size='sm' variant='ghost'>{store.user.roles.filter((code): code is import('{{fullstack.contractPackageName}}').AdminRoleCode => [
41
+ 'admin',
42
+ 'audit_admin',
43
+ 'config_admin',
44
+ 'business_operator',
45
+ 'user',
46
+ ].includes(code)).map(roleLabel).join(', ')}</Badge>
25
47
  </div>
26
48
  <UserProfile columns={2} user={store.user} editable alwaysEditable fields={['avatar', 'displayName', 'email']} avatarAccept='image/png,image/jpeg,image/webp' avatarHint={m.avatar_hint()} loading={store.saving} onsubmit={data => store.saveProfile(data)} onavatarchange={file => void store.uploadAvatar(file)} data-testid='profile-form' />
27
49
  </Card>
@@ -27,14 +27,53 @@
27
27
  let accountStatus = $state<'active' | 'dormant' | 'closed'>('active')
28
28
  let expiresAt = $state('')
29
29
  const columns = $derived([
30
- { key: 'username', sortable: true, label: m.user_account() },
31
- { key: 'email', sortable: true, label: m.user_email() },
32
- { key: 'roles', label: m.user_role() },
33
- { key: 'accountStatus', sortable: true, label: m.account_state() },
34
- { key: 'createdAt', sortable: true, label: m.created_at() },
30
+ {
31
+ key: 'username',
32
+ sortable: true,
33
+ label: m.user_account(),
34
+ },
35
+ {
36
+ key: 'email',
37
+ sortable: true,
38
+ label: m.user_email(),
39
+ },
40
+ {
41
+ key: 'roles',
42
+ label: m.user_role(),
43
+ },
44
+ {
45
+ key: 'accountStatus',
46
+ sortable: true,
47
+ label: m.account_state(),
48
+ },
49
+ {
50
+ key: 'createdAt',
51
+ sortable: true,
52
+ label: m.created_at(),
53
+ },
54
+ ])
55
+ const roleOptions = $derived(AdminRoleCodeSchema.options.map(value => ({
56
+ value,
57
+ label: roleLabel(value),
58
+ })))
59
+ const statusOptions = $derived([
60
+ {
61
+ value: 'all',
62
+ label: m.all_statuses(),
63
+ },
64
+ {
65
+ value: 'active',
66
+ label: m.account_active(),
67
+ },
68
+ {
69
+ value: 'dormant',
70
+ label: m.account_dormant(),
71
+ },
72
+ {
73
+ value: 'closed',
74
+ label: m.account_closed(),
75
+ },
35
76
  ])
36
- const roleOptions = $derived(AdminRoleCodeSchema.options.map(value => ({ value, label: roleLabel(value) })))
37
- const statusOptions = $derived([{ value: 'all', label: m.all_statuses() }, { value: 'active', label: m.account_active() }, { value: 'dormant', label: m.account_dormant() }, { value: 'closed', label: m.account_closed() }])
38
77
 
39
78
  function openEditor(user: AdminUser | null, useInvitation = false) {
40
79
  editing = user
@@ -47,17 +86,44 @@
47
86
  role = user?.roles[0] ?? 'user'
48
87
  accountType = user?.accountType ?? 'permanent'
49
88
  accountStatus = user?.accountStatus ?? 'active'
50
- expiresAt = user?.accountExpiresAt ? store.localDateTime(user.accountExpiresAt) : ''
89
+ expiresAt = user?.accountExpiresAt
90
+ ? store.localDateTime(user.accountExpiresAt)
91
+ : ''
51
92
  store.error = ''
52
93
  editorOpen = true
53
94
  }
54
95
 
55
96
  async function submit(event: SubmitEvent) {
56
97
  event.preventDefault()
57
- const fields = { displayName: displayName.trim(), role, accountType, accountStatus, accountExpiresAt: expiresAt ? new Date(expiresAt).toISOString() : null }
98
+ const fields = {
99
+ displayName: displayName.trim(),
100
+ role,
101
+ accountType,
102
+ accountStatus,
103
+ accountExpiresAt: expiresAt
104
+ ? new Date(expiresAt).toISOString()
105
+ : null,
106
+ }
58
107
  const saved = invitation && !editing
59
- ? await store.inviteUser({ username: username.trim(), email: email.trim() || undefined, phone: phone.trim() || undefined, ...fields, accountStatus: 'active' })
60
- : await store.saveUser(editing ? { id: editing.id, email: email.trim(), ...fields } : { username: username.trim(), password, email: email.trim() || undefined, ...fields })
108
+ ? await store.inviteUser({
109
+ username: username.trim(),
110
+ email: email.trim() || undefined,
111
+ phone: phone.trim() || undefined,
112
+ ...fields,
113
+ accountStatus: 'active',
114
+ })
115
+ : await store.saveUser(editing
116
+ ? {
117
+ id: editing.id,
118
+ email: email.trim(),
119
+ ...fields,
120
+ }
121
+ : {
122
+ username: username.trim(),
123
+ password,
124
+ email: email.trim() || undefined,
125
+ ...fields,
126
+ })
61
127
  if (saved) {
62
128
  editorOpen = false
63
129
  password = ''
@@ -94,7 +160,9 @@
94
160
  event.preventDefault()
95
161
  void store.queryUsers()
96
162
  }}>
97
- <FilterBar activeCount={store.usersStatus === 'all' ? 0 : 1} onreset={() => {
163
+ <FilterBar activeCount={store.usersStatus === 'all'
164
+ ? 0
165
+ : 1} onreset={() => {
98
166
  store.usersSearch = ''
99
167
  store.usersStatus = 'all'
100
168
  store.usersSortBy = 'createdAt'
@@ -115,9 +183,19 @@
115
183
  <div><p class='font-medium'>{user.displayName || user.username}</p><p class='text-xs text-base-content/45'>@{user.username}</p></div>
116
184
  </div>
117
185
  {:else if key === 'roles'}
118
- <Badge variant={user.roles.includes('admin') ? 'primary' : 'ghost'}>{user.roles.map(roleLabel).join(', ')}</Badge>
186
+ <Badge variant={user.roles.includes('admin')
187
+ ? 'primary'
188
+ : 'ghost'}>{user.roles.map(roleLabel).join(', ')}</Badge>
119
189
  {:else if key === 'accountStatus'}
120
- <Badge variant={user.accountStatus === 'active' ? 'success' : user.accountStatus === 'dormant' ? 'warning' : 'ghost'}>{user.accountStatus === 'active' ? m.account_active() : user.accountStatus === 'dormant' ? m.account_dormant() : m.account_closed()}</Badge>
190
+ <Badge variant={user.accountStatus === 'active'
191
+ ? 'success'
192
+ : user.accountStatus === 'dormant'
193
+ ? 'warning'
194
+ : 'ghost'}>{user.accountStatus === 'active'
195
+ ? m.account_active()
196
+ : user.accountStatus === 'dormant'
197
+ ? m.account_dormant()
198
+ : m.account_closed()}</Badge>
121
199
  {:else if key === 'createdAt'}
122
200
  <span class='whitespace-nowrap text-xs text-base-content/60'>{store.formatDate(user.createdAt)}</span>
123
201
  {:else if key === 'email'}
@@ -140,11 +218,21 @@
140
218
  <div class='flex items-center gap-3'>
141
219
  <Avatar name={user.displayName || user.username} src={user.avatarUrl} size='sm' />
142
220
  <div class='min-w-0 flex-1'><p class='truncate font-medium'>{user.displayName || user.username}</p><p class='truncate text-xs text-base-content/45'>@{user.username}</p></div>
143
- <Badge size='sm' variant={user.accountStatus === 'active' ? 'success' : user.accountStatus === 'dormant' ? 'warning' : 'ghost'}>{user.accountStatus === 'active' ? m.account_active() : user.accountStatus === 'dormant' ? m.account_dormant() : m.account_closed()}</Badge>
221
+ <Badge size='sm' variant={user.accountStatus === 'active'
222
+ ? 'success'
223
+ : user.accountStatus === 'dormant'
224
+ ? 'warning'
225
+ : 'ghost'}>{user.accountStatus === 'active'
226
+ ? m.account_active()
227
+ : user.accountStatus === 'dormant'
228
+ ? m.account_dormant()
229
+ : m.account_closed()}</Badge>
144
230
  </div>
145
231
  <p class='mt-3 truncate text-xs text-base-content/60' title={user.email}>{user.email || '—'}</p>
146
232
  <div class='mt-3 flex flex-wrap items-center justify-between gap-2'>
147
- <Badge size='sm' variant={user.roles.includes('admin') ? 'primary' : 'ghost'}>{user.roles.map(roleLabel).join(', ')}</Badge>
233
+ <Badge size='sm' variant={user.roles.includes('admin')
234
+ ? 'primary'
235
+ : 'ghost'}>{user.roles.map(roleLabel).join(', ')}</Badge>
148
236
  {@render userActions(user)}
149
237
  </div>
150
238
  </Card>
@@ -157,7 +245,11 @@
157
245
  </div>
158
246
  </section>
159
247
 
160
- <Modal bind:open={editorOpen} title={editing ? m.user_edit() : invitation ? m.invitation_title() : m.user_create()} closeOnBackdrop={!store.saving} closeOnEscape={!store.saving} size='3xl' data-testid='user-editor'>
248
+ <Modal bind:open={editorOpen} title={editing
249
+ ? m.user_edit()
250
+ : invitation
251
+ ? m.invitation_title()
252
+ : m.user_create()} closeOnBackdrop={!store.saving} closeOnEscape={!store.saving} size='3xl' data-testid='user-editor'>
161
253
  <form onsubmit={submit}>
162
254
  {#if invitation}<p class='mb-4 text-sm text-base-content/60'>{m.invitation_hint()}</p>{/if}
163
255
  <FormLayout columns={2} labelPosition='left' labelWidth='6rem'>
@@ -170,8 +262,30 @@
170
262
  <FormField label={m.user_password()} hint={m.initial_password_rules({ min: store.authConfig?.password.minLength ?? 8 })} required><PasswordInput required bind:value={password} autocomplete='new-password' minLength={store.authConfig?.password.minLength ?? 8} data-testid='user-password' /></FormField>
171
263
  {/if}
172
264
  {#if invitation && store.authConfig?.passwordReset.mode === 'phone'}<FormField label={m.invitation_phone()} required><Input type='tel' bind:value={phone} required maxlength={32} data-testid='invite-phone' /></FormField>{/if}
173
- <FormField label={m.account_type()}><Select bind:value={accountType} options={[{ value: 'permanent', label: m.account_permanent() }, { value: 'temporary', label: m.account_temporary() }]} data-testid='account-type' /></FormField>
174
- <FormField label={m.account_state()}><Select bind:value={accountStatus} disabled={invitation || editing?.id === store.user?.id} options={[{ value: 'active', label: m.account_active() }, { value: 'dormant', label: m.account_dormant() }, { value: 'closed', label: m.account_closed() }]} data-testid='account-state' /></FormField>
265
+ <FormField label={m.account_type()}><Select bind:value={accountType} options={[
266
+ {
267
+ value: 'permanent',
268
+ label: m.account_permanent(),
269
+ },
270
+ {
271
+ value: 'temporary',
272
+ label: m.account_temporary(),
273
+ },
274
+ ]} data-testid='account-type' /></FormField>
275
+ <FormField label={m.account_state()}><Select bind:value={accountStatus} disabled={invitation || editing?.id === store.user?.id} options={[
276
+ {
277
+ value: 'active',
278
+ label: m.account_active(),
279
+ },
280
+ {
281
+ value: 'dormant',
282
+ label: m.account_dormant(),
283
+ },
284
+ {
285
+ value: 'closed',
286
+ label: m.account_closed(),
287
+ },
288
+ ]} data-testid='account-state' /></FormField>
175
289
  <FormField label={m.account_expires()} required={accountType === 'temporary'}><Input type='datetime-local' bind:value={expiresAt} required={accountType === 'temporary'} data-testid='account-expires' /></FormField>
176
290
  <FormField label={m.user_role()}><Select bind:value={role} options={roleOptions} disabled={editing?.id === store.user?.id} data-testid='user-role' /></FormField>
177
291
  <div class='flex justify-end gap-2 border-t border-base-content/8 pt-4'>
@@ -2,11 +2,23 @@ import type { AdminRoleCode } from '{{fullstack.contractPackageName}}'
2
2
  import * as m from '../paraglide/messages.js'
3
3
 
4
4
  export function roleLabel(code: AdminRoleCode): string {
5
- const labels = { admin: m.role_admin, audit_admin: m.role_audit, config_admin: m.role_config, business_operator: m.role_operator, user: m.role_user }
5
+ const labels = {
6
+ admin: m.role_admin,
7
+ audit_admin: m.role_audit,
8
+ config_admin: m.role_config,
9
+ business_operator: m.role_operator,
10
+ user: m.role_user,
11
+ }
6
12
  return labels[code]()
7
13
  }
8
14
 
9
15
  export function roleCapabilities(code: AdminRoleCode): string {
10
- const labels = { admin: m.role_admin_capabilities, audit_admin: m.role_audit_capabilities, config_admin: m.role_config_capabilities, business_operator: m.role_operator_capabilities, user: m.role_user_capabilities }
16
+ const labels = {
17
+ admin: m.role_admin_capabilities,
18
+ audit_admin: m.role_audit_capabilities,
19
+ config_admin: m.role_config_capabilities,
20
+ business_operator: m.role_operator_capabilities,
21
+ user: m.role_user_capabilities,
22
+ }
11
23
  return labels[code]()
12
24
  }
@@ -17,39 +17,71 @@ export function createManagementGuide(store: ManagementStore, platform: 'web' |
17
17
  return createGuide({
18
18
  nav,
19
19
  persistKey: '{{projectName}}-guide',
20
- persistence: platform === 'web' ? 'cookie' : 'localStorage',
21
- tours: [{
22
- id: 'overview',
23
- title: () => m.guide_overview_title(),
24
- description: () => m.guide_overview_description(),
25
- steps: [
26
- { target: 'admin-content', title: () => m.guide_content_title(), description: () => m.guide_content_description() },
27
- { target: 'admin-profile', title: () => m.guide_profile_title(), description: () => m.guide_profile_description() },
28
- { target: 'admin-help', title: () => m.guide_help_title(), description: () => m.guide_help_description() },
29
- ],
30
- }, {
31
- id: 'profile',
32
- title: () => m.guide_profile_tour_title(),
33
- description: () => m.guide_profile_tour_description(),
34
- route: '/settings',
35
- steps: [
36
- { target: 'admin-profile-form', title: () => m.guide_profile_title(), description: () => m.guide_profile_form_description() },
37
- { target: 'admin-preferences', title: () => m.preferences_title(), description: () => m.guide_preferences_description() },
38
- { target: 'admin-password', title: () => m.guide_password_title(), description: () => m.guide_password_description() },
39
- ],
40
- }],
41
- articles: [{
42
- id: 'overview',
43
- title: () => m.guide_overview_title(),
44
- description: () => m.guide_overview_description(),
45
- content: () => m.guide_overview_article(),
46
- tourId: 'overview',
47
- }, {
48
- id: 'profile',
49
- title: () => m.guide_profile_tour_title(),
50
- description: () => m.guide_profile_tour_description(),
51
- content: () => m.guide_profile_article(),
52
- tourId: 'profile',
53
- }],
20
+ persistence: platform === 'web'
21
+ ? 'cookie'
22
+ : 'localStorage',
23
+ tours: [
24
+ {
25
+ id: 'overview',
26
+ title: () => m.guide_overview_title(),
27
+ description: () => m.guide_overview_description(),
28
+ steps: [
29
+ {
30
+ target: 'admin-content',
31
+ title: () => m.guide_content_title(),
32
+ description: () => m.guide_content_description(),
33
+ },
34
+ {
35
+ target: 'admin-profile',
36
+ title: () => m.guide_profile_title(),
37
+ description: () => m.guide_profile_description(),
38
+ },
39
+ {
40
+ target: 'admin-help',
41
+ title: () => m.guide_help_title(),
42
+ description: () => m.guide_help_description(),
43
+ },
44
+ ],
45
+ },
46
+ {
47
+ id: 'profile',
48
+ title: () => m.guide_profile_tour_title(),
49
+ description: () => m.guide_profile_tour_description(),
50
+ route: '/settings',
51
+ steps: [
52
+ {
53
+ target: 'admin-profile-form',
54
+ title: () => m.guide_profile_title(),
55
+ description: () => m.guide_profile_form_description(),
56
+ },
57
+ {
58
+ target: 'admin-preferences',
59
+ title: () => m.preferences_title(),
60
+ description: () => m.guide_preferences_description(),
61
+ },
62
+ {
63
+ target: 'admin-password',
64
+ title: () => m.guide_password_title(),
65
+ description: () => m.guide_password_description(),
66
+ },
67
+ ],
68
+ },
69
+ ],
70
+ articles: [
71
+ {
72
+ id: 'overview',
73
+ title: () => m.guide_overview_title(),
74
+ description: () => m.guide_overview_description(),
75
+ content: () => m.guide_overview_article(),
76
+ tourId: 'overview',
77
+ },
78
+ {
79
+ id: 'profile',
80
+ title: () => m.guide_profile_tour_title(),
81
+ description: () => m.guide_profile_tour_description(),
82
+ content: () => m.guide_profile_article(),
83
+ tourId: 'profile',
84
+ },
85
+ ],
54
86
  })
55
87
  }