@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.
- package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Bt1PjO6o.js} +3 -4
- package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Bt1PjO6o.js.map} +1 -1
- package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-C7c1CN4c.js} +3 -4
- package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-C7c1CN4c.js.map} +1 -1
- package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-C3RXpTp6.js} +3 -4
- package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-C3RXpTp6.js.map} +1 -1
- package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-31ivR6Wq.js} +3 -4
- package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-31ivR6Wq.js.map} +1 -1
- package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BABLe7hL.js} +73 -25
- package/dist/admin/AdminJobDashboard-BABLe7hL.js.map +1 -0
- package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D-G8RIlr.js} +3 -4
- package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D-G8RIlr.js.map} +1 -1
- package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-oIS3K9NX.js} +3 -4
- package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-oIS3K9NX.js.map} +1 -1
- package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-BmZ9mtXh.js} +8 -25
- package/dist/admin/AdminLayout-BmZ9mtXh.js.map +1 -0
- package/dist/admin/AdminNotifications-DHdzksww.js +541 -0
- package/dist/admin/AdminNotifications-DHdzksww.js.map +1 -0
- package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CyZQSXnN.js} +118 -112
- package/dist/admin/AdminParameters-CyZQSXnN.js.map +1 -0
- package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions--xwELDSO.js} +3 -4
- package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions--xwELDSO.js.map} +1 -1
- package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-DvBTG5gd.js} +82 -115
- package/dist/admin/AdminUserLayout-DvBTG5gd.js.map +1 -0
- package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-CzsPBl6Z.js} +7 -6
- package/dist/admin/AdminUserProfile-CzsPBl6Z.js.map +1 -0
- package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-C-aUnhVN.js} +3 -4
- package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-C-aUnhVN.js.map} +1 -1
- package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-BYwei5sj.js} +4 -4
- package/dist/admin/AdminUsers-BYwei5sj.js.map +1 -0
- package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-CkPGLJku.js} +3 -4
- package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-CkPGLJku.js.map} +1 -1
- package/dist/{demo/IconGoogle-CSQLPYwX.js → admin/IconGoogle-8Nkx6yax.js} +2 -4
- package/dist/admin/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
- package/dist/admin/Login-DSBqNsZc.js +274 -0
- package/dist/admin/Login-DSBqNsZc.js.map +1 -0
- package/dist/admin/{Profile-B2EcIDB9.js → Profile-CDRjJo0P.js} +31 -29
- package/dist/admin/Profile-CDRjJo0P.js.map +1 -0
- package/dist/admin/{Register-Z3fxRbUF.js → Register-4QGFOnfh.js} +201 -146
- package/dist/admin/Register-4QGFOnfh.js.map +1 -0
- package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-Gxc9L_mY.js} +9 -10
- package/dist/admin/ResetPassword-Gxc9L_mY.js.map +1 -0
- package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-D7G5NnaN.js} +25 -11
- package/dist/admin/VerifyEmail-D7G5NnaN.js.map +1 -0
- package/dist/admin/adminUserAtom-DCi4wf-v.js +11 -0
- package/dist/admin/adminUserAtom-DCi4wf-v.js.map +1 -0
- package/dist/admin/{core-BVO_TQxb.js → core-D1AbU50V.js} +662 -570
- package/dist/admin/core-D1AbU50V.js.map +1 -0
- package/dist/admin/index.d.ts +141 -53
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +67 -49
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/rolldown-runtime-CiIaOW0V.js +13 -0
- package/dist/{demo/AuthLayout-DN-ClJQk.js → auth/AuthLayout-CfRKcTqP.js} +3 -4
- package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-CfRKcTqP.js.map} +1 -1
- package/dist/{admin/IconGoogle-Ch1m3Uzl.js → auth/IconGoogle-8Nkx6yax.js} +2 -4
- package/dist/auth/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
- package/dist/auth/Login-DJyweoPS.js +274 -0
- package/dist/auth/Login-DJyweoPS.js.map +1 -0
- package/dist/auth/{Profile-BMpXJ0oi.js → Profile-Cy93pNTw.js} +31 -29
- package/dist/auth/Profile-Cy93pNTw.js.map +1 -0
- package/dist/auth/{Register-2gx8qll-.js → Register-CSqzzitW.js} +201 -146
- package/dist/auth/Register-CSqzzitW.js.map +1 -0
- package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-B61QPlQi.js} +9 -10
- package/dist/auth/ResetPassword-B61QPlQi.js.map +1 -0
- package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-CqBJ11id.js} +25 -11
- package/dist/auth/VerifyEmail-CqBJ11id.js.map +1 -0
- package/dist/auth/{core-DyfeVr5c.js → core-C6D3pazL.js} +403 -343
- package/dist/auth/core-C6D3pazL.js.map +1 -0
- package/dist/auth/index.d.ts +93 -54
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +30 -31
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/rolldown-runtime-CiIaOW0V.js +13 -0
- package/dist/core/index.d.ts +123 -62
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +878 -776
- package/dist/core/index.js.map +1 -1
- package/dist/{auth/AuthLayout-C161NeF6.js → demo/AuthLayout-Dq5tSLSc.js} +3 -4
- package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Dq5tSLSc.js.map} +1 -1
- package/dist/demo/DemoButton-_Ws2w-J0.js +181 -0
- package/dist/demo/DemoButton-_Ws2w-J0.js.map +1 -0
- package/dist/demo/DemoControlSelect-ChP4ZOpQ.js +304 -0
- package/dist/demo/DemoControlSelect-ChP4ZOpQ.js.map +1 -0
- package/dist/demo/DemoDataTable-Hwf_UUni.js +361 -0
- package/dist/demo/DemoDataTable-Hwf_UUni.js.map +1 -0
- package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-B01OMVRd.js} +3 -4
- package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-B01OMVRd.js.map} +1 -1
- package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-870PEl0V.js} +4 -5
- package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-870PEl0V.js.map} +1 -1
- package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C1YR27fz.js} +4 -5
- package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C1YR27fz.js.map} +1 -1
- package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-DRbL2eGf.js} +4 -5
- package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-DRbL2eGf.js.map} +1 -1
- package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-DoABiqBW.js} +4 -5
- package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-DoABiqBW.js.map} +1 -1
- package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CN_PDCX2.js} +16 -8
- package/dist/demo/DemoLayout-CN_PDCX2.js.map +1 -0
- package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-B5x-ug3Q.js} +51 -35
- package/dist/demo/DemoLogin-B5x-ug3Q.js.map +1 -0
- package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-Q6sg2xuV.js} +51 -53
- package/dist/demo/DemoRegister-Q6sg2xuV.js.map +1 -0
- package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-DrqZfmEw.js} +14 -19
- package/dist/demo/DemoResetPassword-DrqZfmEw.js.map +1 -0
- package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-CfKS6w1o.js} +4 -5
- package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-CfKS6w1o.js.map} +1 -1
- package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-pT6Gi5b5.js} +4 -5
- package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-pT6Gi5b5.js.map} +1 -1
- package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-I13NBzQQ.js} +3 -4
- package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-I13NBzQQ.js.map} +1 -1
- package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-BqzcrtvN.js} +9 -6
- package/dist/demo/DemoTypeForm-BqzcrtvN.js.map +1 -0
- package/dist/demo/DemoVerifyEmail-HwD8xfQw.js +33 -0
- package/dist/demo/DemoVerifyEmail-HwD8xfQw.js.map +1 -0
- package/dist/{auth/IconGoogle-Ch1m3Uzl.js → demo/IconGoogle-CwQy4G9y.js} +2 -4
- package/dist/demo/{IconGoogle-CSQLPYwX.js.map → IconGoogle-CwQy4G9y.js.map} +1 -1
- package/dist/demo/Login-CqG1iJbn.js +274 -0
- package/dist/demo/Login-CqG1iJbn.js.map +1 -0
- package/dist/demo/{Profile-BE_Y3co2.js → Profile-C0ojJCaG.js} +31 -29
- package/dist/demo/Profile-C0ojJCaG.js.map +1 -0
- package/dist/demo/{Register-fXHmBpr3.js → Register-KKZwr_lL.js} +201 -146
- package/dist/demo/Register-KKZwr_lL.js.map +1 -0
- package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-DMrLFEtr.js} +9 -10
- package/dist/demo/ResetPassword-DMrLFEtr.js.map +1 -0
- package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D49Wud2v.js} +65 -68
- package/dist/demo/Showcase-D49Wud2v.js.map +1 -0
- package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BFCAFz6T.js} +25 -11
- package/dist/demo/VerifyEmail-BFCAFz6T.js.map +1 -0
- package/dist/demo/{auth-Djd7SKiw.js → auth-D9qTZzCa.js} +18 -35
- package/dist/demo/{auth-Djd7SKiw.js.map → auth-D9qTZzCa.js.map} +1 -1
- package/dist/demo/{core-B7LNjM78.js → core-DRtQklr3.js} +752 -647
- package/dist/demo/core-DRtQklr3.js.map +1 -0
- package/dist/demo/index.d.ts +1 -0
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +25 -22
- package/dist/demo/index.js.map +1 -1
- package/dist/demo/rolldown-runtime-CiIaOW0V.js +13 -0
- package/package.json +19 -19
- package/src/admin/AdminRouter.tsx +42 -2
- package/src/admin/atoms/adminUserAtom.ts +7 -0
- package/src/admin/components/AdminLayout.tsx +2 -14
- package/src/admin/components/jobs/AdminJobDashboard.tsx +51 -20
- package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
- package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
- package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
- package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
- package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
- package/src/admin/components/parameters/ParameterTree.tsx +28 -184
- package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
- package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
- package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
- package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
- package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
- package/src/admin/components/users/AdminUserLayout.tsx +84 -127
- package/src/admin/components/users/AdminUserProfile.tsx +5 -2
- package/src/admin/components/users/AdminUsers.tsx +1 -1
- package/src/auth/components/Login.tsx +188 -121
- package/src/auth/components/Profile.tsx +1 -22
- package/src/auth/components/ProfileField.tsx +39 -0
- package/src/auth/components/Register.tsx +215 -158
- package/src/auth/components/ResetPassword.tsx +7 -11
- package/src/auth/components/VerifyEmail.tsx +35 -10
- package/src/auth/components/buttons/UserButton.tsx +19 -21
- package/src/auth/index.ts +1 -0
- package/src/core/components/Flex.tsx +34 -0
- package/src/core/components/buttons/ActionButton.tsx +105 -78
- package/src/core/components/data/DetailDrawer.tsx +102 -96
- package/src/core/components/data/DetailList.tsx +2 -1
- package/src/core/components/dialogs/PromptDialog.tsx +1 -1
- package/src/core/components/layout/Breadcrumb.tsx +4 -7
- package/src/core/components/layout/DashboardShell.tsx +18 -4
- package/src/core/components/layout/Sidebar.tsx +16 -241
- package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
- package/src/core/components/layout/SidebarItem.tsx +146 -0
- package/src/core/components/layout/index.ts +3 -1
- package/src/core/form/components/Control.tsx +31 -29
- package/src/core/form/components/ControlArray.tsx +13 -39
- package/src/core/form/components/ControlDate.tsx +10 -21
- package/src/core/form/components/ControlNumber.tsx +4 -33
- package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
- package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
- package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
- package/src/core/form/components/ControlSelect.tsx +294 -92
- package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
- package/src/core/form/components/TypeForm.tsx +5 -2
- package/src/core/form/index.ts +8 -1
- package/src/core/form/utils/parseInput.ts +7 -3
- package/src/core/index.ts +3 -1
- package/src/core/json/components/JsonViewer.tsx +103 -319
- package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
- package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
- package/src/core/json/components/JsonViewerShared.ts +76 -0
- package/src/core/services/DialogService.tsx +2 -2
- package/src/core/styles.css +13 -2
- package/src/core/table/components/ColumnPicker.tsx +3 -3
- package/src/core/table/components/DataTable.tsx +88 -29
- package/src/core/table/components/DataTableFilters.tsx +6 -11
- package/src/core/table/components/DataTablePagination.tsx +9 -3
- package/src/core/table/components/DataTableToolbar.tsx +7 -3
- package/src/core/table/components/FilterPicker.tsx +3 -3
- package/src/core/table/interfaces/types.ts +29 -0
- package/src/core/utils/icons.tsx +2 -2
- package/src/demo/DemoRouter.ts +8 -1
- package/src/demo/components/DemoLayout.tsx +12 -2
- package/src/demo/components/auth/DemoLogin.tsx +35 -28
- package/src/demo/components/auth/DemoRegister.tsx +35 -49
- package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
- package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
- package/src/demo/components/core/DemoButton.tsx +123 -103
- package/src/demo/components/core/DemoControlSelect.tsx +325 -0
- package/src/demo/components/core/DemoDataTable.tsx +255 -237
- package/src/demo/components/core/DemoTypeForm.tsx +7 -2
- package/src/demo/components/shared/MacWindow.tsx +5 -11
- package/src/demo/components/shared/Showcase.tsx +28 -42
- package/dist/admin/AdminJobDashboard-KIOkeMgE.js.map +0 -1
- package/dist/admin/AdminLayout-B1DXZHDn.js.map +0 -1
- package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
- package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
- package/dist/admin/AdminUserProfile-DuTUnjdG.js.map +0 -1
- package/dist/admin/AdminUsers-CR9z0g_5.js.map +0 -1
- package/dist/admin/Login-DHbYJKwg.js +0 -219
- package/dist/admin/Login-DHbYJKwg.js.map +0 -1
- package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
- package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
- package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
- package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
- package/dist/admin/core-BVO_TQxb.js.map +0 -1
- package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
- package/dist/auth/Login-C7jIqf00.js +0 -219
- package/dist/auth/Login-C7jIqf00.js.map +0 -1
- package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
- package/dist/auth/Register-2gx8qll-.js.map +0 -1
- package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
- package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
- package/dist/auth/core-DyfeVr5c.js.map +0 -1
- package/dist/auth/rolldown-runtime-CjeV3_4I.js +0 -18
- package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
- package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
- package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
- package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
- package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
- package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
- package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
- package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
- package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
- package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
- package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
- package/dist/demo/Login-CoYf_P_F.js +0 -219
- package/dist/demo/Login-CoYf_P_F.js.map +0 -1
- package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
- package/dist/demo/Register-fXHmBpr3.js.map +0 -1
- package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
- package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
- package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
- package/dist/demo/core-B7LNjM78.js.map +0 -1
- package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
- 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,
|
|
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/
|
|
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
|
|
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 = (
|
|
249
|
-
if (loading) return /* @__PURE__ */ jsx(
|
|
250
|
-
return /* @__PURE__ */ jsx(
|
|
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
|
-
|
|
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/
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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":";;;;;;;;;;AAmBA,MAAa,kBAAkB,WAAmB;AAChD,SAAQ,QAAR;EACE,KAAK,UACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAa,cAAc,QAAyB;AAClD,KAAI;AACF,SAAO,KAAK,UAAU,KAAK,MAAM,EAAE;SAC7B;AACN,SAAO,OAAO,IAAI;;;;;;;;ACnBtB,MAAM,8BAA8B,UAAiB;CACnD,MAAM,EAAE,MAAM,SAAS;CAGvB,MAAM,iBAAiB,cAAc;AACnC,MAAI,MAAM,aAAa,SAAS,QAC9B,QAAO,MAAM,YAAY,QAAQ;AAEnC,MAAI,MAAM,aAAa,iBAAiB,KAAA,EACtC,QAAO,MAAM,YAAY;AAE3B,SAAO;IACN,CAAC,MAAM,YAAY,CAAC;CAGvB,MAAM,gBAAgB,cAAc;AAClC,MAAI,CAAC,MAAM,aAAa,OACtB,QAAO,EAAE,OAAO,EAAE,CAAC;AAErB,MAAI;AACF,UAAO,oBAAoB,MAAM,YAAY,OAAO;UAC9C;AACN,UAAO,EAAE,OAAO,EAAE,CAAC;;IAEpB,CAAC,MAAM,aAAa,OAAO,CAAC;CAE/B,MAAM,OAAO,QACX;EACE,QAAQ;EACR,eAAgB,kBAAkB,EAAE;EACpC,SAAS,OAAO,WAAW;AACzB,SAAM,MAAM,OAAO,OAAkC;;EAExD,EACD;EAAC,MAAM;EAAgB;EAAe;EAAe,CACtD;CAGD,MAAM,iBAAiB,cAAc;EACnC,MAAM,SAAS,MAAM,aAAa;AAClC,SACE,UACA,OAAO,WAAW,YAClB,gBAAgB,UAChB,OAAO,KAAK,OAAO,WAAqB,CAAC,SAAS;IAEnD,CAAC,MAAM,aAAa,OAAO,CAAC;CAG/B,MAAM,aAAa,cAAc;EAC/B,MAAM,SAAS,MAAM,aAAa;AAClC,MACE,UACA,OAAO,WAAW,YAClB,gBAAgB,UAChB,OAAO,WAEP,QAAO,OAAO,KAAK,OAAO,WAAqB,CAAC;AAElD,SAAO;IACN,CAAC,MAAM,aAAa,OAAO,CAAC;CAG/B,MAAM,UAAU,cAAc;AAC5B,MAAI,cAAc,EAAG,QAAO;AAC5B,MAAI,cAAc,EAAG,QAAO;AAC5B,SAAO;IACN,CAAC,WAAW,CAAC;AAEhB,QACE,oBAACA,QAAD;EACE,MAAM;EACN,GAAE;EACF,OAAO;GACL,UAAU;GACV,UAAU;GACV,SAAS;GACV;YAED,qBAACA,QAAD;GAAM,WAAU;GAAS,GAAE;GAAO,GAAE;GAAO,OAAO,EAAE,WAAW,GAAG;aAAlE,CAEE,oBAACA,QAAD;IACE,MAAM;IACN,GAAE;IACF,WAAU;IACV,OAAO,EAAE,WAAW,GAAG;cAEtB,mBAAmB,OAClB,qBAACA,QAAD;KAAM,WAAU;KAAS,KAAI;eAA7B;MAEE,oBAACA,QAAD,EAAA,UACG,iBACC,oBAAC,UAAD;OACQ;OACG;OACT,kBAAA;OACA,MAAM;OACN,CAAA,GAEF,qBAACA,QAAD,EAAA,UAAA,CACE,oBAACC,QAAD;OAAM,MAAK;OAAK,GAAE;OAAS,IAAI;iBAAG;OAE3B,CAAA,EACP,oBAAC,MAAD;OAAM,OAAA;OAAM,OAAO,EAAE,YAAY,YAAY;iBAC1C,WAAW,eAAe;OACtB,CAAA,CACF,EAAA,CAAA,EAEJ,CAAA;MAGN,MAAM,aAAa,SAAS,qBAC3B,qBAACD,QAAD,EAAA,UAAA,CACE,oBAACC,QAAD;OAAM,MAAK;OAAK,GAAE;OAAS,IAAI;iBAAG;OAE3B,CAAA,EACP,oBAACA,QAAD;OAAM,MAAK;iBACR,MAAM,YAAY,QAAQ;OACtB,CAAA,CACF,EAAA,CAAA;MAGR,MAAM,aAAa,WAClB,qBAACD,QAAD;OAAM,KAAI;iBAAV,CACE,qBAACA,QAAD,EAAA,UAAA,CACE,oBAACC,QAAD;QAAM,MAAK;QAAK,GAAE;QAAS,IAAI;kBAAG;QAE3B,CAAA,EACP,oBAACA,QAAD;QAAM,MAAK;kBACR,EAAE,MAAM,YAAY,QAAQ,WAAW,EACtC,MAAM,WACP,CAAC;QACG,CAAA,CACF,EAAA,CAAA,EACN,MAAM,YAAY,QAAQ,eACzB,qBAACD,QAAD,EAAA,UAAA,CACE,oBAACC,QAAD;QAAM,MAAK;QAAK,GAAE;QAAS,IAAI;kBAAG;QAE3B,CAAA,EACP,oBAACA,QAAD;QAAM,MAAK;kBACR,MAAM,YAAY,QAAQ;QACtB,CAAA,CACF,EAAA,CAAA,CAEJ;;MAGR,CAAC,MAAM,aAAa,WACnB,MAAM,aAAa,iBAAiB,KAAA,KAClC,oBAACA,QAAD;OAAM,MAAK;OAAK,GAAE;iBAAS;OAGpB,CAAA;MAIV,MAAM,aAAa,QAClB,oBAAC,MAAD;OAAM,YAAA;OAAW,GAAE;OAAK,IAAG;iBACzB,qBAACD,QAAD;QAAM,WAAU;QAAS,KAAI;kBAA7B;SACE,qBAACA,QAAD;UAAM,KAAI;oBAAV,CACE,oBAAC,WAAD;WACE,MAAM;WACN,OAAM;WACN,CAAA,EACF,qBAACC,QAAD;WAAM,MAAK;WAAK,IAAI;WAAK,GAAE;qBAA3B;YAAkC;YACZ,MAAM,YAAY,KAAK;YAAQ;YAC9C;aACF;;SACP,qBAACA,QAAD;UAAM,MAAK;UAAK,GAAE;oBAAlB;WAA2B;WACf;WACT,EAAE,MAAM,YAAY,KAAK,gBAAgB,EACxC,MAAM,WACP,CAAC;WACG;;SACP,oBAAC,MAAD;UAAM,OAAA;UAAM,OAAO,EAAE,YAAY,YAAY;UAAE,IAAG;oBAC/C,WAAW,MAAM,YAAY,KAAK,QAAQ;UACtC,CAAA;SACF;;OACF,CAAA;MAEJ;SAEP,oBAACD,QAAD;KAAM,SAAQ;KAAS,OAAM;KAAS,GAAG;eACvC,oBAACC,QAAD;MAAM,GAAE;MAAS,MAAK;gBAAK;MAEpB,CAAA;KACF,CAAA;IAEJ,CAAA,EAGN,kBAAkB,mBAAmB,QACpC,oBAACD,QAAD;IACE,GAAE;IACF,OAAO;KACL,YAAY;KACZ,WAAW;KACZ;cAED,qBAACA,QAAD;KAAM,SAAQ;KAAW,KAAI;eAA7B,CACE,oBAAC,cAAD;MACE,SAAQ;MACR,eAAe,KAAK,MAAM,EAAE,CAAQ;MACpC,UAAU,MAAM;gBACjB;MAEc,CAAA,EACf,oBAAC,cAAD;MAAc,QAAO;MAAgB;MAAM,SAAS,MAAM;gBAAQ;MAEnD,CAAA,CACV;;IACF,CAAA,CAEJ;;EACF,CAAA;;;;;;;ACnOX,MAAM,gCACJ,oBAACE,QAAD;CACE,MAAM;CACN,GAAE;CACF,GAAE;CACF,OAAO;EACL,UAAU;EACV,UAAU;EACV,SAAS;EACV;WAED,oBAACA,QAAD;EAAM,MAAM;EAAG,SAAQ;EAAS,OAAM;EAAS,GAAE;YAC/C,oBAAC,QAAD,EAAQ,MAAK,MAAO,CAAA;EACf,CAAA;CACF,CAAA;;;;;;;;ACHT,MAAM,oBAAoB,UAAiB;AAEzC,KAAI,MAAM,QACR,QAAO,oBAAC,yBAAD,EAA2B,CAAA;AAIpC,QACE,oBAAC,4BAAD;EACE,gBAAgB,MAAM;EACtB,aAAa,MAAM;EACnB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,CAAA;;;;;;;;ACvBN,MAAM,4BAA4B;AAChC,QACE,oBAACC,QAAD;EAAM,MAAM;EAAG,GAAG;EAAM,OAAM;YAC5B,qBAACA,QAAD;GAAM,WAAU;GAAS,OAAM;GAAS,KAAI;aAA5C,CACE,oBAAC,eAAD;IAAe,MAAM;IAAI,OAAM;IAAgC,CAAA,EAC/D,qBAACA,QAAD;IAAM,WAAU;IAAS,OAAM;IAAS,KAAK;cAA7C,CACE,oBAACC,QAAD;KAAM,IAAI;KAAK,GAAE;eAAS;KAEnB,CAAA,EACP,oBAACA,QAAD;KAAM,MAAK;KAAK,GAAE;KAAS,IAAG;KAAS,KAAK;eAAK;KAE1C,CAAA,CACF;MACF;;EACF,CAAA;;;;;;;ACJX,MAAM,oBAAoB,UAAiB;CACzC,MAAM,EAAE,MAAM,SAAS;CAEvB,MAAM,sBAAsB;AAC1B,MAAI,MAAM,QACR,QACE,oBAACC,QAAD;GAAM,MAAM;GAAG,SAAQ;GAAS,OAAM;aACpC,oBAAC,QAAD,EAAQ,MAAK,MAAO,CAAA;GACf,CAAA;AAIX,MAAI,MAAM,QAAQ,WAAW,EAC3B,QACE,oBAACA,QAAD;GAAM,MAAM;GAAG,SAAQ;GAAS,OAAM;aACpC,oBAACC,QAAD;IAAM,GAAE;IAAS,MAAK;cAAK;IAEpB,CAAA;GACF,CAAA;AAIX,SACE,oBAAC,YAAD;GAAY,MAAM;GAAG,kBAAA;aACnB,oBAAC,UAAD;IACE,QAAQ,MAAM,QAAQ,WAAW,MAAM,EAAE,WAAW,UAAU;IAC9D,YAAY;IACZ,WAAW;cAEV,MAAM,QAAQ,KAAK,YAClB,oBAAC,SAAS,MAAV;KAEE,QACE,oBAACA,QAAD;MAAM,MAAK;MAAK,IAAI;gBACjB,QAAQ;MACJ,CAAA;KAET,OACE,qBAACD,QAAD;MAAM,KAAI;gBAAV,CACE,qBAACC,QAAD;OAAM,MAAK;OAAK,IAAI;iBAApB,CAAyB,YACd,QAAQ,QACZ;UACP,oBAAC,OAAD;OACE,MAAK;OACL,SAAQ;OACR,OAAO,eAAe,QAAQ,OAAO;iBAEpC,QAAQ;OACH,CAAA,CACH;;eAGT,qBAACD,QAAD;MAAM,WAAU;MAAS,KAAK;MAAG,IAAI;gBAArC;OACE,oBAACC,QAAD;QAAM,MAAK;QAAK,GAAE;kBACf,EAAE,QAAQ,WAAW,EAAE,MAAM,WAAW,CAAC;QACrC,CAAA;OACN,QAAQ,qBACP,oBAACA,QAAD;QAAM,MAAK;QAAK,WAAW;kBACxB,QAAQ;QACJ,CAAA;OAER,QAAQ,eACP,qBAACA,QAAD;QAAM,MAAK;QAAK,GAAE;kBAAlB,CAA2B,OACrB,QAAQ,YACP;;OAER,QAAQ,gBACP,oBAAC,OAAD;QAAO,MAAK;QAAK,SAAQ;QAAU,OAAM;kBAAS;QAE1C,CAAA;OAET,QAAQ,WAAW,aAClB,oBAAC,cAAD;QACE,MAAK;QACL,SAAQ;QACR,eAAe,MAAM,WAAW,QAAQ,QAAQ;kBACjD;QAEc,CAAA;OAEZ;;KACO,EAlDT,QAAQ,GAkDC,CAChB;IACO,CAAA;GACA,CAAA;;AAIjB,QACE,oBAACD,QAAD;EACE,GAAG;EACH,GAAE;EACF,GAAE;EACF,OAAO;GACL,YAAY;GACZ,UAAU;GACV,SAAS;GACT,eAAe;GACf,YAAY;GACb;YAED,qBAACA,QAAD;GAAM,WAAU;GAAS,KAAI;GAAK,GAAE;GAAO,OAAO,EAAE,WAAW,GAAG;aAAlE,CACE,qBAACA,QAAD;IAAM,KAAI;cAAV,CACE,oBAAC,aAAD;KAAa,MAAM;KAAI,OAAM;KAAgC,CAAA,EAC7D,oBAACC,QAAD;KAAM,MAAK;KAAK,IAAI;eAAK;KAElB,CAAA,CACF;OACN,eAAe,CACX;;EACF,CAAA;;;;;;;ACvGX,MAAM,oBAAoB,MAAM,UAAiB;CAC/C,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,cAAc,MAAM,KAAK,SAAS,SAAS;CACjD,MAAM,aAAa,MAAM,cAAc,IAAI,MAAM,KAAK,KAAK;CAC3D,MAAM,aAAa,MAAM,mBAAmB,MAAM,KAAK;CACvD,MAAM,SAAS,CAAC;AAahB,QACE,qBAACC,QAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;EACE,SAdc,kBAAkB;AACpC,OAAI,YACF,OAAM,SAAS,MAAM,KAAK,KAAK;OAE/B,OAAM,SAAS,MAAM,KAAK,KAAK;KAEhC;GAAC;GAAa,MAAM,KAAK;GAAM,MAAM;GAAU,MAAM;GAAS,CAAC;EAS5D,cAPmB,kBAAkB,aAAa,KAAK,EAAE,EAAE,CAAC;EAQ5D,cAPmB,kBAAkB,aAAa,MAAM,EAAE,EAAE,CAAC;EAQ7D,GAAE;EACF,OAAO,EAAE,SAAS,SAAS;YAE3B,qBAACA,QAAD;GACE,KAAK;GACL,MAAK;GACL,GAAE;GACF,IAAI,IAAI,MAAM,QAAQ;GACtB,OAAO;IACL,cAAc;IACd,iBACE,cAAc,YACV,uCACA,KAAA;IACP;aAXH,CAaG,cACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAACA,QAAD;IACE,OAAO;KACL,SAAS;KACT,YAAY;KACZ,gBAAgB;KAChB,OAAO;KACR;cAEA,aACC,oBAAC,iBAAD;KACE,MAAM;KACN,OAAM;KACN,CAAA,GAEF,oBAAC,kBAAD;KACE,MAAM;KACN,OAAM;KACN,CAAA;IAEC,CAAA,EACN,aACC,oBAAC,gBAAD;IACE,MAAM;IACN,OAAM;IACN,OAAO,EAAE,YAAY,GAAG;IACxB,CAAA,GAEF,oBAAC,YAAD;IACE,MAAM;IACN,OAAM;IACN,OAAO,EAAE,YAAY,GAAG;IACxB,CAAA,CAEH,EAAA,CAAA,GAEH,qBAAA,UAAA,EAAA,UAAA,CACE,oBAACA,QAAD,EAAM,GAAG,IAAM,CAAA,EACf,oBAAC,cAAD;IACE,MAAM;IACN,OACE,aACI,gCACA;IAEN,OAAO,EAAE,YAAY,GAAG;IACxB,CAAA,CACD,EAAA,CAAA,EAEL,oBAACC,QAAD;IACE,MAAK;IACL,IAAI,aAAa,MAAM;IACvB,GAAG,aAAa,KAAA,IAAY,SAAS,KAAA,IAAY;IACjD,OAAO;KACL,YAAY;KACZ,UAAU;KACV,cAAc;KACf;cAEA,MAAM,KAAK;IACP,CAAA,CACF;;EACQ,CAAA,EAEhB,eACC,oBAAC,UAAD;EAAU,IAAI;YACX,MAAM,KAAK,SAAS,KAAK,UACxB,oBAAC,mBAAD;GAEE,MAAM;GACN,OAAO,MAAM,QAAQ;GACrB,gBAAgB,MAAM;GACtB,UAAU,MAAM;GAChB,eAAe,MAAM;GACrB,UAAU,MAAM;GAChB,EAPK,MAAM,KAOX,CACF;EACO,CAAA,CAER,EAAA,CAAA;EAET;AAEF,kBAAkB,cAAc;;;;;;AC1IhC,MAAM,cACJ,OACA,UAC4B;AAC5B,KAAI,CAAC,MAAM,MAAM,CAAE,QAAO;CAE1B,MAAM,aAAa,MAAM,aAAa;AAEtC,QAAO,MACJ,KAAK,SAAS;EACb,MAAM,mBAAmB,WAAW,KAAK,UAAU,MAAM;EACzD,MAAM,cAAc,KAAK,KAAK,aAAa,CAAC,SAAS,WAAW;EAChE,MAAM,cAAc,KAAK,KAAK,aAAa,CAAC,SAAS,WAAW;AAEhE,MAAI,eAAe,eAAe,iBAAiB,SAAS,EAC1D,QAAO;GACL,GAAG;GACH,UAAU;GACX;AAGH,SAAO;GACP,CACD,QAAQ,SAAwC,SAAS,KAAK;;;;;AAMnE,MAAM,yBAAyB,UAAgD;CAC7E,MAAM,wBAAQ,IAAI,KAAa;CAE/B,MAAM,YAAY,aAAsC;AACtD,OAAK,MAAM,QAAQ,SACjB,KAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,SAAM,IAAI,KAAK,KAAK;AACpB,YAAS,KAAK,SAAS;;;AAK7B,UAAS,MAAM;AACf,QAAO;;;;;AAaT,MAAM,iBAAiB,UAAiB;CACtC,MAAM,CAAC,aAAa,kBAAkB,SAAS,GAAG;CAClD,MAAM,CAAC,eAAe,oBAAoB,eACxC,sBAAsB,MAAM,SAAS,CACtC;CAGD,MAAM,mBAAmB,cACjB,WAAW,MAAM,UAAU,YAAY,EAC7C,CAAC,MAAM,UAAU,YAAY,CAC9B;CAED,MAAM,eAAe,aAAa,SAAiB;AACjD,oBAAkB,SAAS;GACzB,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,OAAI,KAAK,IAAI,KAAK,CAChB,MAAK,OAAO,KAAK;OAEjB,MAAK,IAAI,KAAK;AAEhB,UAAO;IACP;IACD,EAAE,CAAC;CAEN,MAAM,qBAAqB,aACxB,MAA2C;AAC1C,iBAAe,EAAE,cAAc,MAAM;IAEvC,EAAE,CACH;AAED,QACE,oBAACC,QAAD;EACE,GAAG;EACH,GAAE;EACF,GAAE;EACF,OAAO;GACL,YAAY;GACZ,SAAS;GACT,eAAe;GACf,aAAa;GACd;YAED,qBAACA,QAAD;GAAM,WAAU;GAAS,KAAI;GAAK,GAAE;GAAO,OAAO,EAAE,WAAW,GAAG;aAAlE;IACE,qBAACA,QAAD;KAAM,SAAQ;KAAgB,KAAI;eAAlC,CACE,oBAACC,QAAD;MAAM,MAAK;MAAK,IAAI;gBAAK;MAElB,CAAA,EACP,oBAAC,cAAD;MACE,SAAQ;MACR,MAAK;MACL,SAAS,MAAM;MACf,SAAQ;gBAER,oBAAC,aAAD,EAAa,MAAM,IAAM,CAAA;MACZ,CAAA,CACV;;IAEP,oBAAC,WAAD;KACE,aAAY;KACZ,MAAK;KACL,aAAa,oBAAC,YAAD,EAAY,MAAM,IAAM,CAAA;KACrC,OAAO;KACP,UAAU;KACV,CAAA;IAEF,oBAAC,YAAD;KAAY,MAAM;KAAG,kBAAA;KAAiB,OAAO,EAAE,WAAW,GAAG;eAC1D,iBAAiB,WAAW,IAC3B,oBAACA,QAAD;MAAM,MAAK;MAAK,GAAE;MAAS,IAAG;MAAS,IAAG;gBACvC,cAAc,2BAA2B;MACrC,CAAA,GAEP,oBAACD,QAAD;MAAM,WAAU;MAAS,KAAK;MAAG,OAAO,EAAE,KAAK,GAAG;gBAC/C,iBAAiB,KAAK,SACrB,oBAAC,mBAAD;OAEQ;OACN,OAAO;OACP,gBAAgB,MAAM;OACtB,UAAU,MAAM;OACD;OACf,UAAU;OACV,EAPK,KAAK,KAOV,CACF;MACG,CAAA;KAEE,CAAA;IACR;;EACF,CAAA;;;;ACrIX,MAAM,mBAAmB,EACvB,UAAU,sBACgB;CAC1B,MAAM,SAAS,WAAqC;CACpD,MAAM,QAAQ,UAAU;CAGxB,MAAM,CAAC,UAAU,eACf,SAA8B,gBAAgB;CAChD,MAAM,CAAC,gBAAgB,qBAAqB,SAAwB,KAAK;CACzE,MAAM,CAAC,aAAa,kBAAkB,SAAgC,KAAK;CAC3E,MAAM,CAAC,SAAS,cAAc,SAA8B,EAAE,CAAC;CAC/D,MAAM,CAAC,eAAe,oBAAoB,SAAS,MAAM;CACzD,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,MAAM;CAC3D,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAG3C,MAAM,gBAAgB,YAAY,YAAY;AAC5C,MAAI;AAEF,eADa,MAAM,OAAO,iBAAiB,EAAE,CAAC,CACN;WACjC,OAAO;AACd,SAAM,OAAO;IACX,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CAAC;;IAEH,CAAC,QAAQ,MAAM,CAAC;CAGnB,MAAM,oBAAoB,YACxB,OAAO,SAAiB;AACtB,mBAAiB,KAAK;AACtB,oBAAkB,KAAK;AAEvB,MAAI;GACF,MAAM,CAAC,iBAAiB,mBAAmB,MAAM,QAAQ,IAAI,CAC3D,OAAO,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EACvC,OAAO,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CACxC,CAAC;AACF,kBAAe,gBAAgB;AAC/B,cAAW,gBAAgB,SAAS;WAC7B,OAAO;AACd,SAAM,OAAO;IACX,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CAAC;AACF,kBAAe,KAAK;AACpB,cAAW,EAAE,CAAC;YACN;AACR,oBAAiB,MAAM;AACvB,qBAAkB,MAAM;;IAG5B,CAAC,QAAQ,MAAM,CAChB;CAGD,MAAM,aAAa,YACjB,OAAO,WAAoC;AACzC,MAAI,CAAC,kBAAkB,CAAC,YAAa;AAErC,YAAU,KAAK;AACf,MAAI;AACF,SAAM,OAAO,cAAc;IACzB,QAAQ,EAAE,MAAM,gBAAgB;IAChC,MAAM;KACJ,SAAS;KACT,YAAY;KACZ,mBAAmB;KACpB;IACF,CAAC;AAEF,SAAM,QAAQ;IACZ,OAAO;IACP,SAAS,GAAG,eAAe;IAC5B,CAAC;AAGF,SAAM,kBAAkB,eAAe;WAChC,OAAO;AACd,SAAM,OAAO;IACX,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CAAC;AACF,SAAM;YACE;AACR,aAAU,MAAM;;IAGpB;EAAC;EAAQ;EAAgB;EAAa;EAAmB;EAAM,CAChE;AAGD,iBAAgB;AACd,MAAI,eACF,mBAAkB,eAAe;OAC5B;AACL,kBAAe,KAAK;AACpB,cAAW,EAAE,CAAC;;IAEf,CAAC,gBAAgB,kBAAkB,CAAC;CAGvC,MAAM,iBAAiB,YACrB,OAAO,YAAoB;AACzB,MAAI,CAAC,eAAgB;AAErB,MAAI;AACF,SAAM,OAAO,SAAS;IACpB,QAAQ,EAAE,MAAM,gBAAgB;IAChC,MAAM,EAAE,eAAe,SAAS;IACjC,CAAC;AAEF,SAAM,QAAQ;IACZ,OAAO;IACP,SAAS,GAAG,eAAe,0BAA0B;IACtD,CAAC;AAGF,SAAM,kBAAkB,eAAe;WAChC,OAAO;AACd,SAAM,OAAO;IACX,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CAAC;;IAGN;EAAC;EAAQ;EAAgB;EAAmB;EAAM,CACnD;AAGD,KAAI,SAAS,WAAW,EACtB,QACE,oBAACE,QAAD;EAAM,MAAM;EAAG,SAAQ;EAAS,OAAM;YACpC,qBAACA,QAAD;GAAM,WAAU;GAAS,OAAM;GAAS,KAAI;aAA5C;IACE,oBAAC,cAAD;KACE,MAAM;KACN,QAAQ;KACR,OAAM;KACN,CAAA;IACF,oBAACC,QAAD;KAAM,GAAE;eAAS;KAA0B,CAAA;IAC3C,oBAACA,QAAD;KAAM,MAAK;KAAK,GAAE;KAAS,IAAG;KAAS,KAAK;eAAK;KAG1C,CAAA;IACF;;EACF,CAAA;AAIX,QACE,oBAACD,QAAD;EAAM,MAAM;EAAG,GAAE;YACf,qBAAC,MAAD;GACE,YAAA;GACA,GAAG;GACH,GAAG;GACH,OAAO,EACL,eAAe,OAChB;aANH,CAQE,oBAAC,eAAD;IACY;IACM;IAChB,UAAU;IACV,WAAW;IACX,CAAA,EAED,iBACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,kBAAD;IACkB;IACH;IACb,SAAS;IACD;IACR,QAAQ;IACR,CAAA,EAEF,oBAAC,kBAAD;IACkB;IACP;IACT,SAAS;IACT,YAAY;IACZ,CAAA,CACD,EAAA,CAAA,GAEH,oBAAC,qBAAD,EAAuB,CAAA,CAEpB;;EACF,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as ActionButton, b as useToast, l as Flex$1, m as useDialog,
|
|
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
|
-
|
|
136
|
+
|
|
137
|
+
//# sourceMappingURL=AdminSessions--xwELDSO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminSessions
|
|
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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"}
|