@workos-inc/widgets 1.19.0 → 1.19.1-next.1790725314460
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/CHANGELOG.md +6 -0
- package/dist/cjs/lib/admin-portal-audit-log-streaming.cjs +5 -22
- package/dist/cjs/lib/admin-portal-audit-log-streaming.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/relative-time.cjs +7 -12
- package/dist/cjs/lib/api-keys/relative-time.cjs.map +1 -1
- package/dist/cjs/lib/directory-sync.cjs +5 -30
- package/dist/cjs/lib/directory-sync.cjs.map +1 -1
- package/dist/cjs/lib/domain-item.cjs +5 -10
- package/dist/cjs/lib/domain-item.cjs.map +1 -1
- package/dist/cjs/lib/user-security.cjs +9 -17
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.cjs +9 -13
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.d.cts +2 -2
- package/dist/cjs/lib/users-management.cjs +14 -24
- package/dist/cjs/lib/users-management.cjs.map +1 -1
- package/dist/cjs/lib/utils.cjs +49 -13
- package/dist/cjs/lib/utils.cjs.map +1 -1
- package/dist/cjs/use-comparative-readable-date.cjs +128 -0
- package/dist/cjs/use-comparative-readable-date.cjs.map +1 -0
- package/dist/cjs/use-comparative-readable-date.d.cts +8 -0
- package/dist/esm/lib/admin-portal-audit-log-streaming.js +5 -22
- package/dist/esm/lib/admin-portal-audit-log-streaming.js.map +1 -1
- package/dist/esm/lib/api-keys/relative-time.js +7 -12
- package/dist/esm/lib/api-keys/relative-time.js.map +1 -1
- package/dist/esm/lib/directory-sync.js +5 -30
- package/dist/esm/lib/directory-sync.js.map +1 -1
- package/dist/esm/lib/domain-item.js +5 -10
- package/dist/esm/lib/domain-item.js.map +1 -1
- package/dist/esm/lib/identity-providers.d.ts +2 -2
- package/dist/esm/lib/user-security.js +9 -18
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.d.ts +2 -2
- package/dist/esm/lib/user-sessions.js +9 -14
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/lib/users-management.js +14 -25
- package/dist/esm/lib/users-management.js.map +1 -1
- package/dist/esm/lib/utils.js +49 -13
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/use-comparative-readable-date.d.ts +8 -0
- package/dist/esm/use-comparative-readable-date.js +94 -0
- package/dist/esm/use-comparative-readable-date.js.map +1 -0
- package/package.json +1 -1
|
@@ -11,11 +11,10 @@ import { ResetMfaDialog } from "./reset-mfa-dialog.js";
|
|
|
11
11
|
import * as CardList from "./card-list.js";
|
|
12
12
|
import { GenericError } from "./generic-error.js";
|
|
13
13
|
import {
|
|
14
|
-
getComparativeReadableDate,
|
|
15
14
|
getDomProps
|
|
16
15
|
} from "./utils.js";
|
|
17
16
|
import { Translation } from "./i18n/translation.js";
|
|
18
|
-
import {
|
|
17
|
+
import { useComparativeReadableDate } from "../use-comparative-readable-date.js";
|
|
19
18
|
const UserSecurity = ({
|
|
20
19
|
user,
|
|
21
20
|
settings,
|
|
@@ -72,7 +71,9 @@ const UserSecurityLoading = (props) => {
|
|
|
72
71
|
] }) });
|
|
73
72
|
};
|
|
74
73
|
function PasswordSettings({ settings }) {
|
|
75
|
-
const
|
|
74
|
+
const timeAgo = useComparativeReadableDate({
|
|
75
|
+
date: settings.lastUsed ? new Date(settings.lastUsed) : null
|
|
76
|
+
});
|
|
76
77
|
return /* @__PURE__ */ jsxs(Grid, { columns: "auto 1fr auto", align: "center", gap: "4", children: [
|
|
77
78
|
/* @__PURE__ */ jsx(IconPanel, { children: /* @__PURE__ */ jsx(LockClosedIcon, {}) }),
|
|
78
79
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
|
|
@@ -90,13 +91,7 @@ function PasswordSettings({ settings }) {
|
|
|
90
91
|
defaultMessage: "Last used {time}",
|
|
91
92
|
id: "Jqn+r+",
|
|
92
93
|
description: "Label indicating when password was last used with time",
|
|
93
|
-
values: {
|
|
94
|
-
time: getComparativeReadableDate(
|
|
95
|
-
/* @__PURE__ */ new Date(),
|
|
96
|
-
new Date(settings.lastUsed),
|
|
97
|
-
{ locale }
|
|
98
|
-
)
|
|
99
|
-
}
|
|
94
|
+
values: { time: timeAgo }
|
|
100
95
|
}
|
|
101
96
|
) }) : /* @__PURE__ */ jsx(Text, { as: "p", size: "2", color: "gray", children: /* @__PURE__ */ jsx(
|
|
102
97
|
Translation,
|
|
@@ -128,7 +123,9 @@ function MfaSettings({
|
|
|
128
123
|
settings,
|
|
129
124
|
isPasswordSet
|
|
130
125
|
}) {
|
|
131
|
-
const
|
|
126
|
+
const timeAgo = useComparativeReadableDate({
|
|
127
|
+
date: settings.lastUsed ? new Date(settings.lastUsed) : null
|
|
128
|
+
});
|
|
132
129
|
return /* @__PURE__ */ jsxs(Grid, { columns: "auto 1fr auto", align: "center", gap: "4", children: [
|
|
133
130
|
/* @__PURE__ */ jsx(IconPanel, { children: /* @__PURE__ */ jsx(ButtonIcon, {}) }),
|
|
134
131
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
|
|
@@ -157,13 +154,7 @@ function MfaSettings({
|
|
|
157
154
|
defaultMessage: "Last used {time}",
|
|
158
155
|
id: "h3R6gY",
|
|
159
156
|
description: "Label indicating when MFA was last used with time",
|
|
160
|
-
values: {
|
|
161
|
-
time: getComparativeReadableDate(
|
|
162
|
-
/* @__PURE__ */ new Date(),
|
|
163
|
-
new Date(settings.lastUsed),
|
|
164
|
-
{ locale }
|
|
165
|
-
)
|
|
166
|
-
}
|
|
157
|
+
values: { time: timeAgo }
|
|
167
158
|
}
|
|
168
159
|
) })
|
|
169
160
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/user-security.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card, Flex, Grid, Text } from \"@radix-ui/themes\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ButtonIcon, LockClosedIcon } from \"@radix-ui/react-icons\";\nimport { SetPasswordDialog } from \"./set-password-dialog.js\";\nimport { ChangePasswordDialog } from \"./change-password-dialog.js\";\nimport { AddMfaDialog } from \"./add-mfa-dialog.js\";\nimport type {\n AuthenticationSettingsQuery,\n UserFieldsFragment,\n} from \"../api/client-graphql/generated.js\";\nimport { ResetMfaDialog } from \"./reset-mfa-dialog.js\";\nimport * as CardList from \"./card-list.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport {\n getComparativeReadableDate,\n getDomProps,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ntype AuthenticationSettings =\n AuthenticationSettingsQuery[\"authenticationSettings\"];\n\ninterface VerificationMethod {\n isSetUp: boolean;\n lastUsed?: string | null;\n}\n\ninterface UserSecurityProps extends WidgetRootDomProps {\n user: UserFieldsFragment;\n settings: AuthenticationSettings;\n}\n\nconst UserSecurity: React.FC<UserSecurityProps> = ({\n user,\n settings,\n ...domProps\n}) => {\n const passwordSettings: VerificationMethod | null =\n settings.passwordAuthEnabled\n ? { isSetUp: user.passwordSet, lastUsed: user.passwordLastUsedAt }\n : null;\n const mfaSettings: VerificationMethod | null = settings.mfaEnabled\n ? { isSetUp: user.mfaEnabled, lastUsed: user.mfaLastUsedAt }\n : null;\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {passwordSettings && (\n <CardList.Item>\n <PasswordSettings settings={passwordSettings} />\n </CardList.Item>\n )}\n {mfaSettings && (\n <CardList.Item>\n <MfaSettings\n settings={mfaSettings}\n isPasswordSet={!!passwordSettings?.isSetUp}\n />\n </CardList.Item>\n )}\n </CardList.Root>\n );\n};\n\ninterface UserSecurityErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSecurityError: React.FC<UserSecurityErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSecurityLoadingProps extends WidgetRootDomProps {}\n\nconst UserSecurityLoading: React.FC<UserSecurityLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Skeleton>\n </Text>\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Skeleton>\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Skeleton>\n </Text>\n </Flex>\n\n <ChangePasswordDialog>\n <Skeleton>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </Skeleton>\n </ChangePasswordDialog>\n </Grid>\n </Card>\n );\n};\n\nfunction PasswordSettings({ settings }: { settings: VerificationMethod }) {\n const locale = useLocale();\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <LockClosedIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n settings.lastUsed && (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"Jqn+r+\"\n description=\"Label indicating when password was last used with time\"\n values={{\n time: getComparativeReadableDate(\n new Date(),\n new Date(settings.lastUsed),\n { locale },\n ),\n }}\n />\n </Text>\n )\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ChangePasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </ChangePasswordDialog>\n ) : (\n <SetPasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set a password\"\n id=\"zokPvK\"\n description=\"Button label to set a new password\"\n />\n </Button>\n </SetPasswordDialog>\n )}\n </Grid>\n );\n}\n\nfunction MfaSettings({\n settings,\n isPasswordSet,\n}: {\n settings: VerificationMethod;\n isPasswordSet: boolean;\n}) {\n const locale = useLocale();\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <ButtonIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Multi-factor authentication\"\n id=\"f3uhhm\"\n description=\"Label for multi-factor authentication settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n <Text size=\"2\">\n <Translation\n defaultMessage=\"Authenticator app\"\n id=\"0p/a72\"\n description=\"Label indicating MFA is set up with an authenticator app\"\n />\n {settings.lastUsed && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\" mx=\"1\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"h3R6gY\"\n description=\"Label indicating when MFA was last used with time\"\n values={{\n time: getComparativeReadableDate(\n new Date(),\n new Date(settings.lastUsed),\n { locale },\n ),\n }}\n />\n </Text>\n </>\n )}\n </Text>\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Secure your account with an extra verification step\"\n id=\"xZFdkq\"\n description=\"Description for setting up multi-factor authentication\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ResetMfaDialog isPasswordSet={isPasswordSet}>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Disable\"\n id=\"4flMgv\"\n description=\"Button label to disable multi-factor authentication\"\n />\n </Button>\n </ResetMfaDialog>\n ) : (\n <AddMfaDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set up authenticator app\"\n id=\"oLNIQv\"\n description=\"Button label to set up multi-factor authentication with an authenticator app\"\n />\n </Button>\n </AddMfaDialog>\n )}\n </Grid>\n );\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-security\",\n widgetState: state,\n });\n}\n\nexport type {\n UserSecurityProps,\n UserSecurityLoadingProps,\n UserSecurityErrorProps,\n};\nexport { UserSecurity, UserSecurityLoading, UserSecurityError };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/user-security.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card, Flex, Grid, Text } from \"@radix-ui/themes\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ButtonIcon, LockClosedIcon } from \"@radix-ui/react-icons\";\nimport { SetPasswordDialog } from \"./set-password-dialog.js\";\nimport { ChangePasswordDialog } from \"./change-password-dialog.js\";\nimport { AddMfaDialog } from \"./add-mfa-dialog.js\";\nimport type {\n AuthenticationSettingsQuery,\n UserFieldsFragment,\n} from \"../api/client-graphql/generated.js\";\nimport { ResetMfaDialog } from \"./reset-mfa-dialog.js\";\nimport * as CardList from \"./card-list.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport {\n getDomProps,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\ntype AuthenticationSettings =\n AuthenticationSettingsQuery[\"authenticationSettings\"];\n\ninterface VerificationMethod {\n isSetUp: boolean;\n lastUsed?: string | null;\n}\n\ninterface UserSecurityProps extends WidgetRootDomProps {\n user: UserFieldsFragment;\n settings: AuthenticationSettings;\n}\n\nconst UserSecurity: React.FC<UserSecurityProps> = ({\n user,\n settings,\n ...domProps\n}) => {\n const passwordSettings: VerificationMethod | null =\n settings.passwordAuthEnabled\n ? { isSetUp: user.passwordSet, lastUsed: user.passwordLastUsedAt }\n : null;\n const mfaSettings: VerificationMethod | null = settings.mfaEnabled\n ? { isSetUp: user.mfaEnabled, lastUsed: user.mfaLastUsedAt }\n : null;\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {passwordSettings && (\n <CardList.Item>\n <PasswordSettings settings={passwordSettings} />\n </CardList.Item>\n )}\n {mfaSettings && (\n <CardList.Item>\n <MfaSettings\n settings={mfaSettings}\n isPasswordSet={!!passwordSettings?.isSetUp}\n />\n </CardList.Item>\n )}\n </CardList.Root>\n );\n};\n\ninterface UserSecurityErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSecurityError: React.FC<UserSecurityErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSecurityLoadingProps extends WidgetRootDomProps {}\n\nconst UserSecurityLoading: React.FC<UserSecurityLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Skeleton>\n </Text>\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Skeleton>\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Skeleton>\n </Text>\n </Flex>\n\n <ChangePasswordDialog>\n <Skeleton>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </Skeleton>\n </ChangePasswordDialog>\n </Grid>\n </Card>\n );\n};\n\nfunction PasswordSettings({ settings }: { settings: VerificationMethod }) {\n const timeAgo = useComparativeReadableDate({\n date: settings.lastUsed ? new Date(settings.lastUsed) : null,\n });\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <LockClosedIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n settings.lastUsed && (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"Jqn+r+\"\n description=\"Label indicating when password was last used with time\"\n values={{ time: timeAgo }}\n />\n </Text>\n )\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ChangePasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </ChangePasswordDialog>\n ) : (\n <SetPasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set a password\"\n id=\"zokPvK\"\n description=\"Button label to set a new password\"\n />\n </Button>\n </SetPasswordDialog>\n )}\n </Grid>\n );\n}\n\nfunction MfaSettings({\n settings,\n isPasswordSet,\n}: {\n settings: VerificationMethod;\n isPasswordSet: boolean;\n}) {\n const timeAgo = useComparativeReadableDate({\n date: settings.lastUsed ? new Date(settings.lastUsed) : null,\n });\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <ButtonIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Multi-factor authentication\"\n id=\"f3uhhm\"\n description=\"Label for multi-factor authentication settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n <Text size=\"2\">\n <Translation\n defaultMessage=\"Authenticator app\"\n id=\"0p/a72\"\n description=\"Label indicating MFA is set up with an authenticator app\"\n />\n {settings.lastUsed && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\" mx=\"1\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"h3R6gY\"\n description=\"Label indicating when MFA was last used with time\"\n values={{ time: timeAgo }}\n />\n </Text>\n </>\n )}\n </Text>\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Secure your account with an extra verification step\"\n id=\"xZFdkq\"\n description=\"Description for setting up multi-factor authentication\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ResetMfaDialog isPasswordSet={isPasswordSet}>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Disable\"\n id=\"4flMgv\"\n description=\"Button label to disable multi-factor authentication\"\n />\n </Button>\n </ResetMfaDialog>\n ) : (\n <AddMfaDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set up authenticator app\"\n id=\"oLNIQv\"\n description=\"Button label to set up multi-factor authentication with an authenticator app\"\n />\n </Button>\n </AddMfaDialog>\n )}\n </Grid>\n );\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-security\",\n widgetState: state,\n });\n}\n\nexport type {\n UserSecurityProps,\n UserSecurityLoadingProps,\n UserSecurityErrorProps,\n};\nexport { UserSecurity, UserSecurityLoading, UserSecurityError };\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as React$1 from 'react';
|
|
2
1
|
import { WidgetRootDomProps } from './utils.js';
|
|
3
2
|
import { SessionFieldsFragment } from '../api/client-graphql/generated.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
4
|
import './api/types.js';
|
|
5
5
|
import './elements.js';
|
|
6
6
|
import '@radix-ui/themes';
|
|
@@ -19,7 +19,7 @@ interface UserSessionsProps extends WidgetRootDomProps {
|
|
|
19
19
|
sessionsData: SessionFieldsFragment[];
|
|
20
20
|
currentSessionId: string;
|
|
21
21
|
}
|
|
22
|
-
declare const UserSessions: ({ sessionsData: sessions, currentSessionId, ...domProps }: UserSessionsProps) => React
|
|
22
|
+
declare const UserSessions: ({ sessionsData: sessions, currentSessionId, ...domProps }: UserSessionsProps) => React.JSX.Element;
|
|
23
23
|
interface UserSessionsLoadingProps extends WidgetRootDomProps {
|
|
24
24
|
}
|
|
25
25
|
declare const UserSessionsLoading: React.FC<UserSessionsLoadingProps>;
|
|
@@ -3,7 +3,6 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Box, Card, Flex, Text } from "@radix-ui/themes";
|
|
4
4
|
import { Badge, Button, Skeleton } from "./elements.js";
|
|
5
5
|
import {
|
|
6
|
-
getComparativeReadableDate,
|
|
7
6
|
getDomProps,
|
|
8
7
|
getUserLocation,
|
|
9
8
|
parseUserAgent
|
|
@@ -12,11 +11,11 @@ import { LogoutDialog } from "./logout-dialog.js";
|
|
|
12
11
|
import { LogoutAllSessionsDialog } from "./logout-all-sessions-dialog.js";
|
|
13
12
|
import * as CardList from "./card-list.js";
|
|
14
13
|
import { IconPanel } from "./icon-panel.js";
|
|
15
|
-
import
|
|
14
|
+
import * as React from "react";
|
|
16
15
|
import { GenericError } from "./generic-error.js";
|
|
17
16
|
import { LaptopIcon, MobileIcon } from "@radix-ui/react-icons";
|
|
18
17
|
import { Translation } from "./i18n/translation.js";
|
|
19
|
-
import {
|
|
18
|
+
import { useComparativeReadableDate } from "../use-comparative-readable-date.js";
|
|
20
19
|
const UserSessions = ({
|
|
21
20
|
sessionsData: sessions,
|
|
22
21
|
currentSessionId,
|
|
@@ -28,9 +27,9 @@ const UserSessions = ({
|
|
|
28
27
|
const otherSessions = sessions.filter(
|
|
29
28
|
(session) => session.id !== currentSessionId
|
|
30
29
|
);
|
|
31
|
-
const [openLogoutDialog, setOpenLogoutDialog] = useState(false);
|
|
32
|
-
const [sessionToSignOut, setSessionToSignOut] = useState(null);
|
|
33
|
-
const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] = useState(false);
|
|
30
|
+
const [openLogoutDialog, setOpenLogoutDialog] = React.useState(false);
|
|
31
|
+
const [sessionToSignOut, setSessionToSignOut] = React.useState(null);
|
|
32
|
+
const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] = React.useState(false);
|
|
34
33
|
return /* @__PURE__ */ jsxs(
|
|
35
34
|
Flex,
|
|
36
35
|
{
|
|
@@ -147,7 +146,9 @@ const UserSession = ({
|
|
|
147
146
|
session.currentLocation,
|
|
148
147
|
session.ipAddress
|
|
149
148
|
);
|
|
150
|
-
const
|
|
149
|
+
const timeAgo = useComparativeReadableDate({
|
|
150
|
+
date: session.lastActivityAt ? new Date(session.lastActivityAt) : null
|
|
151
|
+
});
|
|
151
152
|
return /* @__PURE__ */ jsxs(Flex, { gap: "4", align: "center", children: [
|
|
152
153
|
/* @__PURE__ */ jsx(IconPanel, { children: userAgent?.isMobile ? /* @__PURE__ */ jsx(MobileIcon, {}) : /* @__PURE__ */ jsx(LaptopIcon, {}) }),
|
|
153
154
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
|
|
@@ -177,13 +178,7 @@ const UserSession = ({
|
|
|
177
178
|
defaultMessage: "Last seen {timeAgo}",
|
|
178
179
|
id: "gF+kUw",
|
|
179
180
|
description: "Text showing when the session was last active",
|
|
180
|
-
values: {
|
|
181
|
-
timeAgo: getComparativeReadableDate(
|
|
182
|
-
/* @__PURE__ */ new Date(),
|
|
183
|
-
new Date(session.lastActivityAt),
|
|
184
|
-
{ locale }
|
|
185
|
-
)
|
|
186
|
-
}
|
|
181
|
+
values: { timeAgo }
|
|
187
182
|
}
|
|
188
183
|
) })
|
|
189
184
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/user-sessions.tsx"],"sourcesContent":["\"use client\";\n\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Badge, Button, Skeleton } from \"./elements.js\";\nimport {\n getComparativeReadableDate,\n getDomProps,\n getUserLocation,\n parseUserAgent,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { LogoutDialog } from \"./logout-dialog.js\";\nimport { LogoutAllSessionsDialog } from \"./logout-all-sessions-dialog.js\";\nimport type { SessionFieldsFragment } from \"../api/client-graphql/generated.js\";\nimport * as CardList from \"./card-list.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { useState } from \"react\";\nimport { GenericError } from \"./generic-error.js\";\nimport { LaptopIcon, MobileIcon } from \"@radix-ui/react-icons\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ninterface UserSessionsProps extends WidgetRootDomProps {\n sessionsData: SessionFieldsFragment[];\n currentSessionId: string;\n}\n\nconst UserSessions = ({\n sessionsData: sessions,\n currentSessionId,\n ...domProps\n}: UserSessionsProps) => {\n const currentSession = sessions.find(\n (session) => session.id === currentSessionId,\n );\n const otherSessions = sessions.filter(\n (session) => session.id !== currentSessionId,\n );\n const [openLogoutDialog, setOpenLogoutDialog] = useState(false);\n const [sessionToSignOut, setSessionToSignOut] =\n useState<SessionFieldsFragment | null>(null);\n const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =\n useState(false);\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <CardList.Root>\n {currentSession && (\n <CardList.Item>\n <UserSession session={currentSession} isCurrentSession />\n </CardList.Item>\n )}\n\n {otherSessions.map((session) => (\n <CardList.Item key={session.id}>\n <UserSession\n session={session}\n onSignOut={() => {\n setSessionToSignOut(session);\n setOpenLogoutDialog(true);\n }}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n {sessions.length > 1 && (\n <Card size=\"2\">\n <Flex gap=\"2\" justify=\"between\" align=\"center\">\n <Box>\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n <Translation\n defaultMessage=\"Sign out of all other devices\"\n id=\"sfkEFa\"\n description=\"Heading for sign out all other devices action\"\n />\n </Text>\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Remove access from all devices except this one\"\n id=\"LsD5BK\"\n description=\"Description for sign out all other devices action\"\n />\n </Text>\n </Box>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setOpenLogoutAllSessionsDialog(true);\n }}\n >\n <Translation\n defaultMessage=\"Sign out\"\n id=\"oKQ0rm\"\n description=\"Button text to sign out of all other devices\"\n />\n </Button>\n </Flex>\n </Card>\n )}\n\n {sessionToSignOut && (\n <LogoutDialog\n session={sessionToSignOut}\n open={openLogoutDialog}\n onOpenChange={setOpenLogoutDialog}\n />\n )}\n\n <LogoutAllSessionsDialog\n open={openLogoutAllSessionsDialog}\n onOpenChange={setOpenLogoutAllSessionsDialog}\n currentSessionId={currentSessionId}\n />\n </Flex>\n );\n};\n\ninterface UserSessionsLoadingProps extends WidgetRootDomProps {}\n\nconst UserSessionsLoading: React.FC<UserSessionsLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface UserSessionsErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSessionsError: React.FC<UserSessionsErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSessionProps {\n session: SessionFieldsFragment;\n isCurrentSession?: boolean;\n onSignOut?: (session: SessionFieldsFragment) => void;\n}\n\nconst UserSession = ({\n session,\n isCurrentSession = false,\n onSignOut,\n}: UserSessionProps) => {\n const userAgent = parseUserAgent(session.userAgent);\n const userLocation = getUserLocation(\n session.currentLocation,\n session.ipAddress,\n );\n const locale = useLocale();\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel>\n {userAgent?.isMobile ? <MobileIcon /> : <LaptopIcon />}\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n {userAgent?.pretty ?? (\n <Translation\n defaultMessage=\"Unknown device\"\n id=\"nF+P+T\"\n description=\"Label for a session whose device could not be determined from its user agent\"\n />\n )}\n </Text>\n\n <Flex gap=\"1\" align=\"center\">\n <Text size=\"2\" color=\"gray\" as=\"p\">\n {userLocation}\n </Text>\n\n {isCurrentSession && (\n <Badge ml=\"2\">\n <Translation\n defaultMessage=\"This device\"\n id=\"Wz8T8u\"\n description=\"Badge label indicating the current device session\"\n />\n </Badge>\n )}\n\n {!isCurrentSession && session.lastActivityAt && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last seen {timeAgo}\"\n id=\"gF+kUw\"\n description=\"Text showing when the session was last active\"\n values={{\n timeAgo: getComparativeReadableDate(\n new Date(),\n new Date(session.lastActivityAt),\n { locale },\n ),\n }}\n />\n </Text>\n </>\n )}\n </Flex>\n </Flex>\n\n {!isCurrentSession && (\n <Flex ml=\"auto\">\n <Button variant=\"secondary\" onClick={() => onSignOut?.(session)}>\n <Translation\n defaultMessage=\"Sign out\"\n id=\"sT1L78\"\n description=\"Button text to sign out of a session\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-sessions\",\n widgetState: state,\n });\n}\n\nexport type { UserSessionsLoadingProps, UserSessionsErrorProps };\nexport { UserSessions, UserSessionsLoading, UserSessionsError };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/user-sessions.tsx"],"sourcesContent":["\"use client\";\n\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Badge, Button, Skeleton } from \"./elements.js\";\nimport {\n getDomProps,\n getUserLocation,\n parseUserAgent,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { LogoutDialog } from \"./logout-dialog.js\";\nimport { LogoutAllSessionsDialog } from \"./logout-all-sessions-dialog.js\";\nimport type { SessionFieldsFragment } from \"../api/client-graphql/generated.js\";\nimport * as CardList from \"./card-list.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport * as React from \"react\";\nimport { GenericError } from \"./generic-error.js\";\nimport { LaptopIcon, MobileIcon } from \"@radix-ui/react-icons\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\ninterface UserSessionsProps extends WidgetRootDomProps {\n sessionsData: SessionFieldsFragment[];\n currentSessionId: string;\n}\n\nconst UserSessions = ({\n sessionsData: sessions,\n currentSessionId,\n ...domProps\n}: UserSessionsProps) => {\n const currentSession = sessions.find(\n (session) => session.id === currentSessionId,\n );\n const otherSessions = sessions.filter(\n (session) => session.id !== currentSessionId,\n );\n const [openLogoutDialog, setOpenLogoutDialog] = React.useState(false);\n const [sessionToSignOut, setSessionToSignOut] =\n React.useState<SessionFieldsFragment | null>(null);\n const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =\n React.useState(false);\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <CardList.Root>\n {currentSession && (\n <CardList.Item>\n <UserSession session={currentSession} isCurrentSession />\n </CardList.Item>\n )}\n\n {otherSessions.map((session) => (\n <CardList.Item key={session.id}>\n <UserSession\n session={session}\n onSignOut={() => {\n setSessionToSignOut(session);\n setOpenLogoutDialog(true);\n }}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n {sessions.length > 1 && (\n <Card size=\"2\">\n <Flex gap=\"2\" justify=\"between\" align=\"center\">\n <Box>\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n <Translation\n defaultMessage=\"Sign out of all other devices\"\n id=\"sfkEFa\"\n description=\"Heading for sign out all other devices action\"\n />\n </Text>\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Remove access from all devices except this one\"\n id=\"LsD5BK\"\n description=\"Description for sign out all other devices action\"\n />\n </Text>\n </Box>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setOpenLogoutAllSessionsDialog(true);\n }}\n >\n <Translation\n defaultMessage=\"Sign out\"\n id=\"oKQ0rm\"\n description=\"Button text to sign out of all other devices\"\n />\n </Button>\n </Flex>\n </Card>\n )}\n\n {sessionToSignOut && (\n <LogoutDialog\n session={sessionToSignOut}\n open={openLogoutDialog}\n onOpenChange={setOpenLogoutDialog}\n />\n )}\n\n <LogoutAllSessionsDialog\n open={openLogoutAllSessionsDialog}\n onOpenChange={setOpenLogoutAllSessionsDialog}\n currentSessionId={currentSessionId}\n />\n </Flex>\n );\n};\n\ninterface UserSessionsLoadingProps extends WidgetRootDomProps {}\n\nconst UserSessionsLoading: React.FC<UserSessionsLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface UserSessionsErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSessionsError: React.FC<UserSessionsErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSessionProps {\n session: SessionFieldsFragment;\n isCurrentSession?: boolean;\n onSignOut?: (session: SessionFieldsFragment) => void;\n}\n\nconst UserSession = ({\n session,\n isCurrentSession = false,\n onSignOut,\n}: UserSessionProps) => {\n const userAgent = parseUserAgent(session.userAgent);\n const userLocation = getUserLocation(\n session.currentLocation,\n session.ipAddress,\n );\n const timeAgo = useComparativeReadableDate({\n date: session.lastActivityAt ? new Date(session.lastActivityAt) : null,\n });\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel>\n {userAgent?.isMobile ? <MobileIcon /> : <LaptopIcon />}\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n {userAgent?.pretty ?? (\n <Translation\n defaultMessage=\"Unknown device\"\n id=\"nF+P+T\"\n description=\"Label for a session whose device could not be determined from its user agent\"\n />\n )}\n </Text>\n\n <Flex gap=\"1\" align=\"center\">\n <Text size=\"2\" color=\"gray\" as=\"p\">\n {userLocation}\n </Text>\n\n {isCurrentSession && (\n <Badge ml=\"2\">\n <Translation\n defaultMessage=\"This device\"\n id=\"Wz8T8u\"\n description=\"Badge label indicating the current device session\"\n />\n </Badge>\n )}\n\n {!isCurrentSession && session.lastActivityAt && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last seen {timeAgo}\"\n id=\"gF+kUw\"\n description=\"Text showing when the session was last active\"\n values={{ timeAgo }}\n />\n </Text>\n </>\n )}\n </Flex>\n </Flex>\n\n {!isCurrentSession && (\n <Flex ml=\"auto\">\n <Button variant=\"secondary\" onClick={() => onSignOut?.(session)}>\n <Translation\n defaultMessage=\"Sign out\"\n id=\"sT1L78\"\n description=\"Button text to sign out of a session\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-sessions\",\n widgetState: state,\n });\n}\n\nexport type { UserSessionsLoadingProps, UserSessionsErrorProps };\nexport { UserSessions, UserSessionsLoading, UserSessionsError };\n"],"mappings":";AAkDM,SAgLM,UA7KA,KAHN;AAhDN,SAAS,KAAK,MAAM,MAAM,YAAY;AACtC,SAAS,OAAO,QAAQ,gBAAgB;AACxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,oBAAoB;AAC7B,SAAS,+BAA+B;AAExC,YAAY,cAAc;AAC1B,SAAS,iBAAiB;AAC1B,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAC7B,SAAS,YAAY,kBAAkB;AACvC,SAAS,mBAAmB;AAC5B,SAAS,kCAAkC;AAO3C,MAAM,eAAe,CAAC;AAAA,EACpB,cAAc;AAAA,EACd;AAAA,EACA,GAAG;AACL,MAAyB;AACvB,QAAM,iBAAiB,SAAS;AAAA,IAC9B,CAAC,YAAY,QAAQ,OAAO;AAAA,EAC9B;AACA,QAAM,gBAAgB,SAAS;AAAA,IAC7B,CAAC,YAAY,QAAQ,OAAO;AAAA,EAC9B;AACA,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAS,KAAK;AACpE,QAAM,CAAC,kBAAkB,mBAAmB,IAC1C,MAAM,SAAuC,IAAI;AACnD,QAAM,CAAC,6BAA6B,8BAA8B,IAChE,MAAM,SAAS,KAAK;AAEtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACH,GAAG,sBAAsB,YAAY,QAAQ;AAAA,MAE9C;AAAA,6BAAC,SAAS,MAAT,EACE;AAAA,4BACC,oBAAC,SAAS,MAAT,EACC,8BAAC,eAAY,SAAS,gBAAgB,kBAAgB,MAAC,GACzD;AAAA,UAGD,cAAc,IAAI,CAAC,YAClB,oBAAC,SAAS,MAAT,EACC;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,WAAW,MAAM;AACf,oCAAoB,OAAO;AAC3B,oCAAoB,IAAI;AAAA,cAC1B;AAAA;AAAA,UACF,KAPkB,QAAQ,EAQ5B,CACD;AAAA,WACH;AAAA,QAEC,SAAS,SAAS,KACjB,oBAAC,QAAK,MAAK,KACT,+BAAC,QAAK,KAAI,KAAI,SAAQ,WAAU,OAAM,UACpC;AAAA,+BAAC,OACC;AAAA,gCAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAC3C;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF;AAAA,YACA,oBAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF;AAAA,aACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,SAAS,MAAM;AACb,+CAA+B,IAAI;AAAA,cACrC;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF;AAAA,WACF,GACF;AAAA,QAGD,oBACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,MAAM;AAAA,YACN,cAAc;AAAA;AAAA,QAChB;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,cAAc;AAAA,YACd;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAIA,MAAM,sBAA0D,CAAC,UAAU;AACzE,SACE,oBAAC,QAAK,MAAK,KAAK,GAAG,sBAAsB,WAAW,KAAK,GACvD,+BAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,wBAAC,YACC,8BAAC,aAAU,GACb;AAAA,IAEA,qBAAC,QAAK,WAAU,UACd;AAAA,0BAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QAClD,8BAAC,YACC;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MAEA,oBAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B,8BAAC,YACC;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAMA,MAAM,oBAAsD,CAAC;AAAA,EAC3D;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE,oBAAC,QAAK,MAAK,KAAK,GAAG,sBAAsB,SAAS,QAAQ,GACxD,8BAAC,gBAAa,OAAc,GAC9B;AAEJ;AAQA,MAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA,mBAAmB;AAAA,EACnB;AACF,MAAwB;AACtB,QAAM,YAAY,eAAe,QAAQ,SAAS;AAClD,QAAM,eAAe;AAAA,IACnB,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,QAAM,UAAU,2BAA2B;AAAA,IACzC,MAAM,QAAQ,iBAAiB,IAAI,KAAK,QAAQ,cAAc,IAAI;AAAA,EACpE,CAAC;AAED,SACE,qBAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,wBAAC,aACE,qBAAW,WAAW,oBAAC,cAAW,IAAK,oBAAC,cAAW,GACtD;AAAA,IAEA,qBAAC,QAAK,WAAU,UACd;AAAA,0BAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QACjD,qBAAW,UACV;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GAEJ;AAAA,MAEA,qBAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,4BAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC5B,wBACH;AAAA,QAEC,oBACC,oBAAC,SAAM,IAAG,KACR;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QAGD,CAAC,oBAAoB,QAAQ,kBAC5B,iCAEE;AAAA,8BAAC,QAAK,MAAK,KAAI,OAAM,QAAO,oBAE5B;AAAA,UACA,oBAAC,QAAK,MAAK,KAAI,OAAM,QACnB;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,QAAQ,EAAE,QAAQ;AAAA;AAAA,UACpB,GACF;AAAA,WACF;AAAA,SAEJ;AAAA,OACF;AAAA,IAEC,CAAC,oBACA,oBAAC,QAAK,IAAG,QACP,8BAAC,UAAO,SAAQ,aAAY,SAAS,MAAM,YAAY,OAAO,GAC5D;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF,GACF;AAAA,KAEJ;AAEJ;AAEA,SAAS,sBACP,OACA,UACA;AACA,SAAO,YAAY;AAAA,IACjB,GAAG;AAAA,IACH,cAAc;AAAA,IACd,UAAU;AAAA,IACV,aAAa;AAAA,EACf,CAAC;AACH;","names":[]}
|
|
@@ -28,7 +28,6 @@ import { UsersFilter } from "./users-filter.js";
|
|
|
28
28
|
import { UsersSearch } from "./users-search.js";
|
|
29
29
|
import {
|
|
30
30
|
getBestName,
|
|
31
|
-
getComparativeReadableDate,
|
|
32
31
|
getDomProps,
|
|
33
32
|
getListMetadata
|
|
34
33
|
} from "./utils.js";
|
|
@@ -39,6 +38,7 @@ import { DotsHorizontalIcon } from "@radix-ui/react-icons";
|
|
|
39
38
|
import { Translation } from "./i18n/translation.js";
|
|
40
39
|
import { useTranslation } from "./i18n/use-translation.js";
|
|
41
40
|
import { useLocale } from "./i18n/use-locale.js";
|
|
41
|
+
import { useComparativeReadableDate } from "../use-comparative-readable-date.js";
|
|
42
42
|
const UsersManagement = ({
|
|
43
43
|
userData,
|
|
44
44
|
rolesData,
|
|
@@ -499,30 +499,19 @@ function LastActiveImpl({
|
|
|
499
499
|
dim
|
|
500
500
|
}) {
|
|
501
501
|
const locale = useLocale();
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
// hard-coded timezone to prevent server/client mismatch
|
|
516
|
-
timeZone: defaultTimeZone,
|
|
517
|
-
month: "long",
|
|
518
|
-
day: "numeric",
|
|
519
|
-
year: "numeric"
|
|
520
|
-
});
|
|
521
|
-
return {
|
|
522
|
-
lastActiveDateTime: lastActiveDateTime2,
|
|
523
|
-
lastActiveDisplay: lastActiveDisplay2
|
|
524
|
-
};
|
|
525
|
-
}, [isHydrated, date, locale]);
|
|
502
|
+
const lastActiveDate = new Date(date);
|
|
503
|
+
const lastActiveDateTime = lastActiveDate.toLocaleTimeString(locale, {
|
|
504
|
+
// hard-coded timezone before hydration to prevent server/client mismatch
|
|
505
|
+
timeZone: isHydrated ? void 0 : "America/Los_Angeles",
|
|
506
|
+
month: "long",
|
|
507
|
+
day: "numeric",
|
|
508
|
+
year: "numeric",
|
|
509
|
+
hour: "numeric",
|
|
510
|
+
minute: "numeric"
|
|
511
|
+
});
|
|
512
|
+
const lastActiveDisplay = useComparativeReadableDate({
|
|
513
|
+
date: lastActiveDate
|
|
514
|
+
});
|
|
526
515
|
if (lastActiveDisplay === "Invalid Date") {
|
|
527
516
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
528
517
|
/* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/users-management.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Box,\n Flex,\n Grid,\n Separator,\n Table,\n Tooltip,\n Text,\n type TextProps,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport {\n Avatar,\n Badge,\n IconButton,\n Button,\n Select,\n Skeleton,\n TextField,\n} from \"./elements.js\";\nimport { InviteUserDialog } from \"./invite-user-dialog.js\";\nimport { SearchProvider, useSearchContext } from \"./search-provider.js\";\nimport { useIsHydrated } from \"./use-is-hydrated.js\";\nimport { UserActionsDropdown } from \"./user-actions-dropdown.js\";\nimport { UsersFilter } from \"./users-filter.js\";\nimport { UsersSearch } from \"./users-search.js\";\nimport {\n getBestName,\n getComparativeReadableDate,\n getDomProps,\n getListMetadata,\n WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { USER_ROW_LIMIT } from \"./constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport type { Member, MembersQueryResult, RolesAndConfig } from \"./api/user.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { DotsHorizontalIcon } from \"@radix-ui/react-icons\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ninterface UsersManagementProps extends WidgetRootDomProps {\n rolesData: RolesAndConfig;\n userData: MembersQueryResult;\n disableRolesFilter?: boolean;\n // When the users list is loading new users\n isPending: boolean;\n}\n\nconst UsersManagement: React.FC<UsersManagementProps> = ({\n userData,\n rolesData,\n isPending,\n disableRolesFilter,\n ...domProps\n}) => {\n const users = userData?.data ?? [];\n const usersCount = users?.length ?? 0;\n const isHydrated = useIsHydrated();\n const pagination = getListMetadata(userData);\n\n const { dispatch } = useUsersManagementContext();\n const isMultipleRolesEnabled = rolesData.multipleRolesEnabled;\n const translate = useTranslation();\n\n // we only want to show the loading indicator for some buttons if the request\n // is still pending after 500ms. If the request is fast enough the indicator\n // is a bit jarring.\n const [deferredLoading, setDeferredLoading] = React.useState(false);\n React.useEffect(() => {\n if (isPending) {\n const timeoutId = window.setTimeout(() => {\n setDeferredLoading(true);\n }, 500);\n return () => {\n window.clearTimeout(timeoutId);\n };\n } else {\n setDeferredLoading(false);\n }\n }, [isPending]);\n\n const showPagination = !!(pagination.before || pagination.after);\n\n return (\n <SearchProvider>\n <Flex\n direction=\"column\"\n gap=\"3\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <Grid columns=\"1fr auto\" gap=\"2\">\n <Flex gap=\"2\" align=\"center\">\n <Box flexBasis=\"380px\" flexGrow=\"0\" flexShrink=\"1\">\n <UsersSearch />\n </Box>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <UsersFilter\n roles={rolesData.roles}\n disabled={disableRolesFilter}\n />\n </Box>\n </Flex>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <InviteUserDialog>\n <Button>\n <Translation\n defaultMessage=\"Invite user\"\n id=\"NBXpRj\"\n description=\"Button text to invite a new user to the organization\"\n />\n </Button>\n </InviteUserDialog>\n </Box>\n </Grid>\n <Table.Root variant=\"ghost\" size=\"1\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"260px\">\n <Translation\n defaultMessage=\"User\"\n id=\"BBh86k\"\n description=\"Column header for user information in the users table\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n {isMultipleRolesEnabled ? (\n <Translation\n defaultMessage=\"Roles\"\n id=\"A1DuWM\"\n description=\"Column header for user roles when multiple roles are enabled\"\n />\n ) : (\n <Translation\n defaultMessage=\"Role\"\n id=\"nQbe+Y\"\n description=\"Column header for user role when only single role is allowed\"\n />\n )}\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Translation\n defaultMessage=\"Last active\"\n id=\"oOwLGt\"\n description=\"Column header showing when users were last active\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n\n <Table.Body\n style={{\n transition: `opacity 0.2s ease-out ${isPending ? \"0.2s\" : \"0s\"}`,\n opacity: isPending && usersCount > 0 ? 0.5 : 1,\n }}\n >\n {users.length > 0 ? (\n users.map((user) => {\n const userDisplayName = getBestName(user);\n const dimText =\n user.status === \"InviteRevoked\" ||\n user.status === \"InviteExpired\";\n return (\n <Table.Row key={user.id} align=\"center\">\n <Table.RowHeaderCell>\n <Flex\n align=\"center\"\n gap=\"3\"\n overflow=\"hidden\"\n height=\"var(--space-7)\"\n >\n <Avatar\n size=\"2\"\n fallback={<FallbackUserIcon />}\n src={user.profilePictureUrl ?? undefined}\n dim={dimText}\n />\n\n {userDisplayName ? (\n <Flex\n direction=\"column\"\n align=\"start\"\n height=\"var(--space-7)\"\n justify=\"center\"\n overflow=\"hidden\"\n >\n <Flex gap=\"2\" align=\"center\" minWidth=\"0\">\n <TableCellText dim={dimText}>\n {userDisplayName}\n </TableCellText>\n <UserBadge user={user} />\n </Flex>\n <TableCellText\n level=\"secondary\"\n title={user.email}\n dim={dimText}\n >\n {user.email}\n </TableCellText>\n </Flex>\n ) : (\n <Flex gap=\"2\" align=\"center\" minWidth=\"0\">\n <TableCellText dim={dimText} title={user.email}>\n {user.email}\n </TableCellText>\n <UserBadge user={user} />\n </Flex>\n )}\n </Flex>\n </Table.RowHeaderCell>\n <Table.Cell>\n <UserRolesCellContent\n user={user}\n isMultipleRolesEnabled={isMultipleRolesEnabled}\n dimText={dimText}\n />\n </Table.Cell>\n <Table.Cell>\n <LastActive user={user} isHydrated={isHydrated} />\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <UserActionsDropdown user={user}>\n <IconButton\n title={translate({\n defaultMessage: \"User actions\",\n id: \"1nsmNS\",\n description:\n \"Button tooltip for opening user actions menu\",\n })}\n >\n <DotsHorizontalIcon />\n </IconButton>\n </UserActionsDropdown>\n </Table.Cell>\n </Table.Row>\n );\n })\n ) : (\n <Table.Row align=\"center\">\n <Table.Cell colSpan={4}>\n <UsersManagementEmptyState isPending={isPending} />\n </Table.Cell>\n </Table.Row>\n )}\n </Table.Body>\n </Table.Root>\n\n {showPagination ? (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n size=\"1\"\n disabled={!pagination.after || isPending || undefined}\n loading={deferredLoading}\n onClick={() => {\n if (pagination.after) {\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { after: pagination.after, before: null },\n });\n }\n }}\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"910Q6b\"\n description=\"Button text to navigate to the previous page of users\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n size=\"1\"\n disabled={!pagination.before || isPending || undefined}\n loading={deferredLoading}\n onClick={() => {\n if (pagination.before) {\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n });\n }\n }}\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"UlAY08\"\n description=\"Button text to navigate to the next page of users\"\n />\n </Button>\n </Flex>\n ) : null}\n </Flex>\n </SearchProvider>\n );\n};\n\ninterface UsersManagementLoadingProps extends WidgetRootDomProps {}\n\nconst UsersManagementLoading: React.FC<UsersManagementLoadingProps> = (\n props,\n) => {\n const translate = useTranslation();\n const placeholderText = (\n <Translation\n defaultMessage=\"All\"\n id=\"l/Do9/\"\n description=\"Filter option to show all users\"\n />\n );\n return (\n <Flex\n direction=\"column\"\n gap=\"3\"\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Grid columns=\"1fr auto\" gap=\"2\">\n <Flex gap=\"2\" align=\"center\">\n <Skeleton loading>\n <Box flexBasis=\"380px\" flexGrow=\"0\" flexShrink=\"1\">\n <TextField\n disabled\n aria-label={translate({\n defaultMessage: \"User search\",\n id: \"lzPOKv\",\n description: \"Label for the user search input field\",\n })}\n />\n </Box>\n </Skeleton>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <Select.Root disabled value=\"all\" onValueChange={() => void 0}>\n <Select.Trigger>{placeholderText}</Select.Trigger>\n <Select.Content>\n <Select.Item value=\"all\">{placeholderText}</Select.Item>\n </Select.Content>\n </Select.Root>\n </Box>\n </Skeleton>\n </Flex>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <Button disabled>\n <Translation\n defaultMessage=\"Invite user\"\n id=\"NBXpRj\"\n description=\"Button text to invite a new user to the organization\"\n />\n </Button>\n </Box>\n </Skeleton>\n </Grid>\n <Table.Root variant=\"ghost\" size=\"1\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"260px\">\n <Skeleton loading>\n <Translation\n defaultMessage=\"User\"\n id=\"BBh86k\"\n description=\"Column header for user information in the users table\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Role\"\n id=\"FK7mP4\"\n description=\"Column header for user role\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Last active\"\n id=\"oOwLGt\"\n description=\"Column header showing when users were last active\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n\n <Table.Body>\n {Array.from({ length: USER_ROW_LIMIT }, (_, index) => (\n <Table.Row key={index} align=\"center\">\n <Table.RowHeaderCell>\n <Flex align=\"center\" gap=\"3\">\n <Skeleton>\n <Avatar size=\"2\" fallback=\"F\" />\n </Skeleton>\n\n <Flex\n direction=\"column\"\n height=\"var(--space-7)\"\n justify=\"center\"\n >\n <Skeleton width=\"180px\" height=\"var(--space-4)\" />\n <Skeleton width=\"90px\" height=\"var(--space-3)\" mt=\"1\" />\n </Flex>\n </Flex>\n </Table.RowHeaderCell>\n <Table.Cell>\n <Flex wrap=\"wrap\" gap=\"1\">\n <Skeleton width=\"75px\" height=\"var(--space-4)\" />\n </Flex>\n </Table.Cell>\n <Table.Cell>\n <Skeleton width=\"120px\" height=\"var(--space-4)\" />\n </Table.Cell>\n <Table.Cell justify=\"end\" />\n </Table.Row>\n ))}\n </Table.Body>\n </Table.Root>\n\n <Flex gap=\"2\" justify=\"end\">\n <Skeleton loading>\n <Button disabled variant=\"secondary\" size=\"1\">\n <Translation\n defaultMessage=\"Previous\"\n id=\"910Q6b\"\n description=\"Button text to navigate to the previous page of users\"\n />\n </Button>\n </Skeleton>\n <Skeleton loading>\n <Button disabled variant=\"secondary\" size=\"1\">\n <Translation\n defaultMessage=\"Next\"\n id=\"UlAY08\"\n description=\"Button text to navigate to the next page of users\"\n />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n );\n};\n\ninterface UsersManagementErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UsersManagementError: React.FC<UsersManagementErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <GenericError\n error={error}\n minHeight=\"676px\"\n {...getWidgetRootDomProps(\"error\", domProps)}\n />\n );\n};\n\nfunction UserBadge({ user }: { user: Member }) {\n if (user.isLoggedInUser) {\n return (\n <Badge color=\"gray\" style={{ userSelect: \"none\" }}>\n <Translation\n defaultMessage=\"You\"\n id=\"ER1Vmv\"\n description=\"Badge indicating the current logged-in user\"\n />\n </Badge>\n );\n }\n if (user.status === \"Invited\") {\n return (\n <Badge color=\"amber\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: \"\n id=\"E2o/+H\"\n description=\"Prefix for status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Invited\"\n id=\"byIkUu\"\n description=\"Badge status indicating user has been invited but not yet accepted\"\n />\n </Badge>\n );\n }\n if (user.status === \"InviteExpired\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: Invite \"\n id=\"BWvbwY\"\n description=\"Prefix for invite status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Expired\"\n id=\"+0sQaN\"\n description=\"Badge status indicating user invitation has expired\"\n />\n </Badge>\n );\n }\n if (user.status === \"InviteRevoked\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: Invite \"\n id=\"BWvbwY\"\n description=\"Prefix for invite status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Revoked\"\n id=\"NNBv+r\"\n description=\"Badge status indicating user invitation has been revoked\"\n />\n </Badge>\n );\n }\n return null;\n}\n\ninterface LastActiveProps {\n user: Member;\n isHydrated: boolean;\n dim?: boolean;\n}\n\nfunction LastActive(props: LastActiveProps) {\n if (!props.user.lastActivityAt) {\n return (\n <>\n <VisuallyHidden>\n {props.user.status === \"Active\" ? (\n <Translation\n defaultMessage=\"Never\"\n id=\"0duvF4\"\n description=\"Screen reader text indicating user has never been active\"\n />\n ) : (\n <Translation\n defaultMessage=\"Not active\"\n id=\"hd2+kk\"\n description=\"Screen reader text indicating user is not active\"\n />\n )}\n </VisuallyHidden>\n <Separator />\n </>\n );\n }\n return <LastActiveImpl {...props} date={props.user.lastActivityAt} />;\n}\n\nfunction LastActiveImpl({\n date,\n isHydrated,\n dim,\n}: LastActiveProps & { date: string }) {\n const locale = useLocale();\n const { lastActiveDateTime, lastActiveDisplay } = React.useMemo(() => {\n const defaultTimeZone = \"America/Los_Angeles\";\n const lastActiveDate = new Date(date);\n const lastActiveDateTime = lastActiveDate.toLocaleTimeString(locale, {\n // hard-coded timezone before hydration to prevent server/client mismatch\n timeZone: isHydrated ? undefined : defaultTimeZone,\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n });\n\n // Server and client may produce a different 'now' date, so only\n // show comparative date if the component is hydrated to prevent a\n // server/client mismatch\n const lastActiveDisplay = isHydrated\n ? getComparativeReadableDate(new Date(), lastActiveDate, { locale })\n : lastActiveDate.toLocaleDateString(locale, {\n // hard-coded timezone to prevent server/client mismatch\n timeZone: defaultTimeZone,\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n });\n\n return {\n lastActiveDateTime,\n lastActiveDisplay,\n };\n }, [isHydrated, date, locale]);\n\n // handle cases where the DB might return an invalid date string\n if (lastActiveDisplay === \"Invalid Date\") {\n return (\n <>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Unknown\"\n id=\"UUigrK\"\n description=\"Screen reader text indicating last active date is unknown\"\n />\n </VisuallyHidden>\n <Separator />\n </>\n );\n }\n\n return (\n <TableCellText asChild dim={dim}>\n <time dateTime={date} title={lastActiveDateTime}>\n {lastActiveDisplay}\n </time>\n </TableCellText>\n );\n}\n\nconst TableCellText = React.forwardRef<HTMLSpanElement, TableCellTextProps>(\n function TableCellText(\n { children, dim, level = \"primary\", ...props },\n forwardedRef,\n ) {\n return (\n <Text\n ref={forwardedRef}\n color={level === \"secondary\" ? \"gray\" : undefined}\n weight={level === \"secondary\" ? \"regular\" : \"medium\"}\n size={level === \"secondary\" ? \"1\" : \"2\"}\n truncate\n {...props}\n style={\n dim\n ? {\n // TODO: use CSS var instead of hard-coded value for opacity\n opacity: 0.6,\n ...props.style,\n }\n : props.style\n }\n >\n {children}\n </Text>\n );\n },\n);\n\ntype TableCellTextProps = TextProps & {\n level?: \"primary\" | \"secondary\";\n dim?: boolean;\n};\n\nconst FallbackUserIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n fill=\"currentColor\"\n viewBox=\"0 0 256 256\"\n >\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <title>User icon</title>\n <path d=\"M229.19,213c-15.81-27.32-40.63-46.49-69.47-54.62a70,70,0,1,0-63.44,0C67.44,166.5,42.62,185.67,26.81,213a6,6,0,1,0,10.38,6C56.4,185.81,90.34,166,128,166s71.6,19.81,90.81,53a6,6,0,1,0,10.38-6ZM70,96a58,58,0,1,1,58,58A58.07,58.07,0,0,1,70,96Z\" />\n </svg>\n);\n\nconst UsersManagementEmptyState = ({ isPending }: { isPending: boolean }) => {\n const { clearSearch } = useSearchContext();\n const {\n state: { searchQuery },\n } = useUsersManagementContext();\n\n // When the search query is cleared, the users query is re-fetched which sends\n // us into a pending state. When this happens we want to keep a snapshot of\n // the previous search query while the query is revalidated. We can use this\n // to keep the 'No users found for query' UI in place until re-fetching is\n // complete, otherwise the view flips to 'No users found' very quickly before\n // the full table is shown again.\n const [{ isClearing, lastSearchQuery }, setClearing] = React.useState({\n isClearing: false,\n lastSearchQuery: null as null | string,\n });\n const [wasPending, setWasPending] = React.useState(isPending);\n if (wasPending !== isPending) {\n setWasPending(isPending);\n if (!isPending) {\n setClearing((prev) =>\n prev.isClearing ? { isClearing: false, lastSearchQuery: null } : prev,\n );\n }\n }\n\n if (searchQuery || isClearing) {\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" direction=\"column\" gap=\"2\">\n <Text size=\"2\">\n <Translation\n defaultMessage=\"No users found for query '{query}'\"\n id=\"wrEZ8+\"\n description=\"Message shown when no users match the search query\"\n values={{\n query: isClearing ? lastSearchQuery : searchQuery,\n }}\n />\n </Text>\n\n <Button\n variant=\"secondary\"\n size=\"1\"\n onClick={() => {\n setClearing({ isClearing: true, lastSearchQuery: searchQuery });\n clearSearch();\n }}\n loading={isPending}\n >\n <Translation\n defaultMessage=\"Clear search\"\n id=\"Xv3fVI\"\n description=\"Button text to clear the current search query\"\n />\n </Button>\n </Flex>\n );\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" gap=\"2\">\n <Text size=\"2\">\n <Translation\n defaultMessage=\"No users found\"\n id=\"MQ+LoA\"\n description=\"Message shown when there are no users in the system\"\n />\n </Text>\n </Flex>\n );\n};\n\ninterface UserRolesCellContentProps {\n user: Member;\n isMultipleRolesEnabled: boolean;\n dimText: boolean;\n}\n\nfunction UserRolesCellContent({\n user,\n isMultipleRolesEnabled,\n dimText,\n}: UserRolesCellContentProps) {\n if (!user.roles || user.roles.length === 0) {\n return (\n <>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"No roles assigned\"\n id=\"CVOVB0\"\n description=\"Screen reader text indicating user has no roles assigned\"\n />\n </VisuallyHidden>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden style={{ userSelect: \"none\" }}>\n –\n </span>\n </>\n );\n }\n\n if (isMultipleRolesEnabled && user.roles.length > 1) {\n const roleNames = user.roles?.map((role) => role.name).join(\", \");\n return (\n <Tooltip content={roleNames} maxWidth=\"250px\">\n <TableCellText dim={dimText}>\n <Translation\n defaultMessage=\"{count} roles\"\n id=\"lWAmRC\"\n description=\"Shows the number of roles assigned to a user (plural)\"\n values={{ count: user.roles.length }}\n />\n </TableCellText>\n </Tooltip>\n );\n }\n\n return <TableCellText dim={dimText}>{user.roles?.[0]?.name}</TableCellText>;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"users-management\",\n widgetState: state,\n });\n}\n\nexport type { UsersManagementLoadingProps, UsersManagementErrorProps };\nexport { UsersManagement, UsersManagementLoading, UsersManagementError };\n"],"mappings":"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","names":["lastActiveDateTime","lastActiveDisplay","TableCellText"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/users-management.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Box,\n Flex,\n Grid,\n Separator,\n Table,\n Tooltip,\n Text,\n type TextProps,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport {\n Avatar,\n Badge,\n IconButton,\n Button,\n Select,\n Skeleton,\n TextField,\n} from \"./elements.js\";\nimport { InviteUserDialog } from \"./invite-user-dialog.js\";\nimport { SearchProvider, useSearchContext } from \"./search-provider.js\";\nimport { useIsHydrated } from \"./use-is-hydrated.js\";\nimport { UserActionsDropdown } from \"./user-actions-dropdown.js\";\nimport { UsersFilter } from \"./users-filter.js\";\nimport { UsersSearch } from \"./users-search.js\";\nimport {\n getBestName,\n getDomProps,\n getListMetadata,\n WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { USER_ROW_LIMIT } from \"./constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport type { Member, MembersQueryResult, RolesAndConfig } from \"./api/user.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { DotsHorizontalIcon } from \"@radix-ui/react-icons\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\ninterface UsersManagementProps extends WidgetRootDomProps {\n rolesData: RolesAndConfig;\n userData: MembersQueryResult;\n disableRolesFilter?: boolean;\n // When the users list is loading new users\n isPending: boolean;\n}\n\nconst UsersManagement: React.FC<UsersManagementProps> = ({\n userData,\n rolesData,\n isPending,\n disableRolesFilter,\n ...domProps\n}) => {\n const users = userData?.data ?? [];\n const usersCount = users?.length ?? 0;\n const isHydrated = useIsHydrated();\n const pagination = getListMetadata(userData);\n\n const { dispatch } = useUsersManagementContext();\n const isMultipleRolesEnabled = rolesData.multipleRolesEnabled;\n const translate = useTranslation();\n\n // we only want to show the loading indicator for some buttons if the request\n // is still pending after 500ms. If the request is fast enough the indicator\n // is a bit jarring.\n const [deferredLoading, setDeferredLoading] = React.useState(false);\n React.useEffect(() => {\n if (isPending) {\n const timeoutId = window.setTimeout(() => {\n setDeferredLoading(true);\n }, 500);\n return () => {\n window.clearTimeout(timeoutId);\n };\n } else {\n // TODO: Fix this\n // oxlint-disable-next-line react/set-state-in-effect\n setDeferredLoading(false);\n }\n }, [isPending]);\n\n const showPagination = !!(pagination.before || pagination.after);\n\n return (\n <SearchProvider>\n <Flex\n direction=\"column\"\n gap=\"3\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <Grid columns=\"1fr auto\" gap=\"2\">\n <Flex gap=\"2\" align=\"center\">\n <Box flexBasis=\"380px\" flexGrow=\"0\" flexShrink=\"1\">\n <UsersSearch />\n </Box>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <UsersFilter\n roles={rolesData.roles}\n disabled={disableRolesFilter}\n />\n </Box>\n </Flex>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <InviteUserDialog>\n <Button>\n <Translation\n defaultMessage=\"Invite user\"\n id=\"NBXpRj\"\n description=\"Button text to invite a new user to the organization\"\n />\n </Button>\n </InviteUserDialog>\n </Box>\n </Grid>\n <Table.Root variant=\"ghost\" size=\"1\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"260px\">\n <Translation\n defaultMessage=\"User\"\n id=\"BBh86k\"\n description=\"Column header for user information in the users table\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n {isMultipleRolesEnabled ? (\n <Translation\n defaultMessage=\"Roles\"\n id=\"A1DuWM\"\n description=\"Column header for user roles when multiple roles are enabled\"\n />\n ) : (\n <Translation\n defaultMessage=\"Role\"\n id=\"nQbe+Y\"\n description=\"Column header for user role when only single role is allowed\"\n />\n )}\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Translation\n defaultMessage=\"Last active\"\n id=\"oOwLGt\"\n description=\"Column header showing when users were last active\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n\n <Table.Body\n style={{\n transition: `opacity 0.2s ease-out ${isPending ? \"0.2s\" : \"0s\"}`,\n opacity: isPending && usersCount > 0 ? 0.5 : 1,\n }}\n >\n {users.length > 0 ? (\n users.map((user) => {\n const userDisplayName = getBestName(user);\n const dimText =\n user.status === \"InviteRevoked\" ||\n user.status === \"InviteExpired\";\n return (\n <Table.Row key={user.id} align=\"center\">\n <Table.RowHeaderCell>\n <Flex\n align=\"center\"\n gap=\"3\"\n overflow=\"hidden\"\n height=\"var(--space-7)\"\n >\n <Avatar\n size=\"2\"\n fallback={<FallbackUserIcon />}\n src={user.profilePictureUrl ?? undefined}\n dim={dimText}\n />\n\n {userDisplayName ? (\n <Flex\n direction=\"column\"\n align=\"start\"\n height=\"var(--space-7)\"\n justify=\"center\"\n overflow=\"hidden\"\n >\n <Flex gap=\"2\" align=\"center\" minWidth=\"0\">\n <TableCellText dim={dimText}>\n {userDisplayName}\n </TableCellText>\n <UserBadge user={user} />\n </Flex>\n <TableCellText\n level=\"secondary\"\n title={user.email}\n dim={dimText}\n >\n {user.email}\n </TableCellText>\n </Flex>\n ) : (\n <Flex gap=\"2\" align=\"center\" minWidth=\"0\">\n <TableCellText dim={dimText} title={user.email}>\n {user.email}\n </TableCellText>\n <UserBadge user={user} />\n </Flex>\n )}\n </Flex>\n </Table.RowHeaderCell>\n <Table.Cell>\n <UserRolesCellContent\n user={user}\n isMultipleRolesEnabled={isMultipleRolesEnabled}\n dimText={dimText}\n />\n </Table.Cell>\n <Table.Cell>\n <LastActive user={user} isHydrated={isHydrated} />\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <UserActionsDropdown user={user}>\n <IconButton\n title={translate({\n defaultMessage: \"User actions\",\n id: \"1nsmNS\",\n description:\n \"Button tooltip for opening user actions menu\",\n })}\n >\n <DotsHorizontalIcon />\n </IconButton>\n </UserActionsDropdown>\n </Table.Cell>\n </Table.Row>\n );\n })\n ) : (\n <Table.Row align=\"center\">\n <Table.Cell colSpan={4}>\n <UsersManagementEmptyState isPending={isPending} />\n </Table.Cell>\n </Table.Row>\n )}\n </Table.Body>\n </Table.Root>\n\n {showPagination ? (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n size=\"1\"\n disabled={!pagination.after || isPending || undefined}\n loading={deferredLoading}\n onClick={() => {\n if (pagination.after) {\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { after: pagination.after, before: null },\n });\n }\n }}\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"910Q6b\"\n description=\"Button text to navigate to the previous page of users\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n size=\"1\"\n disabled={!pagination.before || isPending || undefined}\n loading={deferredLoading}\n onClick={() => {\n if (pagination.before) {\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n });\n }\n }}\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"UlAY08\"\n description=\"Button text to navigate to the next page of users\"\n />\n </Button>\n </Flex>\n ) : null}\n </Flex>\n </SearchProvider>\n );\n};\n\ninterface UsersManagementLoadingProps extends WidgetRootDomProps {}\n\nconst UsersManagementLoading: React.FC<UsersManagementLoadingProps> = (\n props,\n) => {\n const translate = useTranslation();\n const placeholderText = (\n <Translation\n defaultMessage=\"All\"\n id=\"l/Do9/\"\n description=\"Filter option to show all users\"\n />\n );\n return (\n <Flex\n direction=\"column\"\n gap=\"3\"\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Grid columns=\"1fr auto\" gap=\"2\">\n <Flex gap=\"2\" align=\"center\">\n <Skeleton loading>\n <Box flexBasis=\"380px\" flexGrow=\"0\" flexShrink=\"1\">\n <TextField\n disabled\n aria-label={translate({\n defaultMessage: \"User search\",\n id: \"lzPOKv\",\n description: \"Label for the user search input field\",\n })}\n />\n </Box>\n </Skeleton>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <Select.Root disabled value=\"all\" onValueChange={() => void 0}>\n <Select.Trigger>{placeholderText}</Select.Trigger>\n <Select.Content>\n <Select.Item value=\"all\">{placeholderText}</Select.Item>\n </Select.Content>\n </Select.Root>\n </Box>\n </Skeleton>\n </Flex>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <Button disabled>\n <Translation\n defaultMessage=\"Invite user\"\n id=\"NBXpRj\"\n description=\"Button text to invite a new user to the organization\"\n />\n </Button>\n </Box>\n </Skeleton>\n </Grid>\n <Table.Root variant=\"ghost\" size=\"1\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"260px\">\n <Skeleton loading>\n <Translation\n defaultMessage=\"User\"\n id=\"BBh86k\"\n description=\"Column header for user information in the users table\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Role\"\n id=\"FK7mP4\"\n description=\"Column header for user role\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Last active\"\n id=\"oOwLGt\"\n description=\"Column header showing when users were last active\"\n />\n </Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n\n <Table.Body>\n {Array.from({ length: USER_ROW_LIMIT }, (_, index) => (\n <Table.Row key={index} align=\"center\">\n <Table.RowHeaderCell>\n <Flex align=\"center\" gap=\"3\">\n <Skeleton>\n <Avatar size=\"2\" fallback=\"F\" />\n </Skeleton>\n\n <Flex\n direction=\"column\"\n height=\"var(--space-7)\"\n justify=\"center\"\n >\n <Skeleton width=\"180px\" height=\"var(--space-4)\" />\n <Skeleton width=\"90px\" height=\"var(--space-3)\" mt=\"1\" />\n </Flex>\n </Flex>\n </Table.RowHeaderCell>\n <Table.Cell>\n <Flex wrap=\"wrap\" gap=\"1\">\n <Skeleton width=\"75px\" height=\"var(--space-4)\" />\n </Flex>\n </Table.Cell>\n <Table.Cell>\n <Skeleton width=\"120px\" height=\"var(--space-4)\" />\n </Table.Cell>\n <Table.Cell justify=\"end\" />\n </Table.Row>\n ))}\n </Table.Body>\n </Table.Root>\n\n <Flex gap=\"2\" justify=\"end\">\n <Skeleton loading>\n <Button disabled variant=\"secondary\" size=\"1\">\n <Translation\n defaultMessage=\"Previous\"\n id=\"910Q6b\"\n description=\"Button text to navigate to the previous page of users\"\n />\n </Button>\n </Skeleton>\n <Skeleton loading>\n <Button disabled variant=\"secondary\" size=\"1\">\n <Translation\n defaultMessage=\"Next\"\n id=\"UlAY08\"\n description=\"Button text to navigate to the next page of users\"\n />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n );\n};\n\ninterface UsersManagementErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UsersManagementError: React.FC<UsersManagementErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <GenericError\n error={error}\n minHeight=\"676px\"\n {...getWidgetRootDomProps(\"error\", domProps)}\n />\n );\n};\n\nfunction UserBadge({ user }: { user: Member }) {\n if (user.isLoggedInUser) {\n return (\n <Badge color=\"gray\" style={{ userSelect: \"none\" }}>\n <Translation\n defaultMessage=\"You\"\n id=\"ER1Vmv\"\n description=\"Badge indicating the current logged-in user\"\n />\n </Badge>\n );\n }\n if (user.status === \"Invited\") {\n return (\n <Badge color=\"amber\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: \"\n id=\"E2o/+H\"\n description=\"Prefix for status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Invited\"\n id=\"byIkUu\"\n description=\"Badge status indicating user has been invited but not yet accepted\"\n />\n </Badge>\n );\n }\n if (user.status === \"InviteExpired\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: Invite \"\n id=\"BWvbwY\"\n description=\"Prefix for invite status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Expired\"\n id=\"+0sQaN\"\n description=\"Badge status indicating user invitation has expired\"\n />\n </Badge>\n );\n }\n if (user.status === \"InviteRevoked\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Status: Invite \"\n id=\"BWvbwY\"\n description=\"Prefix for invite status indicator in screen reader\"\n />\n </VisuallyHidden>\n <Translation\n defaultMessage=\"Revoked\"\n id=\"NNBv+r\"\n description=\"Badge status indicating user invitation has been revoked\"\n />\n </Badge>\n );\n }\n return null;\n}\n\ninterface LastActiveProps {\n user: Member;\n isHydrated: boolean;\n dim?: boolean;\n}\n\nfunction LastActive(props: LastActiveProps) {\n if (!props.user.lastActivityAt) {\n return (\n <>\n <VisuallyHidden>\n {props.user.status === \"Active\" ? (\n <Translation\n defaultMessage=\"Never\"\n id=\"0duvF4\"\n description=\"Screen reader text indicating user has never been active\"\n />\n ) : (\n <Translation\n defaultMessage=\"Not active\"\n id=\"hd2+kk\"\n description=\"Screen reader text indicating user is not active\"\n />\n )}\n </VisuallyHidden>\n <Separator />\n </>\n );\n }\n return <LastActiveImpl {...props} date={props.user.lastActivityAt} />;\n}\n\nfunction LastActiveImpl({\n date,\n isHydrated,\n dim,\n}: LastActiveProps & { date: string }) {\n const locale = useLocale();\n\n const lastActiveDate = new Date(date);\n const lastActiveDateTime = lastActiveDate.toLocaleTimeString(locale, {\n // hard-coded timezone before hydration to prevent server/client mismatch\n timeZone: isHydrated ? undefined : \"America/Los_Angeles\",\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n });\n\n const lastActiveDisplay = useComparativeReadableDate({\n date: lastActiveDate,\n });\n\n // handle cases where the DB might return an invalid date string\n if (lastActiveDisplay === \"Invalid Date\") {\n return (\n <>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"Unknown\"\n id=\"UUigrK\"\n description=\"Screen reader text indicating last active date is unknown\"\n />\n </VisuallyHidden>\n <Separator />\n </>\n );\n }\n\n return (\n <TableCellText asChild dim={dim}>\n <time dateTime={date} title={lastActiveDateTime}>\n {lastActiveDisplay}\n </time>\n </TableCellText>\n );\n}\n\nconst TableCellText = React.forwardRef<HTMLSpanElement, TableCellTextProps>(\n function TableCellText(\n { children, dim, level = \"primary\", ...props },\n forwardedRef,\n ) {\n return (\n <Text\n ref={forwardedRef}\n color={level === \"secondary\" ? \"gray\" : undefined}\n weight={level === \"secondary\" ? \"regular\" : \"medium\"}\n size={level === \"secondary\" ? \"1\" : \"2\"}\n truncate\n {...props}\n style={\n dim\n ? {\n // TODO: use CSS var instead of hard-coded value for opacity\n opacity: 0.6,\n ...props.style,\n }\n : props.style\n }\n >\n {children}\n </Text>\n );\n },\n);\n\ntype TableCellTextProps = TextProps & {\n level?: \"primary\" | \"secondary\";\n dim?: boolean;\n};\n\nconst FallbackUserIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n fill=\"currentColor\"\n viewBox=\"0 0 256 256\"\n >\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <title>User icon</title>\n <path d=\"M229.19,213c-15.81-27.32-40.63-46.49-69.47-54.62a70,70,0,1,0-63.44,0C67.44,166.5,42.62,185.67,26.81,213a6,6,0,1,0,10.38,6C56.4,185.81,90.34,166,128,166s71.6,19.81,90.81,53a6,6,0,1,0,10.38-6ZM70,96a58,58,0,1,1,58,58A58.07,58.07,0,0,1,70,96Z\" />\n </svg>\n);\n\nconst UsersManagementEmptyState = ({ isPending }: { isPending: boolean }) => {\n const { clearSearch } = useSearchContext();\n const {\n state: { searchQuery },\n } = useUsersManagementContext();\n\n // When the search query is cleared, the users query is re-fetched which sends\n // us into a pending state. When this happens we want to keep a snapshot of\n // the previous search query while the query is revalidated. We can use this\n // to keep the 'No users found for query' UI in place until re-fetching is\n // complete, otherwise the view flips to 'No users found' very quickly before\n // the full table is shown again.\n const [{ isClearing, lastSearchQuery }, setClearing] = React.useState({\n isClearing: false,\n lastSearchQuery: null as null | string,\n });\n const [wasPending, setWasPending] = React.useState(isPending);\n if (wasPending !== isPending) {\n setWasPending(isPending);\n if (!isPending) {\n setClearing((prev) =>\n prev.isClearing ? { isClearing: false, lastSearchQuery: null } : prev,\n );\n }\n }\n\n if (searchQuery || isClearing) {\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" direction=\"column\" gap=\"2\">\n <Text size=\"2\">\n <Translation\n defaultMessage=\"No users found for query '{query}'\"\n id=\"wrEZ8+\"\n description=\"Message shown when no users match the search query\"\n values={{\n query: isClearing ? lastSearchQuery : searchQuery,\n }}\n />\n </Text>\n\n <Button\n variant=\"secondary\"\n size=\"1\"\n onClick={() => {\n setClearing({ isClearing: true, lastSearchQuery: searchQuery });\n clearSearch();\n }}\n loading={isPending}\n >\n <Translation\n defaultMessage=\"Clear search\"\n id=\"Xv3fVI\"\n description=\"Button text to clear the current search query\"\n />\n </Button>\n </Flex>\n );\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" gap=\"2\">\n <Text size=\"2\">\n <Translation\n defaultMessage=\"No users found\"\n id=\"MQ+LoA\"\n description=\"Message shown when there are no users in the system\"\n />\n </Text>\n </Flex>\n );\n};\n\ninterface UserRolesCellContentProps {\n user: Member;\n isMultipleRolesEnabled: boolean;\n dimText: boolean;\n}\n\nfunction UserRolesCellContent({\n user,\n isMultipleRolesEnabled,\n dimText,\n}: UserRolesCellContentProps) {\n if (!user.roles || user.roles.length === 0) {\n return (\n <>\n <VisuallyHidden>\n <Translation\n defaultMessage=\"No roles assigned\"\n id=\"CVOVB0\"\n description=\"Screen reader text indicating user has no roles assigned\"\n />\n </VisuallyHidden>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden style={{ userSelect: \"none\" }}>\n –\n </span>\n </>\n );\n }\n\n if (isMultipleRolesEnabled && user.roles.length > 1) {\n const roleNames = user.roles?.map((role) => role.name).join(\", \");\n return (\n <Tooltip content={roleNames} maxWidth=\"250px\">\n <TableCellText dim={dimText}>\n <Translation\n defaultMessage=\"{count} roles\"\n id=\"lWAmRC\"\n description=\"Shows the number of roles assigned to a user (plural)\"\n values={{ count: user.roles.length }}\n />\n </TableCellText>\n </Tooltip>\n );\n }\n\n return <TableCellText dim={dimText}>{user.roles?.[0]?.name}</TableCellText>;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"users-management\",\n widgetState: state,\n });\n}\n\nexport type { UsersManagementLoadingProps, UsersManagementErrorProps };\nexport { UsersManagement, UsersManagementLoading, UsersManagementError };\n"],"mappings":"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","names":["TableCellText"]}
|