@alepha/ui 0.15.3 → 0.15.5
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-DsmGnHNh.js +3 -0
- package/dist/admin/AdminApiKeys-GMORg-1l.js +442 -0
- package/dist/admin/AdminApiKeys-GMORg-1l.js.map +1 -0
- package/dist/admin/AdminAudits-8SM96viT.js +3 -0
- package/dist/admin/{AdminAudits-Oh7iAfQa.js → AdminAudits-pkWrjq1Z.js} +2 -2
- package/dist/admin/{AdminAudits-Oh7iAfQa.js.map → AdminAudits-pkWrjq1Z.js.map} +1 -1
- package/dist/admin/AdminFiles-B56ocq4H.js +3 -0
- package/dist/admin/{AdminFiles-Cu8GHgQ3.js → AdminFiles-WeQbsCsl.js} +2 -2
- package/dist/admin/{AdminFiles-Cu8GHgQ3.js.map → AdminFiles-WeQbsCsl.js.map} +1 -1
- package/dist/admin/AdminJobs-B-q9iGO3.js +697 -0
- package/dist/admin/AdminJobs-B-q9iGO3.js.map +1 -0
- package/dist/admin/AdminJobs-CED1syCn.js +3 -0
- package/dist/admin/AdminLayout-BX4FIpXv.css +143 -0
- package/dist/admin/AdminLayout-BX4FIpXv.css.map +1 -0
- package/dist/admin/{AdminLayout-QJLIesuG.js → AdminLayout-BqZiXx4H.js} +3 -2
- package/dist/admin/AdminLayout-BqZiXx4H.js.map +1 -0
- package/dist/admin/AdminNotifications-B0B1rdc4.js +3 -0
- package/dist/admin/{AdminNotifications-CgYkBuG_.js → AdminNotifications-Ds5Un0NJ.js} +2 -2
- package/dist/admin/{AdminNotifications-CgYkBuG_.js.map → AdminNotifications-Ds5Un0NJ.js.map} +1 -1
- package/dist/admin/{AdminParameters-Cl-R0nXt.js → AdminParameters-BU3lATdJ.js} +1 -1
- package/dist/admin/{AdminParameters-hjNG_KXb.js → AdminParameters-CfDUpc78.js} +4 -4
- package/dist/admin/{AdminParameters-hjNG_KXb.js.map → AdminParameters-CfDUpc78.js.map} +1 -1
- package/dist/admin/AdminSessions-BDGK2MS6.js +3 -0
- package/dist/admin/{AdminSessions-Bey9cuy1.js → AdminSessions-DzIOxM3b.js} +2 -2
- package/dist/admin/{AdminSessions-Bey9cuy1.js.map → AdminSessions-DzIOxM3b.js.map} +1 -1
- package/dist/admin/{AdminUserAudits-C7AN9jx7.js → AdminUserAudits-CiUPN2BC.js} +2 -2
- package/dist/admin/{AdminUserAudits-C7AN9jx7.js.map → AdminUserAudits-CiUPN2BC.js.map} +1 -1
- package/dist/admin/{AdminUserAudits-Cp_ERd2g.js → AdminUserAudits-Cj79gENT.js} +1 -1
- package/dist/admin/{AdminUserCreate-BVIm4JdN.js → AdminUserCreate-BwQKr4xE.js} +2 -2
- package/dist/admin/{AdminUserCreate-BVIm4JdN.js.map → AdminUserCreate-BwQKr4xE.js.map} +1 -1
- package/dist/admin/{AdminUserCreate-C1aInRDk.js → AdminUserCreate-Cq-mUmBs.js} +1 -1
- package/dist/admin/{AdminUserDetails-Dcn3OwMC.js → AdminUserDetails-DRjVAPFd.js} +1 -1
- package/dist/admin/{AdminUserDetails-yM4x8JE6.js → AdminUserDetails-uqtC5aJ1.js} +2 -2
- package/dist/admin/{AdminUserDetails-yM4x8JE6.js.map → AdminUserDetails-uqtC5aJ1.js.map} +1 -1
- package/dist/admin/{AdminUserLayout-gb-nbggz.js → AdminUserLayout-CGzmHHby.js} +1 -1
- package/dist/admin/{AdminUserLayout-BnfBC1gD.js → AdminUserLayout-CiPay35T.js} +2 -2
- package/dist/admin/{AdminUserLayout-BnfBC1gD.js.map → AdminUserLayout-CiPay35T.js.map} +1 -1
- package/dist/admin/{AdminUserSessions-kmkXG-xf.js → AdminUserSessions-DAE8Nf1F.js} +2 -2
- package/dist/admin/{AdminUserSessions-kmkXG-xf.js.map → AdminUserSessions-DAE8Nf1F.js.map} +1 -1
- package/dist/admin/AdminUserSessions-DcdzuNZ9.js +3 -0
- package/dist/admin/AdminUserSettings-D7V6-ceX.js +3 -0
- package/dist/admin/{AdminUserSettings-DZ9iWhJW.js → AdminUserSettings-EbahaV2a.js} +2 -2
- package/dist/admin/{AdminUserSettings-DZ9iWhJW.js.map → AdminUserSettings-EbahaV2a.js.map} +1 -1
- package/dist/admin/AdminUsers-D9nyzGqQ.js +3 -0
- package/dist/admin/{AdminUsers-D6Y5K8Am.js → AdminUsers-Dcjh0KNW.js} +2 -2
- package/dist/admin/{AdminUsers-D6Y5K8Am.js.map → AdminUsers-Dcjh0KNW.js.map} +1 -1
- package/dist/admin/index.d.ts +39 -51
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +52 -169
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/AuthLayout-BaD7RD2h.css +143 -0
- package/dist/auth/AuthLayout-BaD7RD2h.css.map +1 -0
- package/dist/auth/AuthLayout-Dj5K4SIN.js.map +1 -1
- package/dist/auth/index.d.ts +9 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -2
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +13 -21
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +26 -38
- package/dist/core/index.js.map +1 -1
- package/dist/demo/{DemoLogin-S-b15cmE.js → DemoLogin-CvCG2WVh.js} +3 -1
- package/dist/demo/{DemoLogin-S-b15cmE.js.map → DemoLogin-CvCG2WVh.js.map} +1 -1
- package/dist/demo/{DemoRegister-B29MdAaZ.js → DemoRegister-CmeHbOAs.js} +3 -1
- package/dist/demo/{DemoRegister-B29MdAaZ.js.map → DemoRegister-CmeHbOAs.js.map} +1 -1
- package/dist/demo/{DemoResetPassword-CPTy88iK.js → DemoResetPassword-CKO5iA_6.js} +3 -1
- package/dist/demo/{DemoResetPassword-CPTy88iK.js.map → DemoResetPassword-CKO5iA_6.js.map} +1 -1
- package/dist/demo/index.js +3 -3
- package/package.json +3 -3
- package/src/admin/AdminRouter.ts +34 -0
- package/src/admin/components/AdminLayout.tsx +2 -0
- package/src/admin/components/jobs/AdminJobs.tsx +733 -119
- package/src/admin/components/keys/AdminApiKeys.tsx +537 -0
- package/src/admin/components/parameters/AdminParameters.tsx +2 -3
- package/src/admin/index.ts +3 -5
- package/src/auth/AuthRouter.ts +1 -2
- package/src/auth/components/AuthLayout.tsx +1 -0
- package/src/core/components/buttons/ActionButton.tsx +15 -2
- package/src/core/components/buttons/DarkModeButton.css +6 -0
- package/src/core/components/buttons/DarkModeButton.tsx +18 -71
- package/src/core/components/buttons/LanguageButton.tsx +2 -7
- package/src/core/components/buttons/ThemeButton.tsx +2 -6
- package/src/core/components/layout/AdminShell.tsx +17 -1
- package/src/core/components/layout/AppBar.tsx +5 -8
- package/src/core/index.ts +0 -1
- package/src/core/styles.css +1 -0
- package/src/demo/components/auth/DemoLogin.tsx +2 -0
- package/src/demo/components/auth/DemoRegister.tsx +2 -0
- package/src/demo/components/auth/DemoResetPassword.tsx +2 -0
- package/dist/admin/AdminAudits-BU-p1g7A.js +0 -3
- package/dist/admin/AdminFiles-Bg9feLFH.js +0 -3
- package/dist/admin/AdminLayout-BfeFXiul.js +0 -3
- package/dist/admin/AdminLayout-QJLIesuG.js.map +0 -1
- package/dist/admin/AdminNotifications-DmfGPqHe.js +0 -3
- package/dist/admin/AdminSessions-Cn4_jB04.js +0 -3
- package/dist/admin/AdminUserSessions-rvA0ztxn.js +0 -3
- package/dist/admin/AdminUserSettings-Dg-wTRzN.js +0 -3
- package/dist/admin/AdminUsers-RCaxccEW.js +0 -3
- package/src/admin/MainRouter.ts +0 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserAudits-
|
|
1
|
+
{"version":3,"file":"AdminUserAudits-CiUPN2BC.js","names":[],"sources":["../../src/admin/components/users/AdminUserAudits.tsx"],"sourcesContent":["import { DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge, Group, Tooltip } from \"@mantine/core\";\nimport {\n IconAlertTriangle,\n IconCheck,\n IconInfoCircle,\n IconX,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport type { AdminAuditController, AuditEntity } from \"alepha/api/audits\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\n\nexport interface AdminUserAuditsProps {\n userRealmName?: string;\n}\n\nconst getSeverityColor = (severity: string) => {\n switch (severity) {\n case \"critical\":\n return \"red\";\n case \"warning\":\n return \"yellow\";\n default:\n return \"blue\";\n }\n};\n\nconst getSeverityIcon = (severity: string) => {\n switch (severity) {\n case \"critical\":\n return <IconAlertTriangle size={12} />;\n case \"warning\":\n return <IconAlertTriangle size={12} />;\n default:\n return <IconInfoCircle size={12} />;\n }\n};\n\nconst AdminUserAudits = (_props: AdminUserAuditsProps) => {\n const state = useRouterState();\n const client = useClient<AdminAuditController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n\n const filters = t.object({\n type: t.optional(t.text()),\n action: t.optional(t.text()),\n severity: t.optional(t.enum([\"info\", \"warning\", \"critical\"])),\n success: t.optional(t.boolean()),\n from: t.optional(t.datetime()),\n to: t.optional(t.datetime()),\n });\n\n return (\n <Flex flex={1} direction=\"column\">\n <DataTable<AuditEntity, typeof filters>\n submitOnInit\n defaultSize={15}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 4,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n striped: false,\n highlightOnHover: true,\n }}\n filters={filters}\n items={async (query) => {\n const response = await client.findByUser({\n params: { userId },\n query,\n });\n return response as Page<AuditEntity>;\n }}\n columns={{\n type: {\n label: \"Type\",\n fit: true,\n value: (item) => (\n <Badge size=\"sm\" variant=\"light\" color=\"grape\">\n {item.type}\n </Badge>\n ),\n },\n action: {\n label: \"Action\",\n fit: true,\n value: (item) => (\n <Badge size=\"sm\" variant=\"outline\">\n {item.action}\n </Badge>\n ),\n },\n severity: {\n label: \"Severity\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={getSeverityColor(item.severity)}\n leftSection={getSeverityIcon(item.severity)}\n >\n {item.severity}\n </Badge>\n ),\n },\n description: {\n label: \"Description\",\n value: (item) => (\n <Text size=\"sm\" lineClamp={1}>\n {item.description || \"-\"}\n </Text>\n ),\n },\n resource: {\n label: \"Resource\",\n fit: true,\n value: (item) =>\n item.resourceType ? (\n <Tooltip label={item.resourceId || \"N/A\"}>\n <Badge size=\"xs\" variant=\"dot\" color=\"gray\">\n {item.resourceType}\n </Badge>\n </Tooltip>\n ) : (\n <Text size=\"xs\" c=\"dimmed\">\n -\n </Text>\n ),\n },\n success: {\n label: \"Status\",\n fit: true,\n value: (item) =>\n item.success ? (\n <Group gap={4}>\n <IconCheck size={14} color=\"var(--mantine-color-green-6)\" />\n <Text size=\"xs\" c=\"green\">\n Success\n </Text>\n </Group>\n ) : (\n <Tooltip label={item.errorMessage || \"Failed\"}>\n <Group gap={4}>\n <IconX size={14} color=\"var(--mantine-color-red-6)\" />\n <Text size=\"xs\" c=\"red\">\n Failed\n </Text>\n </Group>\n </Tooltip>\n ),\n },\n ipAddress: {\n label: \"IP\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\" ff=\"monospace\">\n {item.ipAddress || \"-\"}\n </Text>\n ),\n },\n createdAt: {\n label: \"Time\",\n fit: true,\n value: (item) => (\n <Tooltip label={l(item.createdAt, { date: \"medium\" })}>\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n </Tooltip>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminUserAudits;\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ActionButton, Control, Flex } from "@alepha/ui";
|
|
2
2
|
import { t } from "alepha";
|
|
3
3
|
import { useRouter } from "alepha/react/router";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
4
|
import { Card, Stack, Text as Text$1 } from "@mantine/core";
|
|
6
5
|
import { useClient } from "alepha/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useForm } from "alepha/react/form";
|
|
8
8
|
|
|
9
9
|
//#region ../../src/admin/components/users/AdminUserCreate.tsx
|
|
@@ -101,4 +101,4 @@ var AdminUserCreate_default = AdminUserCreate;
|
|
|
101
101
|
|
|
102
102
|
//#endregion
|
|
103
103
|
export { AdminUserCreate_default as t };
|
|
104
|
-
//# sourceMappingURL=AdminUserCreate-
|
|
104
|
+
//# sourceMappingURL=AdminUserCreate-BwQKr4xE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserCreate-
|
|
1
|
+
{"version":3,"file":"AdminUserCreate-BwQKr4xE.js","names":["Text"],"sources":["../../src/admin/components/users/AdminUserCreate.tsx"],"sourcesContent":["import { ActionButton, Control, Flex } from \"@alepha/ui\";\nimport { Card, Stack, Text } from \"@mantine/core\";\nimport { t } from \"alepha\";\nimport type { AdminUserController } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\n\nexport interface AdminUserCreateProps {\n userRealmName?: string;\n}\n\nconst AdminUserCreate = (props: AdminUserCreateProps) => {\n const client = useClient<AdminUserController>();\n const router = useRouter<AdminRouter>();\n\n const form = useForm({\n schema: t.object({\n username: t.optional(\n t.shortText({\n minLength: 3,\n maxLength: 50,\n pattern: \"^[a-zA-Z0-9._-]+$\",\n }),\n ),\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.string()),\n lastName: t.optional(t.string()),\n roles: t.optional(t.array(t.string())),\n enabled: t.optional(t.boolean()),\n password: t.optional(t.string({ minLength: 8 })),\n }),\n handler: async (data) => {\n const user = await client.createUser({\n query: {\n userRealmName: props.userRealmName,\n },\n body: {\n ...data,\n enabled: data.enabled ?? true,\n },\n });\n\n await router.push(\"adminUserDetails\", {\n params: { userId: user.id },\n });\n },\n });\n\n return (\n <Flex flex={1} p=\"md\">\n <Card withBorder p=\"lg\" maw={600} w=\"100%\">\n <form {...form.props}>\n <Stack gap=\"md\">\n <Text size=\"lg\" fw={500}>\n Create New User\n </Text>\n\n <Control title=\"Username\" input={form.input.username} />\n\n <Control title=\"Email\" input={form.input.email} />\n\n <Control title=\"Phone Number\" input={form.input.phoneNumber} />\n\n <Control title=\"First Name\" input={form.input.firstName} />\n\n <Control title=\"Last Name\" input={form.input.lastName} />\n\n <Control title=\"Password\" input={form.input.password} password />\n\n <Control title=\"Roles\" input={form.input.roles} />\n\n <Control title=\"Enabled\" input={form.input.enabled} />\n\n <ActionButton form={form}>Create User</ActionButton>\n </Stack>\n </form>\n </Card>\n </Flex>\n );\n};\n\nexport default AdminUserCreate;\n"],"mappings":";;;;;;;;;AAaA,MAAM,mBAAmB,UAAgC;CACvD,MAAM,SAAS,WAAgC;CAC/C,MAAM,SAAS,WAAwB;CAEvC,MAAM,OAAO,QAAQ;EACnB,QAAQ,EAAE,OAAO;GACf,UAAU,EAAE,SACV,EAAE,UAAU;IACV,WAAW;IACX,WAAW;IACX,SAAS;IACV,CAAC,CACH;GACD,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;GAC5B,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;GACjC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC;GACjC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC;GAChC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;GACtC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;GAChC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,CAAC,CAAC;GACjD,CAAC;EACF,SAAS,OAAO,SAAS;GACvB,MAAM,OAAO,MAAM,OAAO,WAAW;IACnC,OAAO,EACL,eAAe,MAAM,eACtB;IACD,MAAM;KACJ,GAAG;KACH,SAAS,KAAK,WAAW;KAC1B;IACF,CAAC;AAEF,SAAM,OAAO,KAAK,oBAAoB,EACpC,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAC5B,CAAC;;EAEL,CAAC;AAEF,QACE,oBAAC;EAAK,MAAM;EAAG,GAAE;YACf,oBAAC;GAAK;GAAW,GAAE;GAAK,KAAK;GAAK,GAAE;aAClC,oBAAC;IAAK,GAAI,KAAK;cACb,qBAAC;KAAM,KAAI;;MACT,oBAACA;OAAK,MAAK;OAAK,IAAI;iBAAK;QAElB;MAEP,oBAAC;OAAQ,OAAM;OAAW,OAAO,KAAK,MAAM;QAAY;MAExD,oBAAC;OAAQ,OAAM;OAAQ,OAAO,KAAK,MAAM;QAAS;MAElD,oBAAC;OAAQ,OAAM;OAAe,OAAO,KAAK,MAAM;QAAe;MAE/D,oBAAC;OAAQ,OAAM;OAAa,OAAO,KAAK,MAAM;QAAa;MAE3D,oBAAC;OAAQ,OAAM;OAAY,OAAO,KAAK,MAAM;QAAY;MAEzD,oBAAC;OAAQ,OAAM;OAAW,OAAO,KAAK,MAAM;OAAU;QAAW;MAEjE,oBAAC;OAAQ,OAAM;OAAQ,OAAO,KAAK,MAAM;QAAS;MAElD,oBAAC;OAAQ,OAAM;OAAU,OAAO,KAAK,MAAM;QAAW;MAEtD,oBAAC;OAAmB;iBAAM;QAA0B;;MAC9C;KACH;IACF;GACF;;AAIX,8BAAe"}
|
|
@@ -2,10 +2,10 @@ import { ActionButton, ClipboardButton, Control } from "@alepha/ui";
|
|
|
2
2
|
import { t } from "alepha";
|
|
3
3
|
import { IconActivity, IconCalendar, IconCheck, IconDevices, IconKey, IconShieldCheck, IconUser, IconX } from "@tabler/icons-react";
|
|
4
4
|
import { useRouterState } from "alepha/react/router";
|
|
5
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
5
|
import { Badge, Box, Card, Center, Divider, Grid, Group, Loader, Paper, SimpleGrid, Stack, Text as Text$1, ThemeIcon } from "@mantine/core";
|
|
7
6
|
import { useClient } from "alepha/react";
|
|
8
7
|
import { useI18n } from "alepha/react/i18n";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useEffect, useState } from "react";
|
|
10
10
|
import { useForm } from "alepha/react/form";
|
|
11
11
|
|
|
@@ -472,4 +472,4 @@ var AdminUserDetails_default = AdminUserDetails;
|
|
|
472
472
|
|
|
473
473
|
//#endregion
|
|
474
474
|
export { AdminUserDetails_default as t };
|
|
475
|
-
//# sourceMappingURL=AdminUserDetails-
|
|
475
|
+
//# sourceMappingURL=AdminUserDetails-uqtC5aJ1.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserDetails-yM4x8JE6.js","names":["Text"],"sources":["../../src/admin/components/users/AdminUserDetails.tsx"],"sourcesContent":["import { ActionButton, ClipboardButton, Control } from \"@alepha/ui\";\nimport {\n Badge,\n Box,\n Card,\n Center,\n Divider,\n Grid,\n Group,\n Loader,\n Paper,\n SimpleGrid,\n Stack,\n Text,\n ThemeIcon,\n} from \"@mantine/core\";\nimport {\n IconActivity,\n IconCalendar,\n IconCheck,\n IconDevices,\n IconKey,\n IconShieldCheck,\n IconUser,\n IconX,\n} from \"@tabler/icons-react\";\nimport { t } from \"alepha\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport interface AdminUserDetailsProps {\n userRealmName?: string;\n}\n\ninterface DataRowProps {\n label: string;\n value: ReactNode;\n copyValue?: string;\n}\n\nconst DataRow = ({ label, value, copyValue }: DataRowProps) => (\n <Group\n justify=\"space-between\"\n py={8}\n wrap=\"nowrap\"\n style={{ borderBottom: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Text size=\"sm\" c=\"dimmed\" style={{ flexShrink: 0 }}>\n {label}\n </Text>\n <Group gap={6} wrap=\"nowrap\" style={{ minWidth: 0 }}>\n {typeof value === \"string\" ? (\n <Text size=\"sm\" fw={500} truncate style={{ maxWidth: 220 }}>\n {value || \"—\"}\n </Text>\n ) : (\n value\n )}\n {copyValue && (\n <ClipboardButton\n value={copyValue}\n size=\"xs\"\n variant=\"subtle\"\n c=\"dimmed\"\n />\n )}\n </Group>\n </Group>\n);\n\ninterface StatCardProps {\n icon: ReactNode;\n label: string;\n value: string | number;\n color: string;\n}\n\nconst StatCard = ({ icon, label, value, color }: StatCardProps) => (\n <Paper p=\"md\" radius=\"md\" withBorder>\n <Group gap=\"sm\">\n <ThemeIcon size=\"lg\" radius=\"md\" variant=\"light\" color={color}>\n {icon}\n </ThemeIcon>\n <Box>\n <Text size=\"xl\" fw={700} lh={1}>\n {value}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {label}\n </Text>\n </Box>\n </Group>\n </Paper>\n);\n\nconst AdminUserDetails = (props: AdminUserDetailsProps) => {\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [editing, setEditing] = useState(false);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n const form = useForm({\n schema: t.object({\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.string()),\n lastName: t.optional(t.string()),\n roles: t.optional(t.array(t.string())),\n enabled: t.optional(t.boolean()),\n }),\n handler: async (data) => {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: data,\n });\n setUser(updated);\n setEditing(false);\n },\n });\n\n useEffect(() => {\n if (user) {\n form.input.email?.set(user.email ?? \"\");\n form.input.phoneNumber?.set(user.phoneNumber ?? \"\");\n form.input.firstName?.set(user.firstName ?? \"\");\n form.input.lastName?.set(user.lastName ?? \"\");\n form.input.roles?.set(user.roles ?? []);\n form.input.enabled?.set(user.enabled);\n }\n }, [user]);\n\n if (loading) {\n return (\n <Center flex={1} py=\"xl\">\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1} py=\"xl\">\n <Stack align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Stack>\n </Center>\n );\n }\n\n const displayName =\n user.firstName && user.lastName\n ? `${user.firstName} ${user.lastName}`\n : user.firstName || user.lastName || null;\n\n return (\n <Stack gap=\"md\">\n {/* Stats Overview */}\n <SimpleGrid cols={{ base: 2, sm: 4 }}>\n <StatCard\n icon={<IconDevices size={18} />}\n label=\"Sessions\"\n value={0}\n color=\"blue\"\n />\n <StatCard\n icon={<IconActivity size={18} />}\n label=\"API Calls\"\n value={0}\n color=\"green\"\n />\n <StatCard\n icon={<IconKey size={18} />}\n label=\"Failed Logins\"\n value={0}\n color=\"orange\"\n />\n <StatCard\n icon={<IconShieldCheck size={18} />}\n label=\"Roles\"\n value={user.roles.length}\n color=\"violet\"\n />\n </SimpleGrid>\n\n <Grid>\n {/* Left Column - Account Details */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Account Details\n </Text>\n </Group>\n <Box px=\"md\" pb=\"md\">\n <DataRow label=\"User ID\" value={user.id} copyValue={user.id} />\n <DataRow\n label=\"Username\"\n value={user.username || \"—\"}\n copyValue={user.username}\n />\n <DataRow\n label=\"Email\"\n value={\n <Group gap={6}>\n <Text size=\"sm\" fw={500}>\n {user.email || \"—\"}\n </Text>\n {user.email && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={user.emailVerified ? \"green\" : \"orange\"}\n >\n {user.emailVerified ? \"verified\" : \"unverified\"}\n </Badge>\n )}\n </Group>\n }\n copyValue={user.email}\n />\n <DataRow\n label=\"Phone\"\n value={user.phoneNumber || \"—\"}\n copyValue={user.phoneNumber}\n />\n <DataRow label=\"Realm\" value={user.realm} />\n <DataRow\n label=\"Status\"\n value={\n <Group gap={4}>\n <ThemeIcon\n size={16}\n radius=\"xl\"\n color={user.enabled ? \"green\" : \"red\"}\n variant=\"filled\"\n >\n {user.enabled ? (\n <IconCheck size={10} />\n ) : (\n <IconX size={10} />\n )}\n </ThemeIcon>\n <Text size=\"sm\" fw={500}>\n {user.enabled ? \"Active\" : \"Disabled\"}\n </Text>\n </Group>\n }\n />\n </Box>\n </Card>\n </Grid.Col>\n\n {/* Right Column - Personal Info */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Personal Information\n </Text>\n {!editing && (\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(true)}\n >\n Edit\n </ActionButton>\n )}\n </Group>\n\n {editing ? (\n <Box p=\"md\">\n <form {...form.props}>\n <Stack gap=\"sm\">\n <SimpleGrid cols={2}>\n <Control\n title=\"First Name\"\n input={form.input.firstName}\n />\n <Control title=\"Last Name\" input={form.input.lastName} />\n </SimpleGrid>\n <SimpleGrid cols={2}>\n <Control title=\"Email\" input={form.input.email} />\n <Control title=\"Phone\" input={form.input.phoneNumber} />\n </SimpleGrid>\n <Control title=\"Roles\" input={form.input.roles} />\n <Divider />\n <Group justify=\"flex-end\" gap=\"xs\">\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(false)}\n >\n Cancel\n </ActionButton>\n <ActionButton size=\"xs\" form={form}>\n Save\n </ActionButton>\n </Group>\n </Stack>\n </form>\n </Box>\n ) : (\n <Box px=\"md\" pb=\"md\">\n <DataRow label=\"First Name\" value={user.firstName || \"—\"} />\n <DataRow label=\"Last Name\" value={user.lastName || \"—\"} />\n <DataRow label=\"Display Name\" value={displayName || \"—\"} />\n <DataRow\n label=\"Roles\"\n value={\n user.roles.length > 0 ? (\n <Group gap={4}>\n {user.roles.map((role) => (\n <Badge key={role} size=\"xs\" variant=\"light\">\n {role}\n </Badge>\n ))}\n </Group>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n No roles\n </Text>\n )\n }\n />\n </Box>\n )}\n </Card>\n </Grid.Col>\n </Grid>\n\n {/* Timeline */}\n <Card padding={0} radius=\"md\" withBorder>\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Activity Timeline\n </Text>\n </Group>\n <SimpleGrid cols={{ base: 2, sm: 4 }} p=\"md\">\n <Box>\n <Group gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Created\n </Text>\n </Group>\n <Text size=\"sm\" fw={500}>\n {l(user.createdAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.createdAt, { date: \"fromNow\" })}\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Updated\n </Text>\n </Group>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconDevices size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Last Login\n </Text>\n </Group>\n <Text size=\"sm\" c=\"dimmed\">\n —\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconCheck size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Email Verified\n </Text>\n </Group>\n {user.emailVerified ? (\n <>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n Not verified\n </Text>\n )}\n </Box>\n </SimpleGrid>\n </Card>\n </Stack>\n );\n};\n\nexport default AdminUserDetails;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdminUserDetails-uqtC5aJ1.js","names":["Text"],"sources":["../../src/admin/components/users/AdminUserDetails.tsx"],"sourcesContent":["import { ActionButton, ClipboardButton, Control } from \"@alepha/ui\";\nimport {\n Badge,\n Box,\n Card,\n Center,\n Divider,\n Grid,\n Group,\n Loader,\n Paper,\n SimpleGrid,\n Stack,\n Text,\n ThemeIcon,\n} from \"@mantine/core\";\nimport {\n IconActivity,\n IconCalendar,\n IconCheck,\n IconDevices,\n IconKey,\n IconShieldCheck,\n IconUser,\n IconX,\n} from \"@tabler/icons-react\";\nimport { t } from \"alepha\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport interface AdminUserDetailsProps {\n userRealmName?: string;\n}\n\ninterface DataRowProps {\n label: string;\n value: ReactNode;\n copyValue?: string;\n}\n\nconst DataRow = ({ label, value, copyValue }: DataRowProps) => (\n <Group\n justify=\"space-between\"\n py={8}\n wrap=\"nowrap\"\n style={{ borderBottom: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Text size=\"sm\" c=\"dimmed\" style={{ flexShrink: 0 }}>\n {label}\n </Text>\n <Group gap={6} wrap=\"nowrap\" style={{ minWidth: 0 }}>\n {typeof value === \"string\" ? (\n <Text size=\"sm\" fw={500} truncate style={{ maxWidth: 220 }}>\n {value || \"—\"}\n </Text>\n ) : (\n value\n )}\n {copyValue && (\n <ClipboardButton\n value={copyValue}\n size=\"xs\"\n variant=\"subtle\"\n c=\"dimmed\"\n />\n )}\n </Group>\n </Group>\n);\n\ninterface StatCardProps {\n icon: ReactNode;\n label: string;\n value: string | number;\n color: string;\n}\n\nconst StatCard = ({ icon, label, value, color }: StatCardProps) => (\n <Paper p=\"md\" radius=\"md\" withBorder>\n <Group gap=\"sm\">\n <ThemeIcon size=\"lg\" radius=\"md\" variant=\"light\" color={color}>\n {icon}\n </ThemeIcon>\n <Box>\n <Text size=\"xl\" fw={700} lh={1}>\n {value}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {label}\n </Text>\n </Box>\n </Group>\n </Paper>\n);\n\nconst AdminUserDetails = (props: AdminUserDetailsProps) => {\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [editing, setEditing] = useState(false);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n const form = useForm({\n schema: t.object({\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.string()),\n lastName: t.optional(t.string()),\n roles: t.optional(t.array(t.string())),\n enabled: t.optional(t.boolean()),\n }),\n handler: async (data) => {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: data,\n });\n setUser(updated);\n setEditing(false);\n },\n });\n\n useEffect(() => {\n if (user) {\n form.input.email?.set(user.email ?? \"\");\n form.input.phoneNumber?.set(user.phoneNumber ?? \"\");\n form.input.firstName?.set(user.firstName ?? \"\");\n form.input.lastName?.set(user.lastName ?? \"\");\n form.input.roles?.set(user.roles ?? []);\n form.input.enabled?.set(user.enabled);\n }\n }, [user]);\n\n if (loading) {\n return (\n <Center flex={1} py=\"xl\">\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1} py=\"xl\">\n <Stack align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Stack>\n </Center>\n );\n }\n\n const displayName =\n user.firstName && user.lastName\n ? `${user.firstName} ${user.lastName}`\n : user.firstName || user.lastName || null;\n\n return (\n <Stack gap=\"md\">\n {/* Stats Overview */}\n <SimpleGrid cols={{ base: 2, sm: 4 }}>\n <StatCard\n icon={<IconDevices size={18} />}\n label=\"Sessions\"\n value={0}\n color=\"blue\"\n />\n <StatCard\n icon={<IconActivity size={18} />}\n label=\"API Calls\"\n value={0}\n color=\"green\"\n />\n <StatCard\n icon={<IconKey size={18} />}\n label=\"Failed Logins\"\n value={0}\n color=\"orange\"\n />\n <StatCard\n icon={<IconShieldCheck size={18} />}\n label=\"Roles\"\n value={user.roles.length}\n color=\"violet\"\n />\n </SimpleGrid>\n\n <Grid>\n {/* Left Column - Account Details */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Account Details\n </Text>\n </Group>\n <Box px=\"md\" pb=\"md\">\n <DataRow label=\"User ID\" value={user.id} copyValue={user.id} />\n <DataRow\n label=\"Username\"\n value={user.username || \"—\"}\n copyValue={user.username}\n />\n <DataRow\n label=\"Email\"\n value={\n <Group gap={6}>\n <Text size=\"sm\" fw={500}>\n {user.email || \"—\"}\n </Text>\n {user.email && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={user.emailVerified ? \"green\" : \"orange\"}\n >\n {user.emailVerified ? \"verified\" : \"unverified\"}\n </Badge>\n )}\n </Group>\n }\n copyValue={user.email}\n />\n <DataRow\n label=\"Phone\"\n value={user.phoneNumber || \"—\"}\n copyValue={user.phoneNumber}\n />\n <DataRow label=\"Realm\" value={user.realm} />\n <DataRow\n label=\"Status\"\n value={\n <Group gap={4}>\n <ThemeIcon\n size={16}\n radius=\"xl\"\n color={user.enabled ? \"green\" : \"red\"}\n variant=\"filled\"\n >\n {user.enabled ? (\n <IconCheck size={10} />\n ) : (\n <IconX size={10} />\n )}\n </ThemeIcon>\n <Text size=\"sm\" fw={500}>\n {user.enabled ? \"Active\" : \"Disabled\"}\n </Text>\n </Group>\n }\n />\n </Box>\n </Card>\n </Grid.Col>\n\n {/* Right Column - Personal Info */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Personal Information\n </Text>\n {!editing && (\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(true)}\n >\n Edit\n </ActionButton>\n )}\n </Group>\n\n {editing ? (\n <Box p=\"md\">\n <form {...form.props}>\n <Stack gap=\"sm\">\n <SimpleGrid cols={2}>\n <Control\n title=\"First Name\"\n input={form.input.firstName}\n />\n <Control title=\"Last Name\" input={form.input.lastName} />\n </SimpleGrid>\n <SimpleGrid cols={2}>\n <Control title=\"Email\" input={form.input.email} />\n <Control title=\"Phone\" input={form.input.phoneNumber} />\n </SimpleGrid>\n <Control title=\"Roles\" input={form.input.roles} />\n <Divider />\n <Group justify=\"flex-end\" gap=\"xs\">\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(false)}\n >\n Cancel\n </ActionButton>\n <ActionButton size=\"xs\" form={form}>\n Save\n </ActionButton>\n </Group>\n </Stack>\n </form>\n </Box>\n ) : (\n <Box px=\"md\" pb=\"md\">\n <DataRow label=\"First Name\" value={user.firstName || \"—\"} />\n <DataRow label=\"Last Name\" value={user.lastName || \"—\"} />\n <DataRow label=\"Display Name\" value={displayName || \"—\"} />\n <DataRow\n label=\"Roles\"\n value={\n user.roles.length > 0 ? (\n <Group gap={4}>\n {user.roles.map((role) => (\n <Badge key={role} size=\"xs\" variant=\"light\">\n {role}\n </Badge>\n ))}\n </Group>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n No roles\n </Text>\n )\n }\n />\n </Box>\n )}\n </Card>\n </Grid.Col>\n </Grid>\n\n {/* Timeline */}\n <Card padding={0} radius=\"md\" withBorder>\n <Group justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Activity Timeline\n </Text>\n </Group>\n <SimpleGrid cols={{ base: 2, sm: 4 }} p=\"md\">\n <Box>\n <Group gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Created\n </Text>\n </Group>\n <Text size=\"sm\" fw={500}>\n {l(user.createdAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.createdAt, { date: \"fromNow\" })}\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Updated\n </Text>\n </Group>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconDevices size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Last Login\n </Text>\n </Group>\n <Text size=\"sm\" c=\"dimmed\">\n —\n </Text>\n </Box>\n <Box>\n <Group gap={6} mb={4}>\n <IconCheck size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Email Verified\n </Text>\n </Group>\n {user.emailVerified ? (\n <>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n Not verified\n </Text>\n )}\n </Box>\n </SimpleGrid>\n </Card>\n </Stack>\n );\n};\n\nexport default AdminUserDetails;\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ActionButton } from "@alepha/ui";
|
|
2
2
|
import { IconBan, IconChevronDown, IconChevronLeft, IconDevices, IconExternalLink, IconHistory, IconLock, IconMail, IconPencil, IconSettings, IconShieldCheck, IconTrash, IconUser } from "@tabler/icons-react";
|
|
3
3
|
import { NestedView, useActive, useRouter, useRouterState } from "alepha/react/router";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
4
|
import { ActionIcon, Avatar, Badge, Box, Button, Center, Group, Loader, Menu, Stack, Tabs, Text as Text$1, Tooltip } from "@mantine/core";
|
|
6
5
|
import { useClient } from "alepha/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useEffect, useState } from "react";
|
|
8
8
|
|
|
9
9
|
//#region ../../src/admin/components/shared/AdminResourceHeader.tsx
|
|
@@ -331,4 +331,4 @@ var AdminUserLayout_default = AdminUserLayout;
|
|
|
331
331
|
|
|
332
332
|
//#endregion
|
|
333
333
|
export { AdminUserLayout_default as t };
|
|
334
|
-
//# sourceMappingURL=AdminUserLayout-
|
|
334
|
+
//# sourceMappingURL=AdminUserLayout-CiPay35T.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserLayout-BnfBC1gD.js","names":["Text","Text","AdminResourceHeader","AdminResourceTabs"],"sources":["../../src/admin/components/shared/AdminResourceHeader.tsx","../../src/admin/components/shared/AdminResourceTabs.tsx","../../src/admin/components/users/AdminUserLayout.tsx"],"sourcesContent":["import { ActionButton } from \"@alepha/ui\";\nimport {\n ActionIcon,\n Avatar,\n Badge,\n Button,\n Group,\n Menu,\n Stack,\n Text,\n Tooltip,\n} from \"@mantine/core\";\nimport {\n IconChevronDown,\n IconChevronLeft,\n IconExternalLink,\n} from \"@tabler/icons-react\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceAction {\n label: string;\n icon?: ComponentType<{ size?: number }>;\n onClick?: () => void;\n href?: string;\n color?: string;\n disabled?: boolean;\n loading?: boolean;\n variant?: \"filled\" | \"light\" | \"outline\" | \"subtle\";\n}\n\nexport interface AdminResourceHeaderProps {\n /**\n * Back navigation URL\n */\n backHref?: string;\n\n /**\n * Back navigation label\n */\n backLabel?: string;\n\n /**\n * Avatar content (letter, image URL, or custom node)\n */\n avatar?: string | ReactNode;\n\n /**\n * Avatar color\n */\n avatarColor?: string;\n\n /**\n * Resource title (e.g., user name)\n */\n title: string;\n\n /**\n * Secondary text (e.g., email)\n */\n subtitle?: string;\n\n /**\n * Tertiary identifier to copy (e.g., user ID)\n */\n identifier?: string;\n\n /**\n * Label for the identifier tooltip\n */\n identifierLabel?: string;\n\n /**\n * Status badge\n */\n status?: {\n label: string;\n color: \"green\" | \"red\" | \"yellow\" | \"blue\" | \"gray\";\n };\n\n /**\n * Additional badges (e.g., roles)\n */\n badges?: Array<{\n label: string;\n color?: string;\n variant?: \"filled\" | \"light\" | \"outline\" | \"dot\";\n }>;\n\n /**\n * Primary action button\n */\n primaryAction?: AdminResourceAction;\n\n /**\n * Menu actions (shown in dropdown)\n */\n menuActions?: AdminResourceAction[];\n\n /**\n * External link URL\n */\n externalUrl?: string;\n\n /**\n * Loading state\n */\n loading?: boolean;\n}\n\nconst ActionMenuItem = (props: { action: AdminResourceAction }) => {\n const { action } = props;\n const router = useRouter();\n\n const menuItemProps: Record<string, unknown> = {};\n if (action.href) {\n Object.assign(menuItemProps, router.anchor(action.href));\n } else if (action.onClick) {\n menuItemProps.onClick = action.onClick;\n }\n\n return (\n <Menu.Item\n leftSection={action.icon ? <action.icon size={16} /> : undefined}\n color={action.color}\n disabled={action.disabled}\n {...menuItemProps}\n >\n {action.label}\n </Menu.Item>\n );\n};\n\nconst AdminResourceHeader = (props: AdminResourceHeaderProps) => {\n const {\n backHref,\n backLabel = \"Back\",\n avatar,\n avatarColor = \"blue\",\n title,\n subtitle,\n identifier,\n identifierLabel = \"ID\",\n status,\n badges = [],\n primaryAction,\n menuActions = [],\n externalUrl,\n } = props;\n\n const renderAvatar = () => {\n if (typeof avatar === \"string\") {\n if (avatar.startsWith(\"http\") || avatar.startsWith(\"/\")) {\n return (\n <Avatar src={avatar} size={56} radius=\"md\" color={avatarColor} />\n );\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {avatar}\n </Avatar>\n );\n }\n if (avatar) {\n return avatar;\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {title.charAt(0).toUpperCase()}\n </Avatar>\n );\n };\n\n return (\n <Stack gap=\"xs\">\n {/* Breadcrumb / Back navigation */}\n {backHref && (\n <Group>\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n href={backHref}\n leftSection={<IconChevronLeft size={14} />}\n c=\"dimmed\"\n >\n {backLabel}\n </ActionButton>\n </Group>\n )}\n\n {/* Main header */}\n <Group justify=\"space-between\" align=\"flex-start\" wrap=\"nowrap\">\n {/* Left: Avatar + Info */}\n <Group gap=\"md\" wrap=\"nowrap\">\n {renderAvatar()}\n\n <Stack gap={2} justify=\"center\" style={{ minHeight: 56 }}>\n {/* Title row */}\n <Group gap=\"xs\" align=\"center\">\n <Text size=\"md\" fw={600} lh={1.2}>\n {title}\n </Text>\n {status && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={status.color}\n tt=\"lowercase\"\n >\n {status.label}\n </Badge>\n )}\n </Group>\n\n {/* Subtitle */}\n {subtitle && (\n <Text size=\"xs\" c=\"dimmed\">\n {subtitle}\n </Text>\n )}\n </Stack>\n </Group>\n\n {/* Right: Actions */}\n <Group gap=\"xs\">\n {externalUrl && (\n <Tooltip label=\"Open in new tab\" openDelay={500}>\n <ActionIcon\n variant=\"subtle\"\n color=\"gray\"\n component=\"a\"\n href={externalUrl}\n target=\"_blank\"\n >\n <IconExternalLink size={18} />\n </ActionIcon>\n </Tooltip>\n )}\n\n {primaryAction && (\n <ActionButton\n variant={primaryAction.variant ?? \"light\"}\n color={primaryAction.color}\n onClick={primaryAction.onClick}\n href={primaryAction.href}\n loading={primaryAction.loading}\n disabled={primaryAction.disabled}\n leftSection={\n primaryAction.icon ? (\n <primaryAction.icon size={16} />\n ) : undefined\n }\n >\n {primaryAction.label}\n </ActionButton>\n )}\n\n {menuActions.length > 0 && (\n <Menu position=\"bottom-end\" shadow=\"md\" width={220}>\n <Menu.Target>\n <Button\n variant=\"default\"\n rightSection={<IconChevronDown size={16} />}\n >\n Actions\n </Button>\n </Menu.Target>\n <Menu.Dropdown>\n {menuActions.map((action, index) => (\n <ActionMenuItem key={index} action={action} />\n ))}\n </Menu.Dropdown>\n </Menu>\n )}\n </Group>\n </Group>\n </Stack>\n );\n};\n\nexport default AdminResourceHeader;\n","import { Tabs } from \"@mantine/core\";\nimport { useActive, useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceTab {\n /**\n * Tab key/value\n */\n value: string;\n\n /**\n * Tab label\n */\n label: string;\n\n /**\n * Tab icon\n */\n icon?: ComponentType<{ size?: number }>;\n\n /**\n * Navigation href\n */\n href: string;\n\n /**\n * Whether tab is disabled\n */\n disabled?: boolean;\n\n /**\n * Badge count to show\n */\n count?: number;\n}\n\nexport interface AdminResourceTabsProps {\n /**\n * Array of tab configurations\n */\n tabs: AdminResourceTab[];\n\n /**\n * Currently active tab value\n */\n activeTab?: string;\n\n /**\n * Content to render below tabs\n */\n children?: ReactNode;\n}\n\nconst TabItem = (props: { tab: AdminResourceTab }) => {\n const { tab } = props;\n const router = useRouter();\n const { isActive, isPending } = useActive({ href: tab.href });\n const anchorProps = router.anchor(tab.href);\n\n return (\n <Tabs.Tab\n value={tab.value}\n component=\"a\"\n leftSection={tab.icon ? <tab.icon size={16} /> : undefined}\n disabled={tab.disabled}\n data-active={isActive || undefined}\n style={{\n opacity: isPending ? 0.6 : 1,\n }}\n {...anchorProps}\n >\n {tab.label}\n {tab.count !== undefined && tab.count > 0 && ` (${tab.count})`}\n </Tabs.Tab>\n );\n};\n\nconst AdminResourceTabs = (props: AdminResourceTabsProps) => {\n const { tabs, activeTab, children } = props;\n\n return (\n <Tabs value={activeTab} variant=\"default\">\n <Tabs.List>\n {tabs.map((tab) => (\n <TabItem key={tab.value} tab={tab} />\n ))}\n </Tabs.List>\n\n {children}\n </Tabs>\n );\n};\n\nexport default AdminResourceTabs;\n","import { Box, Center, Loader, Stack, Text } from \"@mantine/core\";\nimport {\n IconBan,\n IconDevices,\n IconHistory,\n IconLock,\n IconMail,\n IconPencil,\n IconSettings,\n IconShieldCheck,\n IconTrash,\n IconUser,\n} from \"@tabler/icons-react\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { NestedView, useRouter, useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\nimport AdminResourceHeader from \"../shared/AdminResourceHeader.tsx\";\nimport AdminResourceTabs from \"../shared/AdminResourceTabs.tsx\";\n\nexport interface AdminUserLayoutProps {\n userRealmName?: string;\n}\n\nconst AdminUserLayout = (props: AdminUserLayoutProps) => {\n const router = useRouter<AdminRouter>();\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [actionLoading, setActionLoading] = useState<string | null>(null);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n if (loading) {\n return (\n <Center flex={1}>\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1}>\n <Stack align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Stack>\n </Center>\n );\n }\n\n const displayName =\n user.firstName || user.lastName\n ? `${user.firstName ?? \"\"} ${user.lastName ?? \"\"}`.trim()\n : user.username || user.email || \"User\";\n\n const currentPath = state.url.pathname;\n const getActiveTab = () => {\n if (currentPath.endsWith(\"/sessions\")) return \"sessions\";\n if (currentPath.endsWith(\"/settings\")) return \"settings\";\n if (currentPath.endsWith(\"/audits\")) return \"audits\";\n return \"profile\";\n };\n\n const handleBlockUser = async () => {\n setActionLoading(\"block\");\n try {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: { enabled: !user.enabled },\n });\n setUser(updated);\n } finally {\n setActionLoading(null);\n }\n };\n\n const handleSendVerification = async () => {\n setActionLoading(\"verify\");\n // TODO: Implement send verification\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleResetPassword = async () => {\n setActionLoading(\"reset\");\n // TODO: Implement reset password\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleDeleteUser = async () => {\n if (\n !confirm(\n \"Are you sure you want to delete this user? This action cannot be undone.\",\n )\n ) {\n return;\n }\n setActionLoading(\"delete\");\n try {\n await client.deleteUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n await router.push(\"adminUsers\");\n } finally {\n setActionLoading(null);\n }\n };\n\n return (\n <Box py=\"xl\" px=\"xl\" flex={1}>\n <Stack gap=\"lg\">\n <AdminResourceHeader\n backHref={router.path(\"adminUsers\")}\n backLabel=\"Users\"\n avatar={user.picture || displayName.charAt(0).toUpperCase()}\n avatarColor={user.enabled ? \"blue\" : \"gray\"}\n title={displayName}\n subtitle={user.email || user.username || undefined}\n status={{\n label: user.enabled ? \"Active\" : \"Disabled\",\n color: user.enabled ? \"green\" : \"red\",\n }}\n menuActions={[\n {\n label: \"Edit Profile\",\n icon: IconPencil,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n label: user.enabled ? \"Disable User\" : \"Enable User\",\n icon: user.enabled ? IconBan : IconShieldCheck,\n color: user.enabled ? \"orange\" : \"green\",\n onClick: handleBlockUser,\n loading: actionLoading === \"block\",\n },\n ...(user.email && !user.emailVerified\n ? [\n {\n label: \"Send Verification Email\",\n icon: IconMail,\n onClick: handleSendVerification,\n loading: actionLoading === \"verify\",\n },\n ]\n : []),\n {\n label: \"Reset Password\",\n icon: IconLock,\n onClick: handleResetPassword,\n loading: actionLoading === \"reset\",\n },\n {\n label: \"Delete User\",\n icon: IconTrash,\n color: \"red\",\n onClick: handleDeleteUser,\n loading: actionLoading === \"delete\",\n },\n ]}\n />\n\n <AdminResourceTabs\n activeTab={getActiveTab()}\n tabs={[\n {\n value: \"profile\",\n label: \"Profile\",\n icon: IconUser,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n value: \"sessions\",\n label: \"Sessions\",\n icon: IconDevices,\n href: router.path(\"adminUserSessions\", { params: { userId } }),\n },\n {\n value: \"audits\",\n label: \"Activity\",\n icon: IconHistory,\n href: router.path(\"adminUserAudits\", { params: { userId } }),\n },\n {\n value: \"settings\",\n label: \"Settings\",\n icon: IconSettings,\n href: router.path(\"adminUserSettings\", { params: { userId } }),\n },\n ]}\n />\n\n <NestedView />\n </Stack>\n </Box>\n );\n};\n\nexport default AdminUserLayout;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdminUserLayout-CiPay35T.js","names":["Text","Text","AdminResourceHeader","AdminResourceTabs"],"sources":["../../src/admin/components/shared/AdminResourceHeader.tsx","../../src/admin/components/shared/AdminResourceTabs.tsx","../../src/admin/components/users/AdminUserLayout.tsx"],"sourcesContent":["import { ActionButton } from \"@alepha/ui\";\nimport {\n ActionIcon,\n Avatar,\n Badge,\n Button,\n Group,\n Menu,\n Stack,\n Text,\n Tooltip,\n} from \"@mantine/core\";\nimport {\n IconChevronDown,\n IconChevronLeft,\n IconExternalLink,\n} from \"@tabler/icons-react\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceAction {\n label: string;\n icon?: ComponentType<{ size?: number }>;\n onClick?: () => void;\n href?: string;\n color?: string;\n disabled?: boolean;\n loading?: boolean;\n variant?: \"filled\" | \"light\" | \"outline\" | \"subtle\";\n}\n\nexport interface AdminResourceHeaderProps {\n /**\n * Back navigation URL\n */\n backHref?: string;\n\n /**\n * Back navigation label\n */\n backLabel?: string;\n\n /**\n * Avatar content (letter, image URL, or custom node)\n */\n avatar?: string | ReactNode;\n\n /**\n * Avatar color\n */\n avatarColor?: string;\n\n /**\n * Resource title (e.g., user name)\n */\n title: string;\n\n /**\n * Secondary text (e.g., email)\n */\n subtitle?: string;\n\n /**\n * Tertiary identifier to copy (e.g., user ID)\n */\n identifier?: string;\n\n /**\n * Label for the identifier tooltip\n */\n identifierLabel?: string;\n\n /**\n * Status badge\n */\n status?: {\n label: string;\n color: \"green\" | \"red\" | \"yellow\" | \"blue\" | \"gray\";\n };\n\n /**\n * Additional badges (e.g., roles)\n */\n badges?: Array<{\n label: string;\n color?: string;\n variant?: \"filled\" | \"light\" | \"outline\" | \"dot\";\n }>;\n\n /**\n * Primary action button\n */\n primaryAction?: AdminResourceAction;\n\n /**\n * Menu actions (shown in dropdown)\n */\n menuActions?: AdminResourceAction[];\n\n /**\n * External link URL\n */\n externalUrl?: string;\n\n /**\n * Loading state\n */\n loading?: boolean;\n}\n\nconst ActionMenuItem = (props: { action: AdminResourceAction }) => {\n const { action } = props;\n const router = useRouter();\n\n const menuItemProps: Record<string, unknown> = {};\n if (action.href) {\n Object.assign(menuItemProps, router.anchor(action.href));\n } else if (action.onClick) {\n menuItemProps.onClick = action.onClick;\n }\n\n return (\n <Menu.Item\n leftSection={action.icon ? <action.icon size={16} /> : undefined}\n color={action.color}\n disabled={action.disabled}\n {...menuItemProps}\n >\n {action.label}\n </Menu.Item>\n );\n};\n\nconst AdminResourceHeader = (props: AdminResourceHeaderProps) => {\n const {\n backHref,\n backLabel = \"Back\",\n avatar,\n avatarColor = \"blue\",\n title,\n subtitle,\n identifier,\n identifierLabel = \"ID\",\n status,\n badges = [],\n primaryAction,\n menuActions = [],\n externalUrl,\n } = props;\n\n const renderAvatar = () => {\n if (typeof avatar === \"string\") {\n if (avatar.startsWith(\"http\") || avatar.startsWith(\"/\")) {\n return (\n <Avatar src={avatar} size={56} radius=\"md\" color={avatarColor} />\n );\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {avatar}\n </Avatar>\n );\n }\n if (avatar) {\n return avatar;\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {title.charAt(0).toUpperCase()}\n </Avatar>\n );\n };\n\n return (\n <Stack gap=\"xs\">\n {/* Breadcrumb / Back navigation */}\n {backHref && (\n <Group>\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n href={backHref}\n leftSection={<IconChevronLeft size={14} />}\n c=\"dimmed\"\n >\n {backLabel}\n </ActionButton>\n </Group>\n )}\n\n {/* Main header */}\n <Group justify=\"space-between\" align=\"flex-start\" wrap=\"nowrap\">\n {/* Left: Avatar + Info */}\n <Group gap=\"md\" wrap=\"nowrap\">\n {renderAvatar()}\n\n <Stack gap={2} justify=\"center\" style={{ minHeight: 56 }}>\n {/* Title row */}\n <Group gap=\"xs\" align=\"center\">\n <Text size=\"md\" fw={600} lh={1.2}>\n {title}\n </Text>\n {status && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={status.color}\n tt=\"lowercase\"\n >\n {status.label}\n </Badge>\n )}\n </Group>\n\n {/* Subtitle */}\n {subtitle && (\n <Text size=\"xs\" c=\"dimmed\">\n {subtitle}\n </Text>\n )}\n </Stack>\n </Group>\n\n {/* Right: Actions */}\n <Group gap=\"xs\">\n {externalUrl && (\n <Tooltip label=\"Open in new tab\" openDelay={500}>\n <ActionIcon\n variant=\"subtle\"\n color=\"gray\"\n component=\"a\"\n href={externalUrl}\n target=\"_blank\"\n >\n <IconExternalLink size={18} />\n </ActionIcon>\n </Tooltip>\n )}\n\n {primaryAction && (\n <ActionButton\n variant={primaryAction.variant ?? \"light\"}\n color={primaryAction.color}\n onClick={primaryAction.onClick}\n href={primaryAction.href}\n loading={primaryAction.loading}\n disabled={primaryAction.disabled}\n leftSection={\n primaryAction.icon ? (\n <primaryAction.icon size={16} />\n ) : undefined\n }\n >\n {primaryAction.label}\n </ActionButton>\n )}\n\n {menuActions.length > 0 && (\n <Menu position=\"bottom-end\" shadow=\"md\" width={220}>\n <Menu.Target>\n <Button\n variant=\"default\"\n rightSection={<IconChevronDown size={16} />}\n >\n Actions\n </Button>\n </Menu.Target>\n <Menu.Dropdown>\n {menuActions.map((action, index) => (\n <ActionMenuItem key={index} action={action} />\n ))}\n </Menu.Dropdown>\n </Menu>\n )}\n </Group>\n </Group>\n </Stack>\n );\n};\n\nexport default AdminResourceHeader;\n","import { Tabs } from \"@mantine/core\";\nimport { useActive, useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceTab {\n /**\n * Tab key/value\n */\n value: string;\n\n /**\n * Tab label\n */\n label: string;\n\n /**\n * Tab icon\n */\n icon?: ComponentType<{ size?: number }>;\n\n /**\n * Navigation href\n */\n href: string;\n\n /**\n * Whether tab is disabled\n */\n disabled?: boolean;\n\n /**\n * Badge count to show\n */\n count?: number;\n}\n\nexport interface AdminResourceTabsProps {\n /**\n * Array of tab configurations\n */\n tabs: AdminResourceTab[];\n\n /**\n * Currently active tab value\n */\n activeTab?: string;\n\n /**\n * Content to render below tabs\n */\n children?: ReactNode;\n}\n\nconst TabItem = (props: { tab: AdminResourceTab }) => {\n const { tab } = props;\n const router = useRouter();\n const { isActive, isPending } = useActive({ href: tab.href });\n const anchorProps = router.anchor(tab.href);\n\n return (\n <Tabs.Tab\n value={tab.value}\n component=\"a\"\n leftSection={tab.icon ? <tab.icon size={16} /> : undefined}\n disabled={tab.disabled}\n data-active={isActive || undefined}\n style={{\n opacity: isPending ? 0.6 : 1,\n }}\n {...anchorProps}\n >\n {tab.label}\n {tab.count !== undefined && tab.count > 0 && ` (${tab.count})`}\n </Tabs.Tab>\n );\n};\n\nconst AdminResourceTabs = (props: AdminResourceTabsProps) => {\n const { tabs, activeTab, children } = props;\n\n return (\n <Tabs value={activeTab} variant=\"default\">\n <Tabs.List>\n {tabs.map((tab) => (\n <TabItem key={tab.value} tab={tab} />\n ))}\n </Tabs.List>\n\n {children}\n </Tabs>\n );\n};\n\nexport default AdminResourceTabs;\n","import { Box, Center, Loader, Stack, Text } from \"@mantine/core\";\nimport {\n IconBan,\n IconDevices,\n IconHistory,\n IconLock,\n IconMail,\n IconPencil,\n IconSettings,\n IconShieldCheck,\n IconTrash,\n IconUser,\n} from \"@tabler/icons-react\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { NestedView, useRouter, useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\nimport AdminResourceHeader from \"../shared/AdminResourceHeader.tsx\";\nimport AdminResourceTabs from \"../shared/AdminResourceTabs.tsx\";\n\nexport interface AdminUserLayoutProps {\n userRealmName?: string;\n}\n\nconst AdminUserLayout = (props: AdminUserLayoutProps) => {\n const router = useRouter<AdminRouter>();\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [actionLoading, setActionLoading] = useState<string | null>(null);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n if (loading) {\n return (\n <Center flex={1}>\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1}>\n <Stack align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Stack>\n </Center>\n );\n }\n\n const displayName =\n user.firstName || user.lastName\n ? `${user.firstName ?? \"\"} ${user.lastName ?? \"\"}`.trim()\n : user.username || user.email || \"User\";\n\n const currentPath = state.url.pathname;\n const getActiveTab = () => {\n if (currentPath.endsWith(\"/sessions\")) return \"sessions\";\n if (currentPath.endsWith(\"/settings\")) return \"settings\";\n if (currentPath.endsWith(\"/audits\")) return \"audits\";\n return \"profile\";\n };\n\n const handleBlockUser = async () => {\n setActionLoading(\"block\");\n try {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: { enabled: !user.enabled },\n });\n setUser(updated);\n } finally {\n setActionLoading(null);\n }\n };\n\n const handleSendVerification = async () => {\n setActionLoading(\"verify\");\n // TODO: Implement send verification\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleResetPassword = async () => {\n setActionLoading(\"reset\");\n // TODO: Implement reset password\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleDeleteUser = async () => {\n if (\n !confirm(\n \"Are you sure you want to delete this user? This action cannot be undone.\",\n )\n ) {\n return;\n }\n setActionLoading(\"delete\");\n try {\n await client.deleteUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n await router.push(\"adminUsers\");\n } finally {\n setActionLoading(null);\n }\n };\n\n return (\n <Box py=\"xl\" px=\"xl\" flex={1}>\n <Stack gap=\"lg\">\n <AdminResourceHeader\n backHref={router.path(\"adminUsers\")}\n backLabel=\"Users\"\n avatar={user.picture || displayName.charAt(0).toUpperCase()}\n avatarColor={user.enabled ? \"blue\" : \"gray\"}\n title={displayName}\n subtitle={user.email || user.username || undefined}\n status={{\n label: user.enabled ? \"Active\" : \"Disabled\",\n color: user.enabled ? \"green\" : \"red\",\n }}\n menuActions={[\n {\n label: \"Edit Profile\",\n icon: IconPencil,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n label: user.enabled ? \"Disable User\" : \"Enable User\",\n icon: user.enabled ? IconBan : IconShieldCheck,\n color: user.enabled ? \"orange\" : \"green\",\n onClick: handleBlockUser,\n loading: actionLoading === \"block\",\n },\n ...(user.email && !user.emailVerified\n ? [\n {\n label: \"Send Verification Email\",\n icon: IconMail,\n onClick: handleSendVerification,\n loading: actionLoading === \"verify\",\n },\n ]\n : []),\n {\n label: \"Reset Password\",\n icon: IconLock,\n onClick: handleResetPassword,\n loading: actionLoading === \"reset\",\n },\n {\n label: \"Delete User\",\n icon: IconTrash,\n color: \"red\",\n onClick: handleDeleteUser,\n loading: actionLoading === \"delete\",\n },\n ]}\n />\n\n <AdminResourceTabs\n activeTab={getActiveTab()}\n tabs={[\n {\n value: \"profile\",\n label: \"Profile\",\n icon: IconUser,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n value: \"sessions\",\n label: \"Sessions\",\n icon: IconDevices,\n href: router.path(\"adminUserSessions\", { params: { userId } }),\n },\n {\n value: \"audits\",\n label: \"Activity\",\n icon: IconHistory,\n href: router.path(\"adminUserAudits\", { params: { userId } }),\n },\n {\n value: \"settings\",\n label: \"Settings\",\n icon: IconSettings,\n href: router.path(\"adminUserSettings\", { params: { userId } }),\n },\n ]}\n />\n\n <NestedView />\n </Stack>\n </Box>\n );\n};\n\nexport default AdminUserLayout;\n"],"mappings":"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"}
|
|
@@ -2,10 +2,10 @@ import { ActionButton, DataTable, Flex, Text } from "@alepha/ui";
|
|
|
2
2
|
import { t } from "alepha";
|
|
3
3
|
import { IconDeviceDesktop, IconDeviceMobile, IconDeviceTablet, IconTrash } from "@tabler/icons-react";
|
|
4
4
|
import { useRouterState } from "alepha/react/router";
|
|
5
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
5
|
import { Badge, Group } from "@mantine/core";
|
|
7
6
|
import { useClient } from "alepha/react";
|
|
8
7
|
import { useI18n } from "alepha/react/i18n";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
|
|
11
11
|
//#region ../../src/admin/components/users/AdminUserSessions.tsx
|
|
@@ -127,4 +127,4 @@ var AdminUserSessions_default = AdminUserSessions;
|
|
|
127
127
|
|
|
128
128
|
//#endregion
|
|
129
129
|
export { AdminUserSessions_default as t };
|
|
130
|
-
//# sourceMappingURL=AdminUserSessions-
|
|
130
|
+
//# sourceMappingURL=AdminUserSessions-DAE8Nf1F.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserSessions-
|
|
1
|
+
{"version":3,"file":"AdminUserSessions-DAE8Nf1F.js","names":[],"sources":["../../src/admin/components/users/AdminUserSessions.tsx"],"sourcesContent":["import { ActionButton, DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge, Group } from \"@mantine/core\";\nimport {\n IconDeviceDesktop,\n IconDeviceMobile,\n IconDeviceTablet,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport type { AdminSessionController, SessionEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { useState } from \"react\";\n\nexport interface AdminUserSessionsProps {\n userRealmName?: string;\n}\n\nconst AdminUserSessions = (props: AdminUserSessionsProps) => {\n const state = useRouterState();\n const client = useClient<AdminSessionController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n const [refreshKey, setRefreshKey] = useState(0);\n\n const 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\n const isExpired = (expiresAt: Date | string) => {\n return new Date(expiresAt) < new Date();\n };\n\n const handleDelete = async (sessionId: string) => {\n await client.deleteSession({\n params: { id: sessionId },\n query: { userRealmName: props.userRealmName },\n });\n setRefreshKey((k) => k + 1);\n };\n\n const filters = t.object({});\n\n return (\n <Flex flex={1} direction=\"column\">\n <DataTable<SessionEntity, typeof filters>\n key={refreshKey}\n submitOnInit\n defaultSize={10}\n filters={filters}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n tableTrProps={(item) => {\n if (isExpired(item.expiresAt)) {\n return {\n opacity: 0.5,\n };\n }\n return {};\n }}\n items={async (filters) => {\n const response = await client.findSessions({\n query: {\n ...filters,\n userId,\n userRealmName: props.userRealmName,\n },\n });\n\n return response as Page<SessionEntity>;\n }}\n columns={{\n userAgent: {\n label: \"Device\",\n value: (item) => (\n <Group gap={4}>\n {item.userAgent ? (\n <>\n <Badge\n size=\"xs\"\n variant=\"light\"\n leftSection={getDeviceIcon(item.userAgent.device)}\n >\n {item.userAgent.device}\n </Badge>\n <Text size=\"xs\" c=\"dimmed\">\n {item.userAgent.browser} / {item.userAgent.os}\n </Text>\n </>\n ) : (\n <Text size=\"xs\" c=\"dimmed\">\n -\n </Text>\n )}\n </Group>\n ),\n },\n ip: {\n label: \"IP Address\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" ff=\"monospace\" c=\"dimmed\">\n {item.ip || \"-\"}\n </Text>\n ),\n },\n expiresAt: {\n label: \"Status\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={isExpired(item.expiresAt) ? \"red\" : \"green\"}\n >\n {isExpired(item.expiresAt) ? \"Expired\" : \"Active\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n actions: {\n label: \"\",\n fit: true,\n value: (item) => (\n <ActionButton\n size=\"xs\"\n variant=\"subtle\"\n color=\"red\"\n onClick={() => handleDelete(item.id)}\n >\n <IconTrash size={14} />\n </ActionButton>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminUserSessions;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,qBAAqB,UAAkC;CAC3D,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,SAAS,WAAmC;CAClD,MAAM,EAAE,MAAM,SAAS;CACvB,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAE/C,MAAM,iBAAiB,WAAoB;AACzC,UAAQ,QAAR;GACE,KAAK,SACH,QAAO,oBAAC,oBAAiB,MAAM,KAAM;GACvC,KAAK,SACH,QAAO,oBAAC,oBAAiB,MAAM,KAAM;GACvC,QACE,QAAO,oBAAC,qBAAkB,MAAM,KAAM;;;CAI5C,MAAM,aAAa,cAA6B;AAC9C,SAAO,IAAI,KAAK,UAAU,mBAAG,IAAI,MAAM;;CAGzC,MAAM,eAAe,OAAO,cAAsB;AAChD,QAAM,OAAO,cAAc;GACzB,QAAQ,EAAE,IAAI,WAAW;GACzB,OAAO,EAAE,eAAe,MAAM,eAAe;GAC9C,CAAC;AACF,iBAAe,MAAM,IAAI,EAAE;;AAK7B,QACE,oBAAC;EAAK,MAAM;EAAG,WAAU;YACvB,oBAAC;GAEC;GACA,aAAa;GACb,SARU,EAAE,OAAO,EAAE,CAAC;GAStB,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IAClB;GACD,eAAe,SAAS;AACtB,QAAI,UAAU,KAAK,UAAU,CAC3B,QAAO,EACL,SAAS,IACV;AAEH,WAAO,EAAE;;GAEX,OAAO,OAAO,YAAY;AASxB,WARiB,MAAM,OAAO,aAAa,EACzC,OAAO;KACL,GAAG;KACH;KACA,eAAe,MAAM;KACtB,EACF,CAAC;;GAIJ,SAAS;IACP,WAAW;KACT,OAAO;KACP,QAAQ,SACN,oBAAC;MAAM,KAAK;gBACT,KAAK,YACJ,4CACE,oBAAC;OACC,MAAK;OACL,SAAQ;OACR,aAAa,cAAc,KAAK,UAAU,OAAO;iBAEhD,KAAK,UAAU;QACV,EACR,qBAAC;OAAK,MAAK;OAAK,GAAE;;QACf,KAAK,UAAU;QAAQ;QAAI,KAAK,UAAU;;QACtC,IACN,GAEH,oBAAC;OAAK,MAAK;OAAK,GAAE;iBAAS;QAEpB;OAEH;KAEX;IACD,IAAI;KACF,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAG;MAAY,GAAE;gBAC9B,KAAK,MAAM;OACP;KAEV;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAO,UAAU,KAAK,UAAU,GAAG,QAAQ;gBAE1C,UAAU,KAAK,UAAU,GAAG,YAAY;OACnC;KAEX;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACD,SAAS;KACP,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAM;MACN,eAAe,aAAa,KAAK,GAAG;gBAEpC,oBAAC,aAAU,MAAM,KAAM;OACV;KAElB;IACF;KAlGI,WAmGL;GACG;;AAIX,gCAAe"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ActionButton, Flex, Text } from "@alepha/ui";
|
|
2
2
|
import { IconAlertCircle, IconCheck, IconMail, IconTrash } from "@tabler/icons-react";
|
|
3
3
|
import { useRouter, useRouterState } from "alepha/react/router";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
4
|
import { Alert, Card, Group, Loader, Stack } from "@mantine/core";
|
|
6
5
|
import { useClient } from "alepha/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useEffect, useState } from "react";
|
|
8
8
|
|
|
9
9
|
//#region ../../src/admin/components/users/AdminUserSettings.tsx
|
|
@@ -163,4 +163,4 @@ var AdminUserSettings_default = AdminUserSettings;
|
|
|
163
163
|
|
|
164
164
|
//#endregion
|
|
165
165
|
export { AdminUserSettings_default as t };
|
|
166
|
-
//# sourceMappingURL=AdminUserSettings-
|
|
166
|
+
//# sourceMappingURL=AdminUserSettings-EbahaV2a.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUserSettings-
|
|
1
|
+
{"version":3,"file":"AdminUserSettings-EbahaV2a.js","names":[],"sources":["../../src/admin/components/users/AdminUserSettings.tsx"],"sourcesContent":["import { ActionButton, Flex, Text } from \"@alepha/ui\";\nimport { Alert, Card, Group, Loader, Stack } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconCheck,\n IconMail,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport type {\n AdminUserController,\n UserController,\n UserEntity,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useRouter, useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\n\nexport interface AdminUserSettingsProps {\n userRealmName?: string;\n}\n\nconst AdminUserSettings = (props: AdminUserSettingsProps) => {\n const router = useRouter<AdminRouter>();\n const state = useRouterState();\n const adminClient = useClient<AdminUserController>();\n const userClient = useClient<UserController>();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [deleteLoading, setDeleteLoading] = useState(false);\n const [verifyLoading, setVerifyLoading] = useState(false);\n const [verifySuccess, setVerifySuccess] = useState(false);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await adminClient.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n const handleDelete = async () => {\n if (!confirm(\"Are you sure you want to delete this user?\")) {\n return;\n }\n\n setDeleteLoading(true);\n try {\n await adminClient.deleteUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n await router.push(\"adminUsers\");\n } finally {\n setDeleteLoading(false);\n }\n };\n\n const handleTriggerEmailVerification = async () => {\n if (!user?.email) return;\n\n setVerifyLoading(true);\n setVerifySuccess(false);\n try {\n await userClient.requestEmailVerification({\n query: {\n userRealmName: props.userRealmName,\n method: \"link\",\n verifyUrl: `${window.location.origin}/auth/verify-email`,\n },\n body: { email: user.email },\n });\n setVerifySuccess(true);\n } finally {\n setVerifyLoading(false);\n }\n };\n\n if (loading) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Loader />\n </Flex>\n );\n }\n\n if (!user) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Text c=\"dimmed\">User not found</Text>\n </Flex>\n );\n }\n\n return (\n <Flex flex={1} direction=\"column\" gap=\"md\">\n {user.email && !user.emailVerified && (\n <Card withBorder p=\"lg\">\n <Stack gap=\"md\">\n <Text size=\"lg\" fw={500}>\n Email Verification\n </Text>\n\n <Alert variant=\"light\" color=\"yellow\" icon={<IconMail />}>\n <Text size=\"sm\">\n This user's email ({user.email}) is not verified. You can send a\n verification link to the user.\n </Text>\n </Alert>\n\n {verifySuccess && (\n <Alert variant=\"light\" color=\"green\" icon={<IconCheck />}>\n <Text size=\"sm\">\n Verification link sent successfully to {user.email}.\n </Text>\n </Alert>\n )}\n\n <Group>\n <ActionButton\n leftSection={<IconMail size={16} />}\n loading={verifyLoading}\n onClick={handleTriggerEmailVerification}\n >\n Send Verification Link\n </ActionButton>\n </Group>\n </Stack>\n </Card>\n )}\n\n <Card withBorder p=\"lg\">\n <Stack gap=\"md\">\n <Text size=\"lg\" fw={500} c=\"red\">\n Danger Zone\n </Text>\n\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">\n Deleting this user will permanently remove their account and all\n associated data. This action cannot be undone.\n </Text>\n </Alert>\n\n <Group>\n <ActionButton\n color=\"red\"\n leftSection={<IconTrash size={16} />}\n loading={deleteLoading}\n onClick={handleDelete}\n >\n Delete User\n </ActionButton>\n </Group>\n </Stack>\n </Card>\n </Flex>\n );\n};\n\nexport default AdminUserSettings;\n"],"mappings":"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"}
|
|
@@ -2,10 +2,10 @@ import { DataTable, Text } from "@alepha/ui";
|
|
|
2
2
|
import { t } from "alepha";
|
|
3
3
|
import { IconCheck, IconUsersPlus, IconX } from "@tabler/icons-react";
|
|
4
4
|
import { useRouter } from "alepha/react/router";
|
|
5
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
5
|
import { Badge, Flex as Flex$1, Group } from "@mantine/core";
|
|
7
6
|
import { useClient } from "alepha/react";
|
|
8
7
|
import { useI18n } from "alepha/react/i18n";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { users } from "alepha/api/users";
|
|
10
10
|
|
|
11
11
|
//#region ../../src/admin/components/users/AdminUsers.tsx
|
|
@@ -116,4 +116,4 @@ var AdminUsers_default = AdminUsers;
|
|
|
116
116
|
|
|
117
117
|
//#endregion
|
|
118
118
|
export { AdminUsers_default as t };
|
|
119
|
-
//# sourceMappingURL=AdminUsers-
|
|
119
|
+
//# sourceMappingURL=AdminUsers-Dcjh0KNW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminUsers-
|
|
1
|
+
{"version":3,"file":"AdminUsers-Dcjh0KNW.js","names":["Flex"],"sources":["../../src/admin/components/users/AdminUsers.tsx"],"sourcesContent":["import { DataTable, Text } from \"@alepha/ui\";\nimport { Badge, Flex, Group } from \"@mantine/core\";\nimport { IconCheck, IconUsersPlus, IconX } from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport {\n type AdminUserController,\n type UserEntity,\n users,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\n\nexport interface AdminUsersProps {\n userRealmName?: string;\n}\n\nconst AdminUsers = (props: AdminUsersProps) => {\n const client = useClient<AdminUserController>();\n const router = useRouter<AdminRouter>();\n const { l } = useI18n();\n\n const filters = t.object({\n query: t.optional(\n t.string({\n $control: {\n query: t.omit(users.schema, [\"id\", \"version\"]),\n },\n }),\n ),\n });\n\n return (\n <Flex flex={1} direction=\"column\">\n <DataTable<UserEntity, typeof filters>\n submitOnInit\n actions={[\n {\n icon: IconUsersPlus,\n href: router.path(\"adminUserCreate\"),\n label: \"Create User\",\n },\n ]}\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n striped: false,\n highlightOnHover: true,\n }}\n onFilterChange={(key, value, form) => {\n if (key === \"query\") {\n return form.submit();\n }\n }}\n filters={filters}\n tableTrProps={(item) => {\n const baseProps: Record<string, any> = {\n style: { cursor: \"pointer\" },\n onClick: () =>\n router.push(\"adminUserDetails\", {\n params: { userId: item.id },\n }),\n };\n\n if (!item.enabled) {\n baseProps.opacity = 0.5;\n }\n\n return baseProps;\n }}\n items={async (filters) => {\n const response = await client.findUsers({\n query: {\n ...filters,\n userRealmName: props.userRealmName,\n },\n });\n\n return response as Page<UserEntity>;\n }}\n columns={{\n username: {\n label: \"Username\",\n value: (item) => (\n <Text size=\"sm\" fw={500}>\n {item.username || \"-\"}\n </Text>\n ),\n },\n email: {\n label: \"Email\",\n value: (item) => (\n <Group gap=\"xs\">\n <Text size=\"sm\">{item.email || \"-\"}</Text>\n {item.email && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={item.emailVerified ? \"green\" : \"gray\"}\n leftSection={\n item.emailVerified ? (\n <IconCheck size={10} />\n ) : (\n <IconX size={10} />\n )\n }\n >\n {item.emailVerified ? \"Verified\" : \"Unverified\"}\n </Badge>\n )}\n </Group>\n ),\n },\n roles: {\n label: \"Roles\",\n value: (item) => (\n <Group gap={4}>\n {item.roles.map((role: string) => (\n <Badge key={role} size=\"xs\" variant=\"outline\">\n {role}\n </Badge>\n ))}\n </Group>\n ),\n },\n enabled: {\n label: \"Status\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={item.enabled ? \"green\" : \"red\"}\n >\n {item.enabled ? \"Active\" : \"Disabled\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminUsers;\n"],"mappings":";;;;;;;;;;;AAkBA,MAAM,cAAc,UAA2B;CAC7C,MAAM,SAAS,WAAgC;CAC/C,MAAM,SAAS,WAAwB;CACvC,MAAM,EAAE,MAAM,SAAS;CAEvB,MAAM,UAAU,EAAE,OAAO,EACvB,OAAO,EAAE,SACP,EAAE,OAAO,EACP,UAAU,EACR,OAAO,EAAE,KAAK,MAAM,QAAQ,CAAC,MAAM,UAAU,CAAC,EAC/C,EACF,CAAC,CACH,EACF,CAAC;AAEF,QACE,oBAACA;EAAK,MAAM;EAAG,WAAU;YACvB,oBAAC;GACC;GACA,SAAS,CACP;IACE,MAAM;IACN,MAAM,OAAO,KAAK,kBAAkB;IACpC,OAAO;IACR,CACF;GACD,aAAa;GACb,eAAe;IACb,kBAAkB;IAClB,SAAS;IACV;GACD,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IACjB,SAAS;IACT,kBAAkB;IACnB;GACD,iBAAiB,KAAK,OAAO,SAAS;AACpC,QAAI,QAAQ,QACV,QAAO,KAAK,QAAQ;;GAGf;GACT,eAAe,SAAS;IACtB,MAAM,YAAiC;KACrC,OAAO,EAAE,QAAQ,WAAW;KAC5B,eACE,OAAO,KAAK,oBAAoB,EAC9B,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAC5B,CAAC;KACL;AAED,QAAI,CAAC,KAAK,QACR,WAAU,UAAU;AAGtB,WAAO;;GAET,OAAO,OAAO,YAAY;AAQxB,WAPiB,MAAM,OAAO,UAAU,EACtC,OAAO;KACL,GAAG;KACH,eAAe,MAAM;KACtB,EACF,CAAC;;GAIJ,SAAS;IACP,UAAU;KACR,OAAO;KACP,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAI;gBACjB,KAAK,YAAY;OACb;KAEV;IACD,OAAO;KACL,OAAO;KACP,QAAQ,SACN,qBAAC;MAAM,KAAI;iBACT,oBAAC;OAAK,MAAK;iBAAM,KAAK,SAAS;QAAW,EACzC,KAAK,SACJ,oBAAC;OACC,MAAK;OACL,SAAQ;OACR,OAAO,KAAK,gBAAgB,UAAU;OACtC,aACE,KAAK,gBACH,oBAAC,aAAU,MAAM,KAAM,GAEvB,oBAAC,SAAM,MAAM,KAAM;iBAItB,KAAK,gBAAgB,aAAa;QAC7B;OAEJ;KAEX;IACD,OAAO;KACL,OAAO;KACP,QAAQ,SACN,oBAAC;MAAM,KAAK;gBACT,KAAK,MAAM,KAAK,SACf,oBAAC;OAAiB,MAAK;OAAK,SAAQ;iBACjC;SADS,KAEJ,CACR;OACI;KAEX;IACD,SAAS;KACP,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAO,KAAK,UAAU,UAAU;gBAE/B,KAAK,UAAU,WAAW;OACrB;KAEX;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACF;IACD;GACG;;AAIX,yBAAe"}
|