@workos-inc/widgets 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -8
- package/dist/cjs/admin-portal-domain-verification.client.cjs +34 -20
- package/dist/cjs/admin-portal-domain-verification.client.cjs.map +1 -1
- package/dist/cjs/admin-portal-domain-verification.client.d.cts +3 -2
- package/dist/cjs/{admin-portal-sso-connection-client.cjs → admin-portal-sso-connection.client.cjs} +61 -35
- package/dist/cjs/admin-portal-sso-connection.client.cjs.map +1 -0
- package/dist/cjs/admin-portal-sso-connection.client.d.cts +16 -0
- package/dist/cjs/api/api-provider.cjs +27 -19
- package/dist/cjs/api/api-provider.cjs.map +1 -1
- package/dist/cjs/api/api-provider.d.cts +5 -4
- package/dist/cjs/api/endpoint.cjs +62 -2
- package/dist/cjs/api/endpoint.cjs.map +1 -1
- package/dist/cjs/api/endpoint.d.cts +62 -1
- package/dist/cjs/api/utils.cjs +10 -0
- package/dist/cjs/api/utils.cjs.map +1 -1
- package/dist/cjs/api/utils.d.cts +7 -2
- package/dist/cjs/api/widgets-api-client.cjs +11 -5
- package/dist/cjs/api/widgets-api-client.cjs.map +1 -1
- package/dist/cjs/{api-keys-client.cjs → api-keys.client.cjs} +45 -33
- package/dist/cjs/api-keys.client.cjs.map +1 -0
- package/dist/cjs/api-keys.client.d.cts +15 -0
- package/dist/cjs/index.cjs +9 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +6 -2
- package/dist/cjs/lib/add-mfa-dialog.cjs +1 -1
- package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.cjs +18 -12
- package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.d.cts +10 -6
- package/dist/cjs/lib/admin-portal-sso-connection.cjs +84 -106
- package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-sso-connection.d.cts +13 -6
- package/dist/cjs/lib/api-keys/api-keys.cjs +70 -66
- package/dist/cjs/lib/api-keys/api-keys.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys.d.cts +16 -8
- package/dist/cjs/lib/card-list.cjs.map +1 -0
- package/dist/cjs/lib/constants.cjs +5 -2
- package/dist/cjs/lib/constants.cjs.map +1 -1
- package/dist/cjs/lib/constants.d.cts +2 -1
- package/dist/cjs/lib/elevated-access.cjs.map +1 -1
- package/dist/cjs/lib/empty-state.cjs +24 -8
- package/dist/cjs/lib/empty-state.cjs.map +1 -1
- package/dist/cjs/lib/empty-state.d.cts +6 -2
- package/dist/cjs/lib/errors.cjs +1 -1
- package/dist/cjs/lib/errors.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.cjs +56 -58
- package/dist/cjs/lib/generic-error.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.d.cts +10 -3
- package/dist/cjs/lib/identity-providers.cjs +2 -1
- package/dist/cjs/lib/identity-providers.cjs.map +1 -1
- package/dist/cjs/lib/identity-providers.d.cts +2 -2
- package/dist/cjs/lib/oauth-icons.cjs +12 -7
- package/dist/cjs/lib/oauth-icons.cjs.map +1 -1
- package/dist/cjs/lib/oauth-icons.d.cts +7 -3
- package/dist/cjs/lib/organization-switcher.cjs +62 -9
- package/dist/cjs/lib/organization-switcher.cjs.map +1 -1
- package/dist/cjs/lib/organization-switcher.d.cts +12 -9
- package/dist/cjs/lib/otp-input.cjs +1 -1
- package/dist/cjs/lib/otp-input.cjs.map +1 -1
- package/dist/cjs/lib/pipes.cjs +343 -0
- package/dist/cjs/lib/pipes.cjs.map +1 -0
- package/dist/cjs/lib/pipes.d.cts +19 -0
- package/dist/cjs/lib/provider-icon.cjs +0 -6
- package/dist/cjs/lib/provider-icon.cjs.map +1 -1
- package/dist/cjs/lib/provider-icon.d.cts +4 -1
- package/dist/cjs/lib/save-button.cjs.map +1 -1
- package/dist/cjs/lib/use-permissions.cjs +7 -14
- package/dist/cjs/lib/use-permissions.cjs.map +1 -1
- package/dist/cjs/lib/use-permissions.d.cts +1 -1
- package/dist/cjs/lib/user-profile.cjs +77 -83
- package/dist/cjs/lib/user-profile.cjs.map +1 -1
- package/dist/cjs/lib/user-profile.d.cts +11 -7
- package/dist/cjs/lib/user-security.cjs +31 -25
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-security.d.cts +10 -7
- package/dist/cjs/lib/user-sessions.cjs +20 -10
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.d.cts +10 -6
- package/dist/cjs/lib/users-management.cjs +224 -216
- package/dist/cjs/lib/users-management.cjs.map +1 -1
- package/dist/cjs/lib/users-management.d.cts +10 -7
- package/dist/cjs/lib/utils.cjs +43 -0
- package/dist/cjs/lib/utils.cjs.map +1 -1
- package/dist/cjs/lib/utils.d.cts +29 -2
- package/dist/cjs/organization-switcher.client.cjs +47 -20
- package/dist/cjs/organization-switcher.client.cjs.map +1 -1
- package/dist/cjs/organization-switcher.client.d.cts +2 -1
- package/dist/cjs/pipes.client.cjs +64 -0
- package/dist/cjs/pipes.client.cjs.map +1 -0
- package/dist/cjs/pipes.client.d.cts +15 -0
- package/dist/cjs/user-profile.client.cjs +29 -16
- package/dist/cjs/user-profile.client.cjs.map +1 -1
- package/dist/cjs/user-profile.client.d.cts +4 -3
- package/dist/cjs/user-security.client.cjs +32 -14
- package/dist/cjs/user-security.client.cjs.map +1 -1
- package/dist/cjs/user-security.client.d.cts +3 -2
- package/dist/cjs/user-sessions.client.cjs +42 -28
- package/dist/cjs/user-sessions.client.cjs.map +1 -1
- package/dist/cjs/user-sessions.client.d.cts +4 -2
- package/dist/cjs/users-management.client.cjs +38 -27
- package/dist/cjs/users-management.client.cjs.map +1 -1
- package/dist/cjs/users-management.client.d.cts +3 -2
- package/dist/cjs/workos-widgets.client.cjs +7 -12
- package/dist/cjs/workos-widgets.client.cjs.map +1 -1
- package/dist/css/lib/provider-icon.css +16 -11
- package/dist/esm/admin-portal-domain-verification.client.d.ts +3 -2
- package/dist/esm/admin-portal-domain-verification.client.js +34 -21
- package/dist/esm/admin-portal-domain-verification.client.js.map +1 -1
- package/dist/esm/admin-portal-sso-connection.client.d.ts +16 -0
- package/dist/esm/{admin-portal-sso-connection-client.js → admin-portal-sso-connection.client.js} +61 -36
- package/dist/esm/admin-portal-sso-connection.client.js.map +1 -0
- package/dist/esm/api/api-provider.d.ts +5 -4
- package/dist/esm/api/api-provider.js +26 -19
- package/dist/esm/api/api-provider.js.map +1 -1
- package/dist/esm/api/endpoint.d.ts +62 -1
- package/dist/esm/api/endpoint.js +56 -2
- package/dist/esm/api/endpoint.js.map +1 -1
- package/dist/esm/api/utils.d.ts +7 -2
- package/dist/esm/api/utils.js +9 -0
- package/dist/esm/api/utils.js.map +1 -1
- package/dist/esm/api/widgets-api-client.js +11 -5
- package/dist/esm/api/widgets-api-client.js.map +1 -1
- package/dist/esm/api-keys.client.d.ts +15 -0
- package/dist/esm/api-keys.client.js +75 -0
- package/dist/esm/api-keys.client.js.map +1 -0
- package/dist/esm/index.d.ts +6 -2
- package/dist/esm/index.js +9 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/add-mfa-dialog.js +1 -1
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/admin-portal-domain-verification.d.ts +10 -6
- package/dist/esm/lib/admin-portal-domain-verification.js +18 -12
- package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
- package/dist/esm/lib/admin-portal-sso-connection.d.ts +13 -6
- package/dist/esm/lib/admin-portal-sso-connection.js +88 -107
- package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys.d.ts +16 -8
- package/dist/esm/lib/api-keys/api-keys.js +69 -54
- package/dist/esm/lib/api-keys/api-keys.js.map +1 -1
- package/dist/esm/lib/card-list.js.map +1 -0
- package/dist/esm/lib/constants.d.ts +2 -1
- package/dist/esm/lib/constants.js +3 -1
- package/dist/esm/lib/constants.js.map +1 -1
- package/dist/esm/lib/elevated-access.js.map +1 -1
- package/dist/esm/lib/empty-state.d.ts +6 -2
- package/dist/esm/lib/empty-state.js +24 -8
- package/dist/esm/lib/empty-state.js.map +1 -1
- package/dist/esm/lib/errors.js +1 -1
- package/dist/esm/lib/errors.js.map +1 -1
- package/dist/esm/lib/generic-error.d.ts +10 -3
- package/dist/esm/lib/generic-error.js +56 -60
- package/dist/esm/lib/generic-error.js.map +1 -1
- package/dist/esm/lib/identity-providers.d.ts +2 -2
- package/dist/esm/lib/identity-providers.js +2 -1
- package/dist/esm/lib/identity-providers.js.map +1 -1
- package/dist/esm/lib/oauth-icons.d.ts +7 -3
- package/dist/esm/lib/oauth-icons.js +11 -6
- package/dist/esm/lib/oauth-icons.js.map +1 -1
- package/dist/esm/lib/organization-switcher.d.ts +12 -9
- package/dist/esm/lib/organization-switcher.js +54 -9
- package/dist/esm/lib/organization-switcher.js.map +1 -1
- package/dist/esm/lib/otp-input.js +1 -1
- package/dist/esm/lib/otp-input.js.map +1 -1
- package/dist/esm/lib/pipes.d.ts +19 -0
- package/dist/esm/lib/pipes.js +334 -0
- package/dist/esm/lib/pipes.js.map +1 -0
- package/dist/esm/lib/provider-icon.d.ts +4 -1
- package/dist/esm/lib/provider-icon.js +0 -8
- package/dist/esm/lib/provider-icon.js.map +1 -1
- package/dist/esm/lib/save-button.js.map +1 -1
- package/dist/esm/lib/use-permissions.d.ts +1 -1
- package/dist/esm/lib/use-permissions.js +8 -15
- package/dist/esm/lib/use-permissions.js.map +1 -1
- package/dist/esm/lib/user-profile.d.ts +11 -7
- package/dist/esm/lib/user-profile.js +82 -75
- package/dist/esm/lib/user-profile.js.map +1 -1
- package/dist/esm/lib/user-security.d.ts +10 -7
- package/dist/esm/lib/user-security.js +35 -26
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.d.ts +10 -6
- package/dist/esm/lib/user-sessions.js +21 -10
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/lib/users-management.d.ts +10 -7
- package/dist/esm/lib/users-management.js +230 -217
- package/dist/esm/lib/users-management.js.map +1 -1
- package/dist/esm/lib/utils.d.ts +29 -2
- package/dist/esm/lib/utils.js +46 -1
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/organization-switcher.client.d.ts +2 -1
- package/dist/esm/organization-switcher.client.js +47 -21
- package/dist/esm/organization-switcher.client.js.map +1 -1
- package/dist/esm/pipes.client.d.ts +15 -0
- package/dist/esm/pipes.client.js +42 -0
- package/dist/esm/pipes.client.js.map +1 -0
- package/dist/esm/user-profile.client.d.ts +4 -3
- package/dist/esm/user-profile.client.js +29 -17
- package/dist/esm/user-profile.client.js.map +1 -1
- package/dist/esm/user-security.client.d.ts +3 -2
- package/dist/esm/user-security.client.js +32 -15
- package/dist/esm/user-security.client.js.map +1 -1
- package/dist/esm/user-sessions.client.d.ts +4 -2
- package/dist/esm/user-sessions.client.js +43 -30
- package/dist/esm/user-sessions.client.js.map +1 -1
- package/dist/esm/users-management.client.d.ts +3 -2
- package/dist/esm/users-management.client.js +38 -28
- package/dist/esm/users-management.client.js.map +1 -1
- package/dist/esm/workos-widgets.client.js +7 -12
- package/dist/esm/workos-widgets.client.js.map +1 -1
- package/package.json +20 -10
- package/dist/cjs/admin-portal-sso-connection-client.cjs.map +0 -1
- package/dist/cjs/admin-portal-sso-connection-client.d.cts +0 -12
- package/dist/cjs/api-keys-client.cjs.map +0 -1
- package/dist/cjs/api-keys-client.d.cts +0 -10
- package/dist/cjs/card-list.cjs.map +0 -1
- package/dist/esm/admin-portal-sso-connection-client.d.ts +0 -12
- package/dist/esm/admin-portal-sso-connection-client.js.map +0 -1
- package/dist/esm/api-keys-client.d.ts +0 -10
- package/dist/esm/api-keys-client.js +0 -65
- package/dist/esm/api-keys-client.js.map +0 -1
- package/dist/esm/card-list.js.map +0 -1
- /package/dist/cjs/{card-list.cjs → lib/card-list.cjs} +0 -0
- /package/dist/cjs/{card-list.d.cts → lib/card-list.d.cts} +0 -0
- /package/dist/esm/{card-list.d.ts → lib/card-list.d.ts} +0 -0
- /package/dist/esm/{card-list.js → lib/card-list.js} +0 -0
|
@@ -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 Select,\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 PrimaryButton,\n SecondaryButton,\n SelectContent,\n SelectItem,\n SelectTrigger,\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, getComparativeReadableDate, pluralize } from \"./utils.js\";\nimport { USER_ROW_LIMIT } from \"./constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport clsx from \"clsx\";\nimport { Member, MemberRole, MembersQueryResult } from \"../api/endpoint.js\";\nimport { GenericError } from \"./generic-error.js\";\n\ninterface UsersManagementProps {\n rolesData: { roles: MemberRole[]; multipleRolesEnabled: boolean };\n userData: MembersQueryResult;\n disableRolesFilter?: boolean;\n // When the users list is loading new users\n isPending: boolean;\n}\n\nexport const UsersManagement = ({\n userData,\n rolesData,\n isPending,\n disableRolesFilter,\n}: UsersManagementProps) => {\n const users = userData?.data ?? [];\n const usersCount = users?.length ?? 0;\n const isHydrated = useIsHydrated();\n const { listMetadata: pagination = {} } = userData;\n const { dispatch } = useUsersManagementContext();\n const isMultipleRolesEnabled = rolesData.multipleRolesEnabled;\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 <UsersManagementRoot>\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 <PrimaryButton>Invite user</PrimaryButton>\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 User\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n {`Role${isMultipleRolesEnabled ? \"s\" : \"\"}`}\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n Last active\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 title=\"User actions\">\n <VisuallyHidden>User actions</VisuallyHidden>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM12.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM18.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z\"\n />\n </svg>\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 <SecondaryButton\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 },\n });\n }\n }}\n >\n Previous\n </SecondaryButton>\n <SecondaryButton\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 },\n });\n }\n }}\n >\n Next\n </SecondaryButton>\n </Flex>\n ) : null}\n </UsersManagementRoot>\n </SearchProvider>\n );\n};\n\nexport const UsersManagementLoading: React.FC = () => {\n return (\n <UsersManagementRoot>\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 </Box>\n </Skeleton>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <Select.Root value=\"all\" onValueChange={() => void 0}>\n <SelectTrigger>All</SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All</SelectItem>\n </SelectContent>\n </Select.Root>\n </Box>\n </Skeleton>\n </Flex>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <PrimaryButton>Invite user</PrimaryButton>\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>User</Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n <Skeleton>Role</Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Skeleton>Last active</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 <SecondaryButton size=\"1\">Previous</SecondaryButton>\n </Skeleton>\n <Skeleton loading>\n <SecondaryButton size=\"1\">Next</SecondaryButton>\n </Skeleton>\n </Flex>\n </UsersManagementRoot>\n );\n};\n\nexport function UsersManagementError({ error }: { error: unknown }) {\n return (\n <UsersManagementRoot\n direction=\"row\"\n justify=\"center\"\n align=\"center\"\n minHeight=\"676px\"\n >\n <GenericError error={error} />\n </UsersManagementRoot>\n );\n}\n\nfunction UsersManagementRoot({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof Flex>) {\n return (\n <Flex\n className={clsx(\"woswidgets-widget\", className)}\n data-woswidgets-widget-id=\"users-management\"\n direction=\"column\"\n gap=\"3\"\n {...props}\n >\n {children}\n </Flex>\n );\n}\n\nfunction UserBadge({ user }: { user: Member }) {\n // TODO: This is not yet available in the data. Update here after API is updated.\n if (user.isLoggedInUser) {\n return (\n <Badge color=\"gray\" style={{ userSelect: \"none\" }}>\n You\n </Badge>\n );\n }\n if (user.status === \"Invited\") {\n return (\n <Badge color=\"amber\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: </VisuallyHidden>Invited\n </Badge>\n );\n }\n if (user.status === \"InviteExpired\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: Invite </VisuallyHidden>\n Expired\n </Badge>\n );\n }\n if (user.status === \"InviteRevoked\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: Invite </VisuallyHidden>\n Revoked\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\" ? \"Never\" : \"Not active\"}\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 { lastActiveDateTime, lastActiveDisplay } = React.useMemo(() => {\n const defaultTimeZone = \"America/Los_Angeles\";\n const lastActiveDate = new Date(date);\n const lastActiveDateTime = lastActiveDate.toLocaleTimeString(\"en-US\", {\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)\n : lastActiveDate.toLocaleDateString(\"en-US\", {\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 { lastActiveDateTime, lastActiveDisplay };\n }, [isHydrated, date]);\n\n // handle cases where the DB might return an invalid date string\n if (lastActiveDisplay === \"Invalid Date\") {\n return (\n <>\n <VisuallyHidden>Unknown</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 <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 No users found for query{\" \"}\n <Text weight=\"medium\">\n “{isClearing ? lastSearchQuery : searchQuery}”\n </Text>\n </Text>\n\n <SecondaryButton\n size=\"1\"\n onClick={() => {\n setClearing({ isClearing: true, lastSearchQuery: searchQuery });\n clearSearch();\n }}\n loading={isPending}\n >\n Clear search\n </SecondaryButton>\n </Flex>\n );\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" gap=\"2\">\n <Text size=\"2\">No users found</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>No roles assigned</VisuallyHidden>\n <span aria-hidden style={{ userSelect: \"none\" }}>\n –\n </span>\n </>\n );\n }\n\n if (isMultipleRolesEnabled && user.roles.length > 1) {\n return (\n <Tooltip\n content={user.roles?.map((role) => role.name).join(\", \")}\n maxWidth=\"250px\"\n >\n <TableCellText dim={dimText}>\n {pluralize(\"role\", user.roles.length)}\n </TableCellText>\n </Tooltip>\n );\n }\n\n return <TableCellText dim={dimText}>{user.roles?.[0]?.name}</TableCellText>;\n}\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 Select,\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 PrimaryButton,\n SecondaryButton,\n SelectContent,\n SelectItem,\n SelectTrigger,\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 pluralize,\n WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { USER_ROW_LIMIT } from \"./constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport { Member, MemberRole, MembersQueryResult } from \"../api/endpoint.js\";\nimport { GenericError } from \"./generic-error.js\";\n\ninterface UsersManagementProps extends WidgetRootDomProps {\n rolesData: { roles: MemberRole[]; multipleRolesEnabled: boolean };\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 { listMetadata: pagination = {} } = userData;\n const { dispatch } = useUsersManagementContext();\n const isMultipleRolesEnabled = rolesData.multipleRolesEnabled;\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 <PrimaryButton>Invite user</PrimaryButton>\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 User\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n {`Role${isMultipleRolesEnabled ? \"s\" : \"\"}`}\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n Last active\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 title=\"User actions\">\n <VisuallyHidden>User actions</VisuallyHidden>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM12.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM18.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z\"\n />\n </svg>\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 <SecondaryButton\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 },\n });\n }\n }}\n >\n Previous\n </SecondaryButton>\n <SecondaryButton\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 },\n });\n }\n }}\n >\n Next\n </SecondaryButton>\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 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 </Box>\n </Skeleton>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\">\n <Select.Root value=\"all\" onValueChange={() => void 0}>\n <SelectTrigger>All</SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All</SelectItem>\n </SelectContent>\n </Select.Root>\n </Box>\n </Skeleton>\n </Flex>\n <Skeleton loading>\n <Box flexGrow=\"0\" flexShrink=\"0\" style={{ placeSelf: \"flex-end\" }}>\n <PrimaryButton>Invite user</PrimaryButton>\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>User</Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"100px\">\n <Skeleton>Role</Skeleton>\n </Table.ColumnHeaderCell>\n <Table.ColumnHeaderCell width=\"140px\">\n <Skeleton>Last active</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 <SecondaryButton size=\"1\">Previous</SecondaryButton>\n </Skeleton>\n <Skeleton loading>\n <SecondaryButton size=\"1\">Next</SecondaryButton>\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 // TODO: This is not yet available in the data. Update here after API is updated.\n if (user.isLoggedInUser) {\n return (\n <Badge color=\"gray\" style={{ userSelect: \"none\" }}>\n You\n </Badge>\n );\n }\n if (user.status === \"Invited\") {\n return (\n <Badge color=\"amber\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: </VisuallyHidden>Invited\n </Badge>\n );\n }\n if (user.status === \"InviteExpired\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: Invite </VisuallyHidden>\n Expired\n </Badge>\n );\n }\n if (user.status === \"InviteRevoked\") {\n return (\n <Badge color=\"red\" style={{ userSelect: \"none\" }}>\n <VisuallyHidden>Status: Invite </VisuallyHidden>\n Revoked\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\" ? \"Never\" : \"Not active\"}\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 { lastActiveDateTime, lastActiveDisplay } = React.useMemo(() => {\n const defaultTimeZone = \"America/Los_Angeles\";\n const lastActiveDate = new Date(date);\n const lastActiveDateTime = lastActiveDate.toLocaleTimeString(\"en-US\", {\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)\n : lastActiveDate.toLocaleDateString(\"en-US\", {\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 { lastActiveDateTime, lastActiveDisplay };\n }, [isHydrated, date]);\n\n // handle cases where the DB might return an invalid date string\n if (lastActiveDisplay === \"Invalid Date\") {\n return (\n <>\n <VisuallyHidden>Unknown</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 <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 No users found for query{\" \"}\n <Text weight=\"medium\">\n “{isClearing ? lastSearchQuery : searchQuery}”\n </Text>\n </Text>\n\n <SecondaryButton\n size=\"1\"\n onClick={() => {\n setClearing({ isClearing: true, lastSearchQuery: searchQuery });\n clearSearch();\n }}\n loading={isPending}\n >\n Clear search\n </SecondaryButton>\n </Flex>\n );\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" py=\"8\" gap=\"2\">\n <Text size=\"2\">No users found</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>No roles assigned</VisuallyHidden>\n <span aria-hidden style={{ userSelect: \"none\" }}>\n –\n </span>\n </>\n );\n }\n\n if (isMultipleRolesEnabled && user.roles.length > 1) {\n return (\n <Tooltip\n content={user.roles?.map((role) => role.name).join(\", \")}\n maxWidth=\"250px\"\n >\n <TableCellText dim={dimText}>\n {pluralize(\"role\", user.roles.length)}\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"]}
|
package/dist/esm/lib/utils.d.ts
CHANGED
|
@@ -15,8 +15,31 @@ declare function parseErrorResponse(response: Response): Promise<{
|
|
|
15
15
|
message: string;
|
|
16
16
|
status: number;
|
|
17
17
|
}>;
|
|
18
|
-
declare function namespaceClassNames(className: string): string;
|
|
19
18
|
declare function namespaceClassNames(...classNames: string[]): string;
|
|
19
|
+
interface CommonDomArgs {
|
|
20
|
+
className?: string | undefined | null;
|
|
21
|
+
dataAttributes?: Record<string, string | boolean | undefined | null>;
|
|
22
|
+
}
|
|
23
|
+
interface WidgetRootDomArgs {
|
|
24
|
+
isWidgetRoot: true;
|
|
25
|
+
widgetId: string;
|
|
26
|
+
elementId?: never;
|
|
27
|
+
widgetState: WidgetRootState;
|
|
28
|
+
}
|
|
29
|
+
interface WidgetElementDomArgs {
|
|
30
|
+
isWidgetRoot?: false;
|
|
31
|
+
widgetId?: string;
|
|
32
|
+
elementId?: string;
|
|
33
|
+
widgetState?: never;
|
|
34
|
+
}
|
|
35
|
+
type DomArgs = CommonDomArgs & (WidgetRootDomArgs | WidgetElementDomArgs);
|
|
36
|
+
type DataAttributeProps = {
|
|
37
|
+
[K in `data-${string}`]?: string | boolean;
|
|
38
|
+
};
|
|
39
|
+
type DomProps = {
|
|
40
|
+
className: string | undefined;
|
|
41
|
+
} & DataAttributeProps;
|
|
42
|
+
declare function getDomProps(args: DomArgs): DomProps;
|
|
20
43
|
declare function parseUserAgent(userAgent?: string | null): {
|
|
21
44
|
pretty: string;
|
|
22
45
|
isMobile: boolean;
|
|
@@ -27,5 +50,9 @@ declare function getUserLocation(location?: {
|
|
|
27
50
|
} | null, ipAddress?: string | null): string;
|
|
28
51
|
declare function unreachable(value: never): never;
|
|
29
52
|
declare function pluralize(word?: string, amount?: number, showAmount?: boolean): string;
|
|
53
|
+
interface WidgetRootDomProps {
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
type WidgetRootState = "loading" | "error" | "resolved";
|
|
30
57
|
|
|
31
|
-
export { canUseDOM, getBestName, getComparativeReadableDate, getUserLocation, isErrorLike, isObjectLike, namespaceClassNames, parseErrorResponse, parseUserAgent, pluralize, unreachable };
|
|
58
|
+
export { type WidgetRootDomProps, type WidgetRootState, canUseDOM, getBestName, getComparativeReadableDate, getDomProps, getUserLocation, isErrorLike, isObjectLike, namespaceClassNames, parseErrorResponse, parseUserAgent, pluralize, unreachable };
|
package/dist/esm/lib/utils.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import Bowser from "bowser";
|
|
2
|
-
import
|
|
2
|
+
import cx from "clsx";
|
|
3
|
+
import {
|
|
4
|
+
WIDGETS_CLASS_NAMESPACE,
|
|
5
|
+
WIDGETS_DATA_ATTRIBUTE_NAMESPACE
|
|
6
|
+
} from "./constants.js";
|
|
3
7
|
const canUseDOM = !!(typeof window !== "undefined" && window.document && window.document.createElement);
|
|
4
8
|
function getBestName({
|
|
5
9
|
firstName,
|
|
@@ -66,6 +70,46 @@ async function parseErrorResponse(response) {
|
|
|
66
70
|
function namespaceClassNames(...classNames) {
|
|
67
71
|
return classNames.map((className) => `${WIDGETS_CLASS_NAMESPACE}-${className}`).join(" ");
|
|
68
72
|
}
|
|
73
|
+
function getDomProps(args) {
|
|
74
|
+
let {
|
|
75
|
+
className,
|
|
76
|
+
dataAttributes,
|
|
77
|
+
isWidgetRoot = false,
|
|
78
|
+
widgetId,
|
|
79
|
+
elementId,
|
|
80
|
+
widgetState,
|
|
81
|
+
...passthroughProps
|
|
82
|
+
} = args;
|
|
83
|
+
const props = {
|
|
84
|
+
...passthroughProps,
|
|
85
|
+
className: cx(
|
|
86
|
+
className,
|
|
87
|
+
isWidgetRoot && namespaceClassNames("widget"),
|
|
88
|
+
!!elementId && namespaceClassNames(elementId)
|
|
89
|
+
)
|
|
90
|
+
};
|
|
91
|
+
if (widgetId) {
|
|
92
|
+
props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-widget-id`] = widgetId;
|
|
93
|
+
}
|
|
94
|
+
if (isWidgetRoot) {
|
|
95
|
+
widgetState ??= "resolved";
|
|
96
|
+
props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-widget-state`] = widgetState;
|
|
97
|
+
}
|
|
98
|
+
if (dataAttributes) {
|
|
99
|
+
for (const [key, value] of Object.entries(dataAttributes)) {
|
|
100
|
+
if (value != null) {
|
|
101
|
+
const parts = [widgetId, elementId, key].filter((v) => v != null).map(fastKebabCase).join("-");
|
|
102
|
+
if (parts) {
|
|
103
|
+
props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-${parts}`] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return props;
|
|
109
|
+
}
|
|
110
|
+
function fastKebabCase(alphaString) {
|
|
111
|
+
return alphaString.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
112
|
+
}
|
|
69
113
|
function parseUserAgent(userAgent) {
|
|
70
114
|
const browser = Bowser.getParser(userAgent ?? "");
|
|
71
115
|
const browserName = browser.getBrowserName().replace(/^Mobile\s*/i, "");
|
|
@@ -92,6 +136,7 @@ export {
|
|
|
92
136
|
canUseDOM,
|
|
93
137
|
getBestName,
|
|
94
138
|
getComparativeReadableDate,
|
|
139
|
+
getDomProps,
|
|
95
140
|
getUserLocation,
|
|
96
141
|
isErrorLike,
|
|
97
142
|
isObjectLike,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils.ts"],"sourcesContent":["import { Member } from \"../api/endpoint.js\";\nimport Bowser from \"bowser\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils.ts"],"sourcesContent":["import { Member } from \"../api/endpoint.js\";\nimport Bowser from \"bowser\";\nimport cx from \"clsx\";\nimport {\n WIDGETS_CLASS_NAMESPACE,\n WIDGETS_DATA_ATTRIBUTE_NAMESPACE,\n} from \"./constants.js\";\n\nexport const canUseDOM = !!(\n typeof window !== \"undefined\" &&\n window.document &&\n window.document.createElement\n);\n\nexport function getBestName({\n firstName,\n lastName,\n}: Pick<Member, \"firstName\" | \"lastName\">) {\n return [firstName, lastName].filter(Boolean).join(\" \") || null;\n}\n\nexport function getComparativeReadableDate(\n now: Date,\n then: Date,\n options?: { timeZone?: string },\n): string {\n const timeSince = now.getTime() - then.getTime();\n\n // Has it been less than a minute?\n if (timeSince < 60_000) {\n return \"Just now\";\n }\n\n // Has it been less than an hour?\n if (timeSince < 3_600_000) {\n const timePassed = Math.floor(timeSince / 60_000);\n return timePassed === 1 ? \"1 minute ago\" : `${timePassed} minutes ago`;\n }\n\n // Has it been less than a day?\n if (timeSince < 86_400_000) {\n const timePassed = Math.floor(timeSince / 3_600_000);\n return timePassed === 1 ? \"1 hour ago\" : `${timePassed} hours ago`;\n }\n\n // Has it been less than a week?\n if (timeSince < 604_800_000) {\n const timePassed = Math.floor(timeSince / 86_400_000);\n return timePassed === 1 ? \"1 day ago\" : `${timePassed} days ago`;\n }\n\n // Has it been less than a month?\n if (timeSince < 2_592_000_000) {\n const timePassed = Math.floor(timeSince / 604_800_000);\n return timePassed === 1 ? \"1 week ago\" : `${timePassed} weeks ago`;\n }\n\n // Any later?\n return then.toLocaleDateString(\"en-US\", {\n timeZone: options?.timeZone,\n month: \"long\",\n day: \"numeric\",\n // omit year if it's the same as the current year\n year: now.getFullYear() !== then.getFullYear() ? \"numeric\" : undefined,\n });\n}\n\nexport function isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isErrorLike(\n value: unknown,\n): value is Record<string, unknown> & { message: string } {\n return isObjectLike(value) && typeof value.message === \"string\";\n}\n\nexport async function parseErrorResponse(\n response: Response,\n): Promise<{ message: string; status: number }> {\n try {\n const json = await response.json();\n if (!isObjectLike(json) || typeof json.message !== \"string\") {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n return {\n ...json,\n status: response.status,\n message: json.message || response.statusText,\n };\n } catch {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n}\n\nexport function namespaceClassNames(...classNames: string[]): string {\n return classNames\n .map((className) => `${WIDGETS_CLASS_NAMESPACE}-${className}`)\n .join(\" \");\n}\n\ninterface CommonDomArgs {\n className?: string | undefined | null;\n dataAttributes?: Record<string, string | boolean | undefined | null>;\n}\n\ninterface WidgetRootDomArgs {\n isWidgetRoot: true;\n widgetId: string;\n elementId?: never;\n widgetState: WidgetRootState;\n}\n\ninterface WidgetElementDomArgs {\n isWidgetRoot?: false;\n widgetId?: string;\n elementId?: string;\n widgetState?: never;\n}\n\ntype DomArgs = CommonDomArgs & (WidgetRootDomArgs | WidgetElementDomArgs);\n\ntype DataAttributeProps = {\n [K in `data-${string}`]?: string | boolean;\n};\n\ntype DomProps = {\n className: string | undefined;\n} & DataAttributeProps;\n\nexport function getDomProps(args: DomArgs) {\n // data-woswidgets-widget-id\n let {\n className,\n dataAttributes,\n isWidgetRoot = false,\n widgetId,\n elementId,\n widgetState,\n ...passthroughProps\n } = args;\n const props: DomProps = {\n ...passthroughProps,\n className: cx(\n className,\n isWidgetRoot && namespaceClassNames(\"widget\"),\n !!elementId && namespaceClassNames(elementId),\n ),\n };\n\n if (widgetId) {\n props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-widget-id`] = widgetId;\n }\n\n if (isWidgetRoot) {\n widgetState ??= \"resolved\";\n props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-widget-state`] =\n widgetState;\n }\n\n if (dataAttributes) {\n for (const [key, value] of Object.entries(dataAttributes)) {\n if (value != null) {\n const parts = [widgetId, elementId, key]\n .filter((v) => v != null)\n .map(fastKebabCase)\n .join(\"-\");\n if (parts) {\n props[`data-${WIDGETS_DATA_ATTRIBUTE_NAMESPACE}-${parts}`] = value;\n }\n }\n }\n }\n\n return props;\n}\n\n/**\n * Opt for simplicity and performance over capturing edge cases. Input strings\n * are expected to only be alphabetic.\n */\nfunction fastKebabCase(alphaString: string) {\n return alphaString.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n}\n\nexport function parseUserAgent(userAgent?: string | null) {\n const browser = Bowser.getParser(userAgent ?? \"\");\n const browserName = browser.getBrowserName().replace(/^Mobile\\s*/i, \"\");\n const osName = browser.getOSName();\n const pretty = [browserName, osName].filter(Boolean).join(\" on \");\n\n return { pretty, isMobile: browser.getPlatformType() === \"mobile\" };\n}\n\nexport function getUserLocation(\n location?: {\n cityName: string;\n countryISOCode: string;\n } | null,\n ipAddress?: string | null,\n) {\n if (location) {\n return (\n [location.cityName, location.countryISOCode].filter(Boolean).join(\", \") ||\n \"Unknown location\"\n );\n }\n\n if (ipAddress) {\n return ipAddress;\n }\n\n return \"Unknown location\";\n}\n\nexport function unreachable(value: never): never {\n throw new TypeError(`Unreachable code: ${value}`);\n}\n\nexport function pluralize(word = \"\", amount = 0, showAmount = true): string {\n return `${showAmount ? `${amount} ` : \"\"}${word}${amount === 1 ? \"\" : \"s\"}`;\n}\n\n// Props that all widgets should accept.\nexport interface WidgetRootDomProps {\n className?: string;\n}\n\nexport type WidgetRootState = \"loading\" | \"error\" | \"resolved\";\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AuthToken } from './api/api-provider.js';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { OrganizationSwitcherPassthroughProps } from './lib/organization-switcher.js';
|
|
4
|
-
export { OrganizationSwitcherLoading } from './lib/organization-switcher.js';
|
|
4
|
+
export { OrganizationSwitcherError, OrganizationSwitcherErrorProps, OrganizationSwitcherLoading, OrganizationSwitcherLoadingProps } from './lib/organization-switcher.js';
|
|
5
5
|
import 'react/jsx-runtime';
|
|
6
6
|
import './api/endpoint.js';
|
|
7
7
|
import '@tanstack/react-query';
|
|
8
8
|
import './api/widgets-api-client.js';
|
|
9
|
+
import './lib/utils.js';
|
|
9
10
|
|
|
10
11
|
interface OrganizationSwitcherProps extends OrganizationSwitcherPassthroughProps {
|
|
11
12
|
authToken: AuthToken;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { ApiProvider } from "./api/api-provider.js";
|
|
3
|
+
import { ApiProvider, useApiReady } from "./api/api-provider.js";
|
|
4
4
|
import { useOrganizations } from "./api/endpoint.js";
|
|
5
5
|
import { ErrorBoundary } from "./lib/error-boundary.js";
|
|
6
|
-
import { useIsHydrated } from "./lib/use-is-hydrated.js";
|
|
7
6
|
import {
|
|
8
7
|
OrganizationSwitcherError,
|
|
9
8
|
OrganizationSwitcherLoading,
|
|
@@ -16,45 +15,72 @@ const OrganizationSwitcher = ({
|
|
|
16
15
|
...passthroughProps
|
|
17
16
|
}) => {
|
|
18
17
|
const baseUrl = useWorkOsApiUrl();
|
|
19
|
-
return /* @__PURE__ */ jsx(
|
|
20
|
-
|
|
18
|
+
return /* @__PURE__ */ jsx(
|
|
19
|
+
ErrorBoundary,
|
|
21
20
|
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
fallbackRender: ({ error }) => /* @__PURE__ */ jsx(OrganizationSwitcherError, { ...passthroughProps, error }),
|
|
22
|
+
children: /* @__PURE__ */ jsx(
|
|
23
|
+
ApiProvider,
|
|
24
|
+
{
|
|
25
|
+
widgetType: "organization-switcher",
|
|
26
|
+
authToken,
|
|
27
|
+
baseUrl,
|
|
28
|
+
children: /* @__PURE__ */ jsx(OrganizationSwitcherImpl, { ...passthroughProps })
|
|
29
|
+
}
|
|
30
|
+
)
|
|
26
31
|
}
|
|
27
|
-
)
|
|
32
|
+
);
|
|
28
33
|
};
|
|
29
34
|
const emptyOrganizations = [];
|
|
30
|
-
const
|
|
35
|
+
const OrganizationSwitcherImpl = ({
|
|
31
36
|
variant,
|
|
32
|
-
|
|
37
|
+
switchToOrganization,
|
|
38
|
+
organizationLabel,
|
|
39
|
+
truncateBehavior,
|
|
40
|
+
children,
|
|
41
|
+
...domProps
|
|
33
42
|
}) => {
|
|
34
|
-
const
|
|
43
|
+
const isApiReady = useApiReady();
|
|
35
44
|
const organizationsQuery = useOrganizations({
|
|
36
45
|
query: {
|
|
37
46
|
placeholderData: keepPreviousData
|
|
38
47
|
}
|
|
39
48
|
});
|
|
40
49
|
const organizations = organizationsQuery.data?.data ?? emptyOrganizations;
|
|
41
|
-
if (organizationsQuery.isLoading ||
|
|
42
|
-
|
|
43
|
-
return /* @__PURE__ */ jsx(OrganizationSwitcherLoading, {});
|
|
50
|
+
if (organizationsQuery.isLoading || !isApiReady) {
|
|
51
|
+
return /* @__PURE__ */ jsx(OrganizationSwitcherLoading, { ...domProps });
|
|
44
52
|
}
|
|
45
53
|
if (organizationsQuery.isError) {
|
|
46
|
-
return /* @__PURE__ */ jsx(
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
55
|
+
OrganizationSwitcherError,
|
|
56
|
+
{
|
|
57
|
+
error: organizationsQuery.error,
|
|
58
|
+
...domProps
|
|
59
|
+
}
|
|
60
|
+
);
|
|
47
61
|
}
|
|
48
|
-
return /* @__PURE__ */ jsx(
|
|
49
|
-
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
ErrorBoundary,
|
|
50
64
|
{
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
fallbackRender: ({ error }) => /* @__PURE__ */ jsx(OrganizationSwitcherError, { error, ...domProps }),
|
|
66
|
+
children: /* @__PURE__ */ jsx(
|
|
67
|
+
OrganizationSwitcherPresentational,
|
|
68
|
+
{
|
|
69
|
+
organizations,
|
|
70
|
+
switchToOrganization,
|
|
71
|
+
variant,
|
|
72
|
+
organizationLabel,
|
|
73
|
+
truncateBehavior,
|
|
74
|
+
...domProps,
|
|
75
|
+
children
|
|
76
|
+
}
|
|
77
|
+
)
|
|
53
78
|
}
|
|
54
|
-
)
|
|
79
|
+
);
|
|
55
80
|
};
|
|
56
81
|
export {
|
|
57
82
|
OrganizationSwitcher,
|
|
83
|
+
OrganizationSwitcherError,
|
|
58
84
|
OrganizationSwitcherLoading
|
|
59
85
|
};
|
|
60
86
|
//# sourceMappingURL=organization-switcher.client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/organization-switcher.client.tsx"],"sourcesContent":["\"use client\";\n\nimport { ApiProvider, AuthToken } from \"./api/api-provider.js\";\nimport { OrganizationInfo, useOrganizations } from \"./api/endpoint.js\";\nimport * as React from \"react\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/organization-switcher.client.tsx"],"sourcesContent":["\"use client\";\n\nimport { ApiProvider, AuthToken, useApiReady } from \"./api/api-provider.js\";\nimport { OrganizationInfo, useOrganizations } from \"./api/endpoint.js\";\nimport * as React from \"react\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport {\n OrganizationSwitcherError,\n OrganizationSwitcherLoading,\n OrganizationSwitcher as OrganizationSwitcherPresentational,\n} from \"./lib/organization-switcher.js\";\nimport type {\n OrganizationSwitcherErrorProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherPassthroughProps,\n} from \"./lib/organization-switcher.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\n\ninterface OrganizationSwitcherProps\n extends OrganizationSwitcherPassthroughProps {\n authToken: AuthToken;\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n authToken,\n ...passthroughProps\n}) => {\n const baseUrl = useWorkOsApiUrl();\n return (\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <OrganizationSwitcherError {...passthroughProps} error={error} />\n )}\n >\n <ApiProvider\n widgetType=\"organization-switcher\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <OrganizationSwitcherImpl {...passthroughProps} />\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\n// Constant reference to avoid unnecessary prop changes\nconst emptyOrganizations: OrganizationInfo[] = [];\n\nconst OrganizationSwitcherImpl = ({\n variant,\n switchToOrganization,\n organizationLabel,\n truncateBehavior,\n children,\n ...domProps\n}: OrganizationSwitcherPassthroughProps) => {\n const isApiReady = useApiReady();\n const organizationsQuery = useOrganizations({\n query: {\n placeholderData: keepPreviousData,\n },\n });\n\n const organizations = organizationsQuery.data?.data ?? emptyOrganizations;\n\n if (organizationsQuery.isLoading || !isApiReady) {\n return <OrganizationSwitcherLoading {...domProps} />;\n }\n\n if (organizationsQuery.isError) {\n return (\n <OrganizationSwitcherError\n error={organizationsQuery.error}\n {...domProps}\n />\n );\n }\n\n return (\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <OrganizationSwitcherError error={error} {...domProps} />\n )}\n >\n <OrganizationSwitcherPresentational\n organizations={organizations}\n switchToOrganization={switchToOrganization}\n variant={variant}\n organizationLabel={organizationLabel}\n truncateBehavior={truncateBehavior}\n {...domProps}\n >\n {children}\n </OrganizationSwitcherPresentational>\n </ErrorBoundary>\n );\n};\n\nexport type {\n OrganizationSwitcherProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":";AAgCQ;AA9BR,SAAS,aAAwB,mBAAmB;AACpD,SAA2B,wBAAwB;AAEnD,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA,wBAAwB;AAAA,OACnB;AAMP,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAOjC,MAAM,uBAA4D,CAAC;AAAA,EACjE;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,UAAU,gBAAgB;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAgB,CAAC,EAAE,MAAM,MACvB,oBAAC,6BAA2B,GAAG,kBAAkB,OAAc;AAAA,MAGjE;AAAA,QAAC;AAAA;AAAA,UACC,YAAW;AAAA,UACX;AAAA,UACA;AAAA,UAEA,8BAAC,4BAA0B,GAAG,kBAAkB;AAAA;AAAA,MAClD;AAAA;AAAA,EACF;AAEJ;AAGA,MAAM,qBAAyC,CAAC;AAEhD,MAAM,2BAA2B,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4C;AAC1C,QAAM,aAAa,YAAY;AAC/B,QAAM,qBAAqB,iBAAiB;AAAA,IAC1C,OAAO;AAAA,MACL,iBAAiB;AAAA,IACnB;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,mBAAmB,MAAM,QAAQ;AAEvD,MAAI,mBAAmB,aAAa,CAAC,YAAY;AAC/C,WAAO,oBAAC,+BAA6B,GAAG,UAAU;AAAA,EACpD;AAEA,MAAI,mBAAmB,SAAS;AAC9B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,mBAAmB;AAAA,QACzB,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAgB,CAAC,EAAE,MAAM,MACvB,oBAAC,6BAA0B,OAAe,GAAG,UAAU;AAAA,MAGzD;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACC,GAAG;AAAA,UAEH;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthToken } from './api/api-provider.js';
|
|
2
|
+
export { PipesError, PipesErrorProps, PipesLoading, PipesLoadingProps } from './lib/pipes.js';
|
|
3
|
+
import { WidgetRootDomProps } from './lib/utils.js';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import 'react';
|
|
6
|
+
import './api/endpoint.js';
|
|
7
|
+
import '@tanstack/react-query';
|
|
8
|
+
import './api/widgets-api-client.js';
|
|
9
|
+
|
|
10
|
+
interface PipesProps extends WidgetRootDomProps {
|
|
11
|
+
authToken: AuthToken;
|
|
12
|
+
}
|
|
13
|
+
declare const Pipes: React.FC<PipesProps>;
|
|
14
|
+
|
|
15
|
+
export { Pipes, type PipesProps };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { ApiProvider } from "./api/api-provider.js";
|
|
4
|
+
import { useWorkOsApiUrl } from "./lib/widgets-context.js";
|
|
5
|
+
import {
|
|
6
|
+
Pipes as PipesPresentational,
|
|
7
|
+
PipesError,
|
|
8
|
+
PipesLoading
|
|
9
|
+
} from "./lib/pipes.js";
|
|
10
|
+
import { useMyDataIntegrations } from "./api/endpoint.js";
|
|
11
|
+
import { useIsHydrated } from "./lib/use-is-hydrated.js";
|
|
12
|
+
import { ErrorBoundary } from "./lib/error-boundary.js";
|
|
13
|
+
const Pipes = ({ authToken, ...domProps }) => {
|
|
14
|
+
const baseUrl = useWorkOsApiUrl();
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
ErrorBoundary,
|
|
17
|
+
{
|
|
18
|
+
fallbackRender: ({ error }) => /* @__PURE__ */ jsx(PipesError, { ...domProps, error }),
|
|
19
|
+
children: /* @__PURE__ */ jsx(ApiProvider, { widgetType: "pipes", authToken, baseUrl, children: /* @__PURE__ */ jsx(PipesImpl, { ...domProps }) })
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
const PipesImpl = (props) => {
|
|
24
|
+
const isHydrated = useIsHydrated();
|
|
25
|
+
const integrations = useMyDataIntegrations();
|
|
26
|
+
if (!isHydrated || integrations.isLoading) {
|
|
27
|
+
return /* @__PURE__ */ jsx(PipesLoading, { count: 6, ...props });
|
|
28
|
+
}
|
|
29
|
+
if (integrations.isError) {
|
|
30
|
+
return /* @__PURE__ */ jsx(PipesError, { error: integrations.error, ...props });
|
|
31
|
+
}
|
|
32
|
+
if (integrations.isSuccess) {
|
|
33
|
+
return /* @__PURE__ */ jsx(PipesPresentational, { integrations: integrations.data.data, ...props });
|
|
34
|
+
}
|
|
35
|
+
return /* @__PURE__ */ jsx(PipesError, { error: integrations.error, ...props });
|
|
36
|
+
};
|
|
37
|
+
export {
|
|
38
|
+
Pipes,
|
|
39
|
+
PipesError,
|
|
40
|
+
PipesLoading
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=pipes.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pipes.client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken } from \"./api/api-provider.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport {\n Pipes as PipesPresentational,\n PipesError,\n PipesLoading,\n} from \"./lib/pipes.js\";\nimport type { PipesErrorProps, PipesLoadingProps } from \"./lib/pipes.js\";\nimport { useMyDataIntegrations } from \"./api/endpoint.js\";\nimport { useIsHydrated } from \"./lib/use-is-hydrated.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { WidgetRootDomProps } from \"./lib/utils.js\";\n\ninterface PipesProps extends WidgetRootDomProps {\n authToken: AuthToken;\n}\n\nconst Pipes: React.FC<PipesProps> = ({ authToken, ...domProps }) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary\n fallbackRender={({ error }) => <PipesError {...domProps} error={error} />}\n >\n <ApiProvider widgetType=\"pipes\" authToken={authToken} baseUrl={baseUrl}>\n <PipesImpl {...domProps} />\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\nconst PipesImpl = (props: Omit<PipesProps, \"authToken\">) => {\n const isHydrated = useIsHydrated();\n const integrations = useMyDataIntegrations();\n\n if (!isHydrated || integrations.isLoading) {\n return <PipesLoading count={6} {...props} />;\n }\n\n if (integrations.isError) {\n return <PipesError error={integrations.error} {...props} />;\n }\n\n if (integrations.isSuccess) {\n return (\n <PipesPresentational integrations={integrations.data.data} {...props} />\n );\n }\n\n return <PipesError error={integrations.error} {...props} />;\n};\n\nexport type { PipesProps, PipesLoadingProps, PipesErrorProps };\nexport { Pipes, PipesLoading, PipesError };\n"],"mappings":";AAuBqC;AAtBrC,SAAS,mBAA8B;AACvC,SAAS,uBAAuB;AAChC;AAAA,EACE,SAAS;AAAA,EACT;AAAA,EACA;AAAA,OACK;AAEP,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,MAAM,QAA8B,CAAC,EAAE,WAAW,GAAG,SAAS,MAAM;AAClE,QAAM,UAAU,gBAAgB;AAEhC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAgB,CAAC,EAAE,MAAM,MAAM,oBAAC,cAAY,GAAG,UAAU,OAAc;AAAA,MAEvE,8BAAC,eAAY,YAAW,SAAQ,WAAsB,SACpD,8BAAC,aAAW,GAAG,UAAU,GAC3B;AAAA;AAAA,EACF;AAEJ;AAEA,MAAM,YAAY,CAAC,UAAyC;AAC1D,QAAM,aAAa,cAAc;AACjC,QAAM,eAAe,sBAAsB;AAE3C,MAAI,CAAC,cAAc,aAAa,WAAW;AACzC,WAAO,oBAAC,gBAAa,OAAO,GAAI,GAAG,OAAO;AAAA,EAC5C;AAEA,MAAI,aAAa,SAAS;AACxB,WAAO,oBAAC,cAAW,OAAO,aAAa,OAAQ,GAAG,OAAO;AAAA,EAC3D;AAEA,MAAI,aAAa,WAAW;AAC1B,WACE,oBAAC,uBAAoB,cAAc,aAAa,KAAK,MAAO,GAAG,OAAO;AAAA,EAE1E;AAEA,SAAO,oBAAC,cAAW,OAAO,aAAa,OAAQ,GAAG,OAAO;AAC3D;","names":[]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
export { UserProfileLoading } from './lib/user-profile.js';
|
|
2
|
+
export { UserProfileError, UserProfileErrorProps, UserProfileLoading, UserProfileLoadingProps } from './lib/user-profile.js';
|
|
3
3
|
import { AuthToken } from './api/api-provider.js';
|
|
4
|
-
import '
|
|
4
|
+
import { WidgetRootDomProps } from './lib/utils.js';
|
|
5
5
|
import './api/endpoint.js';
|
|
6
6
|
import '@tanstack/react-query';
|
|
7
7
|
import './api/widgets-api-client.js';
|
|
8
|
+
import 'react/jsx-runtime';
|
|
8
9
|
|
|
9
|
-
interface UserProfileProps {
|
|
10
|
+
interface UserProfileProps extends WidgetRootDomProps {
|
|
10
11
|
authToken: AuthToken;
|
|
11
12
|
}
|
|
12
13
|
declare const UserProfile: React.FC<UserProfileProps>;
|
|
@@ -5,40 +5,52 @@ import {
|
|
|
5
5
|
UserProfileLoading,
|
|
6
6
|
UserProfile as UserProfilePresentational
|
|
7
7
|
} from "./lib/user-profile.js";
|
|
8
|
-
import { useIsHydrated } from "./lib/use-is-hydrated.js";
|
|
9
8
|
import { useMe } from "./api/endpoint.js";
|
|
10
|
-
import { ApiProvider } from "./api/api-provider.js";
|
|
9
|
+
import { ApiProvider, useApiReady } from "./api/api-provider.js";
|
|
11
10
|
import { useWorkOsApiUrl } from "./lib/widgets-context.js";
|
|
12
11
|
import { ErrorBoundary } from "./lib/error-boundary.js";
|
|
13
|
-
const UserProfile = ({
|
|
12
|
+
const UserProfile = ({
|
|
13
|
+
authToken,
|
|
14
|
+
...domProps
|
|
15
|
+
}) => {
|
|
14
16
|
const baseUrl = useWorkOsApiUrl();
|
|
15
17
|
return /* @__PURE__ */ jsx(
|
|
16
|
-
|
|
18
|
+
ErrorBoundary,
|
|
17
19
|
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
fallbackRender: ({ error }) => /* @__PURE__ */ jsx(UserProfileError, { ...domProps, error }),
|
|
21
|
+
children: /* @__PURE__ */ jsx(
|
|
22
|
+
ApiProvider,
|
|
23
|
+
{
|
|
24
|
+
widgetType: "user-profile",
|
|
25
|
+
authToken,
|
|
26
|
+
baseUrl,
|
|
27
|
+
children: /* @__PURE__ */ jsx(UserProfileImpl, { ...domProps })
|
|
28
|
+
}
|
|
29
|
+
)
|
|
22
30
|
}
|
|
23
31
|
);
|
|
24
32
|
};
|
|
25
|
-
const
|
|
26
|
-
const
|
|
33
|
+
const UserProfileImpl = (props) => {
|
|
34
|
+
const isApiReady = useApiReady();
|
|
27
35
|
const meQuery = useMe();
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
!isHydrated || meQuery.isLoading
|
|
31
|
-
) {
|
|
32
|
-
return /* @__PURE__ */ jsx(UserProfileLoading, {});
|
|
36
|
+
if (!isApiReady || meQuery.isLoading) {
|
|
37
|
+
return /* @__PURE__ */ jsx(UserProfileLoading, { ...props });
|
|
33
38
|
}
|
|
34
39
|
if (meQuery.isError) {
|
|
35
|
-
return /* @__PURE__ */ jsx(UserProfileError, { error: meQuery.error });
|
|
40
|
+
return /* @__PURE__ */ jsx(UserProfileError, { error: meQuery.error, ...props });
|
|
36
41
|
}
|
|
37
42
|
const user = meQuery.data;
|
|
38
|
-
return /* @__PURE__ */ jsx(
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
ErrorBoundary,
|
|
45
|
+
{
|
|
46
|
+
fallbackRender: ({ error }) => /* @__PURE__ */ jsx(UserProfileError, { error, ...props }),
|
|
47
|
+
children: /* @__PURE__ */ jsx(UserProfilePresentational, { userData: user, ...props })
|
|
48
|
+
}
|
|
49
|
+
);
|
|
39
50
|
};
|
|
40
51
|
export {
|
|
41
52
|
UserProfile,
|
|
53
|
+
UserProfileError,
|
|
42
54
|
UserProfileLoading
|
|
43
55
|
};
|
|
44
56
|
//# sourceMappingURL=user-profile.client.js.map
|