@alepha/ui 0.16.1 → 0.17.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-GMORg-1l.js → AdminApiKeys-CF_qOO3u.js} +20 -19
- package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +1 -0
- package/dist/admin/{AdminAudits-pkWrjq1Z.js → AdminAudits-BQno3hZG.js} +7 -7
- package/dist/admin/AdminAudits-BQno3hZG.js.map +1 -0
- package/dist/admin/{AdminFiles-WeQbsCsl.js → AdminFiles-kvuUaASF.js} +3 -4
- package/dist/admin/{AdminFiles-WeQbsCsl.js.map → AdminFiles-kvuUaASF.js.map} +1 -1
- package/dist/admin/AdminJobDashboard-CrPxp0W1.js +485 -0
- package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +1 -0
- package/dist/admin/AdminJobExecutions-D-b4Zt7W.js +678 -0
- package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +1 -0
- package/dist/admin/AdminJobRegistry-CNX5cpDx.js +301 -0
- package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +1 -0
- package/dist/admin/{AdminLayout-BqZiXx4H.js → AdminLayout-e-ZP5nWw.js} +6 -9
- package/dist/admin/AdminLayout-e-ZP5nWw.js.map +1 -0
- package/dist/admin/{AdminNotifications-Ds5Un0NJ.js → AdminNotifications-DeHJFf6W.js} +3 -4
- package/dist/admin/{AdminNotifications-Ds5Un0NJ.js.map → AdminNotifications-DeHJFf6W.js.map} +1 -1
- package/dist/admin/AdminParameters-iQE8o7a7.js +774 -0
- package/dist/admin/AdminParameters-iQE8o7a7.js.map +1 -0
- package/dist/admin/{AdminSessions-DzIOxM3b.js → AdminSessions-oKJCbd7w.js} +5 -6
- package/dist/admin/AdminSessions-oKJCbd7w.js.map +1 -0
- package/dist/admin/{AdminUserAudits-CiUPN2BC.js → AdminUserAudits-BNCEle_E.js} +6 -7
- package/dist/admin/AdminUserAudits-BNCEle_E.js.map +1 -0
- package/dist/admin/{AdminUserCreate-BwQKr4xE.js → AdminUserCreate-CgqeFwCt.js} +6 -6
- package/dist/admin/AdminUserCreate-CgqeFwCt.js.map +1 -0
- package/dist/admin/{AdminUserDetails-uqtC5aJ1.js → AdminUserDetails-DDe1A1GP.js} +30 -28
- package/dist/admin/AdminUserDetails-DDe1A1GP.js.map +1 -0
- package/dist/admin/{AdminUserLayout-CiPay35T.js → AdminUserLayout-HAlobhWf.js} +20 -19
- package/dist/admin/AdminUserLayout-HAlobhWf.js.map +1 -0
- package/dist/admin/{AdminUserSessions-DAE8Nf1F.js → AdminUserSessions-Bq1LnVLf.js} +5 -6
- package/dist/admin/AdminUserSessions-Bq1LnVLf.js.map +1 -0
- package/dist/admin/{AdminUserSettings-EbahaV2a.js → AdminUserSettings-BRsBZoxV.js} +10 -9
- package/dist/admin/AdminUserSettings-BRsBZoxV.js.map +1 -0
- package/dist/admin/{AdminUsers-Dcjh0KNW.js → AdminUsers-D71kIOSn.js} +6 -7
- package/dist/admin/AdminUsers-D71kIOSn.js.map +1 -0
- package/dist/admin/index.d.ts +21 -85
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +66 -88
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{AuthLayout-Dj5K4SIN.js → AuthLayout-CdJcrPs4.js} +2 -3
- package/dist/auth/{AuthLayout-Dj5K4SIN.js.map → AuthLayout-CdJcrPs4.js.map} +1 -1
- package/dist/{demo/IconGoogle-CbBF8Hqq.js → auth/IconGoogle-Bm18QD2q.js} +2 -4
- package/dist/auth/{IconGoogle-DpSlPZ1u.js.map → IconGoogle-Bm18QD2q.js.map} +1 -1
- package/dist/auth/{Login-BBqTosqZ.js → Login-BS_FYTy0.js} +19 -13
- package/dist/auth/Login-BS_FYTy0.js.map +1 -0
- package/dist/auth/{Profile-Bxj8Nwom.js → Profile-CjDsW378.js} +17 -12
- package/dist/auth/Profile-CjDsW378.js.map +1 -0
- package/dist/auth/{Register-Ce675Crg.js → Register-C5eqzAaD.js} +27 -17
- package/dist/auth/Register-C5eqzAaD.js.map +1 -0
- package/dist/auth/{ResetPassword-DWdt7c40.js → ResetPassword-XifinVao.js} +17 -10
- package/dist/auth/ResetPassword-XifinVao.js.map +1 -0
- package/dist/auth/{VerifyEmail-CI4JwByV.js → VerifyEmail-DTgbeJOO.js} +9 -6
- package/dist/auth/VerifyEmail-DTgbeJOO.js.map +1 -0
- package/dist/auth/index.d.ts +18 -14
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +19 -18
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/rolldown-runtime-CjeV3_4I.js +18 -0
- package/dist/core/index.d.ts +182 -92
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +789 -476
- package/dist/core/index.js.map +1 -1
- package/dist/demo/DemoDataTable-lnBKWBf8.js +362 -0
- package/dist/demo/DemoDataTable-lnBKWBf8.js.map +1 -0
- package/dist/demo/{DemoHome-Cce2bWmg.js → DemoHome-CUMZsYaH.js} +6 -6
- package/dist/demo/DemoHome-CUMZsYaH.js.map +1 -0
- package/dist/demo/{DemoJsonViewer-Dgdk3Txb.js → DemoJsonViewer-_uokbGaW.js} +18 -19
- package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +1 -0
- package/dist/demo/{DemoLayout-B20TEuhV.js → DemoLayout-DHVoacE6.js} +4 -5
- package/dist/demo/DemoLayout-DHVoacE6.js.map +1 -0
- package/dist/demo/{DemoLogin-CvCG2WVh.js → DemoLogin-DjJ9314c.js} +27 -24
- package/dist/demo/DemoLogin-DjJ9314c.js.map +1 -0
- package/dist/demo/{DemoRegister-CmeHbOAs.js → DemoRegister-DzkJ5M83.js} +39 -32
- package/dist/demo/DemoRegister-DzkJ5M83.js.map +1 -0
- package/dist/demo/{DemoResetPassword-CKO5iA_6.js → DemoResetPassword-DWh4_BpQ.js} +30 -26
- package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +1 -0
- package/dist/demo/{DemoSidebar-MVmQKfMt.js → DemoSidebar-C1csnGhX.js} +4 -5
- package/dist/demo/DemoSidebar-C1csnGhX.js.map +1 -0
- package/dist/demo/{DemoTypeForm-w-qtfRlC.js → DemoTypeForm-CWz6fJrJ.js} +4 -5
- package/dist/demo/DemoTypeForm-CWz6fJrJ.js.map +1 -0
- package/dist/demo/{DemoVerifyEmail-C8FFJT5A.js → DemoVerifyEmail-DbU_tCj8.js} +16 -16
- package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +1 -0
- package/dist/{auth/IconGoogle-DpSlPZ1u.js → demo/IconGoogle-Ch1m3Uzl.js} +2 -4
- package/dist/demo/{IconGoogle-CbBF8Hqq.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
- package/dist/demo/{Showcase-CQrMWars.js → Showcase-BzoXNlCn.js} +11 -13
- package/dist/demo/Showcase-BzoXNlCn.js.map +1 -0
- package/dist/demo/index.d.ts +3 -70
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +11 -15
- package/dist/demo/index.js.map +1 -1
- package/dist/json/index.js +2 -2
- package/dist/json/index.js.map +1 -1
- package/package.json +11 -5
- package/src/admin/AdminRouter.ts +51 -29
- package/src/admin/components/AdminLayout.tsx +6 -9
- package/src/admin/components/audits/AdminAudits.tsx +5 -5
- package/src/admin/components/jobs/AdminJobDashboard.tsx +455 -0
- package/src/admin/components/jobs/AdminJobExecutions.tsx +693 -0
- package/src/admin/components/jobs/AdminJobRegistry.tsx +325 -0
- package/src/admin/components/keys/AdminApiKeys.tsx +28 -31
- package/src/admin/components/parameters/AdminParameters.tsx +156 -78
- package/src/admin/components/parameters/ParameterDetails.tsx +173 -108
- package/src/admin/components/parameters/ParameterEmptyState.tsx +27 -0
- package/src/admin/components/parameters/ParameterHistory.tsx +22 -35
- package/src/admin/components/parameters/ParameterTree.tsx +283 -109
- package/src/admin/components/parameters/types.ts +3 -3
- package/src/admin/components/sessions/AdminSessions.tsx +3 -3
- package/src/admin/components/shared/AdminResourceHeader.tsx +20 -16
- package/src/admin/components/users/AdminUserAudits.tsx +5 -5
- package/src/admin/components/users/AdminUserCreate.tsx +3 -3
- package/src/admin/components/users/AdminUserDetails.tsx +51 -53
- package/src/admin/components/users/AdminUserLayout.tsx +7 -7
- package/src/admin/components/users/AdminUserSessions.tsx +3 -3
- package/src/admin/components/users/AdminUserSettings.tsx +9 -9
- package/src/admin/components/users/AdminUsers.tsx +5 -5
- package/src/admin/components/verifications/AdminVerifications.tsx +3 -3
- package/src/admin/index.ts +0 -24
- package/src/admin/primitives/$uiAdmin.ts +2 -2
- package/src/auth/AuthRouter.ts +1 -0
- package/src/auth/components/Login.tsx +13 -13
- package/src/auth/components/Profile.tsx +17 -26
- package/src/auth/components/Register.tsx +21 -31
- package/src/auth/components/ResetPassword.tsx +13 -22
- package/src/auth/components/VerifyEmail.tsx +5 -5
- package/src/auth/components/buttons/UserButton.tsx +14 -4
- package/src/core/components/buttons/ActionButton.tsx +13 -17
- package/src/core/components/buttons/DarkModeButton.tsx +8 -4
- package/src/core/components/buttons/ToggleSidebarButton.tsx +3 -5
- package/src/core/components/data/ErrorViewer.tsx +15 -15
- package/src/core/components/dialogs/AlertDialog.tsx +3 -3
- package/src/core/components/dialogs/ConfirmDialog.tsx +3 -3
- package/src/core/components/dialogs/PromptDialog.tsx +3 -3
- package/src/core/components/form/Control.tsx +19 -32
- package/src/core/components/form/ControlArray.tsx +206 -96
- package/src/core/components/form/ControlObject.tsx +3 -3
- package/src/core/components/form/ControlQueryBuilder.tsx +20 -22
- package/src/core/components/form/ControlSelect.tsx +4 -0
- package/src/core/components/form/TypeForm.browser.spec.tsx +727 -0
- package/src/core/components/form/TypeForm.tsx +7 -0
- package/src/core/components/layout/AlephaMantineProvider.tsx +1 -0
- package/src/core/components/layout/Breadcrumb.tsx +91 -0
- package/src/core/components/layout/{AdminShell.tsx → DashboardShell.tsx} +77 -32
- package/src/core/components/layout/Omnibar.tsx +2 -1
- package/src/core/components/layout/Sidebar.tsx +63 -19
- package/src/core/components/table/ColumnPicker.tsx +47 -31
- package/src/core/components/table/DataTable.tsx +277 -201
- package/src/core/components/table/DataTableFilters.tsx +8 -0
- package/src/core/components/table/DataTableToolbar.tsx +98 -5
- package/src/core/components/table/FilterPicker.tsx +28 -26
- package/src/core/components/table/types.ts +52 -37
- package/src/core/components/table/useTableSelection.ts +83 -0
- package/src/core/constants/ui.ts +1 -1
- package/src/core/helpers/renderIcon.tsx +5 -2
- package/src/core/index.ts +9 -5
- package/src/core/styles.css +8 -7
- package/src/core/utils/parseInput.ts +1 -0
- package/src/core/utils/string.ts +28 -4
- package/src/demo/components/DemoHome.tsx +5 -5
- package/src/demo/components/DemoLayout.tsx +6 -2
- package/src/demo/components/core/DemoDataTable.tsx +209 -5
- package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
- package/src/demo/components/shared/MacWindow.tsx +7 -7
- package/src/demo/components/shared/Showcase.tsx +3 -3
- package/src/demo/index.ts +0 -11
- package/src/json/components/JsonViewer.tsx +3 -3
- package/dist/admin/AdminApiKeys-DsmGnHNh.js +0 -3
- package/dist/admin/AdminApiKeys-GMORg-1l.js.map +0 -1
- package/dist/admin/AdminAudits-8SM96viT.js +0 -3
- package/dist/admin/AdminAudits-pkWrjq1Z.js.map +0 -1
- package/dist/admin/AdminFiles-B56ocq4H.js +0 -3
- package/dist/admin/AdminJobs-B-q9iGO3.js +0 -697
- package/dist/admin/AdminJobs-B-q9iGO3.js.map +0 -1
- package/dist/admin/AdminJobs-CED1syCn.js +0 -3
- package/dist/admin/AdminLayout-BqZiXx4H.js.map +0 -1
- package/dist/admin/AdminNotifications-B0B1rdc4.js +0 -3
- package/dist/admin/AdminParameters-BU3lATdJ.js +0 -3
- package/dist/admin/AdminParameters-CfDUpc78.js +0 -575
- package/dist/admin/AdminParameters-CfDUpc78.js.map +0 -1
- package/dist/admin/AdminSessions-BDGK2MS6.js +0 -3
- package/dist/admin/AdminSessions-DzIOxM3b.js.map +0 -1
- package/dist/admin/AdminUserAudits-CiUPN2BC.js.map +0 -1
- package/dist/admin/AdminUserAudits-Cj79gENT.js +0 -3
- package/dist/admin/AdminUserCreate-BwQKr4xE.js.map +0 -1
- package/dist/admin/AdminUserCreate-Cq-mUmBs.js +0 -3
- package/dist/admin/AdminUserDetails-DRjVAPFd.js +0 -3
- package/dist/admin/AdminUserDetails-uqtC5aJ1.js.map +0 -1
- package/dist/admin/AdminUserLayout-CGzmHHby.js +0 -3
- package/dist/admin/AdminUserLayout-CiPay35T.js.map +0 -1
- package/dist/admin/AdminUserSessions-DAE8Nf1F.js.map +0 -1
- package/dist/admin/AdminUserSessions-DcdzuNZ9.js +0 -3
- package/dist/admin/AdminUserSettings-D7V6-ceX.js +0 -3
- package/dist/admin/AdminUserSettings-EbahaV2a.js.map +0 -1
- package/dist/admin/AdminUsers-D9nyzGqQ.js +0 -3
- package/dist/admin/AdminUsers-Dcjh0KNW.js.map +0 -1
- package/dist/auth/Login-BBqTosqZ.js.map +0 -1
- package/dist/auth/Login-CoU63mMR.js +0 -4
- package/dist/auth/Profile-Bxj8Nwom.js.map +0 -1
- package/dist/auth/Register-BV_oa_AK.js +0 -4
- package/dist/auth/Register-Ce675Crg.js.map +0 -1
- package/dist/auth/ResetPassword-D5wC8GAA.js +0 -3
- package/dist/auth/ResetPassword-DWdt7c40.js.map +0 -1
- package/dist/auth/VerifyEmail-CI4JwByV.js.map +0 -1
- package/dist/auth/VerifyEmail-DAfqVm5s.js +0 -3
- package/dist/demo/DemoDataTable-CguplbR7.js +0 -150
- package/dist/demo/DemoDataTable-CguplbR7.js.map +0 -1
- package/dist/demo/DemoHome-Cce2bWmg.js.map +0 -1
- package/dist/demo/DemoHome-DC9qkMNe.js +0 -3
- package/dist/demo/DemoJsonViewer-DIssGVlJ.js +0 -4
- package/dist/demo/DemoJsonViewer-Dgdk3Txb.js.map +0 -1
- package/dist/demo/DemoLayout-B20TEuhV.js.map +0 -1
- package/dist/demo/DemoLayout-DSRyf4qJ.js +0 -3
- package/dist/demo/DemoLogin-CvCG2WVh.js.map +0 -1
- package/dist/demo/DemoRegister-CmeHbOAs.js.map +0 -1
- package/dist/demo/DemoResetPassword-CKO5iA_6.js.map +0 -1
- package/dist/demo/DemoSidebar-MVmQKfMt.js.map +0 -1
- package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +0 -1
- package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +0 -1
- package/dist/demo/Showcase-CQrMWars.js.map +0 -1
- package/src/admin/components/jobs/AdminJobs.tsx +0 -772
|
@@ -39,6 +39,8 @@ export interface TypeFormProps<T extends TObject> {
|
|
|
39
39
|
|
|
40
40
|
fill?: boolean;
|
|
41
41
|
flexProps?: FlexProps;
|
|
42
|
+
|
|
43
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/**
|
|
@@ -93,6 +95,7 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
93
95
|
skipSubmitButton = false,
|
|
94
96
|
submitButtonProps,
|
|
95
97
|
fill = true,
|
|
98
|
+
size,
|
|
96
99
|
} = props;
|
|
97
100
|
|
|
98
101
|
const schema = props.schema || form.options.schema;
|
|
@@ -163,6 +166,10 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
163
166
|
...fieldControlProps?.[fieldName],
|
|
164
167
|
};
|
|
165
168
|
|
|
169
|
+
if (size) {
|
|
170
|
+
mergedControlProps.size = size;
|
|
171
|
+
}
|
|
172
|
+
|
|
166
173
|
return (
|
|
167
174
|
<Grid.Col key={fieldName} span={span}>
|
|
168
175
|
<Control input={field} {...mergedControlProps} />
|
|
@@ -72,6 +72,7 @@ const AlephaMantineProvider = (props: AlephaMantineProviderProps) => {
|
|
|
72
72
|
{...props.mantine}
|
|
73
73
|
defaultColorScheme={defaultColorScheme}
|
|
74
74
|
theme={{
|
|
75
|
+
cursorType: "pointer",
|
|
75
76
|
// Spread all theme properties from the selected theme
|
|
76
77
|
...theme,
|
|
77
78
|
// User overrides take precedence
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Anchor, Flex, type FlexProps, Text } from "@mantine/core";
|
|
2
|
+
import { IconChevronRight } from "@tabler/icons-react";
|
|
3
|
+
import { Link, useRouter, useRouterState } from "alepha/react/router";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
import { toTitleCase } from "../../utils/string.ts";
|
|
6
|
+
|
|
7
|
+
export interface BreadcrumbProps extends FlexProps {
|
|
8
|
+
/**
|
|
9
|
+
* Label for the home/root crumb. Set to `false` to hide the root crumb.
|
|
10
|
+
*
|
|
11
|
+
* @default "Home"
|
|
12
|
+
*/
|
|
13
|
+
home?: string | false;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Custom separator between crumbs.
|
|
17
|
+
*
|
|
18
|
+
* @default IconChevronRight
|
|
19
|
+
*/
|
|
20
|
+
separator?: ReactNode;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Size of text and separator icons.
|
|
24
|
+
*
|
|
25
|
+
* @default "xs"
|
|
26
|
+
*/
|
|
27
|
+
size?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Automatic breadcrumb component that reads the current route hierarchy
|
|
32
|
+
* from the Alepha router's layer stack.
|
|
33
|
+
*
|
|
34
|
+
* Pages should define a `label` in their `$page()` options for best results.
|
|
35
|
+
* Falls back to the page name converted to Title Case.
|
|
36
|
+
*/
|
|
37
|
+
const Breadcrumb = ({
|
|
38
|
+
home = "Home",
|
|
39
|
+
separator,
|
|
40
|
+
size = "xs",
|
|
41
|
+
...groupProps
|
|
42
|
+
}: BreadcrumbProps) => {
|
|
43
|
+
const state = useRouterState();
|
|
44
|
+
const router = useRouter();
|
|
45
|
+
|
|
46
|
+
const crumbs: Array<{ label: string; href: string }> = [];
|
|
47
|
+
|
|
48
|
+
// Optionally add home crumb
|
|
49
|
+
if (home !== false) {
|
|
50
|
+
crumbs.push({ label: home, href: "/" });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Build crumbs from layers, skipping the root layout (index 0)
|
|
54
|
+
for (let i = 1; i < state.layers.length; i++) {
|
|
55
|
+
const layer = state.layers[i];
|
|
56
|
+
const route = layer.route as any;
|
|
57
|
+
|
|
58
|
+
// Skip index routes (path "/") — they share the parent URL
|
|
59
|
+
if (route?.path === "/" || route?.path === "") continue;
|
|
60
|
+
|
|
61
|
+
const label = route?.label ?? toTitleCase(layer.name);
|
|
62
|
+
// Use router.path() to resolve dynamic params (e.g. :userId → 3)
|
|
63
|
+
const href = router.path(layer.name);
|
|
64
|
+
crumbs.push({ label, href });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (crumbs.length === 0) return null;
|
|
68
|
+
|
|
69
|
+
const sep = separator ?? <IconChevronRight size={12} color="#9ca3af" />;
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Flex gap={4} {...groupProps}>
|
|
73
|
+
{crumbs.map((crumb, i) => (
|
|
74
|
+
<Flex key={crumb.href} gap={4}>
|
|
75
|
+
{i > 0 && sep}
|
|
76
|
+
{i < crumbs.length - 1 ? (
|
|
77
|
+
<Anchor component={Link} href={crumb.href} size={size} c="dimmed">
|
|
78
|
+
{crumb.label}
|
|
79
|
+
</Anchor>
|
|
80
|
+
) : (
|
|
81
|
+
<Text size={size} fw={500}>
|
|
82
|
+
{crumb.label}
|
|
83
|
+
</Text>
|
|
84
|
+
)}
|
|
85
|
+
</Flex>
|
|
86
|
+
))}
|
|
87
|
+
</Flex>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default Breadcrumb;
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
useState,
|
|
20
20
|
} from "react";
|
|
21
21
|
import { alephaSidebarAtom } from "../../atoms/alephaSidebarAtom.ts";
|
|
22
|
-
import { ui } from "../../constants/ui.ts";
|
|
23
22
|
import AppBar, { type AppBarProps } from "./AppBar.tsx";
|
|
24
23
|
import {
|
|
25
24
|
Sidebar,
|
|
@@ -27,7 +26,7 @@ import {
|
|
|
27
26
|
type SidebarProps,
|
|
28
27
|
} from "./Sidebar.tsx";
|
|
29
28
|
|
|
30
|
-
export interface
|
|
29
|
+
export interface DashboardShellProps {
|
|
31
30
|
appShellProps?: Partial<AppShellProps>;
|
|
32
31
|
appShellMainProps?: Partial<AppShellMainProps>;
|
|
33
32
|
appShellHeaderProps?: Partial<AppShellHeaderProps>;
|
|
@@ -39,6 +38,35 @@ export interface AdminShellProps {
|
|
|
39
38
|
footer?: ReactNode;
|
|
40
39
|
children?: ReactNode;
|
|
41
40
|
|
|
41
|
+
/**
|
|
42
|
+
* AppShell layout mode.
|
|
43
|
+
* - "default": header/footer span full width, navbar below header.
|
|
44
|
+
* - "alt": navbar is full height, header/footer offset by navbar width.
|
|
45
|
+
*/
|
|
46
|
+
layout?: "default" | "alt";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Content rendered above the Sidebar inside the navbar (e.g. logo).
|
|
50
|
+
*/
|
|
51
|
+
navbarHeader?: ReactNode;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Content rendered below the Sidebar inside the navbar (e.g. toggle button).
|
|
55
|
+
*/
|
|
56
|
+
navbarFooter?: ReactNode;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Height of the header bar in pixels.
|
|
60
|
+
* @default 60
|
|
61
|
+
*/
|
|
62
|
+
headerHeight?: number;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Height of the footer bar in pixels.
|
|
66
|
+
* @default 24
|
|
67
|
+
*/
|
|
68
|
+
footerHeight?: number;
|
|
69
|
+
|
|
42
70
|
/**
|
|
43
71
|
* Enable drag-to-resize for the sidebar.
|
|
44
72
|
* Width and constraints are configured in alephaSidebarAtom.
|
|
@@ -59,17 +87,14 @@ export interface AdminShellProps {
|
|
|
59
87
|
container?: boolean | ContainerProps;
|
|
60
88
|
}
|
|
61
89
|
|
|
62
|
-
const
|
|
90
|
+
const DashboardShell = (props: DashboardShellProps) => {
|
|
63
91
|
const router = useRouter();
|
|
64
92
|
const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
|
|
65
|
-
const { opened
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
setSidebar({ ...sidebar, collapsed: props.sidebarProps.collapsed });
|
|
71
|
-
}
|
|
72
|
-
}, []);
|
|
93
|
+
const { opened } = sidebar;
|
|
94
|
+
const collapsed =
|
|
95
|
+
props.sidebarProps?.collapsed !== undefined
|
|
96
|
+
? props.sidebarProps.collapsed
|
|
97
|
+
: sidebar.collapsed;
|
|
73
98
|
|
|
74
99
|
// Resize state
|
|
75
100
|
const [isResizing, setIsResizing] = useState(false);
|
|
@@ -169,13 +194,15 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
169
194
|
// Hover to expand when collapsed (with delay)
|
|
170
195
|
const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
171
196
|
|
|
197
|
+
const expandOnHover = props.sidebarProps?.expandOnHover !== false;
|
|
198
|
+
|
|
172
199
|
const handleNavbarMouseEnter = useCallback(() => {
|
|
173
|
-
if (collapsed) {
|
|
200
|
+
if (collapsed && expandOnHover) {
|
|
174
201
|
hoverTimeoutRef.current = setTimeout(() => {
|
|
175
202
|
setIsHovering(true);
|
|
176
203
|
}, hoverDelay);
|
|
177
204
|
}
|
|
178
|
-
}, [collapsed, hoverDelay]);
|
|
205
|
+
}, [collapsed, expandOnHover, hoverDelay]);
|
|
179
206
|
|
|
180
207
|
const handleNavbarMouseLeave = useCallback(() => {
|
|
181
208
|
if (hoverTimeoutRef.current) {
|
|
@@ -235,10 +262,12 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
235
262
|
appBarProps.container ??= props.container;
|
|
236
263
|
|
|
237
264
|
const hasSidebar = showSidebar && props.sidebarProps !== undefined;
|
|
238
|
-
const hasAppBar =
|
|
265
|
+
const hasAppBar = props.appBarProps || props.header;
|
|
239
266
|
|
|
240
|
-
const
|
|
241
|
-
const
|
|
267
|
+
const hHeight = props.headerHeight ?? 60;
|
|
268
|
+
const fHeight = props.footerHeight ?? 24;
|
|
269
|
+
const headerHeight = hasAppBar ? hHeight : 0;
|
|
270
|
+
const footerHeight = props.footer ? fHeight : 0;
|
|
242
271
|
const expandedWidth = Math.max(sidebar.width, collapsedWidth);
|
|
243
272
|
|
|
244
273
|
// When collapsed but hovering, show defaultWidth (not current width)
|
|
@@ -266,10 +295,10 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
266
295
|
|
|
267
296
|
return (
|
|
268
297
|
<AppShell
|
|
298
|
+
layout={props.layout}
|
|
269
299
|
w={"100%"}
|
|
270
300
|
flex={1}
|
|
271
|
-
|
|
272
|
-
header={hasAppBar ? { height: 60 } : undefined}
|
|
301
|
+
header={hasAppBar ? { height: hHeight } : undefined}
|
|
273
302
|
navbar={
|
|
274
303
|
hasSidebar
|
|
275
304
|
? {
|
|
@@ -283,16 +312,19 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
283
312
|
}
|
|
284
313
|
: undefined
|
|
285
314
|
}
|
|
286
|
-
footer={props.footer ? { height:
|
|
315
|
+
footer={props.footer ? { height: fHeight } : undefined}
|
|
287
316
|
{...props.appShellProps}
|
|
288
317
|
>
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
318
|
+
{hasAppBar && (
|
|
319
|
+
<AppShell.Header {...props.appShellHeaderProps}>
|
|
320
|
+
{props.header ?? (
|
|
321
|
+
<AppBar items={defaultAppBarItems} {...appBarProps} />
|
|
322
|
+
)}
|
|
323
|
+
</AppShell.Header>
|
|
324
|
+
)}
|
|
292
325
|
|
|
293
326
|
{hasSidebar && (
|
|
294
327
|
<AppShell.Navbar
|
|
295
|
-
bg={ui.colors.surface}
|
|
296
328
|
className="alepha-sidebar-navbar"
|
|
297
329
|
data-resizing={isResizing}
|
|
298
330
|
data-hover-expanded={isExpandedByHover}
|
|
@@ -312,11 +344,31 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
312
344
|
}}
|
|
313
345
|
{...props.appShellNavbarProps}
|
|
314
346
|
>
|
|
347
|
+
{props.navbarHeader ? (
|
|
348
|
+
<Flex
|
|
349
|
+
style={{
|
|
350
|
+
borderBottom: "1px solid var(--mantine-color-default-border)",
|
|
351
|
+
}}
|
|
352
|
+
h={headerHeight}
|
|
353
|
+
>
|
|
354
|
+
{props.navbarHeader}
|
|
355
|
+
</Flex>
|
|
356
|
+
) : null}
|
|
315
357
|
<Sidebar
|
|
316
358
|
{...(props.sidebarProps ?? {})}
|
|
317
359
|
collapsed={effectiveCollapsed}
|
|
318
360
|
onItemClick={handleSidebarItemClick}
|
|
319
361
|
/>
|
|
362
|
+
{props.navbarFooter ? (
|
|
363
|
+
<Flex
|
|
364
|
+
style={{
|
|
365
|
+
borderTop: "1px solid var(--mantine-color-default-border)",
|
|
366
|
+
}}
|
|
367
|
+
h={footerHeight}
|
|
368
|
+
>
|
|
369
|
+
{props.navbarFooter}
|
|
370
|
+
</Flex>
|
|
371
|
+
) : null}
|
|
320
372
|
{(canResize || isExpandedByHover) && (
|
|
321
373
|
<Flex
|
|
322
374
|
pos="absolute"
|
|
@@ -335,13 +387,6 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
335
387
|
)}
|
|
336
388
|
|
|
337
389
|
<AppShell.Main
|
|
338
|
-
pl={sidebarWidth}
|
|
339
|
-
pt={headerHeight}
|
|
340
|
-
pb={footerHeight}
|
|
341
|
-
pr={0}
|
|
342
|
-
display={"flex"}
|
|
343
|
-
flex={1}
|
|
344
|
-
style={{ flexDirection: "column" }}
|
|
345
390
|
className="alepha-sidebar-main"
|
|
346
391
|
data-resizing={isResizing}
|
|
347
392
|
{...props.appShellMainProps}
|
|
@@ -362,7 +407,7 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
362
407
|
</AppShell.Main>
|
|
363
408
|
|
|
364
409
|
{props.footer && (
|
|
365
|
-
<AppShell.Footer
|
|
410
|
+
<AppShell.Footer {...props.appShellFooterProps}>
|
|
366
411
|
{props.footer}
|
|
367
412
|
</AppShell.Footer>
|
|
368
413
|
)}
|
|
@@ -370,4 +415,4 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
370
415
|
);
|
|
371
416
|
};
|
|
372
417
|
|
|
373
|
-
export default
|
|
418
|
+
export default DashboardShell;
|
|
@@ -2,6 +2,7 @@ import { Spotlight, type SpotlightActionData } from "@mantine/spotlight";
|
|
|
2
2
|
import { IconSearch } from "@tabler/icons-react";
|
|
3
3
|
import { useStore } from "alepha/react";
|
|
4
4
|
import { useRouter } from "alepha/react/router";
|
|
5
|
+
import { currentUserAtom } from "alepha/security";
|
|
5
6
|
import { type ReactNode, useMemo } from "react";
|
|
6
7
|
import { ui } from "../../constants/ui.ts";
|
|
7
8
|
import { renderIcon } from "../../helpers/renderIcon.tsx";
|
|
@@ -19,7 +20,7 @@ const Omnibar = (props: OmnibarProps) => {
|
|
|
19
20
|
const router = useRouter();
|
|
20
21
|
|
|
21
22
|
// watch user to re-render on permission changes
|
|
22
|
-
const [user] = useStore(
|
|
23
|
+
const [user] = useStore(currentUserAtom);
|
|
23
24
|
|
|
24
25
|
const actions: SpotlightActionData[] = useMemo(
|
|
25
26
|
() =>
|
|
@@ -13,11 +13,13 @@ import { useEvents } from "alepha/react";
|
|
|
13
13
|
import { useRouter } from "alepha/react/router";
|
|
14
14
|
import {
|
|
15
15
|
type ComponentType,
|
|
16
|
+
Fragment,
|
|
16
17
|
type ReactNode,
|
|
17
18
|
useCallback,
|
|
18
19
|
useMemo,
|
|
19
20
|
useState,
|
|
20
21
|
} from "react";
|
|
22
|
+
import { ui } from "../../constants/ui.ts";
|
|
21
23
|
import { renderIcon } from "../../helpers/renderIcon.tsx";
|
|
22
24
|
import ActionButton, { type ActionProps } from "../buttons/ActionButton.tsx";
|
|
23
25
|
import OmnibarButton from "../buttons/OmnibarButton.tsx";
|
|
@@ -35,6 +37,12 @@ export interface SidebarProps {
|
|
|
35
37
|
paths?: string[];
|
|
36
38
|
};
|
|
37
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Whether the sidebar expands on hover when collapsed.
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
expandOnHover?: boolean;
|
|
45
|
+
|
|
38
46
|
/**
|
|
39
47
|
* Automatically populate the menu from the router's pages.
|
|
40
48
|
*/
|
|
@@ -49,19 +57,25 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
49
57
|
const router = useRouter();
|
|
50
58
|
const { onItemClick } = props;
|
|
51
59
|
|
|
52
|
-
const divider = (key: string | number) => {
|
|
60
|
+
const divider = (key: string | number, fill?: boolean) => {
|
|
53
61
|
return (
|
|
54
62
|
<Flex
|
|
55
63
|
key={key}
|
|
56
64
|
h={1}
|
|
57
|
-
bg={"var(--
|
|
65
|
+
bg={"var(--mantine-color-default-border)"}
|
|
58
66
|
my={"xs"}
|
|
59
|
-
mx={
|
|
67
|
+
mx={
|
|
68
|
+
fill
|
|
69
|
+
? "calc(-1 * var(--mantine-spacing-md))"
|
|
70
|
+
: props.collapsed
|
|
71
|
+
? 0
|
|
72
|
+
: "sm"
|
|
73
|
+
}
|
|
60
74
|
/>
|
|
61
75
|
);
|
|
62
76
|
};
|
|
63
77
|
|
|
64
|
-
const renderNode = (item: SidebarNode, key: number) => {
|
|
78
|
+
const renderNode = (item: SidebarNode, key: number | string) => {
|
|
65
79
|
if ("type" in item) {
|
|
66
80
|
// Hide spacers when collapsed
|
|
67
81
|
if (item.type === "spacer") {
|
|
@@ -70,7 +84,7 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
if (item.type === "divider") {
|
|
73
|
-
return divider(key);
|
|
87
|
+
return divider(key, item.fill);
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
if (item.type === "search") {
|
|
@@ -85,24 +99,45 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
85
99
|
return <ToggleSidebarButton key={key} />;
|
|
86
100
|
}
|
|
87
101
|
|
|
102
|
+
// Replace sections with dividers when collapsed
|
|
88
103
|
// Replace sections with dividers when collapsed
|
|
89
104
|
if (item.type === "section") {
|
|
105
|
+
// Hide section if all children are hidden
|
|
106
|
+
if (item.children && item.children.length > 0) {
|
|
107
|
+
const hasVisibleChild = item.children.some(
|
|
108
|
+
(child) => !("can" in child) || !child.can || child.can(),
|
|
109
|
+
);
|
|
110
|
+
if (!hasVisibleChild) return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
if (props.collapsed) {
|
|
91
|
-
return
|
|
114
|
+
return (
|
|
115
|
+
<Fragment key={key}>
|
|
116
|
+
{divider(`${key}-d`)}
|
|
117
|
+
{item.children?.map((child, index) =>
|
|
118
|
+
renderNode(child, `s${key}-${index}`),
|
|
119
|
+
)}
|
|
120
|
+
</Fragment>
|
|
121
|
+
);
|
|
92
122
|
}
|
|
93
123
|
return (
|
|
94
|
-
<
|
|
95
|
-
{
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
|
|
124
|
+
<Fragment key={key}>
|
|
125
|
+
<Flex mt={"md"} align={"center"} gap={"xs"}>
|
|
126
|
+
{renderIcon(item.icon, ui.sizes.icon.sm)}
|
|
127
|
+
<Text size={"xs"} c={"dimmed"} tt={"uppercase"} fw={"bold"}>
|
|
128
|
+
{item.label}
|
|
129
|
+
</Text>
|
|
130
|
+
</Flex>
|
|
131
|
+
{item.children?.map((child, index) =>
|
|
132
|
+
renderNode(child, `s${key}-${index}`),
|
|
133
|
+
)}
|
|
134
|
+
</Fragment>
|
|
100
135
|
);
|
|
101
136
|
}
|
|
102
137
|
}
|
|
103
138
|
|
|
104
139
|
if ("element" in item) {
|
|
105
|
-
return <
|
|
140
|
+
return <Fragment key={key}>{item.element}</Fragment>;
|
|
106
141
|
}
|
|
107
142
|
|
|
108
143
|
// Check visibility control
|
|
@@ -167,7 +202,7 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
167
202
|
};
|
|
168
203
|
|
|
169
204
|
const padding = "md";
|
|
170
|
-
const gap = props.items ? (props.gap ??
|
|
205
|
+
const gap = props.items ? (props.gap ?? 4) : "xs";
|
|
171
206
|
const menu = useMemo(
|
|
172
207
|
() => getSidebarNodes(),
|
|
173
208
|
[props.items, props.autoPopulateMenu],
|
|
@@ -275,8 +310,11 @@ export const SidebarItem = (props: SidebarItemProps) => {
|
|
|
275
310
|
props.theme.button?.size ??
|
|
276
311
|
(level === 0 ? "sm" : "xs")
|
|
277
312
|
}
|
|
278
|
-
tooltip={
|
|
279
|
-
|
|
313
|
+
tooltip={
|
|
314
|
+
item.description
|
|
315
|
+
? { label: item.description, position: "right" }
|
|
316
|
+
: undefined
|
|
317
|
+
}
|
|
280
318
|
color={"gray"}
|
|
281
319
|
variant={"subtle"}
|
|
282
320
|
variantActive={"default"}
|
|
@@ -284,7 +322,7 @@ export const SidebarItem = (props: SidebarItemProps) => {
|
|
|
284
322
|
onClick={handleItemClick}
|
|
285
323
|
leftSection={
|
|
286
324
|
<Flex w={"100%"} align="center" gap={"sm"}>
|
|
287
|
-
{renderIcon(item.icon)}
|
|
325
|
+
{renderIcon(item.icon, ui.sizes.icon.sm)}
|
|
288
326
|
<Flex direction={"column"}>
|
|
289
327
|
<Flex>{item.label}</Flex>
|
|
290
328
|
</Flex>
|
|
@@ -313,7 +351,7 @@ export const SidebarItem = (props: SidebarItemProps) => {
|
|
|
313
351
|
position: "absolute",
|
|
314
352
|
width: 1,
|
|
315
353
|
background:
|
|
316
|
-
"linear-gradient(to bottom, transparent, var(--
|
|
354
|
+
"linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
|
|
317
355
|
top: 48,
|
|
318
356
|
left: 20 + 32 * level,
|
|
319
357
|
bottom: 16,
|
|
@@ -368,7 +406,11 @@ const SidebarCollapsedItem = (props: SidebarItemProps) => {
|
|
|
368
406
|
}}
|
|
369
407
|
radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
|
|
370
408
|
onClick={handleItemClick}
|
|
371
|
-
icon={
|
|
409
|
+
icon={
|
|
410
|
+
renderIcon(item.icon, ui.sizes.icon.sm) ?? (
|
|
411
|
+
<IconSquareRounded size={ui.sizes.icon.sm} />
|
|
412
|
+
)
|
|
413
|
+
}
|
|
372
414
|
href={props.item.href as any}
|
|
373
415
|
target={props.item.target}
|
|
374
416
|
{...props.item.actionProps}
|
|
@@ -401,6 +443,7 @@ export interface SidebarSpacer extends SidebarAbstractItem {
|
|
|
401
443
|
|
|
402
444
|
export interface SidebarDivider extends SidebarAbstractItem {
|
|
403
445
|
type: "divider";
|
|
446
|
+
fill?: true;
|
|
404
447
|
}
|
|
405
448
|
|
|
406
449
|
export interface SidebarSearch extends SidebarAbstractItem {
|
|
@@ -415,6 +458,7 @@ export interface SidebarSection extends SidebarAbstractItem {
|
|
|
415
458
|
type: "section";
|
|
416
459
|
label: string;
|
|
417
460
|
icon?: ReactNode | ComponentType;
|
|
461
|
+
children?: SidebarNode[];
|
|
418
462
|
}
|
|
419
463
|
|
|
420
464
|
export interface SidebarMenuItem extends SidebarAbstractItem {
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Button,
|
|
3
|
-
Checkbox,
|
|
4
|
-
Group,
|
|
5
|
-
Popover,
|
|
6
|
-
ScrollArea,
|
|
7
|
-
Stack,
|
|
8
|
-
Text,
|
|
9
|
-
} from "@mantine/core";
|
|
1
|
+
import { Checkbox, Flex, Popover, ScrollArea, Text } from "@mantine/core";
|
|
10
2
|
import { IconColumns } from "@tabler/icons-react";
|
|
11
3
|
import type { TObject } from "alepha";
|
|
12
4
|
import { useState } from "react";
|
|
13
5
|
import { ui } from "../../constants/ui.ts";
|
|
14
6
|
import ActionButton from "../buttons/ActionButton.tsx";
|
|
15
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
type ColumnVisibility,
|
|
9
|
+
type DataTableColumn,
|
|
10
|
+
DEFAULT_MAX_VISIBLE_COLUMNS,
|
|
11
|
+
} from "./types.ts";
|
|
16
12
|
|
|
17
13
|
export interface ColumnPickerProps<T extends object, Filters extends TObject> {
|
|
18
14
|
columns: { [key: string]: DataTableColumn<T, Filters> };
|
|
@@ -36,11 +32,19 @@ const ColumnPicker = <T extends object, Filters extends TObject>({
|
|
|
36
32
|
onVisibilityChange(newVisibility);
|
|
37
33
|
};
|
|
38
34
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
const handleDefault = () => {
|
|
36
|
+
let count = 0;
|
|
37
|
+
const newVisibility = columnEntries.reduce((acc, [key, col]) => {
|
|
38
|
+
if (col.defaultHidden) {
|
|
39
|
+
acc[key] = false;
|
|
40
|
+
} else if (count < DEFAULT_MAX_VISIBLE_COLUMNS) {
|
|
41
|
+
acc[key] = true;
|
|
42
|
+
count++;
|
|
43
|
+
} else {
|
|
44
|
+
acc[key] = false;
|
|
45
|
+
}
|
|
46
|
+
return acc;
|
|
47
|
+
}, {} as ColumnVisibility);
|
|
44
48
|
onVisibilityChange(newVisibility);
|
|
45
49
|
};
|
|
46
50
|
|
|
@@ -71,7 +75,13 @@ const ColumnPicker = <T extends object, Filters extends TObject>({
|
|
|
71
75
|
}}
|
|
72
76
|
>
|
|
73
77
|
<Popover.Target>
|
|
74
|
-
<
|
|
78
|
+
<div>
|
|
79
|
+
<ActionButton
|
|
80
|
+
variant="subtle"
|
|
81
|
+
icon={IconColumns}
|
|
82
|
+
onClick={() => setOpened((o) => !o)}
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
75
85
|
</Popover.Target>
|
|
76
86
|
<Popover.Dropdown
|
|
77
87
|
bg="transparent"
|
|
@@ -81,43 +91,49 @@ const ColumnPicker = <T extends object, Filters extends TObject>({
|
|
|
81
91
|
backdropFilter: "blur(20px)",
|
|
82
92
|
}}
|
|
83
93
|
>
|
|
84
|
-
<
|
|
85
|
-
|
|
94
|
+
<Flex
|
|
95
|
+
direction="column"
|
|
96
|
+
gap="xs"
|
|
97
|
+
bg={ui.colors.surface}
|
|
98
|
+
p="sm"
|
|
99
|
+
bdrs="sm"
|
|
100
|
+
>
|
|
101
|
+
<Flex justify="space-between">
|
|
86
102
|
<Text size="sm" fw={500}>
|
|
87
103
|
Columns ({visibleCount}/{columnEntries.length})
|
|
88
104
|
</Text>
|
|
89
|
-
<
|
|
90
|
-
<
|
|
105
|
+
<Flex gap={4}>
|
|
106
|
+
<ActionButton
|
|
91
107
|
size="compact-xs"
|
|
92
108
|
variant="subtle"
|
|
93
109
|
onClick={handleShowAll}
|
|
94
110
|
>
|
|
95
111
|
All
|
|
96
|
-
</
|
|
97
|
-
<
|
|
112
|
+
</ActionButton>
|
|
113
|
+
<ActionButton
|
|
98
114
|
size="compact-xs"
|
|
99
115
|
variant="subtle"
|
|
100
|
-
onClick={
|
|
116
|
+
onClick={handleDefault}
|
|
101
117
|
>
|
|
102
|
-
|
|
103
|
-
</
|
|
104
|
-
</
|
|
105
|
-
</
|
|
118
|
+
Default
|
|
119
|
+
</ActionButton>
|
|
120
|
+
</Flex>
|
|
121
|
+
</Flex>
|
|
106
122
|
|
|
107
123
|
<ScrollArea.Autosize mah={300}>
|
|
108
|
-
<
|
|
124
|
+
<Flex direction="column" gap={4}>
|
|
109
125
|
{columnEntries.map(([key, col]) => (
|
|
110
126
|
<Checkbox
|
|
111
127
|
key={key}
|
|
112
|
-
label={col.label}
|
|
128
|
+
label={col.label || key}
|
|
113
129
|
checked={visibility[key] !== false}
|
|
114
130
|
onChange={(e) => handleToggle(key, e.currentTarget.checked)}
|
|
115
131
|
size="sm"
|
|
116
132
|
/>
|
|
117
133
|
))}
|
|
118
|
-
</
|
|
134
|
+
</Flex>
|
|
119
135
|
</ScrollArea.Autosize>
|
|
120
|
-
</
|
|
136
|
+
</Flex>
|
|
121
137
|
</Popover.Dropdown>
|
|
122
138
|
</Popover>
|
|
123
139
|
);
|