@alepha/ui 0.16.0 → 0.16.2

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 (152) hide show
  1. package/dist/admin/{AdminApiKeys-GMORg-1l.js → AdminApiKeys-CoTOTfgU.js} +4 -3
  2. package/dist/admin/{AdminApiKeys-GMORg-1l.js.map → AdminApiKeys-CoTOTfgU.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-pkWrjq1Z.js → AdminAudits-BmsxFbDa.js} +4 -3
  4. package/dist/admin/{AdminAudits-pkWrjq1Z.js.map → AdminAudits-BmsxFbDa.js.map} +1 -1
  5. package/dist/admin/{AdminFiles-WeQbsCsl.js → AdminFiles-BBB8knca.js} +4 -3
  6. package/dist/admin/{AdminFiles-WeQbsCsl.js.map → AdminFiles-BBB8knca.js.map} +1 -1
  7. package/dist/admin/{AdminJobs-B-q9iGO3.js → AdminJobs-C604joTz.js} +4 -3
  8. package/dist/admin/{AdminJobs-B-q9iGO3.js.map → AdminJobs-C604joTz.js.map} +1 -1
  9. package/dist/admin/{AdminLayout-D8yZ-8lG.js → AdminLayout-CsjvpeD1.js} +6 -10
  10. package/dist/admin/AdminLayout-CsjvpeD1.js.map +1 -0
  11. package/dist/admin/{AdminNotifications-Ds5Un0NJ.js → AdminNotifications-LwR6RKrx.js} +4 -3
  12. package/dist/admin/{AdminNotifications-Ds5Un0NJ.js.map → AdminNotifications-LwR6RKrx.js.map} +1 -1
  13. package/dist/admin/AdminParameters-B_83Vie9.js +767 -0
  14. package/dist/admin/AdminParameters-B_83Vie9.js.map +1 -0
  15. package/dist/admin/{AdminSessions-DzIOxM3b.js → AdminSessions-CWnPosdd.js} +4 -3
  16. package/dist/admin/{AdminSessions-DzIOxM3b.js.map → AdminSessions-CWnPosdd.js.map} +1 -1
  17. package/dist/admin/{AdminUserAudits-CiUPN2BC.js → AdminUserAudits-nHv636E_.js} +4 -3
  18. package/dist/admin/{AdminUserAudits-CiUPN2BC.js.map → AdminUserAudits-nHv636E_.js.map} +1 -1
  19. package/dist/admin/{AdminUserCreate-BwQKr4xE.js → AdminUserCreate-CjYD3Kjc.js} +4 -3
  20. package/dist/admin/{AdminUserCreate-BwQKr4xE.js.map → AdminUserCreate-CjYD3Kjc.js.map} +1 -1
  21. package/dist/admin/{AdminUserDetails-uqtC5aJ1.js → AdminUserDetails-Ccq-LsZ0.js} +4 -3
  22. package/dist/admin/{AdminUserDetails-uqtC5aJ1.js.map → AdminUserDetails-Ccq-LsZ0.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-CiPay35T.js → AdminUserLayout-7s41DiF_.js} +6 -7
  24. package/dist/admin/AdminUserLayout-7s41DiF_.js.map +1 -0
  25. package/dist/admin/{AdminUserSessions-DAE8Nf1F.js → AdminUserSessions-Ds3ODq_d.js} +4 -3
  26. package/dist/admin/{AdminUserSessions-DAE8Nf1F.js.map → AdminUserSessions-Ds3ODq_d.js.map} +1 -1
  27. package/dist/admin/{AdminUserSettings-EbahaV2a.js → AdminUserSettings-CGh4gROo.js} +4 -3
  28. package/dist/admin/{AdminUserSettings-EbahaV2a.js.map → AdminUserSettings-CGh4gROo.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-Dcjh0KNW.js → AdminUsers-CvPiBzQK.js} +4 -3
  30. package/dist/admin/{AdminUsers-Dcjh0KNW.js.map → AdminUsers-CvPiBzQK.js.map} +1 -1
  31. package/dist/admin/index.d.ts +22 -10
  32. package/dist/admin/index.d.ts.map +1 -1
  33. package/dist/admin/index.js +47 -48
  34. package/dist/admin/index.js.map +1 -1
  35. package/dist/admin/rolldown-runtime-CjeV3_4I.js +18 -0
  36. package/dist/auth/{AuthLayout-mFOWbiSP.js → AuthLayout-CdJcrPs4.js} +2 -4
  37. package/dist/auth/AuthLayout-CdJcrPs4.js.map +1 -0
  38. package/dist/{demo/IconGoogle-CbBF8Hqq.js → auth/IconGoogle-Bm18QD2q.js} +2 -4
  39. package/dist/auth/{IconGoogle-DpSlPZ1u.js.map → IconGoogle-Bm18QD2q.js.map} +1 -1
  40. package/dist/auth/{Login-BBqTosqZ.js → Login-DS_OqA0G.js} +7 -6
  41. package/dist/auth/Login-DS_OqA0G.js.map +1 -0
  42. package/dist/auth/{Profile-Bxj8Nwom.js → Profile-Di7N7HZL.js} +2 -3
  43. package/dist/auth/{Profile-Bxj8Nwom.js.map → Profile-Di7N7HZL.js.map} +1 -1
  44. package/dist/auth/{Register-Ce675Crg.js → Register-BRR2_gux.js} +7 -6
  45. package/dist/auth/Register-BRR2_gux.js.map +1 -0
  46. package/dist/auth/{ResetPassword-DWdt7c40.js → ResetPassword-oQu72lod.js} +4 -3
  47. package/dist/auth/{ResetPassword-DWdt7c40.js.map → ResetPassword-oQu72lod.js.map} +1 -1
  48. package/dist/auth/{VerifyEmail-CI4JwByV.js → VerifyEmail-DC6HPZjd.js} +4 -3
  49. package/dist/auth/{VerifyEmail-CI4JwByV.js.map → VerifyEmail-DC6HPZjd.js.map} +1 -1
  50. package/dist/auth/index.d.ts +14 -14
  51. package/dist/auth/index.d.ts.map +1 -1
  52. package/dist/auth/index.js +13 -17
  53. package/dist/auth/index.js.map +1 -1
  54. package/dist/auth/rolldown-runtime-CjeV3_4I.js +18 -0
  55. package/dist/core/index.d.ts +147 -68
  56. package/dist/core/index.d.ts.map +1 -1
  57. package/dist/core/index.js +349 -287
  58. package/dist/core/index.js.map +1 -1
  59. package/dist/demo/{DemoDataTable-CguplbR7.js → DemoDataTable-DCsJq8v5.js} +4 -5
  60. package/dist/demo/DemoDataTable-DCsJq8v5.js.map +1 -0
  61. package/dist/demo/{DemoHome-Cce2bWmg.js → DemoHome-DpRrPlBC.js} +4 -3
  62. package/dist/demo/{DemoHome-Cce2bWmg.js.map → DemoHome-DpRrPlBC.js.map} +1 -1
  63. package/dist/demo/{DemoJsonViewer-Dgdk3Txb.js → DemoJsonViewer-zeucGKHV.js} +6 -5
  64. package/dist/demo/DemoJsonViewer-zeucGKHV.js.map +1 -0
  65. package/dist/demo/{DemoLayout-B20TEuhV.js → DemoLayout-PhgbAAiQ.js} +6 -5
  66. package/dist/demo/DemoLayout-PhgbAAiQ.js.map +1 -0
  67. package/dist/demo/{DemoLogin-CvCG2WVh.js → DemoLogin-DSzP0Lkv.js} +8 -10
  68. package/dist/demo/DemoLogin-DSzP0Lkv.js.map +1 -0
  69. package/dist/demo/{DemoRegister-CmeHbOAs.js → DemoRegister-DavFBsCz.js} +8 -10
  70. package/dist/demo/DemoRegister-DavFBsCz.js.map +1 -0
  71. package/dist/demo/{DemoResetPassword-CKO5iA_6.js → DemoResetPassword-BS2rIAQK.js} +5 -7
  72. package/dist/demo/DemoResetPassword-BS2rIAQK.js.map +1 -0
  73. package/dist/demo/{DemoSidebar-MVmQKfMt.js → DemoSidebar-zNkUmHRl.js} +4 -5
  74. package/dist/demo/DemoSidebar-zNkUmHRl.js.map +1 -0
  75. package/dist/demo/{DemoTypeForm-w-qtfRlC.js → DemoTypeForm-B9q7oT0b.js} +4 -5
  76. package/dist/demo/DemoTypeForm-B9q7oT0b.js.map +1 -0
  77. package/dist/demo/{DemoVerifyEmail-C8FFJT5A.js → DemoVerifyEmail-Bi4SdWz0.js} +5 -7
  78. package/dist/demo/DemoVerifyEmail-Bi4SdWz0.js.map +1 -0
  79. package/dist/{auth/IconGoogle-DpSlPZ1u.js → demo/IconGoogle-CTeZyrek.js} +2 -4
  80. package/dist/demo/{IconGoogle-CbBF8Hqq.js.map → IconGoogle-CTeZyrek.js.map} +1 -1
  81. package/dist/demo/{Showcase-CQrMWars.js → Showcase-C9btr_SJ.js} +3 -5
  82. package/dist/demo/Showcase-C9btr_SJ.js.map +1 -0
  83. package/dist/demo/index.d.ts +2 -2
  84. package/dist/demo/index.d.ts.map +1 -1
  85. package/dist/demo/index.js +15 -15
  86. package/dist/demo/rolldown-runtime-CjeV3_4I.js +18 -0
  87. package/package.json +5 -3
  88. package/src/admin/AdminRouter.ts +15 -24
  89. package/src/admin/components/AdminLayout.tsx +6 -10
  90. package/src/admin/components/parameters/AdminParameters.tsx +154 -76
  91. package/src/admin/components/parameters/ParameterDetails.tsx +153 -93
  92. package/src/admin/components/parameters/ParameterEmptyState.tsx +27 -0
  93. package/src/admin/components/parameters/ParameterHistory.tsx +15 -20
  94. package/src/admin/components/parameters/ParameterTree.tsx +280 -104
  95. package/src/admin/components/parameters/types.ts +3 -3
  96. package/src/admin/primitives/$uiAdmin.ts +2 -2
  97. package/src/auth/AuthRouter.ts +1 -4
  98. package/src/auth/components/AuthLayout.tsx +0 -1
  99. package/src/core/components/buttons/ActionButton.tsx +4 -15
  100. package/src/core/components/buttons/DarkModeButton.tsx +8 -4
  101. package/src/core/components/buttons/ToggleSidebarButton.tsx +3 -5
  102. package/src/core/components/form/Control.tsx +10 -32
  103. package/src/core/components/form/ControlArray.tsx +200 -89
  104. package/src/core/components/form/TypeForm.browser.spec.tsx +727 -0
  105. package/src/core/components/layout/AlephaMantineProvider.tsx +1 -0
  106. package/src/core/components/layout/Breadcrumb.tsx +91 -0
  107. package/src/core/components/layout/{AdminShell.tsx → DashboardShell.tsx} +77 -32
  108. package/src/core/components/layout/Sidebar.tsx +58 -18
  109. package/src/core/constants/ui.ts +1 -1
  110. package/src/core/helpers/renderIcon.tsx +5 -2
  111. package/src/core/index.ts +9 -5
  112. package/src/core/styles.css +7 -6
  113. package/src/core/utils/string.ts +28 -4
  114. package/src/demo/components/DemoLayout.tsx +6 -2
  115. package/dist/admin/AdminApiKeys-DsmGnHNh.js +0 -3
  116. package/dist/admin/AdminAudits-8SM96viT.js +0 -3
  117. package/dist/admin/AdminFiles-B56ocq4H.js +0 -3
  118. package/dist/admin/AdminJobs-CED1syCn.js +0 -3
  119. package/dist/admin/AdminLayout-D8yZ-8lG.js.map +0 -1
  120. package/dist/admin/AdminNotifications-B0B1rdc4.js +0 -3
  121. package/dist/admin/AdminParameters-BU3lATdJ.js +0 -3
  122. package/dist/admin/AdminParameters-CfDUpc78.js +0 -575
  123. package/dist/admin/AdminParameters-CfDUpc78.js.map +0 -1
  124. package/dist/admin/AdminSessions-BDGK2MS6.js +0 -3
  125. package/dist/admin/AdminUserAudits-Cj79gENT.js +0 -3
  126. package/dist/admin/AdminUserCreate-Cq-mUmBs.js +0 -3
  127. package/dist/admin/AdminUserDetails-DRjVAPFd.js +0 -3
  128. package/dist/admin/AdminUserLayout-CGzmHHby.js +0 -3
  129. package/dist/admin/AdminUserLayout-CiPay35T.js.map +0 -1
  130. package/dist/admin/AdminUserSessions-DcdzuNZ9.js +0 -3
  131. package/dist/admin/AdminUserSettings-D7V6-ceX.js +0 -3
  132. package/dist/admin/AdminUsers-D9nyzGqQ.js +0 -3
  133. package/dist/auth/AuthLayout-mFOWbiSP.js.map +0 -1
  134. package/dist/auth/Login-BBqTosqZ.js.map +0 -1
  135. package/dist/auth/Login-CoU63mMR.js +0 -4
  136. package/dist/auth/Register-BV_oa_AK.js +0 -4
  137. package/dist/auth/Register-Ce675Crg.js.map +0 -1
  138. package/dist/auth/ResetPassword-D5wC8GAA.js +0 -3
  139. package/dist/auth/VerifyEmail-DAfqVm5s.js +0 -3
  140. package/dist/demo/DemoDataTable-CguplbR7.js.map +0 -1
  141. package/dist/demo/DemoHome-DC9qkMNe.js +0 -3
  142. package/dist/demo/DemoJsonViewer-DIssGVlJ.js +0 -4
  143. package/dist/demo/DemoJsonViewer-Dgdk3Txb.js.map +0 -1
  144. package/dist/demo/DemoLayout-B20TEuhV.js.map +0 -1
  145. package/dist/demo/DemoLayout-DSRyf4qJ.js +0 -3
  146. package/dist/demo/DemoLogin-CvCG2WVh.js.map +0 -1
  147. package/dist/demo/DemoRegister-CmeHbOAs.js.map +0 -1
  148. package/dist/demo/DemoResetPassword-CKO5iA_6.js.map +0 -1
  149. package/dist/demo/DemoSidebar-MVmQKfMt.js.map +0 -1
  150. package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +0 -1
  151. package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +0 -1
  152. package/dist/demo/Showcase-CQrMWars.js.map +0 -1
@@ -0,0 +1,767 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
2
+ import { ActionButton, Flex, Text, TypeForm, useToast } from "@alepha/ui";
3
+ import { jsonSchemaToTypeBox, t } from "alepha";
4
+ import { IconArrowLeft, IconChevronDown, IconChevronRight, IconClock, IconFolder, IconFolderOpen, IconHistory, IconRefresh, IconSearch, IconSettings } from "@tabler/icons-react";
5
+ import { Badge, Box, Card, Code, Collapse, Flex as Flex$1, Group, Loader, ScrollArea, Stack, TextInput, Timeline, UnstyledButton } from "@mantine/core";
6
+ import { useClient } from "alepha/react";
7
+ import { useI18n } from "alepha/react/i18n";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { memo, useCallback, useEffect, useMemo, useState } from "react";
10
+ import { useForm } from "alepha/react/form";
11
+
12
+ //#region ../../src/admin/components/parameters/types.ts
13
+ const getStatusColor = (status) => {
14
+ switch (status) {
15
+ case "current": return "green";
16
+ case "next": return "blue";
17
+ case "future": return "cyan";
18
+ case "expired": return "gray";
19
+ default: return "gray";
20
+ }
21
+ };
22
+ const formatJson = (obj) => {
23
+ try {
24
+ return JSON.stringify(obj, null, 2);
25
+ } catch {
26
+ return String(obj);
27
+ }
28
+ };
29
+
30
+ //#endregion
31
+ //#region ../../src/admin/components/parameters/ParameterDetails.tsx
32
+ /**
33
+ * Loading state.
34
+ */
35
+ const LoadingState = () => /* @__PURE__ */ jsx(Box, {
36
+ flex: 1,
37
+ h: "100%",
38
+ p: "md",
39
+ style: {
40
+ overflow: "hidden",
41
+ minWidth: 0,
42
+ display: "flex"
43
+ },
44
+ children: /* @__PURE__ */ jsx(Flex, {
45
+ flex: 1,
46
+ justify: "center",
47
+ align: "center",
48
+ h: "100%",
49
+ children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
50
+ })
51
+ });
52
+ /**
53
+ * The actual form component - only rendered when a config is selected.
54
+ */
55
+ const ConfigForm = ({ selectedConfig, configValue, saving, onSave }) => {
56
+ const { l } = useI18n();
57
+ const currentContent = useMemo(() => {
58
+ if (configValue?.current?.content) return configValue.current.content;
59
+ if (configValue?.currentValue !== void 0) return configValue.currentValue;
60
+ return null;
61
+ }, [configValue]);
62
+ const schemaForForm = useMemo(() => {
63
+ if (!configValue?.schema) return t.object({});
64
+ try {
65
+ return jsonSchemaToTypeBox(configValue.schema);
66
+ } catch {
67
+ return t.object({});
68
+ }
69
+ }, [configValue?.schema]);
70
+ const form = useForm({
71
+ schema: schemaForForm,
72
+ initialValues: currentContent ?? {},
73
+ handler: async (values) => {
74
+ await onSave(values);
75
+ }
76
+ }, [
77
+ selectedConfig,
78
+ schemaForForm,
79
+ currentContent
80
+ ]);
81
+ const hasValidSchema = useMemo(() => {
82
+ const schema = configValue?.schema;
83
+ return schema && typeof schema === "object" && "properties" in schema && Object.keys(schema.properties).length > 0;
84
+ }, [configValue?.schema]);
85
+ const fieldCount = useMemo(() => {
86
+ const schema = configValue?.schema;
87
+ if (schema && typeof schema === "object" && "properties" in schema && schema.properties) return Object.keys(schema.properties).length;
88
+ return 0;
89
+ }, [configValue?.schema]);
90
+ const columns = useMemo(() => {
91
+ if (fieldCount <= 2) return 1;
92
+ if (fieldCount <= 6) return 2;
93
+ return 3;
94
+ }, [fieldCount]);
95
+ return /* @__PURE__ */ jsx(Box, {
96
+ flex: 1,
97
+ h: "100%",
98
+ style: {
99
+ overflow: "hidden",
100
+ minWidth: 0,
101
+ display: "flex"
102
+ },
103
+ children: /* @__PURE__ */ jsxs(Flex, {
104
+ direction: "column",
105
+ h: "100%",
106
+ w: "100%",
107
+ style: { minHeight: 0 },
108
+ children: [/* @__PURE__ */ jsx(Box, {
109
+ flex: 1,
110
+ p: "md",
111
+ className: "overflow-auto",
112
+ style: { minHeight: 0 },
113
+ children: currentContent !== null ? /* @__PURE__ */ jsxs(Stack, {
114
+ gap: "lg",
115
+ children: [
116
+ /* @__PURE__ */ jsx(Box, { children: hasValidSchema ? /* @__PURE__ */ jsx(TypeForm, {
117
+ form,
118
+ columns,
119
+ skipSubmitButton: true,
120
+ fill: false
121
+ }) : /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
122
+ size: "xs",
123
+ c: "dimmed",
124
+ mb: 4,
125
+ children: "Current Value"
126
+ }), /* @__PURE__ */ jsx(Code, {
127
+ block: true,
128
+ style: { whiteSpace: "pre-wrap" },
129
+ children: formatJson(currentContent)
130
+ })] }) }),
131
+ configValue?.current?.changeDescription && /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
132
+ size: "xs",
133
+ c: "dimmed",
134
+ mb: 4,
135
+ children: "Change Description"
136
+ }), /* @__PURE__ */ jsx(Text, {
137
+ size: "sm",
138
+ children: configValue.current.changeDescription
139
+ })] }),
140
+ configValue?.current && /* @__PURE__ */ jsxs(Group, {
141
+ gap: "xl",
142
+ children: [/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
143
+ size: "xs",
144
+ c: "dimmed",
145
+ mb: 2,
146
+ children: "Updated"
147
+ }), /* @__PURE__ */ jsx(Text, {
148
+ size: "sm",
149
+ children: l(configValue.current.updatedAt, { date: "fromNow" })
150
+ })] }), configValue.current.creatorName && /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
151
+ size: "xs",
152
+ c: "dimmed",
153
+ mb: 2,
154
+ children: "Updated By"
155
+ }), /* @__PURE__ */ jsx(Text, {
156
+ size: "sm",
157
+ children: configValue.current.creatorName
158
+ })] })]
159
+ }),
160
+ !configValue?.current && configValue?.currentValue !== void 0 && /* @__PURE__ */ jsx(Text, {
161
+ size: "xs",
162
+ c: "dimmed",
163
+ children: "This configuration is using its default value. No versions have been saved to the database yet."
164
+ }),
165
+ configValue?.next && /* @__PURE__ */ jsx(Card, {
166
+ withBorder: true,
167
+ p: "sm",
168
+ bg: "var(--mantine-color-blue-light)",
169
+ children: /* @__PURE__ */ jsxs(Stack, {
170
+ gap: "xs",
171
+ children: [
172
+ /* @__PURE__ */ jsxs(Group, {
173
+ gap: "xs",
174
+ children: [/* @__PURE__ */ jsx(IconClock, {
175
+ size: 14,
176
+ color: "var(--mantine-color-blue-6)"
177
+ }), /* @__PURE__ */ jsxs(Text, {
178
+ size: "xs",
179
+ fw: 500,
180
+ c: "blue",
181
+ children: [
182
+ "Scheduled Update (v",
183
+ configValue.next.version,
184
+ ")"
185
+ ]
186
+ })]
187
+ }),
188
+ /* @__PURE__ */ jsxs(Text, {
189
+ size: "xs",
190
+ c: "dimmed",
191
+ children: [
192
+ "Activates",
193
+ " ",
194
+ l(configValue.next.activationDate, { date: "fromNow" })
195
+ ]
196
+ }),
197
+ /* @__PURE__ */ jsx(Code, {
198
+ block: true,
199
+ style: { whiteSpace: "pre-wrap" },
200
+ fz: "xs",
201
+ children: formatJson(configValue.next.content)
202
+ })
203
+ ]
204
+ })
205
+ })
206
+ ]
207
+ }) : /* @__PURE__ */ jsx(Flex, {
208
+ justify: "center",
209
+ align: "center",
210
+ h: 200,
211
+ children: /* @__PURE__ */ jsx(Text, {
212
+ c: "dimmed",
213
+ size: "sm",
214
+ children: "No current value"
215
+ })
216
+ })
217
+ }), hasValidSchema && currentContent !== null && /* @__PURE__ */ jsx(Box, {
218
+ p: "md",
219
+ style: {
220
+ flexShrink: 0,
221
+ borderTop: "1px solid var(--mantine-color-default-border)"
222
+ },
223
+ children: /* @__PURE__ */ jsxs(Group, {
224
+ justify: "flex-end",
225
+ gap: "sm",
226
+ children: [/* @__PURE__ */ jsx(ActionButton, {
227
+ variant: "subtle",
228
+ onClick: () => form.reset({}),
229
+ disabled: saving,
230
+ children: "Reset"
231
+ }), /* @__PURE__ */ jsx(ActionButton, {
232
+ intent: "primary",
233
+ form,
234
+ loading: saving,
235
+ children: "Save Changes"
236
+ })]
237
+ })
238
+ })]
239
+ })
240
+ });
241
+ };
242
+ /**
243
+ * Parameter details panel.
244
+ * Shows loading state or the config form.
245
+ * Note: Empty state is handled by parent (AdminParameters).
246
+ */
247
+ const ParameterDetails = ({ selectedConfig, configValue, loading, saving, onSave }) => {
248
+ if (loading) return /* @__PURE__ */ jsx(LoadingState, {});
249
+ return /* @__PURE__ */ jsx(ConfigForm, {
250
+ selectedConfig,
251
+ configValue,
252
+ saving,
253
+ onSave
254
+ });
255
+ };
256
+
257
+ //#endregion
258
+ //#region ../../src/admin/components/parameters/ParameterEmptyState.tsx
259
+ /**
260
+ * Empty state displayed when no parameter is selected.
261
+ * Invites user to select a parameter from the tree.
262
+ */
263
+ const ParameterEmptyState = () => {
264
+ return /* @__PURE__ */ jsx(Flex$1, {
265
+ flex: 1,
266
+ p: "xl",
267
+ align: "center",
268
+ children: /* @__PURE__ */ jsxs(Stack, {
269
+ align: "center",
270
+ gap: "md",
271
+ children: [/* @__PURE__ */ jsx(IconArrowLeft, {
272
+ size: 32,
273
+ color: "var(--mantine-color-dimmed)"
274
+ }), /* @__PURE__ */ jsxs(Stack, {
275
+ align: "center",
276
+ gap: 4,
277
+ children: [/* @__PURE__ */ jsx(Text, {
278
+ fw: 500,
279
+ c: "dimmed",
280
+ children: "No Parameter Selected"
281
+ }), /* @__PURE__ */ jsx(Text, {
282
+ size: "xs",
283
+ c: "dimmed",
284
+ ta: "center",
285
+ maw: 240,
286
+ children: "Choose a parameter from the tree to view and edit its configuration"
287
+ })]
288
+ })]
289
+ })
290
+ });
291
+ };
292
+
293
+ //#endregion
294
+ //#region ../../src/admin/components/parameters/ParameterHistory.tsx
295
+ const ParameterHistory = ({ history, loading, onRollback }) => {
296
+ const { l } = useI18n();
297
+ const renderContent = () => {
298
+ if (loading) return /* @__PURE__ */ jsx(Flex, {
299
+ flex: 1,
300
+ justify: "center",
301
+ align: "center",
302
+ children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
303
+ });
304
+ if (history.length === 0) return /* @__PURE__ */ jsx(Flex, {
305
+ flex: 1,
306
+ justify: "center",
307
+ align: "center",
308
+ children: /* @__PURE__ */ jsx(Text, {
309
+ c: "dimmed",
310
+ size: "xs",
311
+ children: "Empty"
312
+ })
313
+ });
314
+ return /* @__PURE__ */ jsx(ScrollArea, {
315
+ flex: 1,
316
+ offsetScrollbars: true,
317
+ children: /* @__PURE__ */ jsx(Timeline, {
318
+ active: history.findIndex((h) => h.status === "current"),
319
+ bulletSize: 24,
320
+ lineWidth: 2,
321
+ children: history.map((version) => /* @__PURE__ */ jsx(Timeline.Item, {
322
+ bullet: /* @__PURE__ */ jsx(Text, {
323
+ size: "xs",
324
+ fw: 500,
325
+ children: version.version
326
+ }),
327
+ title: /* @__PURE__ */ jsxs(Group, {
328
+ gap: "xs",
329
+ children: [/* @__PURE__ */ jsxs(Text, {
330
+ size: "xs",
331
+ fw: 500,
332
+ children: ["Version ", version.version]
333
+ }), /* @__PURE__ */ jsx(Badge, {
334
+ size: "xs",
335
+ variant: "light",
336
+ color: getStatusColor(version.status),
337
+ children: version.status
338
+ })]
339
+ }),
340
+ children: /* @__PURE__ */ jsxs(Stack, {
341
+ gap: 4,
342
+ mt: 4,
343
+ children: [
344
+ /* @__PURE__ */ jsx(Text, {
345
+ size: "xs",
346
+ c: "dimmed",
347
+ children: l(version.createdAt, { date: "fromNow" })
348
+ }),
349
+ version.changeDescription && /* @__PURE__ */ jsx(Text, {
350
+ size: "xs",
351
+ lineClamp: 2,
352
+ children: version.changeDescription
353
+ }),
354
+ version.creatorName && /* @__PURE__ */ jsxs(Text, {
355
+ size: "xs",
356
+ c: "dimmed",
357
+ children: ["by ", version.creatorName]
358
+ }),
359
+ version.migrationLog && /* @__PURE__ */ jsx(Badge, {
360
+ size: "xs",
361
+ variant: "outline",
362
+ color: "orange",
363
+ children: "Schema Changed"
364
+ }),
365
+ version.status === "expired" && /* @__PURE__ */ jsx(ActionButton, {
366
+ size: "compact-xs",
367
+ variant: "subtle",
368
+ onClick: () => onRollback(version.version),
369
+ children: "Rollback to this version"
370
+ })
371
+ ]
372
+ })
373
+ }, version.id))
374
+ })
375
+ });
376
+ };
377
+ return /* @__PURE__ */ jsx(Box, {
378
+ w: 160,
379
+ h: "100%",
380
+ p: "xs",
381
+ style: {
382
+ flexShrink: 0,
383
+ overflow: "hidden",
384
+ display: "flex",
385
+ flexDirection: "column",
386
+ borderLeft: "1px solid var(--mantine-color-default-border)"
387
+ },
388
+ children: /* @__PURE__ */ jsxs(Stack, {
389
+ gap: "xs",
390
+ h: "100%",
391
+ style: { minHeight: 0 },
392
+ children: [/* @__PURE__ */ jsxs(Group, {
393
+ gap: "xs",
394
+ children: [/* @__PURE__ */ jsx(IconHistory, {
395
+ size: 16,
396
+ color: "var(--mantine-color-dimmed)"
397
+ }), /* @__PURE__ */ jsx(Text, {
398
+ size: "sm",
399
+ fw: 500,
400
+ children: "History"
401
+ })]
402
+ }), renderContent()]
403
+ })
404
+ });
405
+ };
406
+
407
+ //#endregion
408
+ //#region ../../src/admin/components/parameters/ParameterTree.tsx
409
+ /**
410
+ * Filters tree nodes by search query.
411
+ */
412
+ const filterTree = (nodes, query) => {
413
+ if (!query.trim()) return nodes;
414
+ const lowerQuery = query.toLowerCase();
415
+ return nodes.map((node) => {
416
+ const filteredChildren = filterTree(node.children, query);
417
+ const nameMatches = node.name.toLowerCase().includes(lowerQuery);
418
+ const pathMatches = node.path.toLowerCase().includes(lowerQuery);
419
+ if (nameMatches || pathMatches || filteredChildren.length > 0) return {
420
+ ...node,
421
+ children: filteredChildren
422
+ };
423
+ return null;
424
+ }).filter((node) => node !== null);
425
+ };
426
+ /**
427
+ * Memoized tree node to prevent unnecessary re-renders.
428
+ */
429
+ const TreeNode = memo(({ node, level, selectedConfig, onSelect, expandedNodes, onToggle }) => {
430
+ const [isHovered, setIsHovered] = useState(false);
431
+ const hasChildren = node.children.length > 0;
432
+ const isExpanded = expandedNodes.has(node.path);
433
+ const isSelected = selectedConfig === node.path;
434
+ const isLeaf = !hasChildren;
435
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(UnstyledButton, {
436
+ onClick: useCallback(() => {
437
+ if (hasChildren) onToggle(node.path);
438
+ else onSelect(node.path);
439
+ }, [
440
+ hasChildren,
441
+ node.path,
442
+ onToggle,
443
+ onSelect
444
+ ]),
445
+ onMouseEnter: useCallback(() => setIsHovered(true), []),
446
+ onMouseLeave: useCallback(() => setIsHovered(false), []),
447
+ w: "100%",
448
+ style: { display: "block" },
449
+ children: /* @__PURE__ */ jsxs(Group, {
450
+ gap: 6,
451
+ wrap: "nowrap",
452
+ p: "4px 8px",
453
+ pl: 8 + level * 16,
454
+ style: {
455
+ borderRadius: "var(--mantine-radius-sm)",
456
+ backgroundColor: isSelected || isHovered ? "var(--mantine-color-default-hover)" : void 0
457
+ },
458
+ children: [hasChildren ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Box, {
459
+ style: {
460
+ display: "flex",
461
+ alignItems: "center",
462
+ justifyContent: "center",
463
+ width: 16
464
+ },
465
+ children: isExpanded ? /* @__PURE__ */ jsx(IconChevronDown, {
466
+ size: 14,
467
+ color: "var(--mantine-color-dimmed)"
468
+ }) : /* @__PURE__ */ jsx(IconChevronRight, {
469
+ size: 14,
470
+ color: "var(--mantine-color-dimmed)"
471
+ })
472
+ }), isExpanded ? /* @__PURE__ */ jsx(IconFolderOpen, {
473
+ size: 16,
474
+ color: "var(--mantine-color-dimmed)",
475
+ style: { flexShrink: 0 }
476
+ }) : /* @__PURE__ */ jsx(IconFolder, {
477
+ size: 16,
478
+ color: "var(--mantine-color-dimmed)",
479
+ style: { flexShrink: 0 }
480
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Box, { w: 16 }), /* @__PURE__ */ jsx(IconSettings, {
481
+ size: 16,
482
+ color: isSelected ? "var(--mantine-color-blue-6)" : "var(--mantine-color-dimmed)",
483
+ style: { flexShrink: 0 }
484
+ })] }), /* @__PURE__ */ jsx(Text, {
485
+ size: "sm",
486
+ fw: isSelected ? 600 : 400,
487
+ c: isSelected ? void 0 : isLeaf ? void 0 : "dimmed",
488
+ style: {
489
+ whiteSpace: "nowrap",
490
+ overflow: "hidden",
491
+ textOverflow: "ellipsis"
492
+ },
493
+ children: node.name
494
+ })]
495
+ })
496
+ }), hasChildren && /* @__PURE__ */ jsx(Collapse, {
497
+ in: isExpanded,
498
+ children: node.children.map((child) => /* @__PURE__ */ jsx(TreeNode, {
499
+ node: child,
500
+ level: level + 1,
501
+ selectedConfig,
502
+ onSelect,
503
+ expandedNodes,
504
+ onToggle
505
+ }, child.path))
506
+ })] });
507
+ });
508
+ TreeNode.displayName = "TreeNode";
509
+ /**
510
+ * Collects all folder paths to expand by default.
511
+ */
512
+ const collectAllFolderPaths = (nodes) => {
513
+ const paths = /* @__PURE__ */ new Set();
514
+ const traverse = (nodeList) => {
515
+ for (const node of nodeList) if (node.children.length > 0) {
516
+ paths.add(node.path);
517
+ traverse(node.children);
518
+ }
519
+ };
520
+ traverse(nodes);
521
+ return paths;
522
+ };
523
+ const ParameterTree = ({ treeData, selectedConfig, onSelect, onRefresh }) => {
524
+ const [searchQuery, setSearchQuery] = useState("");
525
+ const [expandedNodes, setExpandedNodes] = useState(() => collectAllFolderPaths(treeData));
526
+ const filteredTreeData = useMemo(() => filterTree(treeData, searchQuery), [treeData, searchQuery]);
527
+ const handleToggle = useCallback((path) => {
528
+ setExpandedNodes((prev) => {
529
+ const next = new Set(prev);
530
+ if (next.has(path)) next.delete(path);
531
+ else next.add(path);
532
+ return next;
533
+ });
534
+ }, []);
535
+ const handleSearchChange = useCallback((e) => {
536
+ setSearchQuery(e.currentTarget.value);
537
+ }, []);
538
+ return /* @__PURE__ */ jsx(Box, {
539
+ w: 280,
540
+ h: "100%",
541
+ p: "sm",
542
+ style: {
543
+ flexShrink: 0,
544
+ display: "flex",
545
+ flexDirection: "column",
546
+ borderRight: "1px solid var(--mantine-color-default-border)"
547
+ },
548
+ children: /* @__PURE__ */ jsxs(Stack, {
549
+ gap: "sm",
550
+ h: "100%",
551
+ style: { minHeight: 0 },
552
+ children: [
553
+ /* @__PURE__ */ jsxs(Group, {
554
+ justify: "space-between",
555
+ gap: "xs",
556
+ children: [/* @__PURE__ */ jsx(Text, {
557
+ size: "sm",
558
+ fw: 600,
559
+ children: "Parameters"
560
+ }), /* @__PURE__ */ jsx(ActionButton, {
561
+ variant: "subtle",
562
+ size: "compact-xs",
563
+ onClick: onRefresh,
564
+ tooltip: "Refresh",
565
+ children: /* @__PURE__ */ jsx(IconRefresh, { size: 14 })
566
+ })]
567
+ }),
568
+ /* @__PURE__ */ jsx(TextInput, {
569
+ placeholder: "Search...",
570
+ size: "xs",
571
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 14 }),
572
+ value: searchQuery,
573
+ onChange: handleSearchChange
574
+ }),
575
+ /* @__PURE__ */ jsx(ScrollArea, {
576
+ flex: 1,
577
+ offsetScrollbars: true,
578
+ style: { minHeight: 0 },
579
+ children: filteredTreeData.length === 0 ? /* @__PURE__ */ jsx(Text, {
580
+ size: "xs",
581
+ c: "dimmed",
582
+ ta: "center",
583
+ py: "md",
584
+ children: searchQuery ? "No matching parameters" : "No parameters"
585
+ }) : /* @__PURE__ */ jsx(Stack, {
586
+ gap: 0,
587
+ style: { gap: 1 },
588
+ children: filteredTreeData.map((node) => /* @__PURE__ */ jsx(TreeNode, {
589
+ node,
590
+ level: 0,
591
+ selectedConfig,
592
+ onSelect,
593
+ expandedNodes,
594
+ onToggle: handleToggle
595
+ }, node.path))
596
+ })
597
+ })
598
+ ]
599
+ })
600
+ });
601
+ };
602
+
603
+ //#endregion
604
+ //#region ../../src/admin/components/parameters/AdminParameters.tsx
605
+ var AdminParameters_exports = /* @__PURE__ */ __exportAll({ default: () => AdminParameters });
606
+ const AdminParameters = ({ treeData: initialTreeData }) => {
607
+ const client = useClient();
608
+ const toast = useToast();
609
+ const [treeData, setTreeData] = useState(initialTreeData);
610
+ const [selectedConfig, setSelectedConfig] = useState(null);
611
+ const [configValue, setConfigValue] = useState(null);
612
+ const [history, setHistory] = useState([]);
613
+ const [loadingConfig, setLoadingConfig] = useState(false);
614
+ const [loadingHistory, setLoadingHistory] = useState(false);
615
+ const [saving, setSaving] = useState(false);
616
+ const handleRefresh = useCallback(async () => {
617
+ try {
618
+ setTreeData(await client.getParameterTree({}));
619
+ } catch (error) {
620
+ toast.danger({
621
+ title: "Failed to refresh parameters",
622
+ message: error instanceof Error ? error.message : "Unknown error"
623
+ });
624
+ }
625
+ }, [client, toast]);
626
+ const loadConfigDetails = useCallback(async (name) => {
627
+ setLoadingConfig(true);
628
+ setLoadingHistory(true);
629
+ try {
630
+ const [currentResponse, historyResponse] = await Promise.all([client.getCurrent({ params: { name } }), client.getHistory({ params: { name } })]);
631
+ setConfigValue(currentResponse);
632
+ setHistory(historyResponse.versions);
633
+ } catch (error) {
634
+ toast.danger({
635
+ title: "Failed to load configuration",
636
+ message: error instanceof Error ? error.message : "Unknown error"
637
+ });
638
+ setConfigValue(null);
639
+ setHistory([]);
640
+ } finally {
641
+ setLoadingConfig(false);
642
+ setLoadingHistory(false);
643
+ }
644
+ }, [client, toast]);
645
+ const handleSave = useCallback(async (values) => {
646
+ if (!selectedConfig || !configValue) return;
647
+ setSaving(true);
648
+ try {
649
+ await client.createVersion({
650
+ params: { name: selectedConfig },
651
+ body: {
652
+ content: values,
653
+ schemaHash: "",
654
+ changeDescription: "Updated via admin UI"
655
+ }
656
+ });
657
+ toast.success({
658
+ title: "Configuration saved",
659
+ message: `${selectedConfig} has been updated`
660
+ });
661
+ await loadConfigDetails(selectedConfig);
662
+ } catch (error) {
663
+ toast.danger({
664
+ title: "Failed to save configuration",
665
+ message: error instanceof Error ? error.message : "Unknown error"
666
+ });
667
+ throw error;
668
+ } finally {
669
+ setSaving(false);
670
+ }
671
+ }, [
672
+ client,
673
+ selectedConfig,
674
+ configValue,
675
+ loadConfigDetails,
676
+ toast
677
+ ]);
678
+ useEffect(() => {
679
+ if (selectedConfig) loadConfigDetails(selectedConfig);
680
+ else {
681
+ setConfigValue(null);
682
+ setHistory([]);
683
+ }
684
+ }, [selectedConfig, loadConfigDetails]);
685
+ const handleRollback = useCallback(async (version) => {
686
+ if (!selectedConfig) return;
687
+ try {
688
+ await client.rollback({
689
+ params: { name: selectedConfig },
690
+ body: { targetVersion: version }
691
+ });
692
+ toast.success({
693
+ title: "Rollback successful",
694
+ message: `${selectedConfig} rolled back to version ${version}`
695
+ });
696
+ await loadConfigDetails(selectedConfig);
697
+ } catch (error) {
698
+ toast.danger({
699
+ title: "Rollback failed",
700
+ message: error instanceof Error ? error.message : "Unknown error"
701
+ });
702
+ }
703
+ }, [
704
+ client,
705
+ selectedConfig,
706
+ loadConfigDetails,
707
+ toast
708
+ ]);
709
+ if (treeData.length === 0) return /* @__PURE__ */ jsx(Flex$1, {
710
+ flex: 1,
711
+ justify: "center",
712
+ align: "center",
713
+ children: /* @__PURE__ */ jsxs(Stack, {
714
+ align: "center",
715
+ gap: "xs",
716
+ children: [
717
+ /* @__PURE__ */ jsx(IconSettings, {
718
+ size: 48,
719
+ stroke: 1.5,
720
+ color: "var(--mantine-color-dimmed)"
721
+ }),
722
+ /* @__PURE__ */ jsx(Text, {
723
+ c: "dimmed",
724
+ children: "No Parameters Found"
725
+ }),
726
+ /* @__PURE__ */ jsx(Text, {
727
+ size: "xs",
728
+ c: "dimmed",
729
+ ta: "center",
730
+ maw: 400,
731
+ children: "Define parameters using the $parameter primitive to manage dynamic application settings. Parameters will appear here once created."
732
+ })
733
+ ]
734
+ })
735
+ });
736
+ return /* @__PURE__ */ jsx(Flex$1, {
737
+ flex: 1,
738
+ p: "md",
739
+ children: /* @__PURE__ */ jsxs(Card, {
740
+ withBorder: true,
741
+ p: 0,
742
+ w: "100%",
743
+ style: { flexDirection: "row" },
744
+ children: [/* @__PURE__ */ jsx(ParameterTree, {
745
+ treeData,
746
+ selectedConfig,
747
+ onSelect: setSelectedConfig,
748
+ onRefresh: handleRefresh
749
+ }), selectedConfig ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ParameterDetails, {
750
+ selectedConfig,
751
+ configValue,
752
+ loading: loadingConfig,
753
+ saving,
754
+ onSave: handleSave
755
+ }), /* @__PURE__ */ jsx(ParameterHistory, {
756
+ selectedConfig,
757
+ history,
758
+ loading: loadingHistory,
759
+ onRollback: handleRollback
760
+ })] }) : /* @__PURE__ */ jsx(ParameterEmptyState, {})]
761
+ })
762
+ });
763
+ };
764
+
765
+ //#endregion
766
+ export { AdminParameters_exports as n, AdminParameters as t };
767
+ //# sourceMappingURL=AdminParameters-B_83Vie9.js.map