@alepha/ui 0.18.2 → 0.18.3

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 (231) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Dy_k-4Vd.js} +2 -2
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Dy_k-4Vd.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-CKiFMSSU.js} +2 -2
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-CKiFMSSU.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-PhC_dZqo.js} +2 -2
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-PhC_dZqo.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-DFTjijGp.js} +2 -2
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-DFTjijGp.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D9E-CS-U.js} +2 -2
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D9E-CS-U.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-Ci9ue1zC.js} +2 -2
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-Ci9ue1zC.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-I6TlUMPc.js} +2 -2
  16. package/dist/admin/{AdminLayout-B1DXZHDn.js.map → AdminLayout-I6TlUMPc.js.map} +1 -1
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions-Bz5NRuoW.js} +2 -2
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions-Bz5NRuoW.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DuTUnjdG.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-CT_YDim0.js} +2 -2
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-CT_YDim0.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-D1UfGya9.js} +2 -2
  30. package/dist/admin/{AdminUsers-CR9z0g_5.js.map → AdminUsers-D1UfGya9.js.map} +1 -1
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/Login-xtNmQtGh.js +275 -0
  34. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  35. package/dist/admin/{Profile-B2EcIDB9.js → Profile-_AtPUwAP.js} +31 -27
  36. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  37. package/dist/admin/{Register-Z3fxRbUF.js → Register-JcCjHUUn.js} +198 -142
  38. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  39. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-CwGBPLJO.js} +7 -7
  40. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  41. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-hNxWejWf.js} +23 -8
  42. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  43. package/dist/admin/{core-BVO_TQxb.js → core-CYaRQ8O-.js} +709 -556
  44. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  45. package/dist/admin/index.d.ts +83 -44
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +58 -39
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-C161NeF6.js → AuthLayout-AvLlcLjS.js} +2 -2
  50. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  51. package/dist/auth/Login-BA1E8IZl.js +275 -0
  52. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  53. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-YcWdeuFz.js} +31 -27
  54. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  55. package/dist/auth/{Register-2gx8qll-.js → Register-CPhEO5MG.js} +198 -142
  56. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  57. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  58. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  59. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  60. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  61. package/dist/auth/{core-DyfeVr5c.js → core-D5jIAVF2.js} +386 -294
  62. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  63. package/dist/auth/index.d.ts +93 -48
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +28 -24
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +116 -61
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +873 -701
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-DN-ClJQk.js → AuthLayout-Brri4A-L.js} +2 -2
  72. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  73. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  74. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  75. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  76. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  77. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  78. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  79. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-CUWdLHim.js} +2 -2
  80. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  81. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-a8OhMMvq.js} +3 -3
  82. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  83. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C13OVDfS.js} +3 -3
  84. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  85. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-D_De3UiT.js} +2 -2
  86. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  87. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  88. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  89. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CHU8WTwO.js} +14 -5
  90. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  91. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-BBlrWpml.js} +49 -32
  92. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  93. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-BuNE3_-f.js} +49 -50
  94. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  95. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  96. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  97. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-Giy2HRBD.js} +3 -3
  98. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  99. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-ubcw-vog.js} +3 -3
  100. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-ubcw-vog.js.map} +1 -1
  101. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-9die_dYT.js} +2 -2
  102. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-9die_dYT.js.map} +1 -1
  103. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  104. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  105. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  106. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  107. package/dist/demo/Login-C12N4oGs.js +275 -0
  108. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  109. package/dist/demo/{Profile-BE_Y3co2.js → Profile-DS5q4vOh.js} +31 -27
  110. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  111. package/dist/demo/{Register-fXHmBpr3.js → Register-B4hLBeEv.js} +198 -142
  112. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  113. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  114. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  115. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D6Fxt4X4.js} +64 -65
  116. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  117. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  118. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  119. package/dist/demo/{auth-Djd7SKiw.js → auth-ByVTreDl.js} +8 -8
  120. package/dist/demo/{auth-Djd7SKiw.js.map → auth-ByVTreDl.js.map} +1 -1
  121. package/dist/demo/{core-B7LNjM78.js → core-DFgB3yU4.js} +741 -573
  122. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  123. package/dist/demo/index.d.ts +1 -0
  124. package/dist/demo/index.d.ts.map +1 -1
  125. package/dist/demo/index.js +24 -18
  126. package/dist/demo/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/admin/AdminRouter.tsx +24 -1
  129. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  130. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  131. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  132. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  133. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  134. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  135. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  136. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  137. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  138. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  139. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  140. package/src/auth/components/Login.tsx +188 -121
  141. package/src/auth/components/Profile.tsx +1 -22
  142. package/src/auth/components/ProfileField.tsx +39 -0
  143. package/src/auth/components/Register.tsx +215 -158
  144. package/src/auth/components/ResetPassword.tsx +7 -11
  145. package/src/auth/components/VerifyEmail.tsx +35 -10
  146. package/src/auth/components/buttons/UserButton.tsx +19 -21
  147. package/src/auth/index.ts +1 -0
  148. package/src/core/components/Flex.tsx +10 -0
  149. package/src/core/components/buttons/ActionButton.tsx +104 -78
  150. package/src/core/components/data/DetailDrawer.tsx +102 -96
  151. package/src/core/components/data/DetailList.tsx +2 -1
  152. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  153. package/src/core/components/layout/DashboardShell.tsx +18 -4
  154. package/src/core/components/layout/Sidebar.tsx +16 -241
  155. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  156. package/src/core/components/layout/SidebarItem.tsx +146 -0
  157. package/src/core/components/layout/index.ts +3 -1
  158. package/src/core/form/components/Control.tsx +31 -29
  159. package/src/core/form/components/ControlArray.tsx +13 -39
  160. package/src/core/form/components/ControlDate.tsx +10 -21
  161. package/src/core/form/components/ControlNumber.tsx +4 -33
  162. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  163. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  164. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  165. package/src/core/form/components/ControlSelect.tsx +294 -92
  166. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  167. package/src/core/form/components/TypeForm.tsx +5 -2
  168. package/src/core/form/index.ts +8 -1
  169. package/src/core/form/utils/parseInput.ts +7 -3
  170. package/src/core/index.ts +3 -1
  171. package/src/core/json/components/JsonViewer.tsx +103 -319
  172. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  173. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  174. package/src/core/json/components/JsonViewerShared.ts +76 -0
  175. package/src/core/styles.css +12 -2
  176. package/src/core/table/components/ColumnPicker.tsx +3 -3
  177. package/src/core/table/components/DataTable.tsx +89 -29
  178. package/src/core/table/components/DataTableFilters.tsx +6 -11
  179. package/src/core/table/components/DataTablePagination.tsx +9 -3
  180. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  181. package/src/core/table/components/FilterPicker.tsx +3 -3
  182. package/src/core/table/interfaces/types.ts +29 -0
  183. package/src/core/utils/icons.tsx +2 -2
  184. package/src/demo/DemoRouter.ts +8 -1
  185. package/src/demo/components/DemoLayout.tsx +12 -2
  186. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  187. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  188. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  189. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  190. package/src/demo/components/core/DemoButton.tsx +123 -103
  191. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  192. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  193. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  194. package/src/demo/components/shared/MacWindow.tsx +5 -11
  195. package/src/demo/components/shared/Showcase.tsx +28 -42
  196. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  197. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  198. package/dist/admin/Login-DHbYJKwg.js +0 -219
  199. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  200. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  201. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  202. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  203. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  204. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  205. package/dist/auth/Login-C7jIqf00.js +0 -219
  206. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  207. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  208. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  209. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  210. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  211. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  212. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  213. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  214. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  215. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  216. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  217. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  218. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  219. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  220. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  221. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  222. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  223. package/dist/demo/Login-CoYf_P_F.js +0 -219
  224. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  225. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  226. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  227. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  228. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  229. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  230. package/dist/demo/core-B7LNjM78.js.map +0 -1
  231. package/src/demo/styles.css +0 -0
@@ -1,13 +1,8 @@
1
- import { ActionButton, Flex, Text, TypeForm } from "@alepha/ui";
2
- import { Card, Code, Loader } from "@mantine/core";
3
- import { IconClock } from "@tabler/icons-react";
4
- import { jsonSchemaToTypeBox, type TObject, t } from "alepha";
5
- import { useForm } from "alepha/react/form";
6
- import { useI18n } from "alepha/react/i18n";
7
- import { useMemo } from "react";
8
- import { formatJson, type ParameterValue } from "./types.ts";
1
+ import ParameterDetailsConfigForm from "./ParameterDetailsConfigForm.tsx";
2
+ import ParameterDetailsLoading from "./ParameterDetailsLoading.tsx";
3
+ import type { ParameterValue } from "./types.ts";
9
4
 
10
- export interface ParameterDetailsProps {
5
+ interface Props {
11
6
  selectedConfig: string | null;
12
7
  configValue: ParameterValue | null;
13
8
  loading: boolean;
@@ -15,277 +10,24 @@ export interface ParameterDetailsProps {
15
10
  onSave: (values: Record<string, unknown>) => Promise<void>;
16
11
  }
17
12
 
18
- /**
19
- * Loading state.
20
- */
21
- const LoadingState = () => (
22
- <Flex
23
- flex={1}
24
- h="100%"
25
- p="md"
26
- style={{
27
- overflow: "hidden",
28
- minWidth: 0,
29
- display: "flex",
30
- }}
31
- >
32
- <Flex flex={1} justify="center" align="center" h="100%">
33
- <Loader size="sm" />
34
- </Flex>
35
- </Flex>
36
- );
37
-
38
- interface ConfigFormProps {
39
- selectedConfig: string;
40
- configValue: ParameterValue | null;
41
- saving: boolean;
42
- onSave: (values: Record<string, unknown>) => Promise<void>;
43
- }
44
-
45
- /**
46
- * The actual form component - only rendered when a config is selected.
47
- */
48
- const ConfigForm = ({
49
- selectedConfig,
50
- configValue,
51
- saving,
52
- onSave,
53
- }: ConfigFormProps) => {
54
- const { l } = useI18n();
55
-
56
- // Get the current value to display (from saved version or default)
57
- const currentContent = useMemo(() => {
58
- if (configValue?.current?.content) {
59
- return configValue.current.content;
60
- }
61
- if (configValue?.currentValue !== undefined) {
62
- return configValue.currentValue;
63
- }
64
- return null;
65
- }, [configValue]);
66
-
67
- // Convert JSON Schema from API to TypeBox schema
68
- const schemaForForm = useMemo(() => {
69
- if (!configValue?.schema) {
70
- return t.object({});
71
- }
72
- try {
73
- return jsonSchemaToTypeBox(configValue.schema) as TObject;
74
- } catch {
75
- return t.object({});
76
- }
77
- }, [configValue?.schema]);
78
-
79
- const form = useForm(
80
- {
81
- schema: schemaForForm,
82
- initialValues: (currentContent ?? {}) as Record<string, unknown>,
83
- handler: async (values) => {
84
- await onSave(values as Record<string, unknown>);
85
- },
86
- },
87
- [selectedConfig, schemaForForm, currentContent],
88
- );
89
-
90
- // Check if we have a valid schema with properties
91
- const hasValidSchema = useMemo(() => {
92
- const schema = configValue?.schema;
93
- return (
94
- schema &&
95
- typeof schema === "object" &&
96
- "properties" in schema &&
97
- Object.keys(schema.properties as object).length > 0
98
- );
99
- }, [configValue?.schema]);
100
-
101
- // Count the number of fields to determine column layout
102
- const fieldCount = useMemo(() => {
103
- const schema = configValue?.schema;
104
- if (
105
- schema &&
106
- typeof schema === "object" &&
107
- "properties" in schema &&
108
- schema.properties
109
- ) {
110
- return Object.keys(schema.properties as object).length;
111
- }
112
- return 0;
113
- }, [configValue?.schema]);
114
-
115
- // Determine optimal column count based on field count
116
- const columns = useMemo(() => {
117
- if (fieldCount <= 2) return 1;
118
- if (fieldCount <= 6) return 2;
119
- return 3;
120
- }, [fieldCount]);
121
-
122
- return (
123
- <Flex
124
- flex={1}
125
- h="100%"
126
- style={{
127
- overflow: "hidden",
128
- minWidth: 0,
129
- display: "flex",
130
- }}
131
- >
132
- <Flex direction="column" h="100%" w="100%" style={{ minHeight: 0 }}>
133
- {/* Content */}
134
- <Flex
135
- flex={1}
136
- p="md"
137
- className="overflow-auto"
138
- style={{ minHeight: 0 }}
139
- >
140
- {currentContent !== null ? (
141
- <Flex direction="column" gap="lg">
142
- {/* Form or JSON view */}
143
- <Flex>
144
- {hasValidSchema ? (
145
- <TypeForm
146
- form={form}
147
- columns={columns}
148
- skipSubmitButton
149
- fill={false}
150
- />
151
- ) : (
152
- <Flex>
153
- <Text size="xs" c="dimmed" mb={4}>
154
- Current Value
155
- </Text>
156
- <Code block style={{ whiteSpace: "pre-wrap" }}>
157
- {formatJson(currentContent)}
158
- </Code>
159
- </Flex>
160
- )}
161
- </Flex>
162
-
163
- {/* Metadata */}
164
- {configValue?.current?.changeDescription && (
165
- <Flex>
166
- <Text size="xs" c="dimmed" mb={4}>
167
- Change Description
168
- </Text>
169
- <Text size="sm">{configValue.current.changeDescription}</Text>
170
- </Flex>
171
- )}
172
-
173
- {configValue?.current && (
174
- <Flex gap="xl">
175
- <Flex>
176
- <Text size="xs" c="dimmed" mb={2}>
177
- Updated
178
- </Text>
179
- <Text size="sm">
180
- {l(configValue.current.updatedAt, { date: "fromNow" })}
181
- </Text>
182
- </Flex>
183
- {configValue.current.creatorName && (
184
- <Flex>
185
- <Text size="xs" c="dimmed" mb={2}>
186
- Updated By
187
- </Text>
188
- <Text size="sm">{configValue.current.creatorName}</Text>
189
- </Flex>
190
- )}
191
- </Flex>
192
- )}
193
-
194
- {!configValue?.current &&
195
- configValue?.currentValue !== undefined && (
196
- <Text size="xs" c="dimmed">
197
- This configuration is using its default value. No versions
198
- have been saved to the database yet.
199
- </Text>
200
- )}
201
-
202
- {/* Scheduled update preview */}
203
- {configValue?.next && (
204
- <Card withBorder p="sm" bg="var(--mantine-color-blue-light)">
205
- <Flex direction="column" gap="xs">
206
- <Flex gap="xs">
207
- <IconClock
208
- size={14}
209
- color="var(--mantine-color-blue-6)"
210
- />
211
- <Text size="xs" fw={500} c="blue">
212
- Scheduled Update (v{configValue.next.version})
213
- </Text>
214
- </Flex>
215
- <Text size="xs" c="dimmed">
216
- Activates{" "}
217
- {l(configValue.next.activationDate, {
218
- date: "fromNow",
219
- })}
220
- </Text>
221
- <Code block style={{ whiteSpace: "pre-wrap" }} fz="xs">
222
- {formatJson(configValue.next.content)}
223
- </Code>
224
- </Flex>
225
- </Card>
226
- )}
227
- </Flex>
228
- ) : (
229
- <Flex justify="center" align="center" h={200}>
230
- <Text c="dimmed" size="sm">
231
- No current value
232
- </Text>
233
- </Flex>
234
- )}
235
- </Flex>
236
-
237
- {/* Footer with actions */}
238
- {hasValidSchema && currentContent !== null && (
239
- <Flex
240
- p="md"
241
- style={{
242
- flexShrink: 0,
243
- borderTop: "1px solid var(--mantine-color-default-border)",
244
- }}
245
- >
246
- <Flex justify="flex-end" gap="sm">
247
- <ActionButton
248
- variant="subtle"
249
- onClick={() => form.reset({} as any)}
250
- disabled={saving}
251
- >
252
- Reset
253
- </ActionButton>
254
- <ActionButton intent="primary" form={form} loading={saving}>
255
- Save Changes
256
- </ActionButton>
257
- </Flex>
258
- </Flex>
259
- )}
260
- </Flex>
261
- </Flex>
262
- );
263
- };
264
-
265
13
  /**
266
14
  * Parameter details panel.
267
15
  * Shows loading state or the config form.
268
16
  * Note: Empty state is handled by parent (AdminParameters).
269
17
  */
270
- const ParameterDetails = ({
271
- selectedConfig,
272
- configValue,
273
- loading,
274
- saving,
275
- onSave,
276
- }: ParameterDetailsProps) => {
18
+ const ParameterDetails = (props: Props) => {
277
19
  // Loading state
278
- if (loading) {
279
- return <LoadingState />;
20
+ if (props.loading) {
21
+ return <ParameterDetailsLoading />;
280
22
  }
281
23
 
282
24
  // Config form (selectedConfig is guaranteed to be non-null by parent)
283
25
  return (
284
- <ConfigForm
285
- selectedConfig={selectedConfig!}
286
- configValue={configValue}
287
- saving={saving}
288
- onSave={onSave}
26
+ <ParameterDetailsConfigForm
27
+ selectedConfig={props.selectedConfig!}
28
+ configValue={props.configValue}
29
+ saving={props.saving}
30
+ onSave={props.onSave}
289
31
  />
290
32
  );
291
33
  };
@@ -0,0 +1,238 @@
1
+ import { ActionButton, Flex, Text, TypeForm } from "@alepha/ui";
2
+ import { Card, Code } from "@mantine/core";
3
+ import { IconClock } from "@tabler/icons-react";
4
+ import { jsonSchemaToTypeBox, type TObject, t } from "alepha";
5
+ import { useForm } from "alepha/react/form";
6
+ import { useI18n } from "alepha/react/i18n";
7
+ import { useMemo } from "react";
8
+ import { formatJson, type ParameterValue } from "./types.ts";
9
+
10
+ interface Props {
11
+ selectedConfig: string;
12
+ configValue: ParameterValue | null;
13
+ saving: boolean;
14
+ onSave: (values: Record<string, unknown>) => Promise<void>;
15
+ }
16
+
17
+ /**
18
+ * The actual form component - only rendered when a config is selected.
19
+ */
20
+ const ParameterDetailsConfigForm = (props: Props) => {
21
+ const { l } = useI18n();
22
+
23
+ // Get the current value to display (from saved version or default)
24
+ const currentContent = useMemo(() => {
25
+ if (props.configValue?.current?.content) {
26
+ return props.configValue.current.content;
27
+ }
28
+ if (props.configValue?.currentValue !== undefined) {
29
+ return props.configValue.currentValue;
30
+ }
31
+ return null;
32
+ }, [props.configValue]);
33
+
34
+ // Convert JSON Schema from API to TypeBox schema
35
+ const schemaForForm = useMemo(() => {
36
+ if (!props.configValue?.schema) {
37
+ return t.object({});
38
+ }
39
+ try {
40
+ return jsonSchemaToTypeBox(props.configValue.schema) as TObject;
41
+ } catch {
42
+ return t.object({});
43
+ }
44
+ }, [props.configValue?.schema]);
45
+
46
+ const form = useForm(
47
+ {
48
+ schema: schemaForForm,
49
+ initialValues: (currentContent ?? {}) as Record<string, unknown>,
50
+ handler: async (values) => {
51
+ await props.onSave(values as Record<string, unknown>);
52
+ },
53
+ },
54
+ [props.selectedConfig, schemaForForm, currentContent],
55
+ );
56
+
57
+ // Check if we have a valid schema with properties
58
+ const hasValidSchema = useMemo(() => {
59
+ const schema = props.configValue?.schema;
60
+ return (
61
+ schema &&
62
+ typeof schema === "object" &&
63
+ "properties" in schema &&
64
+ Object.keys(schema.properties as object).length > 0
65
+ );
66
+ }, [props.configValue?.schema]);
67
+
68
+ // Count the number of fields to determine column layout
69
+ const fieldCount = useMemo(() => {
70
+ const schema = props.configValue?.schema;
71
+ if (
72
+ schema &&
73
+ typeof schema === "object" &&
74
+ "properties" in schema &&
75
+ schema.properties
76
+ ) {
77
+ return Object.keys(schema.properties as object).length;
78
+ }
79
+ return 0;
80
+ }, [props.configValue?.schema]);
81
+
82
+ // Determine optimal column count based on field count
83
+ const columns = useMemo(() => {
84
+ if (fieldCount <= 2) return 1;
85
+ if (fieldCount <= 6) return 2;
86
+ return 3;
87
+ }, [fieldCount]);
88
+
89
+ return (
90
+ <Flex
91
+ flex={1}
92
+ h="100%"
93
+ style={{
94
+ overflow: "hidden",
95
+ minWidth: 0,
96
+ display: "flex",
97
+ }}
98
+ >
99
+ <Flex direction="column" h="100%" w="100%" style={{ minHeight: 0 }}>
100
+ {/* Content */}
101
+ <Flex
102
+ flex={1}
103
+ p="md"
104
+ className="overflow-auto"
105
+ style={{ minHeight: 0 }}
106
+ >
107
+ {currentContent !== null ? (
108
+ <Flex direction="column" gap="lg">
109
+ {/* Form or JSON view */}
110
+ <Flex>
111
+ {hasValidSchema ? (
112
+ <TypeForm
113
+ form={form}
114
+ columns={columns}
115
+ skipSubmitButton
116
+ fill={false}
117
+ />
118
+ ) : (
119
+ <Flex>
120
+ <Text size="xs" c="dimmed" mb={4}>
121
+ Current Value
122
+ </Text>
123
+ <Code block style={{ whiteSpace: "pre-wrap" }}>
124
+ {formatJson(currentContent)}
125
+ </Code>
126
+ </Flex>
127
+ )}
128
+ </Flex>
129
+
130
+ {/* Metadata */}
131
+ {props.configValue?.current?.changeDescription && (
132
+ <Flex>
133
+ <Text size="xs" c="dimmed" mb={4}>
134
+ Change Description
135
+ </Text>
136
+ <Text size="sm">
137
+ {props.configValue.current.changeDescription}
138
+ </Text>
139
+ </Flex>
140
+ )}
141
+
142
+ {props.configValue?.current && (
143
+ <Flex gap="xl">
144
+ <Flex>
145
+ <Text size="xs" c="dimmed" mb={2}>
146
+ Updated
147
+ </Text>
148
+ <Text size="sm">
149
+ {l(props.configValue.current.updatedAt, {
150
+ date: "fromNow",
151
+ })}
152
+ </Text>
153
+ </Flex>
154
+ {props.configValue.current.creatorName && (
155
+ <Flex>
156
+ <Text size="xs" c="dimmed" mb={2}>
157
+ Updated By
158
+ </Text>
159
+ <Text size="sm">
160
+ {props.configValue.current.creatorName}
161
+ </Text>
162
+ </Flex>
163
+ )}
164
+ </Flex>
165
+ )}
166
+
167
+ {!props.configValue?.current &&
168
+ props.configValue?.currentValue !== undefined && (
169
+ <Text size="xs" c="dimmed">
170
+ This configuration is using its default value. No versions
171
+ have been saved to the database yet.
172
+ </Text>
173
+ )}
174
+
175
+ {/* Scheduled update preview */}
176
+ {props.configValue?.next && (
177
+ <Card withBorder p="sm" bg="var(--mantine-color-blue-light)">
178
+ <Flex direction="column" gap="xs">
179
+ <Flex gap="xs">
180
+ <IconClock
181
+ size={14}
182
+ color="var(--mantine-color-blue-6)"
183
+ />
184
+ <Text size="xs" fw={500} c="blue">
185
+ Scheduled Update (v{props.configValue.next.version})
186
+ </Text>
187
+ </Flex>
188
+ <Text size="xs" c="dimmed">
189
+ Activates{" "}
190
+ {l(props.configValue.next.activationDate, {
191
+ date: "fromNow",
192
+ })}
193
+ </Text>
194
+ <Code block style={{ whiteSpace: "pre-wrap" }} fz="xs">
195
+ {formatJson(props.configValue.next.content)}
196
+ </Code>
197
+ </Flex>
198
+ </Card>
199
+ )}
200
+ </Flex>
201
+ ) : (
202
+ <Flex justify="center" align="center" h={200}>
203
+ <Text c="dimmed" size="sm">
204
+ No current value
205
+ </Text>
206
+ </Flex>
207
+ )}
208
+ </Flex>
209
+
210
+ {/* Footer with actions */}
211
+ {hasValidSchema && currentContent !== null && (
212
+ <Flex
213
+ p="md"
214
+ style={{
215
+ flexShrink: 0,
216
+ borderTop: "1px solid var(--mantine-color-default-border)",
217
+ }}
218
+ >
219
+ <Flex justify="flex-end" gap="sm">
220
+ <ActionButton
221
+ variant="subtle"
222
+ onClick={() => form.reset({} as any)}
223
+ disabled={props.saving}
224
+ >
225
+ Reset
226
+ </ActionButton>
227
+ <ActionButton intent="primary" form={form} loading={props.saving}>
228
+ Save Changes
229
+ </ActionButton>
230
+ </Flex>
231
+ </Flex>
232
+ )}
233
+ </Flex>
234
+ </Flex>
235
+ );
236
+ };
237
+
238
+ export default ParameterDetailsConfigForm;
@@ -0,0 +1,24 @@
1
+ import { Flex } from "@alepha/ui";
2
+ import { Loader } from "@mantine/core";
3
+
4
+ /**
5
+ * Loading state for the parameter details panel.
6
+ */
7
+ const ParameterDetailsLoading = () => (
8
+ <Flex
9
+ flex={1}
10
+ h="100%"
11
+ p="md"
12
+ style={{
13
+ overflow: "hidden",
14
+ minWidth: 0,
15
+ display: "flex",
16
+ }}
17
+ >
18
+ <Flex flex={1} justify="center" align="center" h="100%">
19
+ <Loader size="sm" />
20
+ </Flex>
21
+ </Flex>
22
+ );
23
+
24
+ export default ParameterDetailsLoading;
@@ -5,22 +5,21 @@ import type { ParameterResponse } from "alepha/api/parameters";
5
5
  import { useI18n } from "alepha/react/i18n";
6
6
  import { getStatusColor } from "./types.ts";
7
7
 
8
- export interface ParameterHistoryProps {
8
+ interface Props {
9
9
  selectedConfig: string | null;
10
10
  history: ParameterResponse[];
11
11
  loading: boolean;
12
12
  onRollback: (version: number) => void;
13
13
  }
14
14
 
15
- const ParameterHistory = ({
16
- history,
17
- loading,
18
- onRollback,
19
- }: ParameterHistoryProps) => {
15
+ /**
16
+ * Parameter version history timeline panel.
17
+ */
18
+ const ParameterHistory = (props: Props) => {
20
19
  const { l } = useI18n();
21
20
 
22
21
  const renderContent = () => {
23
- if (loading) {
22
+ if (props.loading) {
24
23
  return (
25
24
  <Flex flex={1} justify="center" align="center">
26
25
  <Loader size="sm" />
@@ -28,7 +27,7 @@ const ParameterHistory = ({
28
27
  );
29
28
  }
30
29
 
31
- if (history.length === 0) {
30
+ if (props.history.length === 0) {
32
31
  return (
33
32
  <Flex flex={1} justify="center" align="center">
34
33
  <Text c="dimmed" size="xs">
@@ -41,11 +40,11 @@ const ParameterHistory = ({
41
40
  return (
42
41
  <ScrollArea flex={1} offsetScrollbars>
43
42
  <Timeline
44
- active={history.findIndex((h) => h.status === "current")}
43
+ active={props.history.findIndex((h) => h.status === "current")}
45
44
  bulletSize={24}
46
45
  lineWidth={2}
47
46
  >
48
- {history.map((version) => (
47
+ {props.history.map((version) => (
49
48
  <Timeline.Item
50
49
  key={version.id}
51
50
  bullet={
@@ -91,7 +90,7 @@ const ParameterHistory = ({
91
90
  <ActionButton
92
91
  size="compact-xs"
93
92
  variant="subtle"
94
- onClick={() => onRollback(version.version)}
93
+ onClick={() => props.onRollback(version.version)}
95
94
  >
96
95
  Rollback to this version
97
96
  </ActionButton>