@alepha/ui 0.18.2 → 0.19.0

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 (257) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Bt1PjO6o.js} +3 -4
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Bt1PjO6o.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-C7c1CN4c.js} +3 -4
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-C7c1CN4c.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-C3RXpTp6.js} +3 -4
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-C3RXpTp6.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-31ivR6Wq.js} +3 -4
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-31ivR6Wq.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BABLe7hL.js} +73 -25
  10. package/dist/admin/AdminJobDashboard-BABLe7hL.js.map +1 -0
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D-G8RIlr.js} +3 -4
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D-G8RIlr.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-oIS3K9NX.js} +3 -4
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-oIS3K9NX.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-BmZ9mtXh.js} +8 -25
  16. package/dist/admin/AdminLayout-BmZ9mtXh.js.map +1 -0
  17. package/dist/admin/AdminNotifications-DHdzksww.js +541 -0
  18. package/dist/admin/AdminNotifications-DHdzksww.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CyZQSXnN.js} +118 -112
  20. package/dist/admin/AdminParameters-CyZQSXnN.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions--xwELDSO.js} +3 -4
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions--xwELDSO.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-DvBTG5gd.js} +82 -115
  24. package/dist/admin/AdminUserLayout-DvBTG5gd.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-CzsPBl6Z.js} +7 -6
  26. package/dist/admin/AdminUserProfile-CzsPBl6Z.js.map +1 -0
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-C-aUnhVN.js} +3 -4
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-C-aUnhVN.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-BYwei5sj.js} +4 -4
  30. package/dist/admin/AdminUsers-BYwei5sj.js.map +1 -0
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-CkPGLJku.js} +3 -4
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-CkPGLJku.js.map} +1 -1
  33. package/dist/{demo/IconGoogle-CSQLPYwX.js → admin/IconGoogle-8Nkx6yax.js} +2 -4
  34. package/dist/admin/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  35. package/dist/admin/Login-DSBqNsZc.js +274 -0
  36. package/dist/admin/Login-DSBqNsZc.js.map +1 -0
  37. package/dist/admin/{Profile-B2EcIDB9.js → Profile-CDRjJo0P.js} +31 -29
  38. package/dist/admin/Profile-CDRjJo0P.js.map +1 -0
  39. package/dist/admin/{Register-Z3fxRbUF.js → Register-4QGFOnfh.js} +201 -146
  40. package/dist/admin/Register-4QGFOnfh.js.map +1 -0
  41. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-Gxc9L_mY.js} +9 -10
  42. package/dist/admin/ResetPassword-Gxc9L_mY.js.map +1 -0
  43. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-D7G5NnaN.js} +25 -11
  44. package/dist/admin/VerifyEmail-D7G5NnaN.js.map +1 -0
  45. package/dist/admin/adminUserAtom-DCi4wf-v.js +11 -0
  46. package/dist/admin/adminUserAtom-DCi4wf-v.js.map +1 -0
  47. package/dist/admin/{core-BVO_TQxb.js → core-D1AbU50V.js} +662 -570
  48. package/dist/admin/core-D1AbU50V.js.map +1 -0
  49. package/dist/admin/index.d.ts +141 -53
  50. package/dist/admin/index.d.ts.map +1 -1
  51. package/dist/admin/index.js +67 -49
  52. package/dist/admin/index.js.map +1 -1
  53. package/dist/admin/rolldown-runtime-CiIaOW0V.js +13 -0
  54. package/dist/{demo/AuthLayout-DN-ClJQk.js → auth/AuthLayout-CfRKcTqP.js} +3 -4
  55. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-CfRKcTqP.js.map} +1 -1
  56. package/dist/{admin/IconGoogle-Ch1m3Uzl.js → auth/IconGoogle-8Nkx6yax.js} +2 -4
  57. package/dist/auth/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  58. package/dist/auth/Login-DJyweoPS.js +274 -0
  59. package/dist/auth/Login-DJyweoPS.js.map +1 -0
  60. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-Cy93pNTw.js} +31 -29
  61. package/dist/auth/Profile-Cy93pNTw.js.map +1 -0
  62. package/dist/auth/{Register-2gx8qll-.js → Register-CSqzzitW.js} +201 -146
  63. package/dist/auth/Register-CSqzzitW.js.map +1 -0
  64. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-B61QPlQi.js} +9 -10
  65. package/dist/auth/ResetPassword-B61QPlQi.js.map +1 -0
  66. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-CqBJ11id.js} +25 -11
  67. package/dist/auth/VerifyEmail-CqBJ11id.js.map +1 -0
  68. package/dist/auth/{core-DyfeVr5c.js → core-C6D3pazL.js} +403 -343
  69. package/dist/auth/core-C6D3pazL.js.map +1 -0
  70. package/dist/auth/index.d.ts +93 -54
  71. package/dist/auth/index.d.ts.map +1 -1
  72. package/dist/auth/index.js +30 -31
  73. package/dist/auth/index.js.map +1 -1
  74. package/dist/auth/rolldown-runtime-CiIaOW0V.js +13 -0
  75. package/dist/core/index.d.ts +123 -62
  76. package/dist/core/index.d.ts.map +1 -1
  77. package/dist/core/index.js +878 -776
  78. package/dist/core/index.js.map +1 -1
  79. package/dist/{auth/AuthLayout-C161NeF6.js → demo/AuthLayout-Dq5tSLSc.js} +3 -4
  80. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Dq5tSLSc.js.map} +1 -1
  81. package/dist/demo/DemoButton-_Ws2w-J0.js +181 -0
  82. package/dist/demo/DemoButton-_Ws2w-J0.js.map +1 -0
  83. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js +304 -0
  84. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js.map +1 -0
  85. package/dist/demo/DemoDataTable-Hwf_UUni.js +361 -0
  86. package/dist/demo/DemoDataTable-Hwf_UUni.js.map +1 -0
  87. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-B01OMVRd.js} +3 -4
  88. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-B01OMVRd.js.map} +1 -1
  89. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-870PEl0V.js} +4 -5
  90. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-870PEl0V.js.map} +1 -1
  91. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C1YR27fz.js} +4 -5
  92. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C1YR27fz.js.map} +1 -1
  93. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-DRbL2eGf.js} +4 -5
  94. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-DRbL2eGf.js.map} +1 -1
  95. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-DoABiqBW.js} +4 -5
  96. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-DoABiqBW.js.map} +1 -1
  97. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CN_PDCX2.js} +16 -8
  98. package/dist/demo/DemoLayout-CN_PDCX2.js.map +1 -0
  99. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-B5x-ug3Q.js} +51 -35
  100. package/dist/demo/DemoLogin-B5x-ug3Q.js.map +1 -0
  101. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-Q6sg2xuV.js} +51 -53
  102. package/dist/demo/DemoRegister-Q6sg2xuV.js.map +1 -0
  103. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-DrqZfmEw.js} +14 -19
  104. package/dist/demo/DemoResetPassword-DrqZfmEw.js.map +1 -0
  105. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-CfKS6w1o.js} +4 -5
  106. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-CfKS6w1o.js.map} +1 -1
  107. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-pT6Gi5b5.js} +4 -5
  108. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-pT6Gi5b5.js.map} +1 -1
  109. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-I13NBzQQ.js} +3 -4
  110. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-I13NBzQQ.js.map} +1 -1
  111. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-BqzcrtvN.js} +9 -6
  112. package/dist/demo/DemoTypeForm-BqzcrtvN.js.map +1 -0
  113. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js +33 -0
  114. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js.map +1 -0
  115. package/dist/{auth/IconGoogle-Ch1m3Uzl.js → demo/IconGoogle-CwQy4G9y.js} +2 -4
  116. package/dist/demo/{IconGoogle-CSQLPYwX.js.map → IconGoogle-CwQy4G9y.js.map} +1 -1
  117. package/dist/demo/Login-CqG1iJbn.js +274 -0
  118. package/dist/demo/Login-CqG1iJbn.js.map +1 -0
  119. package/dist/demo/{Profile-BE_Y3co2.js → Profile-C0ojJCaG.js} +31 -29
  120. package/dist/demo/Profile-C0ojJCaG.js.map +1 -0
  121. package/dist/demo/{Register-fXHmBpr3.js → Register-KKZwr_lL.js} +201 -146
  122. package/dist/demo/Register-KKZwr_lL.js.map +1 -0
  123. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-DMrLFEtr.js} +9 -10
  124. package/dist/demo/ResetPassword-DMrLFEtr.js.map +1 -0
  125. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D49Wud2v.js} +65 -68
  126. package/dist/demo/Showcase-D49Wud2v.js.map +1 -0
  127. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BFCAFz6T.js} +25 -11
  128. package/dist/demo/VerifyEmail-BFCAFz6T.js.map +1 -0
  129. package/dist/demo/{auth-Djd7SKiw.js → auth-D9qTZzCa.js} +18 -35
  130. package/dist/demo/{auth-Djd7SKiw.js.map → auth-D9qTZzCa.js.map} +1 -1
  131. package/dist/demo/{core-B7LNjM78.js → core-DRtQklr3.js} +752 -647
  132. package/dist/demo/core-DRtQklr3.js.map +1 -0
  133. package/dist/demo/index.d.ts +1 -0
  134. package/dist/demo/index.d.ts.map +1 -1
  135. package/dist/demo/index.js +25 -22
  136. package/dist/demo/index.js.map +1 -1
  137. package/dist/demo/rolldown-runtime-CiIaOW0V.js +13 -0
  138. package/package.json +19 -19
  139. package/src/admin/AdminRouter.tsx +42 -2
  140. package/src/admin/atoms/adminUserAtom.ts +7 -0
  141. package/src/admin/components/AdminLayout.tsx +2 -14
  142. package/src/admin/components/jobs/AdminJobDashboard.tsx +51 -20
  143. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  144. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  145. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  146. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  147. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  148. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  149. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  150. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  151. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  152. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  153. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  154. package/src/admin/components/users/AdminUserLayout.tsx +84 -127
  155. package/src/admin/components/users/AdminUserProfile.tsx +5 -2
  156. package/src/admin/components/users/AdminUsers.tsx +1 -1
  157. package/src/auth/components/Login.tsx +188 -121
  158. package/src/auth/components/Profile.tsx +1 -22
  159. package/src/auth/components/ProfileField.tsx +39 -0
  160. package/src/auth/components/Register.tsx +215 -158
  161. package/src/auth/components/ResetPassword.tsx +7 -11
  162. package/src/auth/components/VerifyEmail.tsx +35 -10
  163. package/src/auth/components/buttons/UserButton.tsx +19 -21
  164. package/src/auth/index.ts +1 -0
  165. package/src/core/components/Flex.tsx +34 -0
  166. package/src/core/components/buttons/ActionButton.tsx +105 -78
  167. package/src/core/components/data/DetailDrawer.tsx +102 -96
  168. package/src/core/components/data/DetailList.tsx +2 -1
  169. package/src/core/components/dialogs/PromptDialog.tsx +1 -1
  170. package/src/core/components/layout/Breadcrumb.tsx +4 -7
  171. package/src/core/components/layout/DashboardShell.tsx +18 -4
  172. package/src/core/components/layout/Sidebar.tsx +16 -241
  173. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  174. package/src/core/components/layout/SidebarItem.tsx +146 -0
  175. package/src/core/components/layout/index.ts +3 -1
  176. package/src/core/form/components/Control.tsx +31 -29
  177. package/src/core/form/components/ControlArray.tsx +13 -39
  178. package/src/core/form/components/ControlDate.tsx +10 -21
  179. package/src/core/form/components/ControlNumber.tsx +4 -33
  180. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  181. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  182. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  183. package/src/core/form/components/ControlSelect.tsx +294 -92
  184. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  185. package/src/core/form/components/TypeForm.tsx +5 -2
  186. package/src/core/form/index.ts +8 -1
  187. package/src/core/form/utils/parseInput.ts +7 -3
  188. package/src/core/index.ts +3 -1
  189. package/src/core/json/components/JsonViewer.tsx +103 -319
  190. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  191. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  192. package/src/core/json/components/JsonViewerShared.ts +76 -0
  193. package/src/core/services/DialogService.tsx +2 -2
  194. package/src/core/styles.css +13 -2
  195. package/src/core/table/components/ColumnPicker.tsx +3 -3
  196. package/src/core/table/components/DataTable.tsx +88 -29
  197. package/src/core/table/components/DataTableFilters.tsx +6 -11
  198. package/src/core/table/components/DataTablePagination.tsx +9 -3
  199. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  200. package/src/core/table/components/FilterPicker.tsx +3 -3
  201. package/src/core/table/interfaces/types.ts +29 -0
  202. package/src/core/utils/icons.tsx +2 -2
  203. package/src/demo/DemoRouter.ts +8 -1
  204. package/src/demo/components/DemoLayout.tsx +12 -2
  205. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  206. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  207. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  208. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  209. package/src/demo/components/core/DemoButton.tsx +123 -103
  210. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  211. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  212. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  213. package/src/demo/components/shared/MacWindow.tsx +5 -11
  214. package/src/demo/components/shared/Showcase.tsx +28 -42
  215. package/dist/admin/AdminJobDashboard-KIOkeMgE.js.map +0 -1
  216. package/dist/admin/AdminLayout-B1DXZHDn.js.map +0 -1
  217. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  218. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  219. package/dist/admin/AdminUserProfile-DuTUnjdG.js.map +0 -1
  220. package/dist/admin/AdminUsers-CR9z0g_5.js.map +0 -1
  221. package/dist/admin/Login-DHbYJKwg.js +0 -219
  222. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  223. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  224. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  225. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  226. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  227. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  228. package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
  229. package/dist/auth/Login-C7jIqf00.js +0 -219
  230. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  231. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  232. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  233. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  234. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  235. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  236. package/dist/auth/rolldown-runtime-CjeV3_4I.js +0 -18
  237. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  238. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  239. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  240. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  241. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  242. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  243. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  244. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  245. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  246. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  247. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  248. package/dist/demo/Login-CoYf_P_F.js +0 -219
  249. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  250. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  251. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  252. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  253. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  254. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  255. package/dist/demo/core-B7LNjM78.js.map +0 -1
  256. package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
  257. package/src/demo/styles.css +0 -0
@@ -1,4 +1,4 @@
1
- import { _ as ActionButton, b as useToast, i as TypeForm, l as Flex$1, o as Text$1 } from "./core-BVO_TQxb.js";
1
+ import { _ as ActionButton, b as useToast, i as TypeForm, l as Flex$1, s as Text$1 } from "./core-D1AbU50V.js";
2
2
  import { jsonSchemaToTypeBox, t } from "alepha";
3
3
  import { useForm } from "alepha/react/form";
4
4
  import { useI18n } from "alepha/react/i18n";
@@ -7,7 +7,6 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { memo, useCallback, useEffect, useMemo, useState } from "react";
8
8
  import { IconArrowLeft, IconChevronDown, IconChevronRight, IconClock, IconFolder, IconFolderOpen, IconHistory, IconRefresh, IconSearch, IconSettings } from "@tabler/icons-react";
9
9
  import { useClient } from "alepha/react";
10
-
11
10
  //#region ../../src/admin/components/parameters/types.ts
12
11
  const getStatusColor = (status) => {
13
12
  switch (status) {
@@ -25,67 +24,46 @@ const formatJson = (obj) => {
25
24
  return String(obj);
26
25
  }
27
26
  };
28
-
29
27
  //#endregion
30
- //#region ../../src/admin/components/parameters/ParameterDetails.tsx
31
- /**
32
- * Loading state.
33
- */
34
- const LoadingState = () => /* @__PURE__ */ jsx(Flex$1, {
35
- flex: 1,
36
- h: "100%",
37
- p: "md",
38
- style: {
39
- overflow: "hidden",
40
- minWidth: 0,
41
- display: "flex"
42
- },
43
- children: /* @__PURE__ */ jsx(Flex$1, {
44
- flex: 1,
45
- justify: "center",
46
- align: "center",
47
- h: "100%",
48
- children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
49
- })
50
- });
28
+ //#region ../../src/admin/components/parameters/ParameterDetailsConfigForm.tsx
51
29
  /**
52
30
  * The actual form component - only rendered when a config is selected.
53
31
  */
54
- const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
32
+ const ParameterDetailsConfigForm = (props) => {
55
33
  const { l } = useI18n();
56
34
  const currentContent = useMemo(() => {
57
- if (configValue?.current?.content) return configValue.current.content;
58
- if (configValue?.currentValue !== void 0) return configValue.currentValue;
35
+ if (props.configValue?.current?.content) return props.configValue.current.content;
36
+ if (props.configValue?.currentValue !== void 0) return props.configValue.currentValue;
59
37
  return null;
60
- }, [configValue]);
38
+ }, [props.configValue]);
61
39
  const schemaForForm = useMemo(() => {
62
- if (!configValue?.schema) return t.object({});
40
+ if (!props.configValue?.schema) return t.object({});
63
41
  try {
64
- return jsonSchemaToTypeBox(configValue.schema);
42
+ return jsonSchemaToTypeBox(props.configValue.schema);
65
43
  } catch {
66
44
  return t.object({});
67
45
  }
68
- }, [configValue?.schema]);
46
+ }, [props.configValue?.schema]);
69
47
  const form = useForm({
70
48
  schema: schemaForForm,
71
49
  initialValues: currentContent ?? {},
72
50
  handler: async (values) => {
73
- await onSave(values);
51
+ await props.onSave(values);
74
52
  }
75
53
  }, [
76
- selectedConfig,
54
+ props.selectedConfig,
77
55
  schemaForForm,
78
56
  currentContent
79
57
  ]);
80
58
  const hasValidSchema = useMemo(() => {
81
- const schema = configValue?.schema;
59
+ const schema = props.configValue?.schema;
82
60
  return schema && typeof schema === "object" && "properties" in schema && Object.keys(schema.properties).length > 0;
83
- }, [configValue?.schema]);
61
+ }, [props.configValue?.schema]);
84
62
  const fieldCount = useMemo(() => {
85
- const schema = configValue?.schema;
63
+ const schema = props.configValue?.schema;
86
64
  if (schema && typeof schema === "object" && "properties" in schema && schema.properties) return Object.keys(schema.properties).length;
87
65
  return 0;
88
- }, [configValue?.schema]);
66
+ }, [props.configValue?.schema]);
89
67
  const columns = useMemo(() => {
90
68
  if (fieldCount <= 2) return 1;
91
69
  if (fieldCount <= 6) return 2;
@@ -128,16 +106,16 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
128
106
  style: { whiteSpace: "pre-wrap" },
129
107
  children: formatJson(currentContent)
130
108
  })] }) }),
131
- configValue?.current?.changeDescription && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
109
+ props.configValue?.current?.changeDescription && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
132
110
  size: "xs",
133
111
  c: "dimmed",
134
112
  mb: 4,
135
113
  children: "Change Description"
136
114
  }), /* @__PURE__ */ jsx(Text$1, {
137
115
  size: "sm",
138
- children: configValue.current.changeDescription
116
+ children: props.configValue.current.changeDescription
139
117
  })] }),
140
- configValue?.current && /* @__PURE__ */ jsxs(Flex$1, {
118
+ props.configValue?.current && /* @__PURE__ */ jsxs(Flex$1, {
141
119
  gap: "xl",
142
120
  children: [/* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
143
121
  size: "xs",
@@ -146,23 +124,23 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
146
124
  children: "Updated"
147
125
  }), /* @__PURE__ */ jsx(Text$1, {
148
126
  size: "sm",
149
- children: l(configValue.current.updatedAt, { date: "fromNow" })
150
- })] }), configValue.current.creatorName && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
127
+ children: l(props.configValue.current.updatedAt, { date: "fromNow" })
128
+ })] }), props.configValue.current.creatorName && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
151
129
  size: "xs",
152
130
  c: "dimmed",
153
131
  mb: 2,
154
132
  children: "Updated By"
155
133
  }), /* @__PURE__ */ jsx(Text$1, {
156
134
  size: "sm",
157
- children: configValue.current.creatorName
135
+ children: props.configValue.current.creatorName
158
136
  })] })]
159
137
  }),
160
- !configValue?.current && configValue?.currentValue !== void 0 && /* @__PURE__ */ jsx(Text$1, {
138
+ !props.configValue?.current && props.configValue?.currentValue !== void 0 && /* @__PURE__ */ jsx(Text$1, {
161
139
  size: "xs",
162
140
  c: "dimmed",
163
141
  children: "This configuration is using its default value. No versions have been saved to the database yet."
164
142
  }),
165
- configValue?.next && /* @__PURE__ */ jsx(Card, {
143
+ props.configValue?.next && /* @__PURE__ */ jsx(Card, {
166
144
  withBorder: true,
167
145
  p: "sm",
168
146
  bg: "var(--mantine-color-blue-light)",
@@ -181,7 +159,7 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
181
159
  c: "blue",
182
160
  children: [
183
161
  "Scheduled Update (v",
184
- configValue.next.version,
162
+ props.configValue.next.version,
185
163
  ")"
186
164
  ]
187
165
  })]
@@ -192,14 +170,14 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
192
170
  children: [
193
171
  "Activates",
194
172
  " ",
195
- l(configValue.next.activationDate, { date: "fromNow" })
173
+ l(props.configValue.next.activationDate, { date: "fromNow" })
196
174
  ]
197
175
  }),
198
176
  /* @__PURE__ */ jsx(Code, {
199
177
  block: true,
200
178
  style: { whiteSpace: "pre-wrap" },
201
179
  fz: "xs",
202
- children: formatJson(configValue.next.content)
180
+ children: formatJson(props.configValue.next.content)
203
181
  })
204
182
  ]
205
183
  })
@@ -227,12 +205,12 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
227
205
  children: [/* @__PURE__ */ jsx(ActionButton, {
228
206
  variant: "subtle",
229
207
  onClick: () => form.reset({}),
230
- disabled: saving,
208
+ disabled: props.saving,
231
209
  children: "Reset"
232
210
  }), /* @__PURE__ */ jsx(ActionButton, {
233
211
  intent: "primary",
234
212
  form,
235
- loading: saving,
213
+ loading: props.saving,
236
214
  children: "Save Changes"
237
215
  })]
238
216
  })
@@ -240,21 +218,44 @@ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
240
218
  })
241
219
  });
242
220
  };
221
+ //#endregion
222
+ //#region ../../src/admin/components/parameters/ParameterDetailsLoading.tsx
223
+ /**
224
+ * Loading state for the parameter details panel.
225
+ */
226
+ const ParameterDetailsLoading = () => /* @__PURE__ */ jsx(Flex$1, {
227
+ flex: 1,
228
+ h: "100%",
229
+ p: "md",
230
+ style: {
231
+ overflow: "hidden",
232
+ minWidth: 0,
233
+ display: "flex"
234
+ },
235
+ children: /* @__PURE__ */ jsx(Flex$1, {
236
+ flex: 1,
237
+ justify: "center",
238
+ align: "center",
239
+ h: "100%",
240
+ children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
241
+ })
242
+ });
243
+ //#endregion
244
+ //#region ../../src/admin/components/parameters/ParameterDetails.tsx
243
245
  /**
244
246
  * Parameter details panel.
245
247
  * Shows loading state or the config form.
246
248
  * Note: Empty state is handled by parent (AdminParameters).
247
249
  */
248
- const ParameterDetails = ({ selectedConfig, configValue, loading, saving, onSave }) => {
249
- if (loading) return /* @__PURE__ */ jsx(LoadingState, {});
250
- return /* @__PURE__ */ jsx(ConfigForm, {
251
- selectedConfig,
252
- configValue,
253
- saving,
254
- onSave
250
+ const ParameterDetails = (props) => {
251
+ if (props.loading) return /* @__PURE__ */ jsx(ParameterDetailsLoading, {});
252
+ return /* @__PURE__ */ jsx(ParameterDetailsConfigForm, {
253
+ selectedConfig: props.selectedConfig,
254
+ configValue: props.configValue,
255
+ saving: props.saving,
256
+ onSave: props.onSave
255
257
  });
256
258
  };
257
-
258
259
  //#endregion
259
260
  //#region ../../src/admin/components/parameters/ParameterEmptyState.tsx
260
261
  /**
@@ -292,19 +293,21 @@ const ParameterEmptyState = () => {
292
293
  })
293
294
  });
294
295
  };
295
-
296
296
  //#endregion
297
297
  //#region ../../src/admin/components/parameters/ParameterHistory.tsx
298
- const ParameterHistory = ({ history, loading, onRollback }) => {
298
+ /**
299
+ * Parameter version history timeline panel.
300
+ */
301
+ const ParameterHistory = (props) => {
299
302
  const { l } = useI18n();
300
303
  const renderContent = () => {
301
- if (loading) return /* @__PURE__ */ jsx(Flex$1, {
304
+ if (props.loading) return /* @__PURE__ */ jsx(Flex$1, {
302
305
  flex: 1,
303
306
  justify: "center",
304
307
  align: "center",
305
308
  children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
306
309
  });
307
- if (history.length === 0) return /* @__PURE__ */ jsx(Flex$1, {
310
+ if (props.history.length === 0) return /* @__PURE__ */ jsx(Flex$1, {
308
311
  flex: 1,
309
312
  justify: "center",
310
313
  align: "center",
@@ -318,10 +321,10 @@ const ParameterHistory = ({ history, loading, onRollback }) => {
318
321
  flex: 1,
319
322
  offsetScrollbars: true,
320
323
  children: /* @__PURE__ */ jsx(Timeline, {
321
- active: history.findIndex((h) => h.status === "current"),
324
+ active: props.history.findIndex((h) => h.status === "current"),
322
325
  bulletSize: 24,
323
326
  lineWidth: 2,
324
- children: history.map((version) => /* @__PURE__ */ jsx(Timeline.Item, {
327
+ children: props.history.map((version) => /* @__PURE__ */ jsx(Timeline.Item, {
325
328
  bullet: /* @__PURE__ */ jsx(Text$1, {
326
329
  size: "xs",
327
330
  fw: 500,
@@ -369,7 +372,7 @@ const ParameterHistory = ({ history, loading, onRollback }) => {
369
372
  version.status === "expired" && /* @__PURE__ */ jsx(ActionButton, {
370
373
  size: "compact-xs",
371
374
  variant: "subtle",
372
- onClick: () => onRollback(version.version),
375
+ onClick: () => props.onRollback(version.version),
373
376
  children: "Rollback to this version"
374
377
  })
375
378
  ]
@@ -408,44 +411,26 @@ const ParameterHistory = ({ history, loading, onRollback }) => {
408
411
  })
409
412
  });
410
413
  };
411
-
412
414
  //#endregion
413
- //#region ../../src/admin/components/parameters/ParameterTree.tsx
414
- /**
415
- * Filters tree nodes by search query.
416
- */
417
- const filterTree = (nodes, query) => {
418
- if (!query.trim()) return nodes;
419
- const lowerQuery = query.toLowerCase();
420
- return nodes.map((node) => {
421
- const filteredChildren = filterTree(node.children, query);
422
- const nameMatches = node.name.toLowerCase().includes(lowerQuery);
423
- const pathMatches = node.path.toLowerCase().includes(lowerQuery);
424
- if (nameMatches || pathMatches || filteredChildren.length > 0) return {
425
- ...node,
426
- children: filteredChildren
427
- };
428
- return null;
429
- }).filter((node) => node !== null);
430
- };
415
+ //#region ../../src/admin/components/parameters/ParameterTreeNode.tsx
431
416
  /**
432
417
  * Memoized tree node to prevent unnecessary re-renders.
433
418
  */
434
- const TreeNode = memo(({ node, level, selectedConfig, onSelect, expandedNodes, onToggle }) => {
419
+ const ParameterTreeNode = memo((props) => {
435
420
  const [isHovered, setIsHovered] = useState(false);
436
- const hasChildren = node.children.length > 0;
437
- const isExpanded = expandedNodes.has(node.path);
438
- const isSelected = selectedConfig === node.path;
421
+ const hasChildren = props.node.children.length > 0;
422
+ const isExpanded = props.expandedNodes.has(props.node.path);
423
+ const isSelected = props.selectedConfig === props.node.path;
439
424
  const isLeaf = !hasChildren;
440
425
  return /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(UnstyledButton, {
441
426
  onClick: useCallback(() => {
442
- if (hasChildren) onToggle(node.path);
443
- else onSelect(node.path);
427
+ if (hasChildren) props.onToggle(props.node.path);
428
+ else props.onSelect(props.node.path);
444
429
  }, [
445
430
  hasChildren,
446
- node.path,
447
- onToggle,
448
- onSelect
431
+ props.node.path,
432
+ props.onToggle,
433
+ props.onSelect
449
434
  ]),
450
435
  onMouseEnter: useCallback(() => setIsHovered(true), []),
451
436
  onMouseLeave: useCallback(() => setIsHovered(false), []),
@@ -455,7 +440,7 @@ const TreeNode = memo(({ node, level, selectedConfig, onSelect, expandedNodes, o
455
440
  gap: 6,
456
441
  wrap: "nowrap",
457
442
  p: "4px 8px",
458
- pl: 8 + level * 16,
443
+ pl: 8 + props.level * 16,
459
444
  style: {
460
445
  borderRadius: "var(--mantine-radius-sm)",
461
446
  backgroundColor: isSelected || isHovered ? "var(--mantine-color-default-hover)" : void 0
@@ -495,22 +480,41 @@ const TreeNode = memo(({ node, level, selectedConfig, onSelect, expandedNodes, o
495
480
  overflow: "hidden",
496
481
  textOverflow: "ellipsis"
497
482
  },
498
- children: node.name
483
+ children: props.node.name
499
484
  })]
500
485
  })
501
486
  }), hasChildren && /* @__PURE__ */ jsx(Collapse, {
502
487
  in: isExpanded,
503
- children: node.children.map((child) => /* @__PURE__ */ jsx(TreeNode, {
488
+ children: props.node.children.map((child) => /* @__PURE__ */ jsx(ParameterTreeNode, {
504
489
  node: child,
505
- level: level + 1,
506
- selectedConfig,
507
- onSelect,
508
- expandedNodes,
509
- onToggle
490
+ level: props.level + 1,
491
+ selectedConfig: props.selectedConfig,
492
+ onSelect: props.onSelect,
493
+ expandedNodes: props.expandedNodes,
494
+ onToggle: props.onToggle
510
495
  }, child.path))
511
496
  })] });
512
497
  });
513
- TreeNode.displayName = "TreeNode";
498
+ ParameterTreeNode.displayName = "ParameterTreeNode";
499
+ //#endregion
500
+ //#region ../../src/admin/components/parameters/ParameterTree.tsx
501
+ /**
502
+ * Filters tree nodes by search query.
503
+ */
504
+ const filterTree = (nodes, query) => {
505
+ if (!query.trim()) return nodes;
506
+ const lowerQuery = query.toLowerCase();
507
+ return nodes.map((node) => {
508
+ const filteredChildren = filterTree(node.children, query);
509
+ const nameMatches = node.name.toLowerCase().includes(lowerQuery);
510
+ const pathMatches = node.path.toLowerCase().includes(lowerQuery);
511
+ if (nameMatches || pathMatches || filteredChildren.length > 0) return {
512
+ ...node,
513
+ children: filteredChildren
514
+ };
515
+ return null;
516
+ }).filter((node) => node !== null);
517
+ };
514
518
  /**
515
519
  * Collects all folder paths to expand by default.
516
520
  */
@@ -525,10 +529,13 @@ const collectAllFolderPaths = (nodes) => {
525
529
  traverse(nodes);
526
530
  return paths;
527
531
  };
528
- const ParameterTree = ({ treeData, selectedConfig, onSelect, onRefresh }) => {
532
+ /**
533
+ * Parameter tree sidebar with search and refresh.
534
+ */
535
+ const ParameterTree = (props) => {
529
536
  const [searchQuery, setSearchQuery] = useState("");
530
- const [expandedNodes, setExpandedNodes] = useState(() => collectAllFolderPaths(treeData));
531
- const filteredTreeData = useMemo(() => filterTree(treeData, searchQuery), [treeData, searchQuery]);
537
+ const [expandedNodes, setExpandedNodes] = useState(() => collectAllFolderPaths(props.treeData));
538
+ const filteredTreeData = useMemo(() => filterTree(props.treeData, searchQuery), [props.treeData, searchQuery]);
532
539
  const handleToggle = useCallback((path) => {
533
540
  setExpandedNodes((prev) => {
534
541
  const next = new Set(prev);
@@ -566,7 +573,7 @@ const ParameterTree = ({ treeData, selectedConfig, onSelect, onRefresh }) => {
566
573
  }), /* @__PURE__ */ jsx(ActionButton, {
567
574
  variant: "subtle",
568
575
  size: "compact-xs",
569
- onClick: onRefresh,
576
+ onClick: props.onRefresh,
570
577
  tooltip: "Refresh",
571
578
  children: /* @__PURE__ */ jsx(IconRefresh, { size: 14 })
572
579
  })]
@@ -592,11 +599,11 @@ const ParameterTree = ({ treeData, selectedConfig, onSelect, onRefresh }) => {
592
599
  direction: "column",
593
600
  gap: 0,
594
601
  style: { gap: 1 },
595
- children: filteredTreeData.map((node) => /* @__PURE__ */ jsx(TreeNode, {
602
+ children: filteredTreeData.map((node) => /* @__PURE__ */ jsx(ParameterTreeNode, {
596
603
  node,
597
604
  level: 0,
598
- selectedConfig,
599
- onSelect,
605
+ selectedConfig: props.selectedConfig,
606
+ onSelect: props.onSelect,
600
607
  expandedNodes,
601
608
  onToggle: handleToggle
602
609
  }, node.path))
@@ -606,7 +613,6 @@ const ParameterTree = ({ treeData, selectedConfig, onSelect, onRefresh }) => {
606
613
  })
607
614
  });
608
615
  };
609
-
610
616
  //#endregion
611
617
  //#region ../../src/admin/components/parameters/AdminParameters.tsx
612
618
  const AdminParameters = ({ treeData: initialTreeData }) => {
@@ -768,7 +774,7 @@ const AdminParameters = ({ treeData: initialTreeData }) => {
768
774
  })
769
775
  });
770
776
  };
771
-
772
777
  //#endregion
773
778
  export { AdminParameters as default };
774
- //# sourceMappingURL=AdminParameters-BspPeqp_.js.map
779
+
780
+ //# sourceMappingURL=AdminParameters-CyZQSXnN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminParameters-CyZQSXnN.js","names":["Flex","Text","Flex","Flex","Text","Flex","Text","Flex","Text","Flex","Text","Flex","Text"],"sources":["../../src/admin/components/parameters/types.ts","../../src/admin/components/parameters/ParameterDetailsConfigForm.tsx","../../src/admin/components/parameters/ParameterDetailsLoading.tsx","../../src/admin/components/parameters/ParameterDetails.tsx","../../src/admin/components/parameters/ParameterEmptyState.tsx","../../src/admin/components/parameters/ParameterHistory.tsx","../../src/admin/components/parameters/ParameterTreeNode.tsx","../../src/admin/components/parameters/ParameterTree.tsx","../../src/admin/components/parameters/AdminParameters.tsx"],"sourcesContent":["import type { ParameterResponse } from \"alepha/api/parameters\";\n\nexport interface ParameterValue {\n current?: ParameterResponse;\n next?: ParameterResponse;\n /**\n * Default value from the registered $parameter primitive.\n */\n defaultValue?: unknown;\n /**\n * Current in-memory value (may be default if never saved).\n */\n currentValue?: unknown;\n /**\n * TypeBox/JSON schema for the parameter (as JSON from API).\n */\n schema?: Record<string, unknown>;\n}\n\nexport const getStatusColor = (status: string) => {\n switch (status) {\n case \"current\":\n return \"green\";\n case \"next\":\n return \"blue\";\n case \"future\":\n return \"cyan\";\n case \"expired\":\n return \"gray\";\n default:\n return \"gray\";\n }\n};\n\nexport const formatJson = (obj: unknown): string => {\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return String(obj);\n }\n};\n","import { ActionButton, Flex, Text, TypeForm } from \"@alepha/ui\";\nimport { Card, Code } from \"@mantine/core\";\nimport { IconClock } from \"@tabler/icons-react\";\nimport { jsonSchemaToTypeBox, type TObject, t } from \"alepha\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useMemo } from \"react\";\nimport { formatJson, type ParameterValue } from \"./types.ts\";\n\ninterface Props {\n selectedConfig: string;\n configValue: ParameterValue | null;\n saving: boolean;\n onSave: (values: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * The actual form component - only rendered when a config is selected.\n */\nconst ParameterDetailsConfigForm = (props: Props) => {\n const { l } = useI18n();\n\n // Get the current value to display (from saved version or default)\n const currentContent = useMemo(() => {\n if (props.configValue?.current?.content) {\n return props.configValue.current.content;\n }\n if (props.configValue?.currentValue !== undefined) {\n return props.configValue.currentValue;\n }\n return null;\n }, [props.configValue]);\n\n // Convert JSON Schema from API to TypeBox schema\n const schemaForForm = useMemo(() => {\n if (!props.configValue?.schema) {\n return t.object({});\n }\n try {\n return jsonSchemaToTypeBox(props.configValue.schema) as TObject;\n } catch {\n return t.object({});\n }\n }, [props.configValue?.schema]);\n\n const form = useForm(\n {\n schema: schemaForForm,\n initialValues: (currentContent ?? {}) as Record<string, unknown>,\n handler: async (values) => {\n await props.onSave(values as Record<string, unknown>);\n },\n },\n [props.selectedConfig, schemaForForm, currentContent],\n );\n\n // Check if we have a valid schema with properties\n const hasValidSchema = useMemo(() => {\n const schema = props.configValue?.schema;\n return (\n schema &&\n typeof schema === \"object\" &&\n \"properties\" in schema &&\n Object.keys(schema.properties as object).length > 0\n );\n }, [props.configValue?.schema]);\n\n // Count the number of fields to determine column layout\n const fieldCount = useMemo(() => {\n const schema = props.configValue?.schema;\n if (\n schema &&\n typeof schema === \"object\" &&\n \"properties\" in schema &&\n schema.properties\n ) {\n return Object.keys(schema.properties as object).length;\n }\n return 0;\n }, [props.configValue?.schema]);\n\n // Determine optimal column count based on field count\n const columns = useMemo(() => {\n if (fieldCount <= 2) return 1;\n if (fieldCount <= 6) return 2;\n return 3;\n }, [fieldCount]);\n\n return (\n <Flex\n flex={1}\n h=\"100%\"\n style={{\n overflow: \"hidden\",\n minWidth: 0,\n display: \"flex\",\n }}\n >\n <Flex direction=\"column\" h=\"100%\" w=\"100%\" style={{ minHeight: 0 }}>\n {/* Content */}\n <Flex\n flex={1}\n p=\"md\"\n className=\"overflow-auto\"\n style={{ minHeight: 0 }}\n >\n {currentContent !== null ? (\n <Flex direction=\"column\" gap=\"lg\">\n {/* Form or JSON view */}\n <Flex>\n {hasValidSchema ? (\n <TypeForm\n form={form}\n columns={columns}\n skipSubmitButton\n fill={false}\n />\n ) : (\n <Flex>\n <Text size=\"xs\" c=\"dimmed\" mb={4}>\n Current Value\n </Text>\n <Code block style={{ whiteSpace: \"pre-wrap\" }}>\n {formatJson(currentContent)}\n </Code>\n </Flex>\n )}\n </Flex>\n\n {/* Metadata */}\n {props.configValue?.current?.changeDescription && (\n <Flex>\n <Text size=\"xs\" c=\"dimmed\" mb={4}>\n Change Description\n </Text>\n <Text size=\"sm\">\n {props.configValue.current.changeDescription}\n </Text>\n </Flex>\n )}\n\n {props.configValue?.current && (\n <Flex gap=\"xl\">\n <Flex>\n <Text size=\"xs\" c=\"dimmed\" mb={2}>\n Updated\n </Text>\n <Text size=\"sm\">\n {l(props.configValue.current.updatedAt, {\n date: \"fromNow\",\n })}\n </Text>\n </Flex>\n {props.configValue.current.creatorName && (\n <Flex>\n <Text size=\"xs\" c=\"dimmed\" mb={2}>\n Updated By\n </Text>\n <Text size=\"sm\">\n {props.configValue.current.creatorName}\n </Text>\n </Flex>\n )}\n </Flex>\n )}\n\n {!props.configValue?.current &&\n props.configValue?.currentValue !== undefined && (\n <Text size=\"xs\" c=\"dimmed\">\n This configuration is using its default value. No versions\n have been saved to the database yet.\n </Text>\n )}\n\n {/* Scheduled update preview */}\n {props.configValue?.next && (\n <Card withBorder p=\"sm\" bg=\"var(--mantine-color-blue-light)\">\n <Flex direction=\"column\" gap=\"xs\">\n <Flex gap=\"xs\">\n <IconClock\n size={14}\n color=\"var(--mantine-color-blue-6)\"\n />\n <Text size=\"xs\" fw={500} c=\"blue\">\n Scheduled Update (v{props.configValue.next.version})\n </Text>\n </Flex>\n <Text size=\"xs\" c=\"dimmed\">\n Activates{\" \"}\n {l(props.configValue.next.activationDate, {\n date: \"fromNow\",\n })}\n </Text>\n <Code block style={{ whiteSpace: \"pre-wrap\" }} fz=\"xs\">\n {formatJson(props.configValue.next.content)}\n </Code>\n </Flex>\n </Card>\n )}\n </Flex>\n ) : (\n <Flex justify=\"center\" align=\"center\" h={200}>\n <Text c=\"dimmed\" size=\"sm\">\n No current value\n </Text>\n </Flex>\n )}\n </Flex>\n\n {/* Footer with actions */}\n {hasValidSchema && currentContent !== null && (\n <Flex\n p=\"md\"\n style={{\n flexShrink: 0,\n borderTop: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex justify=\"flex-end\" gap=\"sm\">\n <ActionButton\n variant=\"subtle\"\n onClick={() => form.reset({} as any)}\n disabled={props.saving}\n >\n Reset\n </ActionButton>\n <ActionButton intent=\"primary\" form={form} loading={props.saving}>\n Save Changes\n </ActionButton>\n </Flex>\n </Flex>\n )}\n </Flex>\n </Flex>\n );\n};\n\nexport default ParameterDetailsConfigForm;\n","import { Flex } from \"@alepha/ui\";\nimport { Loader } from \"@mantine/core\";\n\n/**\n * Loading state for the parameter details panel.\n */\nconst ParameterDetailsLoading = () => (\n <Flex\n flex={1}\n h=\"100%\"\n p=\"md\"\n style={{\n overflow: \"hidden\",\n minWidth: 0,\n display: \"flex\",\n }}\n >\n <Flex flex={1} justify=\"center\" align=\"center\" h=\"100%\">\n <Loader size=\"sm\" />\n </Flex>\n </Flex>\n);\n\nexport default ParameterDetailsLoading;\n","import ParameterDetailsConfigForm from \"./ParameterDetailsConfigForm.tsx\";\nimport ParameterDetailsLoading from \"./ParameterDetailsLoading.tsx\";\nimport type { ParameterValue } from \"./types.ts\";\n\ninterface Props {\n selectedConfig: string | null;\n configValue: ParameterValue | null;\n loading: boolean;\n saving: boolean;\n onSave: (values: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * Parameter details panel.\n * Shows loading state or the config form.\n * Note: Empty state is handled by parent (AdminParameters).\n */\nconst ParameterDetails = (props: Props) => {\n // Loading state\n if (props.loading) {\n return <ParameterDetailsLoading />;\n }\n\n // Config form (selectedConfig is guaranteed to be non-null by parent)\n return (\n <ParameterDetailsConfigForm\n selectedConfig={props.selectedConfig!}\n configValue={props.configValue}\n saving={props.saving}\n onSave={props.onSave}\n />\n );\n};\n\nexport default ParameterDetails;\n","import { Flex, Text } from \"@alepha/ui\";\nimport { IconArrowLeft } from \"@tabler/icons-react\";\n\n/**\n * Empty state displayed when no parameter is selected.\n * Invites user to select a parameter from the tree.\n */\nconst ParameterEmptyState = () => {\n return (\n <Flex flex={1} p={\"xl\"} align=\"center\">\n <Flex direction=\"column\" align=\"center\" gap=\"md\">\n <IconArrowLeft size={32} color=\"var(--mantine-color-dimmed)\" />\n <Flex direction=\"column\" align=\"center\" gap={4}>\n <Text fw={500} c=\"dimmed\">\n No Parameter Selected\n </Text>\n <Text size=\"xs\" c=\"dimmed\" ta=\"center\" maw={240}>\n Choose a parameter from the tree to view and edit its configuration\n </Text>\n </Flex>\n </Flex>\n </Flex>\n );\n};\n\nexport default ParameterEmptyState;\n","import { ActionButton, Flex, Text } from \"@alepha/ui\";\nimport { Badge, Loader, ScrollArea, Timeline } from \"@mantine/core\";\nimport { IconHistory } from \"@tabler/icons-react\";\nimport type { ParameterResponse } from \"alepha/api/parameters\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { getStatusColor } from \"./types.ts\";\n\ninterface Props {\n selectedConfig: string | null;\n history: ParameterResponse[];\n loading: boolean;\n onRollback: (version: number) => void;\n}\n\n/**\n * Parameter version history timeline panel.\n */\nconst ParameterHistory = (props: Props) => {\n const { l } = useI18n();\n\n const renderContent = () => {\n if (props.loading) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Loader size=\"sm\" />\n </Flex>\n );\n }\n\n if (props.history.length === 0) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Text c=\"dimmed\" size=\"xs\">\n Empty\n </Text>\n </Flex>\n );\n }\n\n return (\n <ScrollArea flex={1} offsetScrollbars>\n <Timeline\n active={props.history.findIndex((h) => h.status === \"current\")}\n bulletSize={24}\n lineWidth={2}\n >\n {props.history.map((version) => (\n <Timeline.Item\n key={version.id}\n bullet={\n <Text size=\"xs\" fw={500}>\n {version.version}\n </Text>\n }\n title={\n <Flex gap=\"xs\">\n <Text size=\"xs\" fw={500}>\n Version {version.version}\n </Text>\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={getStatusColor(version.status)}\n >\n {version.status}\n </Badge>\n </Flex>\n }\n >\n <Flex direction=\"column\" gap={4} mt={4}>\n <Text size=\"xs\" c=\"dimmed\">\n {l(version.createdAt, { date: \"fromNow\" })}\n </Text>\n {version.changeDescription && (\n <Text size=\"xs\" lineClamp={2}>\n {version.changeDescription}\n </Text>\n )}\n {version.creatorName && (\n <Text size=\"xs\" c=\"dimmed\">\n by {version.creatorName}\n </Text>\n )}\n {version.migrationLog && (\n <Badge size=\"xs\" variant=\"outline\" color=\"orange\">\n Schema Changed\n </Badge>\n )}\n {version.status === \"expired\" && (\n <ActionButton\n size=\"compact-xs\"\n variant=\"subtle\"\n onClick={() => props.onRollback(version.version)}\n >\n Rollback to this version\n </ActionButton>\n )}\n </Flex>\n </Timeline.Item>\n ))}\n </Timeline>\n </ScrollArea>\n );\n };\n\n return (\n <Flex\n w={220}\n h=\"100%\"\n p=\"xs\"\n style={{\n flexShrink: 0,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n borderLeft: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex direction=\"column\" gap=\"xs\" h=\"100%\" style={{ minHeight: 0 }}>\n <Flex gap=\"xs\">\n <IconHistory size={16} color=\"var(--mantine-color-dimmed)\" />\n <Text size=\"sm\" fw={500}>\n History\n </Text>\n </Flex>\n {renderContent()}\n </Flex>\n </Flex>\n );\n};\n\nexport default ParameterHistory;\n","import { Flex, Text } from \"@alepha/ui\";\nimport { Collapse, UnstyledButton } from \"@mantine/core\";\nimport {\n IconChevronDown,\n IconChevronRight,\n IconFolder,\n IconFolderOpen,\n IconSettings,\n} from \"@tabler/icons-react\";\nimport type { ParameterTreeNode as ParameterTreeNodeData } from \"alepha/api/parameters\";\nimport { memo, useCallback, useState } from \"react\";\n\ninterface Props {\n node: ParameterTreeNodeData;\n level: number;\n selectedConfig: string | null;\n onSelect: (name: string) => void;\n expandedNodes: Set<string>;\n onToggle: (path: string) => void;\n}\n\n/**\n * Memoized tree node to prevent unnecessary re-renders.\n */\nconst ParameterTreeNode = memo((props: Props) => {\n const [isHovered, setIsHovered] = useState(false);\n const hasChildren = props.node.children.length > 0;\n const isExpanded = props.expandedNodes.has(props.node.path);\n const isSelected = props.selectedConfig === props.node.path;\n const isLeaf = !hasChildren;\n\n const handleClick = useCallback(() => {\n if (hasChildren) {\n props.onToggle(props.node.path);\n } else {\n props.onSelect(props.node.path);\n }\n }, [hasChildren, props.node.path, props.onToggle, props.onSelect]);\n\n const handleMouseEnter = useCallback(() => setIsHovered(true), []);\n const handleMouseLeave = useCallback(() => setIsHovered(false), []);\n\n return (\n <Flex>\n <UnstyledButton\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n w=\"100%\"\n style={{ display: \"block\" }}\n >\n <Flex\n gap={6}\n wrap=\"nowrap\"\n p=\"4px 8px\"\n pl={8 + props.level * 16}\n style={{\n borderRadius: \"var(--mantine-radius-sm)\",\n backgroundColor:\n isSelected || isHovered\n ? \"var(--mantine-color-default-hover)\"\n : undefined,\n }}\n >\n {hasChildren ? (\n <>\n <Flex\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n }}\n >\n {isExpanded ? (\n <IconChevronDown\n size={14}\n color=\"var(--mantine-color-dimmed)\"\n />\n ) : (\n <IconChevronRight\n size={14}\n color=\"var(--mantine-color-dimmed)\"\n />\n )}\n </Flex>\n {isExpanded ? (\n <IconFolderOpen\n size={16}\n color=\"var(--mantine-color-dimmed)\"\n style={{ flexShrink: 0 }}\n />\n ) : (\n <IconFolder\n size={16}\n color=\"var(--mantine-color-dimmed)\"\n style={{ flexShrink: 0 }}\n />\n )}\n </>\n ) : (\n <>\n <Flex w={16} />\n <IconSettings\n size={16}\n color={\n isSelected\n ? \"var(--mantine-color-blue-6)\"\n : \"var(--mantine-color-dimmed)\"\n }\n style={{ flexShrink: 0 }}\n />\n </>\n )}\n <Text\n size=\"sm\"\n fw={isSelected ? 600 : 400}\n c={isSelected ? undefined : isLeaf ? undefined : \"dimmed\"}\n style={{\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {props.node.name}\n </Text>\n </Flex>\n </UnstyledButton>\n\n {hasChildren && (\n <Collapse in={isExpanded}>\n {props.node.children.map((child: ParameterTreeNodeData) => (\n <ParameterTreeNode\n key={child.path}\n node={child}\n level={props.level + 1}\n selectedConfig={props.selectedConfig}\n onSelect={props.onSelect}\n expandedNodes={props.expandedNodes}\n onToggle={props.onToggle}\n />\n ))}\n </Collapse>\n )}\n </Flex>\n );\n});\n\nParameterTreeNode.displayName = \"ParameterTreeNode\";\n\nexport default ParameterTreeNode;\n","import { ActionButton, Flex, Text } from \"@alepha/ui\";\nimport { ScrollArea, TextInput } from \"@mantine/core\";\nimport { IconRefresh, IconSearch } from \"@tabler/icons-react\";\nimport type { ParameterTreeNode as ParameterTreeNodeData } from \"alepha/api/parameters\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport ParameterTreeNode from \"./ParameterTreeNode.tsx\";\n\n/**\n * Filters tree nodes by search query.\n */\nconst filterTree = (\n nodes: ParameterTreeNodeData[],\n query: string,\n): ParameterTreeNodeData[] => {\n if (!query.trim()) return nodes;\n\n const lowerQuery = query.toLowerCase();\n\n return nodes\n .map((node) => {\n const filteredChildren = filterTree(node.children, query);\n const nameMatches = node.name.toLowerCase().includes(lowerQuery);\n const pathMatches = node.path.toLowerCase().includes(lowerQuery);\n\n if (nameMatches || pathMatches || filteredChildren.length > 0) {\n return {\n ...node,\n children: filteredChildren,\n };\n }\n\n return null;\n })\n .filter((node): node is ParameterTreeNodeData => node !== null);\n};\n\n/**\n * Collects all folder paths to expand by default.\n */\nconst collectAllFolderPaths = (nodes: ParameterTreeNodeData[]): Set<string> => {\n const paths = new Set<string>();\n\n const traverse = (nodeList: ParameterTreeNodeData[]) => {\n for (const node of nodeList) {\n if (node.children.length > 0) {\n paths.add(node.path);\n traverse(node.children);\n }\n }\n };\n\n traverse(nodes);\n return paths;\n};\n\ninterface Props {\n treeData: ParameterTreeNodeData[];\n selectedConfig: string | null;\n onSelect: (name: string) => void;\n onRefresh: () => void;\n}\n\n/**\n * Parameter tree sidebar with search and refresh.\n */\nconst ParameterTree = (props: Props) => {\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [expandedNodes, setExpandedNodes] = useState<Set<string>>(() =>\n collectAllFolderPaths(props.treeData),\n );\n\n // Filter tree by search query\n const filteredTreeData = useMemo(\n () => filterTree(props.treeData, searchQuery),\n [props.treeData, searchQuery],\n );\n\n const handleToggle = useCallback((path: string) => {\n setExpandedNodes((prev) => {\n const next = new Set(prev);\n if (next.has(path)) {\n next.delete(path);\n } else {\n next.add(path);\n }\n return next;\n });\n }, []);\n\n const handleSearchChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchQuery(e.currentTarget.value);\n },\n [],\n );\n\n return (\n <Flex\n w={280}\n h=\"100%\"\n p=\"sm\"\n style={{\n flexShrink: 0,\n display: \"flex\",\n flexDirection: \"column\",\n borderRight: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex direction=\"column\" gap=\"sm\" h=\"100%\" style={{ minHeight: 0 }}>\n <Flex justify=\"space-between\" gap=\"xs\">\n <Text size=\"sm\" fw={600}>\n Parameters\n </Text>\n <ActionButton\n variant=\"subtle\"\n size=\"compact-xs\"\n onClick={props.onRefresh}\n tooltip=\"Refresh\"\n >\n <IconRefresh size={14} />\n </ActionButton>\n </Flex>\n\n <TextInput\n placeholder=\"Search...\"\n size=\"xs\"\n leftSection={<IconSearch size={14} />}\n value={searchQuery}\n onChange={handleSearchChange}\n />\n\n <ScrollArea flex={1} offsetScrollbars style={{ minHeight: 0 }}>\n {filteredTreeData.length === 0 ? (\n <Text size=\"xs\" c=\"dimmed\" ta=\"center\" py=\"md\">\n {searchQuery ? \"No matching parameters\" : \"No parameters\"}\n </Text>\n ) : (\n <Flex direction=\"column\" gap={0} style={{ gap: 1 }}>\n {filteredTreeData.map((node) => (\n <ParameterTreeNode\n key={node.path}\n node={node}\n level={0}\n selectedConfig={props.selectedConfig}\n onSelect={props.onSelect}\n expandedNodes={expandedNodes}\n onToggle={handleToggle}\n />\n ))}\n </Flex>\n )}\n </ScrollArea>\n </Flex>\n </Flex>\n );\n};\n\nexport default ParameterTree;\n","import { Flex, Text, useToast } from \"@alepha/ui\";\nimport { Card } from \"@mantine/core\";\nimport { IconSettings } from \"@tabler/icons-react\";\nimport type {\n AdminParameterController,\n ParameterResponse,\n ParameterTreeNode,\n} from \"alepha/api/parameters\";\nimport { useClient } from \"alepha/react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport ParameterDetails from \"./ParameterDetails.tsx\";\nimport ParameterEmptyState from \"./ParameterEmptyState.tsx\";\nimport ParameterHistory from \"./ParameterHistory.tsx\";\nimport ParameterTree from \"./ParameterTree.tsx\";\nimport type { ParameterValue } from \"./types.ts\";\n\nexport interface AdminParametersProps {\n treeData: ParameterTreeNode[];\n}\n\nconst AdminParameters = ({\n treeData: initialTreeData,\n}: AdminParametersProps) => {\n const client = useClient<AdminParameterController>();\n const toast = useToast();\n\n // State\n const [treeData, setTreeData] =\n useState<ParameterTreeNode[]>(initialTreeData);\n const [selectedConfig, setSelectedConfig] = useState<string | null>(null);\n const [configValue, setConfigValue] = useState<ParameterValue | null>(null);\n const [history, setHistory] = useState<ParameterResponse[]>([]);\n const [loadingConfig, setLoadingConfig] = useState(false);\n const [loadingHistory, setLoadingHistory] = useState(false);\n const [saving, setSaving] = useState(false);\n\n // Refresh tree data\n const handleRefresh = useCallback(async () => {\n try {\n const tree = await client.getParameterTree({});\n setTreeData(tree as ParameterTreeNode[]);\n } catch (error) {\n toast.danger({\n title: \"Failed to refresh parameters\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }, [client, toast]);\n\n // Load config value and history when selection changes\n const loadConfigDetails = useCallback(\n async (name: string) => {\n setLoadingConfig(true);\n setLoadingHistory(true);\n\n try {\n const [currentResponse, historyResponse] = await Promise.all([\n client.getCurrent({ params: { name } }),\n client.getHistory({ params: { name } }),\n ]);\n setConfigValue(currentResponse);\n setHistory(historyResponse.versions);\n } catch (error) {\n toast.danger({\n title: \"Failed to load configuration\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n setConfigValue(null);\n setHistory([]);\n } finally {\n setLoadingConfig(false);\n setLoadingHistory(false);\n }\n },\n [client, toast],\n );\n\n // Handle save\n const handleSave = useCallback(\n async (values: Record<string, unknown>) => {\n if (!selectedConfig || !configValue) return;\n\n setSaving(true);\n try {\n await client.createVersion({\n params: { name: selectedConfig },\n body: {\n content: values,\n schemaHash: \"\", // Schema hash is computed server-side when empty\n changeDescription: \"Updated via admin UI\",\n },\n });\n\n toast.success({\n title: \"Configuration saved\",\n message: `${selectedConfig} has been updated`,\n });\n\n // Reload details\n await loadConfigDetails(selectedConfig);\n } catch (error) {\n toast.danger({\n title: \"Failed to save configuration\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n throw error;\n } finally {\n setSaving(false);\n }\n },\n [client, selectedConfig, configValue, loadConfigDetails, toast],\n );\n\n // Load details when selection changes\n useEffect(() => {\n if (selectedConfig) {\n loadConfigDetails(selectedConfig);\n } else {\n setConfigValue(null);\n setHistory([]);\n }\n }, [selectedConfig, loadConfigDetails]);\n\n // Handle rollback\n const handleRollback = useCallback(\n async (version: number) => {\n if (!selectedConfig) return;\n\n try {\n await client.rollback({\n params: { name: selectedConfig },\n body: { targetVersion: version },\n });\n\n toast.success({\n title: \"Rollback successful\",\n message: `${selectedConfig} rolled back to version ${version}`,\n });\n\n // Reload details\n await loadConfigDetails(selectedConfig);\n } catch (error) {\n toast.danger({\n title: \"Rollback failed\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n },\n [client, selectedConfig, loadConfigDetails, toast],\n );\n\n // Empty state when no configs exist\n if (treeData.length === 0) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Flex direction=\"column\" align=\"center\" gap=\"xs\">\n <IconSettings\n size={48}\n stroke={1.5}\n color=\"var(--mantine-color-dimmed)\"\n />\n <Text c=\"dimmed\">No Parameters Found</Text>\n <Text size=\"xs\" c=\"dimmed\" ta=\"center\" maw={400}>\n Define parameters using the $parameter primitive to manage dynamic\n application settings. Parameters will appear here once created.\n </Text>\n </Flex>\n </Flex>\n );\n }\n\n return (\n <Flex flex={1} p=\"md\">\n <Card\n withBorder\n p={0}\n w={\"100%\"}\n style={{\n flexDirection: \"row\",\n }}\n >\n <ParameterTree\n treeData={treeData}\n selectedConfig={selectedConfig}\n onSelect={setSelectedConfig}\n onRefresh={handleRefresh}\n />\n\n {selectedConfig ? (\n <>\n <ParameterDetails\n selectedConfig={selectedConfig}\n configValue={configValue}\n loading={loadingConfig}\n saving={saving}\n onSave={handleSave}\n />\n\n <ParameterHistory\n selectedConfig={selectedConfig}\n history={history}\n loading={loadingHistory}\n onRollback={handleRollback}\n />\n </>\n ) : (\n <ParameterEmptyState />\n )}\n </Card>\n </Flex>\n );\n};\n\nexport default AdminParameters;\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { _ as ActionButton, b as useToast, l as Flex$1, m as useDialog, o as Text$1, r as DataTable } from "./core-BVO_TQxb.js";
1
+ import { _ as ActionButton, b as useToast, l as Flex$1, m as useDialog, r as DataTable, s as Text$1 } from "./core-D1AbU50V.js";
2
2
  import { t } from "alepha";
3
3
  import { useI18n } from "alepha/react/i18n";
4
4
  import { Badge } from "@mantine/core";
@@ -8,7 +8,6 @@ import { IconDeviceDesktop, IconDeviceMobile, IconDeviceTablet, IconTrash } from
8
8
  import { useRouter } from "alepha/react/router";
9
9
  import { useClient } from "alepha/react";
10
10
  import { sessions } from "alepha/api/users";
11
-
12
11
  //#region ../../src/admin/components/sessions/AdminSessions.tsx
13
12
  const filters = t.object({ userId: t.optional(t.uuid({ $control: { query: t.pick(sessions.schema, ["userId"]) } })) });
14
13
  const getDeviceIcon = (device) => {
@@ -132,7 +131,7 @@ const AdminSessions = (props) => {
132
131
  }, refreshKey)
133
132
  });
134
133
  };
135
-
136
134
  //#endregion
137
135
  export { AdminSessions as default };
138
- //# sourceMappingURL=AdminSessions-BnH5CZQl.js.map
136
+
137
+ //# sourceMappingURL=AdminSessions--xwELDSO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminSessions-BnH5CZQl.js","names":["Flex","Text"],"sources":["../../src/admin/components/sessions/AdminSessions.tsx"],"sourcesContent":["import {\n ActionButton,\n DataTable,\n Flex,\n Text,\n useDialog,\n useToast,\n} from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport {\n IconDeviceDesktop,\n IconDeviceMobile,\n IconDeviceTablet,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport {\n type AdminSessionController,\n type SessionEntity,\n sessions,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.tsx\";\n\nexport interface AdminSessionsProps {\n userRealmName?: string;\n}\n\nconst filters = t.object({\n userId: t.optional(\n t.uuid({\n $control: {\n query: t.pick(sessions.schema, [\"userId\"]),\n },\n }),\n ),\n});\n\nconst getDeviceIcon = (device?: string) => {\n switch (device) {\n case \"MOBILE\":\n return <IconDeviceMobile size={14} />;\n case \"TABLET\":\n return <IconDeviceTablet size={14} />;\n default:\n return <IconDeviceDesktop size={14} />;\n }\n};\n\nconst isExpired = (expiresAt: Date | string) =>\n new Date(expiresAt) < new Date();\n\nconst AdminSessions = (props: AdminSessionsProps) => {\n const client = useClient<AdminSessionController>();\n const router = useRouter<AdminRouter>();\n const { l } = useI18n();\n const dialog = useDialog();\n const toast = useToast();\n const [refreshKey, setRefreshKey] = useState(0);\n\n const handleDelete = async (session: SessionEntity) => {\n const confirmed = await dialog.confirm({\n title: \"Revoke session\",\n message:\n \"Are you sure you want to revoke this session? The user will be signed out.\",\n });\n if (!confirmed) return;\n await client.deleteSession({\n params: { id: session.id },\n query: { userRealmName: props.userRealmName },\n });\n toast.success(\"Session revoked\");\n setRefreshKey((k) => k + 1);\n };\n\n return (\n <Flex p=\"md\" flex={1} direction=\"column\">\n <DataTable<SessionEntity, typeof filters>\n key={refreshKey}\n submitOnInit\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n onFilterChange={(_key, _value, form) => form.submit()}\n filters={filters}\n tableTrProps={(item) => ({\n style: {\n opacity: isExpired(item.expiresAt) ? 0.5 : 1,\n },\n })}\n items={async (filters) => {\n const response = await client.findSessions({\n query: {\n ...filters,\n userRealmName: props.userRealmName,\n },\n });\n return response as Page<SessionEntity>;\n }}\n columns={{\n userId: {\n label: \"User\",\n value: (item) => (\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n href={router.path(\"adminUserProfile\", {\n params: { userId: item.userId },\n })}\n >\n <Text size=\"xs\" ff=\"monospace\">\n {item.userId.slice(0, 8)}...\n </Text>\n </ActionButton>\n ),\n },\n userAgent: {\n label: \"Device\",\n value: (item) => (\n <Flex gap={4} align=\"center\">\n {item.userAgent ? (\n <>\n {getDeviceIcon(item.userAgent.device)}\n <Text size=\"xs\">\n {item.userAgent.browser} / {item.userAgent.os}\n </Text>\n </>\n ) : (\n <Text size=\"xs\" muted>\n —\n </Text>\n )}\n </Flex>\n ),\n },\n ip: {\n label: \"IP\",\n value: (item) => (\n <Text size=\"xs\" ff=\"monospace\" muted>\n {item.ip || \"—\"}\n </Text>\n ),\n },\n expiresAt: {\n label: \"Status\",\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={isExpired(item.expiresAt) ? \"gray\" : \"green\"}\n >\n {isExpired(item.expiresAt) ? \"Expired\" : \"Active\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n value: (item) => (\n <Text size=\"xs\" muted>\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n rowActions={(item) => [\n {\n label: \"Revoke session\",\n icon: IconTrash,\n color: \"red\",\n onClick: () => handleDelete(item),\n visible: !isExpired(item.expiresAt),\n },\n ]}\n />\n </Flex>\n );\n};\n\nexport default AdminSessions;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminSessions--xwELDSO.js","names":["Flex","Text"],"sources":["../../src/admin/components/sessions/AdminSessions.tsx"],"sourcesContent":["import {\n ActionButton,\n DataTable,\n Flex,\n Text,\n useDialog,\n useToast,\n} from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport {\n IconDeviceDesktop,\n IconDeviceMobile,\n IconDeviceTablet,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport {\n type AdminSessionController,\n type SessionEntity,\n sessions,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.tsx\";\n\nexport interface AdminSessionsProps {\n userRealmName?: string;\n}\n\nconst filters = t.object({\n userId: t.optional(\n t.uuid({\n $control: {\n query: t.pick(sessions.schema, [\"userId\"]),\n },\n }),\n ),\n});\n\nconst getDeviceIcon = (device?: string) => {\n switch (device) {\n case \"MOBILE\":\n return <IconDeviceMobile size={14} />;\n case \"TABLET\":\n return <IconDeviceTablet size={14} />;\n default:\n return <IconDeviceDesktop size={14} />;\n }\n};\n\nconst isExpired = (expiresAt: Date | string) =>\n new Date(expiresAt) < new Date();\n\nconst AdminSessions = (props: AdminSessionsProps) => {\n const client = useClient<AdminSessionController>();\n const router = useRouter<AdminRouter>();\n const { l } = useI18n();\n const dialog = useDialog();\n const toast = useToast();\n const [refreshKey, setRefreshKey] = useState(0);\n\n const handleDelete = async (session: SessionEntity) => {\n const confirmed = await dialog.confirm({\n title: \"Revoke session\",\n message:\n \"Are you sure you want to revoke this session? The user will be signed out.\",\n });\n if (!confirmed) return;\n await client.deleteSession({\n params: { id: session.id },\n query: { userRealmName: props.userRealmName },\n });\n toast.success(\"Session revoked\");\n setRefreshKey((k) => k + 1);\n };\n\n return (\n <Flex p=\"md\" flex={1} direction=\"column\">\n <DataTable<SessionEntity, typeof filters>\n key={refreshKey}\n submitOnInit\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n onFilterChange={(_key, _value, form) => form.submit()}\n filters={filters}\n tableTrProps={(item) => ({\n style: {\n opacity: isExpired(item.expiresAt) ? 0.5 : 1,\n },\n })}\n items={async (filters) => {\n const response = await client.findSessions({\n query: {\n ...filters,\n userRealmName: props.userRealmName,\n },\n });\n return response as Page<SessionEntity>;\n }}\n columns={{\n userId: {\n label: \"User\",\n value: (item) => (\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n href={router.path(\"adminUserProfile\", {\n params: { userId: item.userId },\n })}\n >\n <Text size=\"xs\" ff=\"monospace\">\n {item.userId.slice(0, 8)}...\n </Text>\n </ActionButton>\n ),\n },\n userAgent: {\n label: \"Device\",\n value: (item) => (\n <Flex gap={4} align=\"center\">\n {item.userAgent ? (\n <>\n {getDeviceIcon(item.userAgent.device)}\n <Text size=\"xs\">\n {item.userAgent.browser} / {item.userAgent.os}\n </Text>\n </>\n ) : (\n <Text size=\"xs\" muted>\n —\n </Text>\n )}\n </Flex>\n ),\n },\n ip: {\n label: \"IP\",\n value: (item) => (\n <Text size=\"xs\" ff=\"monospace\" muted>\n {item.ip || \"—\"}\n </Text>\n ),\n },\n expiresAt: {\n label: \"Status\",\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={isExpired(item.expiresAt) ? \"gray\" : \"green\"}\n >\n {isExpired(item.expiresAt) ? \"Expired\" : \"Active\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n value: (item) => (\n <Text size=\"xs\" muted>\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n rowActions={(item) => [\n {\n label: \"Revoke session\",\n icon: IconTrash,\n color: \"red\",\n onClick: () => handleDelete(item),\n visible: !isExpired(item.expiresAt),\n },\n ]}\n />\n </Flex>\n );\n};\n\nexport default AdminSessions;\n"],"mappings":"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"}