@workos-inc/widgets 1.20.0 → 1.20.1
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/api/client-graphql/generated.cjs.map +1 -1
- package/dist/cjs/api/client-graphql/generated.d.cts +4 -4
- package/dist/cjs/lib/api-keys/api-keys-table.cjs +6 -6
- package/dist/cjs/lib/api-keys/api-keys-table.cjs.map +1 -1
- package/dist/cjs/lib/user-api-keys/user-api-keys-table.cjs +6 -6
- package/dist/cjs/lib/user-api-keys/user-api-keys-table.cjs.map +1 -1
- package/dist/cjs/lib/users-management.cjs +8 -8
- package/dist/cjs/lib/users-management.cjs.map +1 -1
- package/dist/esm/api/client-graphql/generated.d.ts +4 -4
- package/dist/esm/api/client-graphql/generated.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys-table.js +6 -6
- package/dist/esm/lib/api-keys/api-keys-table.js.map +1 -1
- package/dist/esm/lib/user-api-keys/user-api-keys-table.js +6 -6
- package/dist/esm/lib/user-api-keys/user-api-keys-table.js.map +1 -1
- package/dist/esm/lib/users-management.js +8 -8
- package/dist/esm/lib/users-management.js.map +1 -1
- package/package.json +1 -1
|
@@ -174,8 +174,8 @@ function ApiKeysTable({ apiKeys }) {
|
|
|
174
174
|
const { dispatch } = useApiKeysContext();
|
|
175
175
|
const pagination = getListMetadata(apiKeys);
|
|
176
176
|
const hasPagination = !!(pagination.before || pagination.after);
|
|
177
|
-
const hasPreviousPage = !!pagination.
|
|
178
|
-
const hasNextPage = !!pagination.
|
|
177
|
+
const hasPreviousPage = !!pagination.before;
|
|
178
|
+
const hasNextPage = !!pagination.after;
|
|
179
179
|
return /* @__PURE__ */ jsxs(Flex, {
|
|
180
180
|
direction: "column",
|
|
181
181
|
align: "stretch",
|
|
@@ -228,8 +228,8 @@ function ApiKeysTable({ apiKeys }) {
|
|
|
228
228
|
onClick: () => dispatch({
|
|
229
229
|
type: "SET_PAGINATION",
|
|
230
230
|
pagination: {
|
|
231
|
-
before:
|
|
232
|
-
after:
|
|
231
|
+
before: pagination.before,
|
|
232
|
+
after: null
|
|
233
233
|
}
|
|
234
234
|
}),
|
|
235
235
|
children: /* @__PURE__ */ jsx(Translation, {
|
|
@@ -244,8 +244,8 @@ function ApiKeysTable({ apiKeys }) {
|
|
|
244
244
|
onClick: () => dispatch({
|
|
245
245
|
type: "SET_PAGINATION",
|
|
246
246
|
pagination: {
|
|
247
|
-
before:
|
|
248
|
-
after:
|
|
247
|
+
before: null,
|
|
248
|
+
after: pagination.after
|
|
249
249
|
}
|
|
250
250
|
}),
|
|
251
251
|
children: /* @__PURE__ */ jsx(Translation, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys-table.js","names":["Button","DropdownMenu.Root","DropdownMenu.Trigger","IconButton","DropdownMenu.Content","DropdownMenu.Item","DropdownMenu.Separator"],"sources":["../../../../src/lib/api-keys/api-keys-table.tsx"],"sourcesContent":["import { Flex, Text, Table, Code, Heading } from \"@radix-ui/themes\";\nimport { Button, DropdownMenu, IconButton } from \"../elements.js\";\nimport { DotsHorizontalIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\nimport { useState } from \"react\";\nimport { RevokeApiKeyDialog } from \"./revoke-api-key-dialog.js\";\nimport { CreateApiKeyButton } from \"./create-api-key.js\";\nimport { ApiKeyDetailsDialog } from \"./api-key-details-dialog.js\";\nimport { RelativeTime } from \"./relative-time.js\";\nimport {\n ListOrganizationApiKeysResponse,\n ListOrganizationApiKeysResponseData,\n} from \"../api/types.js\";\nimport { useApiKeysContext } from \"./api-keys-context.js\";\nimport { useApiKeysSearchContext } from \"./api-keys-search-provider.js\";\nimport { ApiKeysSearch } from \"./api-keys-search.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport { getListMetadata } from \"../utils/get-list-metadata.js\";\nimport {\n ApiKeyExpiresOn,\n EditApiKeyExpirationDialog,\n} from \"./api-key-expiration.js\";\nimport { useExpireApiKey } from \"../api/api-key.js\";\n\nfunction NoApiKeys() {\n const { clearSearch } = useApiKeysSearchContext();\n return (\n <Flex p=\"6\" gap=\"4\" justify=\"center\" align=\"center\" direction=\"column\">\n <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\" align=\"center\">\n <MagnifyingGlassIcon\n style={{ color: \"var(--gray-9)\" }}\n width=\"32px\"\n height=\"32px\"\n />\n <Heading size=\"5\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n <Translation\n defaultMessage=\"No API keys match your search\"\n id=\"cKitHb\"\n description=\"Empty state message when no API keys match search\"\n />\n </Heading>\n </Flex>\n\n <Button variant=\"secondary\" onClick={clearSearch}>\n <Translation\n defaultMessage=\"Clear search\"\n id=\"jTupOW\"\n description=\"Button to clear API key search filters\"\n />\n </Button>\n </Flex>\n );\n}\n\nfunction ApiKeysTableHeader() {\n return (\n <Flex justify=\"between\" align=\"center\">\n <ApiKeysSearch name=\"api-keys-widget-search\" style={{ width: \"390px\" }} />\n <CreateApiKeyButton />\n </Flex>\n );\n}\n\ninterface ApiKeyRowProps {\n apiKey: ListOrganizationApiKeysResponseData;\n}\n\nfunction ApiKeyRow({ apiKey }: ApiKeyRowProps) {\n const [revokeDialogOpen, setRevokeDialogOpen] = useState(false);\n const [detailsOpen, setDetailsOpen] = useState(false);\n const [editExpirationOpen, setEditExpirationOpen] = useState(false);\n const {\n mutate: expireApiKey,\n error: expireError,\n isPending: expirePending,\n isSuccess: expireSuccess,\n reset: resetExpireApiKey,\n } = useExpireApiKey();\n const translate = useTranslation();\n const openEditExpirationDialog = () => {\n resetExpireApiKey();\n setEditExpirationOpen(true);\n };\n return (\n <>\n <RevokeApiKeyDialog\n // always remount the form when the dialog is opened to reset the validation errors\n key={`${revokeDialogOpen}`}\n open={revokeDialogOpen}\n onOpenChange={setRevokeDialogOpen}\n apiKey={apiKey}\n />\n <ApiKeyDetailsDialog\n open={detailsOpen}\n onOpenChange={setDetailsOpen}\n apiKey={apiKey}\n permissions={apiKey.permissions}\n />\n <EditApiKeyExpirationDialog\n open={editExpirationOpen}\n onOpenChange={(open) => {\n if (open) {\n resetExpireApiKey();\n }\n setEditExpirationOpen(open);\n }}\n apiKeyName={apiKey.name}\n expiresAt={apiKey.expiresAt}\n error={expireError}\n isPending={expirePending}\n isSuccess={expireSuccess}\n onReset={resetExpireApiKey}\n onSave={(expiresAt) =>\n expireApiKey(\n { apiKeyId: apiKey.id, expiresAt },\n { onSuccess: () => setEditExpirationOpen(false) },\n )\n }\n />\n <Table.Row align=\"center\">\n <Table.Cell>\n <Text>{apiKey.name}</Text>\n </Table.Cell>\n <Table.Cell>\n <Code color=\"gray\">{apiKey.obfuscatedValue}</Code>\n </Table.Cell>\n <Table.Cell>\n <Text\n style={apiKey.lastUsedAt ? undefined : { color: \"var(--gray-10)\" }}\n >\n <RelativeTime\n date={apiKey.lastUsedAt ? new Date(apiKey.lastUsedAt) : undefined}\n />\n </Text>\n </Table.Cell>\n <Table.Cell>\n <Text>\n <ApiKeyExpiresOn expiresAt={apiKey.expiresAt} includeTime />\n </Text>\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n {(() => {\n const title = translate({\n defaultMessage: \"API key actions\",\n id: \"RIBfYe\",\n description: \"Tooltip for API key actions menu button\",\n });\n return (\n <IconButton title={title}>\n <DotsHorizontalIcon />\n </IconButton>\n );\n })()}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content size=\"2\" align=\"end\">\n <DropdownMenu.Item onSelect={() => setDetailsOpen(true)}>\n <Translation\n defaultMessage=\"View details\"\n id=\"VGKbbj\"\n description=\"Menu item to view API key details\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={openEditExpirationDialog}>\n <Translation\n defaultMessage=\"Edit expiration\"\n id=\"fONrTk\"\n description=\"Menu item to edit an API key expiration\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n variant=\"destructive\"\n onSelect={() => setRevokeDialogOpen(true)}\n >\n <Translation\n defaultMessage=\"Revoke key\"\n id=\"KZIJPP\"\n description=\"Menu item to revoke an API key\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </Table.Cell>\n </Table.Row>\n </>\n );\n}\n\nexport function ApiKeysTable({\n apiKeys,\n}: {\n apiKeys: ListOrganizationApiKeysResponse;\n}) {\n const { dispatch } = useApiKeysContext();\n\n // The API response previously returned an object with the `listMetadata`\n // property. We might not need this, but it's a defensive check until we\n // verify the API response changes are correct.\n const pagination = getListMetadata(apiKeys);\n\n const hasPagination = !!(pagination.before || pagination.after);\n const hasPreviousPage = !!pagination.after;\n const hasNextPage = !!pagination.before;\n\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"3\">\n <ApiKeysTableHeader />\n {apiKeys.data.length === 0 ? (\n <NoApiKeys />\n ) : (\n <>\n <Table.Root variant=\"ghost\" size=\"2\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Name\"\n id=\"VYbVXN\"\n description=\"Table column header for API key name\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Secret key\"\n id=\"H5k7GB\"\n description=\"Table column header for API key secret value\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Last used\"\n id=\"E46t3O\"\n description=\"Table column header for API key last used timestamp\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Expires\"\n id=\"3q8EjA\"\n description=\"Table column header for API key expiration date\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {apiKeys.data.map((apiKey) => (\n <ApiKeyRow key={apiKey.id} apiKey={apiKey} />\n ))}\n </Table.Body>\n </Table.Root>\n {hasPagination && (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n disabled={!hasPreviousPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: null, after: pagination.after },\n })\n }\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"f7TUj0\"\n description=\"Button to navigate to previous page of API keys\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n disabled={!hasNextPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n })\n }\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2EBxV\"\n description=\"Button to navigate to next page of API keys\"\n />\n </Button>\n </Flex>\n )}\n </>\n )}\n </Flex>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-keys-table.js","names":["Button","DropdownMenu.Root","DropdownMenu.Trigger","IconButton","DropdownMenu.Content","DropdownMenu.Item","DropdownMenu.Separator"],"sources":["../../../../src/lib/api-keys/api-keys-table.tsx"],"sourcesContent":["import { Flex, Text, Table, Code, Heading } from \"@radix-ui/themes\";\nimport { Button, DropdownMenu, IconButton } from \"../elements.js\";\nimport { DotsHorizontalIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\nimport { useState } from \"react\";\nimport { RevokeApiKeyDialog } from \"./revoke-api-key-dialog.js\";\nimport { CreateApiKeyButton } from \"./create-api-key.js\";\nimport { ApiKeyDetailsDialog } from \"./api-key-details-dialog.js\";\nimport { RelativeTime } from \"./relative-time.js\";\nimport {\n ListOrganizationApiKeysResponse,\n ListOrganizationApiKeysResponseData,\n} from \"../api/types.js\";\nimport { useApiKeysContext } from \"./api-keys-context.js\";\nimport { useApiKeysSearchContext } from \"./api-keys-search-provider.js\";\nimport { ApiKeysSearch } from \"./api-keys-search.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport { getListMetadata } from \"../utils/get-list-metadata.js\";\nimport {\n ApiKeyExpiresOn,\n EditApiKeyExpirationDialog,\n} from \"./api-key-expiration.js\";\nimport { useExpireApiKey } from \"../api/api-key.js\";\n\nfunction NoApiKeys() {\n const { clearSearch } = useApiKeysSearchContext();\n return (\n <Flex p=\"6\" gap=\"4\" justify=\"center\" align=\"center\" direction=\"column\">\n <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\" align=\"center\">\n <MagnifyingGlassIcon\n style={{ color: \"var(--gray-9)\" }}\n width=\"32px\"\n height=\"32px\"\n />\n <Heading size=\"5\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n <Translation\n defaultMessage=\"No API keys match your search\"\n id=\"cKitHb\"\n description=\"Empty state message when no API keys match search\"\n />\n </Heading>\n </Flex>\n\n <Button variant=\"secondary\" onClick={clearSearch}>\n <Translation\n defaultMessage=\"Clear search\"\n id=\"jTupOW\"\n description=\"Button to clear API key search filters\"\n />\n </Button>\n </Flex>\n );\n}\n\nfunction ApiKeysTableHeader() {\n return (\n <Flex justify=\"between\" align=\"center\">\n <ApiKeysSearch name=\"api-keys-widget-search\" style={{ width: \"390px\" }} />\n <CreateApiKeyButton />\n </Flex>\n );\n}\n\ninterface ApiKeyRowProps {\n apiKey: ListOrganizationApiKeysResponseData;\n}\n\nfunction ApiKeyRow({ apiKey }: ApiKeyRowProps) {\n const [revokeDialogOpen, setRevokeDialogOpen] = useState(false);\n const [detailsOpen, setDetailsOpen] = useState(false);\n const [editExpirationOpen, setEditExpirationOpen] = useState(false);\n const {\n mutate: expireApiKey,\n error: expireError,\n isPending: expirePending,\n isSuccess: expireSuccess,\n reset: resetExpireApiKey,\n } = useExpireApiKey();\n const translate = useTranslation();\n const openEditExpirationDialog = () => {\n resetExpireApiKey();\n setEditExpirationOpen(true);\n };\n return (\n <>\n <RevokeApiKeyDialog\n // always remount the form when the dialog is opened to reset the validation errors\n key={`${revokeDialogOpen}`}\n open={revokeDialogOpen}\n onOpenChange={setRevokeDialogOpen}\n apiKey={apiKey}\n />\n <ApiKeyDetailsDialog\n open={detailsOpen}\n onOpenChange={setDetailsOpen}\n apiKey={apiKey}\n permissions={apiKey.permissions}\n />\n <EditApiKeyExpirationDialog\n open={editExpirationOpen}\n onOpenChange={(open) => {\n if (open) {\n resetExpireApiKey();\n }\n setEditExpirationOpen(open);\n }}\n apiKeyName={apiKey.name}\n expiresAt={apiKey.expiresAt}\n error={expireError}\n isPending={expirePending}\n isSuccess={expireSuccess}\n onReset={resetExpireApiKey}\n onSave={(expiresAt) =>\n expireApiKey(\n { apiKeyId: apiKey.id, expiresAt },\n { onSuccess: () => setEditExpirationOpen(false) },\n )\n }\n />\n <Table.Row align=\"center\">\n <Table.Cell>\n <Text>{apiKey.name}</Text>\n </Table.Cell>\n <Table.Cell>\n <Code color=\"gray\">{apiKey.obfuscatedValue}</Code>\n </Table.Cell>\n <Table.Cell>\n <Text\n style={apiKey.lastUsedAt ? undefined : { color: \"var(--gray-10)\" }}\n >\n <RelativeTime\n date={apiKey.lastUsedAt ? new Date(apiKey.lastUsedAt) : undefined}\n />\n </Text>\n </Table.Cell>\n <Table.Cell>\n <Text>\n <ApiKeyExpiresOn expiresAt={apiKey.expiresAt} includeTime />\n </Text>\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n {(() => {\n const title = translate({\n defaultMessage: \"API key actions\",\n id: \"RIBfYe\",\n description: \"Tooltip for API key actions menu button\",\n });\n return (\n <IconButton title={title}>\n <DotsHorizontalIcon />\n </IconButton>\n );\n })()}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content size=\"2\" align=\"end\">\n <DropdownMenu.Item onSelect={() => setDetailsOpen(true)}>\n <Translation\n defaultMessage=\"View details\"\n id=\"VGKbbj\"\n description=\"Menu item to view API key details\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={openEditExpirationDialog}>\n <Translation\n defaultMessage=\"Edit expiration\"\n id=\"fONrTk\"\n description=\"Menu item to edit an API key expiration\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n variant=\"destructive\"\n onSelect={() => setRevokeDialogOpen(true)}\n >\n <Translation\n defaultMessage=\"Revoke key\"\n id=\"KZIJPP\"\n description=\"Menu item to revoke an API key\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </Table.Cell>\n </Table.Row>\n </>\n );\n}\n\nexport function ApiKeysTable({\n apiKeys,\n}: {\n apiKeys: ListOrganizationApiKeysResponse;\n}) {\n const { dispatch } = useApiKeysContext();\n\n // The API response previously returned an object with the `listMetadata`\n // property. We might not need this, but it's a defensive check until we\n // verify the API response changes are correct.\n const pagination = getListMetadata(apiKeys);\n\n const hasPagination = !!(pagination.before || pagination.after);\n const hasPreviousPage = !!pagination.before;\n const hasNextPage = !!pagination.after;\n\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"3\">\n <ApiKeysTableHeader />\n {apiKeys.data.length === 0 ? (\n <NoApiKeys />\n ) : (\n <>\n <Table.Root variant=\"ghost\" size=\"2\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Name\"\n id=\"VYbVXN\"\n description=\"Table column header for API key name\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Secret key\"\n id=\"H5k7GB\"\n description=\"Table column header for API key secret value\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Last used\"\n id=\"E46t3O\"\n description=\"Table column header for API key last used timestamp\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"25%\">\n <Translation\n defaultMessage=\"Expires\"\n id=\"3q8EjA\"\n description=\"Table column header for API key expiration date\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {apiKeys.data.map((apiKey) => (\n <ApiKeyRow key={apiKey.id} apiKey={apiKey} />\n ))}\n </Table.Body>\n </Table.Root>\n {hasPagination && (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n disabled={!hasPreviousPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n })\n }\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"f7TUj0\"\n description=\"Button to navigate to previous page of API keys\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n disabled={!hasNextPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: null, after: pagination.after },\n })\n }\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2EBxV\"\n description=\"Button to navigate to next page of API keys\"\n />\n </Button>\n </Flex>\n )}\n </>\n )}\n </Flex>\n );\n}\n"],"mappings":"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"}
|
|
@@ -176,8 +176,8 @@ function UserApiKeysTable({ apiKeys, canCreate, canManageAll }) {
|
|
|
176
176
|
const { dispatch } = useUserApiKeysContext();
|
|
177
177
|
const pagination = getListMetadata(apiKeys);
|
|
178
178
|
const hasPagination = !!(pagination.before || pagination.after);
|
|
179
|
-
const hasPreviousPage = !!pagination.
|
|
180
|
-
const hasNextPage = !!pagination.
|
|
179
|
+
const hasPreviousPage = !!pagination.before;
|
|
180
|
+
const hasNextPage = !!pagination.after;
|
|
181
181
|
return /* @__PURE__ */ jsxs(Flex, {
|
|
182
182
|
direction: "column",
|
|
183
183
|
align: "stretch",
|
|
@@ -241,8 +241,8 @@ function UserApiKeysTable({ apiKeys, canCreate, canManageAll }) {
|
|
|
241
241
|
onClick: () => dispatch({
|
|
242
242
|
type: "SET_PAGINATION",
|
|
243
243
|
pagination: {
|
|
244
|
-
before:
|
|
245
|
-
after:
|
|
244
|
+
before: pagination.before,
|
|
245
|
+
after: null
|
|
246
246
|
}
|
|
247
247
|
}),
|
|
248
248
|
children: /* @__PURE__ */ jsx(Translation, {
|
|
@@ -257,8 +257,8 @@ function UserApiKeysTable({ apiKeys, canCreate, canManageAll }) {
|
|
|
257
257
|
onClick: () => dispatch({
|
|
258
258
|
type: "SET_PAGINATION",
|
|
259
259
|
pagination: {
|
|
260
|
-
before:
|
|
261
|
-
after:
|
|
260
|
+
before: null,
|
|
261
|
+
after: pagination.after
|
|
262
262
|
}
|
|
263
263
|
}),
|
|
264
264
|
children: /* @__PURE__ */ jsx(Translation, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-api-keys-table.js","names":["Button","DropdownMenu.Root","DropdownMenu.Trigger","IconButton","DropdownMenu.Content","DropdownMenu.Item","DropdownMenu.Separator"],"sources":["../../../../src/lib/user-api-keys/user-api-keys-table.tsx"],"sourcesContent":["import { Flex, Text, Table, Code, Heading } from \"@radix-ui/themes\";\nimport { Button, DropdownMenu, IconButton } from \"../elements.js\";\nimport { DotsHorizontalIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\nimport { useState } from \"react\";\nimport { RevokeUserApiKeyDialog } from \"./revoke-user-api-key-dialog.js\";\nimport { CreateUserApiKeyButton } from \"./create-user-api-key.js\";\nimport { UserApiKeyDetailsDialog } from \"./user-api-key-details-dialog.js\";\nimport { RelativeTime } from \"../api-keys/relative-time.js\";\nimport type {\n ListUserApiKeysResponse,\n ListUserApiKeysResponseData,\n} from \"../api/user-api-key.js\";\nimport { useUserApiKeysContext } from \"./user-api-keys-context.js\";\nimport { useUserApiKeysSearchContext } from \"./user-api-keys-search-provider.js\";\nimport { UserApiKeysSearch } from \"./user-api-keys-search.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport { getListMetadata } from \"../utils/get-list-metadata.js\";\nimport {\n ApiKeyExpiresOn,\n EditApiKeyExpirationDialog,\n} from \"../api-keys/api-key-expiration.js\";\nimport { useExpireUserApiKey } from \"../api/user-api-key.js\";\nimport { getUserApiKeyCreatedByLabel } from \"./user-api-key-owner.js\";\n\nfunction NoUserApiKeys() {\n const { clearSearch } = useUserApiKeysSearchContext();\n return (\n <Flex p=\"6\" gap=\"4\" justify=\"center\" align=\"center\" direction=\"column\">\n <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\" align=\"center\">\n <MagnifyingGlassIcon\n style={{ color: \"var(--gray-9)\" }}\n width=\"32px\"\n height=\"32px\"\n />\n <Heading size=\"5\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n <Translation\n defaultMessage=\"No API keys match your search\"\n id=\"cKitHb\"\n description=\"Empty state message when no API keys match search\"\n />\n </Heading>\n </Flex>\n\n <Button variant=\"secondary\" onClick={clearSearch}>\n <Translation\n defaultMessage=\"Clear search\"\n id=\"jTupOW\"\n description=\"Button to clear API key search filters\"\n />\n </Button>\n </Flex>\n );\n}\n\nfunction UserApiKeysTableHeader({ canCreate }: { canCreate: boolean }) {\n return (\n <Flex justify=\"between\" align=\"center\">\n <UserApiKeysSearch\n name=\"user-api-keys-widget-search\"\n style={{ width: \"390px\" }}\n />\n <CreateUserApiKeyButton canCreate={canCreate} />\n </Flex>\n );\n}\n\ninterface UserApiKeyRowProps {\n apiKey: ListUserApiKeysResponseData;\n canManageAll: boolean;\n}\n\nfunction UserApiKeyRow({ apiKey, canManageAll }: UserApiKeyRowProps) {\n const [revokeDialogOpen, setRevokeDialogOpen] = useState(false);\n const [detailsOpen, setDetailsOpen] = useState(false);\n const [editExpirationOpen, setEditExpirationOpen] = useState(false);\n const {\n mutate: expireUserApiKey,\n error: expireError,\n isPending: expirePending,\n isSuccess: expireSuccess,\n reset: resetExpireUserApiKey,\n } = useExpireUserApiKey();\n const translate = useTranslation();\n const openEditExpirationDialog = () => {\n resetExpireUserApiKey();\n setEditExpirationOpen(true);\n };\n return (\n <>\n <RevokeUserApiKeyDialog\n key={`${revokeDialogOpen}`}\n open={revokeDialogOpen}\n onOpenChange={setRevokeDialogOpen}\n apiKey={apiKey}\n />\n <UserApiKeyDetailsDialog\n open={detailsOpen}\n onOpenChange={setDetailsOpen}\n apiKey={apiKey}\n permissions={apiKey.permissions}\n />\n <EditApiKeyExpirationDialog\n open={editExpirationOpen}\n onOpenChange={(open) => {\n if (open) {\n resetExpireUserApiKey();\n }\n setEditExpirationOpen(open);\n }}\n apiKeyName={apiKey.name}\n expiresAt={apiKey.expiresAt}\n error={expireError}\n isPending={expirePending}\n isSuccess={expireSuccess}\n onReset={resetExpireUserApiKey}\n onSave={(expiresAt) =>\n expireUserApiKey(\n { apiKeyId: apiKey.id, expiresAt },\n { onSuccess: () => setEditExpirationOpen(false) },\n )\n }\n />\n <Table.Row align=\"center\">\n <Table.Cell>\n <Text>{apiKey.name}</Text>\n </Table.Cell>\n <Table.Cell>\n <Code color=\"gray\">{apiKey.obfuscatedValue}</Code>\n </Table.Cell>\n {canManageAll ? (\n <Table.Cell>\n <Text>{getUserApiKeyCreatedByLabel(apiKey)}</Text>\n </Table.Cell>\n ) : null}\n <Table.Cell>\n <Text\n style={apiKey.lastUsedAt ? undefined : { color: \"var(--gray-10)\" }}\n >\n <RelativeTime\n date={apiKey.lastUsedAt ? new Date(apiKey.lastUsedAt) : undefined}\n />\n </Text>\n </Table.Cell>\n <Table.Cell>\n <Text>\n <ApiKeyExpiresOn expiresAt={apiKey.expiresAt} includeTime />\n </Text>\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n {(() => {\n const title = translate({\n defaultMessage: \"API key actions\",\n id: \"RIBfYe\",\n description: \"Tooltip for API key actions menu button\",\n });\n return (\n <IconButton title={title}>\n <DotsHorizontalIcon />\n </IconButton>\n );\n })()}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content size=\"2\" align=\"end\">\n <DropdownMenu.Item onSelect={() => setDetailsOpen(true)}>\n <Translation\n defaultMessage=\"View details\"\n id=\"VGKbbj\"\n description=\"Menu item to view API key details\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={openEditExpirationDialog}>\n <Translation\n defaultMessage=\"Edit expiration\"\n id=\"fONrTk\"\n description=\"Menu item to edit an API key expiration\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n variant=\"destructive\"\n onSelect={() => setRevokeDialogOpen(true)}\n >\n <Translation\n defaultMessage=\"Revoke key\"\n id=\"KZIJPP\"\n description=\"Menu item to revoke an API key\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </Table.Cell>\n </Table.Row>\n </>\n );\n}\n\nexport function UserApiKeysTable({\n apiKeys,\n canCreate,\n canManageAll,\n}: {\n apiKeys: ListUserApiKeysResponse;\n canCreate: boolean;\n canManageAll: boolean;\n}) {\n const { dispatch } = useUserApiKeysContext();\n const pagination = getListMetadata(apiKeys);\n\n const hasPagination = !!(pagination.before || pagination.after);\n const hasPreviousPage = !!pagination.after;\n const hasNextPage = !!pagination.before;\n\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"3\">\n <UserApiKeysTableHeader canCreate={canCreate} />\n {apiKeys.data.length === 0 ? (\n <NoUserApiKeys />\n ) : (\n <>\n <Table.Root variant=\"ghost\" size=\"2\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Name\"\n id=\"VYbVXN\"\n description=\"Table column header for API key name\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Secret key\"\n id=\"H5k7GB\"\n description=\"Table column header for API key secret value\"\n />\n </Table.ColumnHeaderCell>\n {canManageAll ? (\n <Table.ColumnHeaderCell width=\"20%\">\n <Translation\n defaultMessage=\"Created by\"\n id=\"en10bZ\"\n description=\"Table column header for API key creator\"\n />\n </Table.ColumnHeaderCell>\n ) : null}\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Last used\"\n id=\"E46t3O\"\n description=\"Table column header for API key last used timestamp\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Expires\"\n id=\"3q8EjA\"\n description=\"Table column header for API key expiration date\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {apiKeys.data.map((apiKey) => (\n <UserApiKeyRow\n key={apiKey.id}\n apiKey={apiKey}\n canManageAll={canManageAll}\n />\n ))}\n </Table.Body>\n </Table.Root>\n {hasPagination && (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n disabled={!hasPreviousPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: null, after: pagination.after },\n })\n }\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"f7TUj0\"\n description=\"Button to navigate to previous page of API keys\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n disabled={!hasNextPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n })\n }\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2EBxV\"\n description=\"Button to navigate to next page of API keys\"\n />\n </Button>\n </Flex>\n )}\n </>\n )}\n </Flex>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"user-api-keys-table.js","names":["Button","DropdownMenu.Root","DropdownMenu.Trigger","IconButton","DropdownMenu.Content","DropdownMenu.Item","DropdownMenu.Separator"],"sources":["../../../../src/lib/user-api-keys/user-api-keys-table.tsx"],"sourcesContent":["import { Flex, Text, Table, Code, Heading } from \"@radix-ui/themes\";\nimport { Button, DropdownMenu, IconButton } from \"../elements.js\";\nimport { DotsHorizontalIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\nimport { useState } from \"react\";\nimport { RevokeUserApiKeyDialog } from \"./revoke-user-api-key-dialog.js\";\nimport { CreateUserApiKeyButton } from \"./create-user-api-key.js\";\nimport { UserApiKeyDetailsDialog } from \"./user-api-key-details-dialog.js\";\nimport { RelativeTime } from \"../api-keys/relative-time.js\";\nimport type {\n ListUserApiKeysResponse,\n ListUserApiKeysResponseData,\n} from \"../api/user-api-key.js\";\nimport { useUserApiKeysContext } from \"./user-api-keys-context.js\";\nimport { useUserApiKeysSearchContext } from \"./user-api-keys-search-provider.js\";\nimport { UserApiKeysSearch } from \"./user-api-keys-search.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport { getListMetadata } from \"../utils/get-list-metadata.js\";\nimport {\n ApiKeyExpiresOn,\n EditApiKeyExpirationDialog,\n} from \"../api-keys/api-key-expiration.js\";\nimport { useExpireUserApiKey } from \"../api/user-api-key.js\";\nimport { getUserApiKeyCreatedByLabel } from \"./user-api-key-owner.js\";\n\nfunction NoUserApiKeys() {\n const { clearSearch } = useUserApiKeysSearchContext();\n return (\n <Flex p=\"6\" gap=\"4\" justify=\"center\" align=\"center\" direction=\"column\">\n <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\" align=\"center\">\n <MagnifyingGlassIcon\n style={{ color: \"var(--gray-9)\" }}\n width=\"32px\"\n height=\"32px\"\n />\n <Heading size=\"5\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n <Translation\n defaultMessage=\"No API keys match your search\"\n id=\"cKitHb\"\n description=\"Empty state message when no API keys match search\"\n />\n </Heading>\n </Flex>\n\n <Button variant=\"secondary\" onClick={clearSearch}>\n <Translation\n defaultMessage=\"Clear search\"\n id=\"jTupOW\"\n description=\"Button to clear API key search filters\"\n />\n </Button>\n </Flex>\n );\n}\n\nfunction UserApiKeysTableHeader({ canCreate }: { canCreate: boolean }) {\n return (\n <Flex justify=\"between\" align=\"center\">\n <UserApiKeysSearch\n name=\"user-api-keys-widget-search\"\n style={{ width: \"390px\" }}\n />\n <CreateUserApiKeyButton canCreate={canCreate} />\n </Flex>\n );\n}\n\ninterface UserApiKeyRowProps {\n apiKey: ListUserApiKeysResponseData;\n canManageAll: boolean;\n}\n\nfunction UserApiKeyRow({ apiKey, canManageAll }: UserApiKeyRowProps) {\n const [revokeDialogOpen, setRevokeDialogOpen] = useState(false);\n const [detailsOpen, setDetailsOpen] = useState(false);\n const [editExpirationOpen, setEditExpirationOpen] = useState(false);\n const {\n mutate: expireUserApiKey,\n error: expireError,\n isPending: expirePending,\n isSuccess: expireSuccess,\n reset: resetExpireUserApiKey,\n } = useExpireUserApiKey();\n const translate = useTranslation();\n const openEditExpirationDialog = () => {\n resetExpireUserApiKey();\n setEditExpirationOpen(true);\n };\n return (\n <>\n <RevokeUserApiKeyDialog\n key={`${revokeDialogOpen}`}\n open={revokeDialogOpen}\n onOpenChange={setRevokeDialogOpen}\n apiKey={apiKey}\n />\n <UserApiKeyDetailsDialog\n open={detailsOpen}\n onOpenChange={setDetailsOpen}\n apiKey={apiKey}\n permissions={apiKey.permissions}\n />\n <EditApiKeyExpirationDialog\n open={editExpirationOpen}\n onOpenChange={(open) => {\n if (open) {\n resetExpireUserApiKey();\n }\n setEditExpirationOpen(open);\n }}\n apiKeyName={apiKey.name}\n expiresAt={apiKey.expiresAt}\n error={expireError}\n isPending={expirePending}\n isSuccess={expireSuccess}\n onReset={resetExpireUserApiKey}\n onSave={(expiresAt) =>\n expireUserApiKey(\n { apiKeyId: apiKey.id, expiresAt },\n { onSuccess: () => setEditExpirationOpen(false) },\n )\n }\n />\n <Table.Row align=\"center\">\n <Table.Cell>\n <Text>{apiKey.name}</Text>\n </Table.Cell>\n <Table.Cell>\n <Code color=\"gray\">{apiKey.obfuscatedValue}</Code>\n </Table.Cell>\n {canManageAll ? (\n <Table.Cell>\n <Text>{getUserApiKeyCreatedByLabel(apiKey)}</Text>\n </Table.Cell>\n ) : null}\n <Table.Cell>\n <Text\n style={apiKey.lastUsedAt ? undefined : { color: \"var(--gray-10)\" }}\n >\n <RelativeTime\n date={apiKey.lastUsedAt ? new Date(apiKey.lastUsedAt) : undefined}\n />\n </Text>\n </Table.Cell>\n <Table.Cell>\n <Text>\n <ApiKeyExpiresOn expiresAt={apiKey.expiresAt} includeTime />\n </Text>\n </Table.Cell>\n <Table.Cell justify=\"end\">\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n {(() => {\n const title = translate({\n defaultMessage: \"API key actions\",\n id: \"RIBfYe\",\n description: \"Tooltip for API key actions menu button\",\n });\n return (\n <IconButton title={title}>\n <DotsHorizontalIcon />\n </IconButton>\n );\n })()}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content size=\"2\" align=\"end\">\n <DropdownMenu.Item onSelect={() => setDetailsOpen(true)}>\n <Translation\n defaultMessage=\"View details\"\n id=\"VGKbbj\"\n description=\"Menu item to view API key details\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={openEditExpirationDialog}>\n <Translation\n defaultMessage=\"Edit expiration\"\n id=\"fONrTk\"\n description=\"Menu item to edit an API key expiration\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n variant=\"destructive\"\n onSelect={() => setRevokeDialogOpen(true)}\n >\n <Translation\n defaultMessage=\"Revoke key\"\n id=\"KZIJPP\"\n description=\"Menu item to revoke an API key\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </Table.Cell>\n </Table.Row>\n </>\n );\n}\n\nexport function UserApiKeysTable({\n apiKeys,\n canCreate,\n canManageAll,\n}: {\n apiKeys: ListUserApiKeysResponse;\n canCreate: boolean;\n canManageAll: boolean;\n}) {\n const { dispatch } = useUserApiKeysContext();\n const pagination = getListMetadata(apiKeys);\n\n const hasPagination = !!(pagination.before || pagination.after);\n const hasPreviousPage = !!pagination.before;\n const hasNextPage = !!pagination.after;\n\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"3\">\n <UserApiKeysTableHeader canCreate={canCreate} />\n {apiKeys.data.length === 0 ? (\n <NoUserApiKeys />\n ) : (\n <>\n <Table.Root variant=\"ghost\" size=\"2\">\n <Table.Header>\n <Table.Row>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Name\"\n id=\"VYbVXN\"\n description=\"Table column header for API key name\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Secret key\"\n id=\"H5k7GB\"\n description=\"Table column header for API key secret value\"\n />\n </Table.ColumnHeaderCell>\n {canManageAll ? (\n <Table.ColumnHeaderCell width=\"20%\">\n <Translation\n defaultMessage=\"Created by\"\n id=\"en10bZ\"\n description=\"Table column header for API key creator\"\n />\n </Table.ColumnHeaderCell>\n ) : null}\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Last used\"\n id=\"E46t3O\"\n description=\"Table column header for API key last used timestamp\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width={canManageAll ? \"20%\" : \"25%\"}>\n <Translation\n defaultMessage=\"Expires\"\n id=\"3q8EjA\"\n description=\"Table column header for API key expiration date\"\n />\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"28px\" />\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {apiKeys.data.map((apiKey) => (\n <UserApiKeyRow\n key={apiKey.id}\n apiKey={apiKey}\n canManageAll={canManageAll}\n />\n ))}\n </Table.Body>\n </Table.Root>\n {hasPagination && (\n <Flex gap=\"2\" justify=\"end\">\n <Button\n variant=\"secondary\"\n disabled={!hasPreviousPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: pagination.before, after: null },\n })\n }\n >\n <Translation\n defaultMessage=\"Previous\"\n id=\"f7TUj0\"\n description=\"Button to navigate to previous page of API keys\"\n />\n </Button>\n <Button\n variant=\"secondary\"\n disabled={!hasNextPage}\n size=\"1\"\n onClick={() =>\n dispatch({\n type: \"SET_PAGINATION\",\n pagination: { before: null, after: pagination.after },\n })\n }\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2EBxV\"\n description=\"Button to navigate to next page of API keys\"\n />\n </Button>\n </Flex>\n )}\n </>\n )}\n </Flex>\n );\n}\n"],"mappings":"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"}
|
|
@@ -202,14 +202,14 @@ const UsersManagement = ({ userData, rolesData, isPending, disableRolesFilter, .
|
|
|
202
202
|
children: [/* @__PURE__ */ jsx(Button$1, {
|
|
203
203
|
variant: "secondary",
|
|
204
204
|
size: "1",
|
|
205
|
-
disabled: !pagination.
|
|
205
|
+
disabled: !pagination.before || isPending || void 0,
|
|
206
206
|
loading: deferredLoading,
|
|
207
207
|
onClick: () => {
|
|
208
|
-
if (pagination.
|
|
208
|
+
if (pagination.before) dispatch({
|
|
209
209
|
type: "SET_PAGINATION",
|
|
210
210
|
pagination: {
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
before: pagination.before,
|
|
212
|
+
after: null
|
|
213
213
|
}
|
|
214
214
|
});
|
|
215
215
|
},
|
|
@@ -221,14 +221,14 @@ const UsersManagement = ({ userData, rolesData, isPending, disableRolesFilter, .
|
|
|
221
221
|
}), /* @__PURE__ */ jsx(Button$1, {
|
|
222
222
|
variant: "secondary",
|
|
223
223
|
size: "1",
|
|
224
|
-
disabled: !pagination.
|
|
224
|
+
disabled: !pagination.after || isPending || void 0,
|
|
225
225
|
loading: deferredLoading,
|
|
226
226
|
onClick: () => {
|
|
227
|
-
if (pagination.
|
|
227
|
+
if (pagination.after) dispatch({
|
|
228
228
|
type: "SET_PAGINATION",
|
|
229
229
|
pagination: {
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
after: pagination.after,
|
|
231
|
+
before: null
|
|
232
232
|
}
|
|
233
233
|
});
|
|
234
234
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users-management.js","names":["Button","Avatar","IconButton","Skeleton","TextField","Select.Root","Select.Trigger","Select.Content","Select.Item","Badge"],"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 { getBestName } from \"./utils/get-best-name.js\";\nimport { getWidgetDomProps } from \"./utils/widget-dom-props.js\";\nimport { getListMetadata } from \"./utils/get-list-metadata.js\";\nimport { WidgetRootState, type WidgetRootDomProps } from \"./widget-types.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 getWidgetDomProps({\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":";;;;;;;;;;;;;;;;;;;;;;;;AAmDA,MAAM,mBAAmD,EACvD,UACA,WACA,WACA,oBACA,GAAG,eACC;CACJ,MAAM,QAAQ,UAAU,QAAQ,CAAC;CACjC,MAAM,aAAa,OAAO,UAAU;CACpC,MAAM,aAAa,cAAc;CACjC,MAAM,aAAa,gBAAgB,QAAQ;CAE3C,MAAM,EAAE,aAAa,0BAA0B;CAC/C,MAAM,yBAAyB,UAAU;CACzC,MAAM,YAAY,eAAe;CAKjC,MAAM,CAAC,iBAAiB,sBAAsB,MAAM,SAAS,KAAK;CAClE,MAAM,gBAAgB;EACpB,IAAI,WAAW;GACb,MAAM,YAAY,OAAO,iBAAiB;IACxC,mBAAmB,IAAI;GACzB,GAAG,GAAG;GACN,aAAa;IACX,OAAO,aAAa,SAAS;GAC/B;EACF,OAGE,mBAAmB,KAAK;CAE5B,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,iBAAiB,CAAC,EAAE,WAAW,UAAU,WAAW;CAE1D,OACE,oBAAC,gBAAD,EAAA,UACE,qBAAC,MAAD;EACE,WAAU;EACV,KAAI;EACJ,GAAI,sBAAsB,YAAY,QAAQ;EAHhD,UAAA;GAKE,qBAAC,MAAD;IAAM,SAAQ;IAAW,KAAI;IAA7B,UAAA,CACE,qBAAC,MAAD;KAAM,KAAI;KAAI,OAAM;KAApB,UAAA,CACE,oBAAC,KAAD;MAAK,WAAU;MAAQ,UAAS;MAAI,YAAW;MAC7C,UAAA,oBAAC,aAAD,CAAc,CAAA;KACX,CAAA,GACL,oBAAC,KAAD;MAAK,UAAS;MAAI,YAAW;MAC3B,UAAA,oBAAC,aAAD;OACE,OAAO,UAAU;OACjB,UAAU;MACX,CAAA;KACE,CAAA,CACD;IACN,CAAA,GAAA,oBAAC,KAAD;KAAK,UAAS;KAAI,YAAW;KAAI,OAAO,EAAE,WAAW,WAAW;KAC9D,UAAA,oBAAC,kBAAD,EAAA,UACE,oBAACA,UAAD,EAAA,UACE,oBAAC,aAAD;MACE,gBAAe;MACf,IAAG;MACH,aAAY;KACb,CAAA,EACK,CAAA,EACQ,CAAA;IACf,CAAA,CACD;;GACN,qBAAC,MAAM,MAAP;IAAY,SAAQ;IAAQ,MAAK;IAAjC,UAAA,CACE,oBAAC,MAAM,QAAP,EAAA,UACE,qBAAC,MAAM,KAAP,EAAA,UAAA;KACE,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC5B,UAAA,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA;KACqB,CAAA;KACxB,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC3B,UAAA,yBACC,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA,IAED,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA;KAEmB,CAAA;KACxB,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC5B,UAAA,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA;KACqB,CAAA;KACxB,oBAAC,MAAM,kBAAP,EAAwB,OAAM,OAAQ,CAAA;IAC7B,EAAA,CAAA,EACC,CAAA,GAEd,oBAAC,MAAM,MAAP;KACE,OAAO;MACL,YAAY,yBAAyB,YAAY,SAAS;MAC1D,SAAS,aAAa,aAAa,IAAI,KAAM;KAC/C;KAEC,UAAA,MAAM,SAAS,IACd,MAAM,KAAK,SAAS;MAClB,MAAM,kBAAkB,YAAY,IAAI;MACxC,MAAM,UACJ,KAAK,WAAW,mBAChB,KAAK,WAAW;MAClB,OACE,qBAAC,MAAM,KAAP;OAAyB,OAAM;OAA/B,UAAA;QACE,oBAAC,MAAM,eAAP,EAAA,UACE,qBAAC,MAAD;SACE,OAAM;SACN,KAAI;SACJ,UAAS;SACT,QAAO;SAJT,UAAA,CAME,oBAACC,UAAD;UACE,MAAK;UACL,UAAU,oBAAC,kBAAD,CAAmB,CAAA;UAC7B,KAAK,KAAK,qBAAqB;UAC/B,KAAK;SACN,CAAA,GAEA,kBACC,qBAAC,MAAD;UACE,WAAU;UACV,OAAM;UACN,QAAO;UACP,SAAQ;UACR,UAAS;UALX,UAAA,CAOE,qBAAC,MAAD;WAAM,KAAI;WAAI,OAAM;WAAS,UAAS;WAAtC,UAAA,CACE,oBAAC,eAAD;YAAe,KAAK;YACjB,UAAA;WACY,CAAA,GACf,oBAAC,WAAD,EAAiB,KAAO,CAAA,CACpB;UACN,CAAA,GAAA,oBAAC,eAAD;WACE,OAAM;WACN,OAAO,KAAK;WACZ,KAAK;WAEJ,UAAA,KAAK;UACO,CAAA,CACX;SAEN,CAAA,IAAA,qBAAC,MAAD;UAAM,KAAI;UAAI,OAAM;UAAS,UAAS;UAAtC,UAAA,CACE,oBAAC,eAAD;WAAe,KAAK;WAAS,OAAO,KAAK;WACtC,UAAA,KAAK;UACO,CAAA,GACf,oBAAC,WAAD,EAAiB,KAAO,CAAA,CACpB;SAEJ,CAAA,CAAA;QACa,CAAA,EAAA,CAAA;QACrB,oBAAC,MAAM,MAAP,EAAA,UACE,oBAAC,sBAAD;SACQ;SACkB;SACf;QACV,CAAA,EACS,CAAA;QACZ,oBAAC,MAAM,MAAP,EAAA,UACE,oBAAC,YAAD;SAAkB;SAAkB;QAAa,CAAA,EACvC,CAAA;QACZ,oBAAC,MAAM,MAAP;SAAY,SAAQ;SAClB,UAAA,oBAAC,qBAAD;UAA2B;UACzB,UAAA,oBAACC,cAAD;WACE,OAAO,UAAU;YACf,gBAAgB;YAChB,IAAI;YACJ,aACE;WACJ,CAAC;WAED,UAAA,oBAAC,oBAAD,CAAqB,CAAA;UACX,CAAA;SACO,CAAA;QACX,CAAA;OACH;MAvEK,GAAA,KAAK,EAuEV;KAEf,CAAC,IAED,oBAAC,MAAM,KAAP;MAAW,OAAM;MACf,UAAA,oBAAC,MAAM,MAAP;OAAY,SAAS;OACnB,UAAA,oBAAC,2BAAD,EAAsC,UAAY,CAAA;MACxC,CAAA;KACH,CAAA;IAEH,CAAA,CACF;;GAEX,iBACC,qBAAC,MAAD;IAAM,KAAI;IAAI,SAAQ;IAAtB,UAAA,CACE,oBAACF,UAAD;KACE,SAAQ;KACR,MAAK;KACL,UAAU,CAAC,WAAW,SAAS,aAAa;KAC5C,SAAS;KACT,eAAe;MACb,IAAI,WAAW,OACb,SAAS;OACP,MAAM;OACN,YAAY;QAAE,OAAO,WAAW;QAAO,QAAQ;OAAK;MACtD,CAAC;KAEL;KAEA,UAAA,oBAAC,aAAD;MACE,gBAAe;MACf,IAAG;MACH,aAAY;KACb,CAAA;IACK,CAAA,GACR,oBAACA,UAAD;KACE,SAAQ;KACR,MAAK;KACL,UAAU,CAAC,WAAW,UAAU,aAAa;KAC7C,SAAS;KACT,eAAe;MACb,IAAI,WAAW,QACb,SAAS;OACP,MAAM;OACN,YAAY;QAAE,QAAQ,WAAW;QAAQ,OAAO;OAAK;MACvD,CAAC;KAEL;KAEA,UAAA,oBAAC,aAAD;MACE,gBAAe;MACf,IAAG;MACH,aAAY;KACb,CAAA;IACK,CAAA,CACJ;GACJ,CAAA,IAAA;EACA;CACQ,CAAA,EAAA,CAAA;AAEpB;AAIA,MAAM,0BACJ,UACG;CACH,MAAM,YAAY,eAAe;CACjC,MAAM,kBACJ,oBAAC,aAAD;EACE,gBAAe;EACf,IAAG;EACH,aAAY;CACb,CAAA;CAEH,OACE,qBAAC,MAAD;EACE,WAAU;EACV,KAAI;EACJ,GAAI,sBAAsB,WAAW,KAAK;EAH5C,UAAA;GAKE,qBAAC,MAAD;IAAM,SAAQ;IAAW,KAAI;IAA7B,UAAA,CACE,qBAAC,MAAD;KAAM,KAAI;KAAI,OAAM;KAApB,UAAA,CACE,oBAACG,YAAD;MAAU,SAAA;MACR,UAAA,oBAAC,KAAD;OAAK,WAAU;OAAQ,UAAS;OAAI,YAAW;OAC7C,UAAA,oBAACC,aAAD;QACE,UAAA;QACA,cAAY,UAAU;SACpB,gBAAgB;SAChB,IAAI;SACJ,aAAa;QACf,CAAC;OACF,CAAA;MACE,CAAA;KACG,CAAA,GACV,oBAACD,YAAD;MAAU,SAAA;MACR,UAAA,oBAAC,KAAD;OAAK,UAAS;OAAI,YAAW;OAC3B,UAAA,qBAACE,MAAD;QAAa,UAAA;QAAS,OAAM;QAAM,qBAAqB,KAAK;QAA5D,UAAA,CACE,oBAACC,eAAD,EAAA,UAAiB,gBAAgC,CAAA,GACjD,oBAACC,eAAD,EAAA,UACE,oBAACC,YAAD;SAAa,OAAM;SAAO,UAAA;QAA6B,CAAA,EACzC,CAAA,CACL;;MACV,CAAA;KACG,CAAA,CACN;IACN,CAAA,GAAA,oBAACL,YAAD;KAAU,SAAA;KACR,UAAA,oBAAC,KAAD;MAAK,UAAS;MAAI,YAAW;MAAI,OAAO,EAAE,WAAW,WAAW;MAC9D,UAAA,oBAACH,UAAD;OAAQ,UAAA;OACN,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACK,CAAA;KACL,CAAA;IACG,CAAA,CACN;;GACN,qBAAC,MAAM,MAAP;IAAY,SAAQ;IAAQ,MAAK;IAAjC,UAAA,CACE,oBAAC,MAAM,QAAP,EAAA,UACE,qBAAC,MAAM,KAAP,EAAA,UAAA;KACE,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC5B,UAAA,oBAACG,YAAD;OAAU,SAAA;OACR,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACO,CAAA;KACY,CAAA;KACxB,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC5B,UAAA,oBAACA,YAAD,EAAA,UACE,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA,EACO,CAAA;KACY,CAAA;KACxB,oBAAC,MAAM,kBAAP;MAAwB,OAAM;MAC5B,UAAA,oBAACA,YAAD,EAAA,UACE,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA,EACO,CAAA;KACY,CAAA;KACxB,oBAAC,MAAM,kBAAP,EAAwB,OAAM,OAAQ,CAAA;IAC7B,EAAA,CAAA,EACC,CAAA,GAEd,oBAAC,MAAM,MAAP,EAAA,UACG,MAAM,KAAK,EAAE,QAAA,GAAuB,IAAI,GAAG,UAC1C,qBAAC,MAAM,KAAP;KAAuB,OAAM;KAA7B,UAAA;MACE,oBAAC,MAAM,eAAP,EAAA,UACE,qBAAC,MAAD;OAAM,OAAM;OAAS,KAAI;OAAzB,UAAA,CACE,oBAACA,YAAD,EAAA,UACE,oBAACF,UAAD;QAAQ,MAAK;QAAI,UAAS;OAAK,CAAA,EACvB,CAAA,GAEV,qBAAC,MAAD;QACE,WAAU;QACV,QAAO;QACP,SAAQ;QAHV,UAAA,CAKE,oBAACE,YAAD;SAAU,OAAM;SAAQ,QAAO;QAAkB,CAAA,GACjD,oBAACA,YAAD;SAAU,OAAM;SAAO,QAAO;SAAiB,IAAG;QAAK,CAAA,CACnD;OACF,CAAA,CAAA;MACa,CAAA,EAAA,CAAA;MACrB,oBAAC,MAAM,MAAP,EAAA,UACE,oBAAC,MAAD;OAAM,MAAK;OAAO,KAAI;OACpB,UAAA,oBAACA,YAAD;QAAU,OAAM;QAAO,QAAO;OAAkB,CAAA;MAC5C,CAAA,EACI,CAAA;MACZ,oBAAC,MAAM,MAAP,EAAA,UACE,oBAACA,YAAD;OAAU,OAAM;OAAQ,QAAO;MAAkB,CAAA,EACvC,CAAA;MACZ,oBAAC,MAAM,MAAP,EAAY,SAAQ,MAAO,CAAA;KAClB;IA1BK,GAAA,KA0BL,CACZ,EACS,CAAA,CACF;;GAEZ,qBAAC,MAAD;IAAM,KAAI;IAAI,SAAQ;IAAtB,UAAA,CACE,oBAACA,YAAD;KAAU,SAAA;KACR,UAAA,oBAACH,UAAD;MAAQ,UAAA;MAAS,SAAQ;MAAY,MAAK;MACxC,UAAA,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA;KACK,CAAA;IACA,CAAA,GACV,oBAACG,YAAD;KAAU,SAAA;KACR,UAAA,oBAACH,UAAD;MAAQ,UAAA;MAAS,SAAQ;MAAY,MAAK;MACxC,UAAA,oBAAC,aAAD;OACE,gBAAe;OACf,IAAG;OACH,aAAY;MACb,CAAA;KACK,CAAA;IACA,CAAA,CACN;;EACF;;AAEV;AAMA,MAAM,wBAA6D,EACjE,OACA,GAAG,eACC;CACJ,OACE,oBAAC,cAAD;EACS;EACP,WAAU;EACV,GAAI,sBAAsB,SAAS,QAAQ;CAC5C,CAAA;AAEL;AAEA,SAAS,UAAU,EAAE,QAA0B;CAC7C,IAAI,KAAK,gBACP,OACE,oBAACS,SAAD;EAAO,OAAM;EAAO,OAAO,EAAE,YAAY,OAAO;EAC9C,UAAA,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA;CACI,CAAA;CAGX,IAAI,KAAK,WAAW,WAClB,OACE,qBAACA,SAAD;EAAO,OAAM;EAAQ,OAAO,EAAE,YAAY,OAAO;EAAjD,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,EACa,CAAA,GAChB,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,CACI;;CAGX,IAAI,KAAK,WAAW,iBAClB,OACE,qBAACA,SAAD;EAAO,OAAM;EAAM,OAAO,EAAE,YAAY,OAAO;EAA/C,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,EACa,CAAA,GAChB,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,CACI;;CAGX,IAAI,KAAK,WAAW,iBAClB,OACE,qBAACA,SAAD;EAAO,OAAM;EAAM,OAAO,EAAE,YAAY,OAAO;EAA/C,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,EACa,CAAA,GAChB,oBAAC,aAAD;GACE,gBAAe;GACf,IAAG;GACH,aAAY;EACb,CAAA,CACI;;CAGX,OAAO;AACT;AAQA,SAAS,WAAW,OAAwB;CAC1C,IAAI,CAAC,MAAM,KAAK,gBACd,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAA,UACG,MAAM,KAAK,WAAW,WACrB,oBAAC,aAAD;EACE,gBAAe;EACf,IAAG;EACH,aAAY;CACb,CAAA,IAED,oBAAC,aAAD;EACE,gBAAe;EACf,IAAG;EACH,aAAY;CACb,CAAA,EAEW,CAAA,GAChB,oBAAC,WAAD,CAAY,CAAA,CACZ,EAAA,CAAA;CAGN,OAAO,oBAAC,gBAAD;EAAgB,GAAI;EAAO,MAAM,MAAM,KAAK;CAAiB,CAAA;AACtE;AAEA,SAAS,eAAe,EACtB,MACA,YACA,OACqC;CACrC,MAAM,SAAS,UAAU;CAEzB,MAAM,iBAAiB,IAAI,KAAK,IAAI;CACpC,MAAM,qBAAqB,eAAe,mBAAmB,QAAQ;EAEnE,UAAU,aAAa,SAAY;EACnC,OAAO;EACP,KAAK;EACL,MAAM;EACN,MAAM;EACN,QAAQ;CACV,CAAC;CAED,MAAM,oBAAoB,2BAA2B,EACnD,MAAM,eACR,CAAC;CAGD,IAAI,sBAAsB,gBACxB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,aAAD;EACE,gBAAe;EACf,IAAG;EACH,aAAY;CACb,CAAA,EACa,CAAA,GAChB,oBAAC,WAAD,CAAY,CAAA,CACZ,EAAA,CAAA;CAIN,OACE,oBAAC,eAAD;EAAe,SAAA;EAAa;EAC1B,UAAA,oBAAC,QAAD;GAAM,UAAU;GAAM,OAAO;GAC1B,UAAA;EACG,CAAA;CACO,CAAA;AAEnB;AAEA,MAAM,gBAAgB,MAAM,WAC1B,SAAS,cACP,EAAE,UAAU,KAAK,QAAQ,WAAW,GAAG,SACvC,cACA;CACA,OACE,oBAAC,MAAD;EACE,KAAK;EACL,OAAO,UAAU,cAAc,SAAS;EACxC,QAAQ,UAAU,cAAc,YAAY;EAC5C,MAAM,UAAU,cAAc,MAAM;EACpC,UAAA;EACA,GAAI;EACJ,OACE,MACI;GAEE,SAAS;GACT,GAAG,MAAM;EACX,IACA,MAAM;EAGX;CACG,CAAA;AAEV,CACF;AAOA,MAAM,yBACJ,qBAAC,OAAD;CACE,OAAM;CACN,OAAM;CACN,QAAO;CACP,MAAK;CACL,SAAQ;CALV,UAAA,CAQE,oBAAC,SAAD,EAAA,UAAO,YAAgB,CAAA,GACvB,oBAAC,QAAD,EAAM,GAAE,kPAAmP,CAAA,CACxP;;AAGP,MAAM,6BAA6B,EAAE,gBAAwC;CAC3E,MAAM,EAAE,gBAAgB,iBAAiB;CACzC,MAAM,EACJ,OAAO,EAAE,kBACP,0BAA0B;CAQ9B,MAAM,CAAC,EAAE,YAAY,mBAAmB,eAAe,MAAM,SAAS;EACpE,YAAY;EACZ,iBAAiB;CACnB,CAAC;CACD,MAAM,CAAC,YAAY,iBAAiB,MAAM,SAAS,SAAS;CAC5D,IAAI,eAAe,WAAW;EAC5B,cAAc,SAAS;EACvB,IAAI,CAAC,WACH,aAAa,SACX,KAAK,aAAa;GAAE,YAAY;GAAO,iBAAiB;EAAK,IAAI,IACnE;CAEJ;CAEA,IAAI,eAAe,YACjB,OACE,qBAAC,MAAD;EAAM,OAAM;EAAS,SAAQ;EAAS,IAAG;EAAI,WAAU;EAAS,KAAI;EAApE,UAAA,CACE,oBAAC,MAAD;GAAM,MAAK;GACT,UAAA,oBAAC,aAAD;IACE,gBAAe;IACf,IAAG;IACH,aAAY;IACZ,QAAQ,EACN,OAAO,aAAa,kBAAkB,YACxC;GACD,CAAA;EACG,CAAA,GAEN,oBAACT,UAAD;GACE,SAAQ;GACR,MAAK;GACL,eAAe;IACb,YAAY;KAAE,YAAY;KAAM,iBAAiB;IAAY,CAAC;IAC9D,YAAY;GACd;GACA,SAAS;GAET,UAAA,oBAAC,aAAD;IACE,gBAAe;IACf,IAAG;IACH,aAAY;GACb,CAAA;EACK,CAAA,CACJ;;CAIV,OACE,oBAAC,MAAD;EAAM,OAAM;EAAS,SAAQ;EAAS,IAAG;EAAI,KAAI;EAC/C,UAAA,oBAAC,MAAD;GAAM,MAAK;GACT,UAAA,oBAAC,aAAD;IACE,gBAAe;IACf,IAAG;IACH,aAAY;GACb,CAAA;EACG,CAAA;CACF,CAAA;AAEV;AAQA,SAAS,qBAAqB,EAC5B,MACA,wBACA,WAC4B;CAC5B,IAAI,CAAC,KAAK,SAAS,KAAK,MAAM,WAAW,GACvC,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,aAAD;EACE,gBAAe;EACf,IAAG;EACH,aAAY;CACb,CAAA,EACa,CAAA,GAEhB,oBAAC,QAAD;EAAM,eAAA;EAAY,OAAO,EAAE,YAAY,OAAO;EAAG,UAAA;CAE3C,CAAA,CACN,EAAA,CAAA;CAIN,IAAI,0BAA0B,KAAK,MAAM,SAAS,GAAG;EACnD,MAAM,YAAY,KAAK,OAAO,KAAK,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI;EAChE,OACE,oBAAC,SAAD;GAAS,SAAS;GAAW,UAAS;GACpC,UAAA,oBAAC,eAAD;IAAe,KAAK;IAClB,UAAA,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;KACZ,QAAQ,EAAE,OAAO,KAAK,MAAM,OAAO;IACpC,CAAA;GACY,CAAA;EACR,CAAA;CAEb;CAEA,OAAO,oBAAC,eAAD;EAAe,KAAK;EAAU,UAAA,KAAK,QAAQ,EAAE,EAAE;CAAoB,CAAA;AAC5E;AAEA,SAAS,sBACP,OACA,UACA;CACA,OAAO,kBAAkB;EACvB,GAAG;EACH,cAAc;EACd,UAAU;EACV,aAAa;CACf,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"users-management.js","names":["Button","Avatar","IconButton","Skeleton","TextField","Select.Root","Select.Trigger","Select.Content","Select.Item","Badge"],"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 { getBestName } from \"./utils/get-best-name.js\";\nimport { getWidgetDomProps } from \"./utils/widget-dom-props.js\";\nimport { getListMetadata } from \"./utils/get-list-metadata.js\";\nimport { WidgetRootState, type WidgetRootDomProps } from \"./widget-types.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.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=\"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.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=\"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 getWidgetDomProps({\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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"}
|