@workos-inc/widgets 1.20.3-next.1793998900035 → 1.21.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +3 -8
  2. package/dist/cjs/widgets/organization-switcher/organization-switcher.cjs +2 -2
  3. package/dist/cjs/widgets/organization-switcher/organization-switcher.cjs.map +1 -1
  4. package/dist/cjs/widgets/pipes/pipes-connections.cjs +15 -15
  5. package/dist/cjs/widgets/pipes/pipes-connections.cjs.map +1 -1
  6. package/dist/cjs/widgets/pipes/pipes-credential-attribution.cjs +2 -2
  7. package/dist/cjs/widgets/pipes/pipes-credential-attribution.cjs.map +1 -1
  8. package/dist/cjs/widgets/pipes/pipes.cjs +6 -6
  9. package/dist/cjs/widgets/pipes/pipes.cjs.map +1 -1
  10. package/dist/cjs/widgets/pipes-admin/pipes-admin.cjs +15 -15
  11. package/dist/cjs/widgets/pipes-admin/pipes-admin.cjs.map +1 -1
  12. package/dist/cjs/widgets/user-sessions/user-sessions.cjs +1 -1
  13. package/dist/cjs/widgets/user-sessions/user-sessions.cjs.map +1 -1
  14. package/dist/esm/widgets/organization-switcher/organization-switcher.js +2 -2
  15. package/dist/esm/widgets/organization-switcher/organization-switcher.js.map +1 -1
  16. package/dist/esm/widgets/pipes/pipes-connections.js +15 -15
  17. package/dist/esm/widgets/pipes/pipes-connections.js.map +1 -1
  18. package/dist/esm/widgets/pipes/pipes-credential-attribution.js +2 -2
  19. package/dist/esm/widgets/pipes/pipes-credential-attribution.js.map +1 -1
  20. package/dist/esm/widgets/pipes/pipes.js +6 -6
  21. package/dist/esm/widgets/pipes/pipes.js.map +1 -1
  22. package/dist/esm/widgets/pipes-admin/pipes-admin.js +15 -15
  23. package/dist/esm/widgets/pipes-admin/pipes-admin.js.map +1 -1
  24. package/dist/esm/widgets/user-sessions/user-sessions.js +1 -1
  25. package/dist/esm/widgets/user-sessions/user-sessions.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/widgets/organization-switcher/organization-switcher.tsx +2 -2
  28. package/src/widgets/pipes/pipes-connections.tsx +15 -15
  29. package/src/widgets/pipes/pipes-credential-attribution.tsx +2 -2
  30. package/src/widgets/pipes/pipes.tsx +6 -6
  31. package/src/widgets/pipes-admin/pipes-admin.tsx +15 -15
  32. package/src/widgets/user-sessions/user-sessions.tsx +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"user-sessions.cjs","names":["React","Flex","Card","Box","Text","Translation","Button","LogoutDialog","LogoutAllSessionsDialog","Skeleton","IconPanel","GenericError","useTranslation","parseUserAgent","useComparativeReadableDate","MobileIcon","LaptopIcon","Badge","getWidgetDomProps"],"sources":["../../../../src/widgets/user-sessions/user-sessions.tsx"],"sourcesContent":["\"use client\";\n\nimport { LaptopIcon, MobileIcon } from \"@radix-ui/react-icons\";\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport type { SessionFieldsFragment } from \"../../api/client-graphql/generated.js\";\nimport * as CardList from \"../../components/card-list.js\";\nimport { Badge, Button, Skeleton } from \"../../components/elements.js\";\nimport { GenericError } from \"../../components/generic-error.js\";\nimport { IconPanel } from \"../../components/icon-panel.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { parseUserAgent } from \"../../lib/parse-user-agent.js\";\nimport { useComparativeReadableDate } from \"../../lib/use-comparative-readable-date.js\";\nimport { getWidgetDomProps } from \"../../lib/widget-dom-props.js\";\nimport type {\n WidgetRootDomProps,\n WidgetRootState,\n} from \"../../lib/widget-types.js\";\nimport { LogoutAllSessionsDialog } from \"./logout-all-sessions-dialog.js\";\nimport { LogoutDialog } from \"./logout-dialog.js\";\n\ninterface UserSessionsProps extends WidgetRootDomProps {\n sessionsData: SessionFieldsFragment[];\n currentSessionId: string;\n}\n\nconst UserSessions: React.FC<UserSessionsProps> = ({\n sessionsData: sessions,\n currentSessionId,\n ...domProps\n}) => {\n const currentSession = sessions.find(\n (session) => session.id === currentSessionId,\n );\n const otherSessions = sessions.filter(\n (session) => session.id !== currentSessionId,\n );\n const [openLogoutDialog, setOpenLogoutDialog] = React.useState(false);\n const [sessionToSignOut, setSessionToSignOut] =\n React.useState<SessionFieldsFragment | null>(null);\n const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =\n React.useState(false);\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <CardList.Root>\n {currentSession && (\n <CardList.Item>\n <UserSession session={currentSession} isCurrentSession />\n </CardList.Item>\n )}\n\n {otherSessions.map((session) => (\n <CardList.Item key={session.id}>\n <UserSession\n session={session}\n onSignOut={() => {\n setSessionToSignOut(session);\n setOpenLogoutDialog(true);\n }}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n {sessions.length > 1 && (\n <Card size=\"2\">\n <Flex gap=\"2\" justify=\"between\" align=\"center\">\n <Box>\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n <Translation\n defaultMessage=\"Sign out of all other devices\"\n id=\"sfkEFa\"\n description=\"Heading for sign out all other devices action\"\n />\n </Text>\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Remove access from all devices except this one\"\n id=\"LsD5BK\"\n description=\"Description for sign out all other devices action\"\n />\n </Text>\n </Box>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setOpenLogoutAllSessionsDialog(true);\n }}\n >\n <Translation\n defaultMessage=\"Sign out\"\n id=\"oKQ0rm\"\n description=\"Button text to sign out of all other devices\"\n />\n </Button>\n </Flex>\n </Card>\n )}\n\n {sessionToSignOut && (\n <LogoutDialog\n session={sessionToSignOut}\n open={openLogoutDialog}\n onOpenChange={setOpenLogoutDialog}\n />\n )}\n\n <LogoutAllSessionsDialog\n open={openLogoutAllSessionsDialog}\n onOpenChange={setOpenLogoutAllSessionsDialog}\n currentSessionId={currentSessionId}\n />\n </Flex>\n );\n};\n\ninterface UserSessionsLoadingProps extends WidgetRootDomProps {}\n\nconst UserSessionsLoading: React.FC<UserSessionsLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface UserSessionsErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSessionsError: React.FC<UserSessionsErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSessionProps {\n session: SessionFieldsFragment;\n isCurrentSession?: boolean;\n onSignOut?: (session: SessionFieldsFragment) => void;\n}\n\nconst UserSession: React.FC<UserSessionProps> = ({\n session,\n isCurrentSession = false,\n onSignOut,\n}) => {\n const translate = useTranslation();\n const userAgent = parseUserAgent(session.userAgent);\n const userLocation =\n getUserLocation(session.currentLocation, session.ipAddress) ||\n translate({\n defaultMessage: \"Unknown location\",\n description:\n \"Text for a session whose location could not be determined from its user agent\",\n id: \"4+P9Yz\",\n });\n const timeAgo = useComparativeReadableDate({\n date: session.lastActivityAt ? new Date(session.lastActivityAt) : null,\n });\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel>\n {userAgent?.isMobile ? <MobileIcon /> : <LaptopIcon />}\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n {userAgent?.pretty ?? (\n <Translation\n defaultMessage=\"Unknown device\"\n id=\"nF+P+T\"\n description=\"Label for a session whose device could not be determined from its user agent\"\n />\n )}\n </Text>\n\n <Flex gap=\"1\" align=\"center\">\n <Text size=\"2\" color=\"gray\" as=\"p\">\n {userLocation}\n </Text>\n\n {isCurrentSession && (\n <Badge ml=\"2\">\n <Translation\n defaultMessage=\"This device\"\n id=\"Wz8T8u\"\n description=\"Badge label indicating the current device session\"\n />\n </Badge>\n )}\n\n {!isCurrentSession &&\n session.lastActivityAt &&\n timeAgo.state === \"valid\" && (\n <>\n <Text size=\"2\" color=\"gray\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last seen {timeAgo}\"\n id=\"gF+kUw\"\n description=\"Text showing when the session was last active\"\n values={{ timeAgo: timeAgo.formatted }}\n />\n </Text>\n </>\n )}\n </Flex>\n </Flex>\n\n {!isCurrentSession && (\n <Flex ml=\"auto\">\n <Button variant=\"secondary\" onClick={() => onSignOut?.(session)}>\n <Translation\n defaultMessage=\"Sign out\"\n id=\"sT1L78\"\n description=\"Button text to sign out of a session\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getWidgetDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-sessions\",\n widgetState: state,\n });\n}\n\nfunction getUserLocation(\n location?: {\n cityName: string;\n countryISOCode: string;\n } | null,\n ipAddress?: string | null,\n): string | null {\n if (location) {\n return (\n [location.cityName, location.countryISOCode].filter(Boolean).join(\", \") ||\n null\n );\n }\n\n return ipAddress || null;\n}\n\nexport type { UserSessionsLoadingProps, UserSessionsErrorProps };\nexport { UserSessions, UserSessionsLoading, UserSessionsError };\n"],"mappings":"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"}
1
+ {"version":3,"file":"user-sessions.cjs","names":["React","Flex","Card","Box","Text","Translation","Button","LogoutDialog","LogoutAllSessionsDialog","Skeleton","IconPanel","GenericError","useTranslation","parseUserAgent","useComparativeReadableDate","MobileIcon","LaptopIcon","Badge","getWidgetDomProps"],"sources":["../../../../src/widgets/user-sessions/user-sessions.tsx"],"sourcesContent":["\"use client\";\n\nimport { LaptopIcon, MobileIcon } from \"@radix-ui/react-icons\";\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport type { SessionFieldsFragment } from \"../../api/client-graphql/generated.js\";\nimport * as CardList from \"../../components/card-list.js\";\nimport { Badge, Button, Skeleton } from \"../../components/elements.js\";\nimport { GenericError } from \"../../components/generic-error.js\";\nimport { IconPanel } from \"../../components/icon-panel.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { parseUserAgent } from \"../../lib/parse-user-agent.js\";\nimport { useComparativeReadableDate } from \"../../lib/use-comparative-readable-date.js\";\nimport { getWidgetDomProps } from \"../../lib/widget-dom-props.js\";\nimport type {\n WidgetRootDomProps,\n WidgetRootState,\n} from \"../../lib/widget-types.js\";\nimport { LogoutAllSessionsDialog } from \"./logout-all-sessions-dialog.js\";\nimport { LogoutDialog } from \"./logout-dialog.js\";\n\ninterface UserSessionsProps extends WidgetRootDomProps {\n sessionsData: SessionFieldsFragment[];\n currentSessionId: string;\n}\n\nconst UserSessions: React.FC<UserSessionsProps> = ({\n sessionsData: sessions,\n currentSessionId,\n ...domProps\n}) => {\n const currentSession = sessions.find(\n (session) => session.id === currentSessionId,\n );\n const otherSessions = sessions.filter(\n (session) => session.id !== currentSessionId,\n );\n const [openLogoutDialog, setOpenLogoutDialog] = React.useState(false);\n const [sessionToSignOut, setSessionToSignOut] =\n React.useState<SessionFieldsFragment | null>(null);\n const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =\n React.useState(false);\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n <CardList.Root>\n {currentSession && (\n <CardList.Item>\n <UserSession session={currentSession} isCurrentSession />\n </CardList.Item>\n )}\n\n {otherSessions.map((session) => (\n <CardList.Item key={session.id}>\n <UserSession\n session={session}\n onSignOut={() => {\n setSessionToSignOut(session);\n setOpenLogoutDialog(true);\n }}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n {sessions.length > 1 && (\n <Card size=\"2\">\n <Flex gap=\"2\" justify=\"between\" align=\"center\">\n <Box>\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n <Translation\n defaultMessage=\"Sign out of all other devices\"\n id=\"sfkEFa\"\n description=\"Heading for sign out all other devices action\"\n />\n </Text>\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Remove access from all devices except this one\"\n id=\"LsD5BK\"\n description=\"Description for sign out all other devices action\"\n />\n </Text>\n </Box>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setOpenLogoutAllSessionsDialog(true);\n }}\n >\n <Translation\n defaultMessage=\"Sign out\"\n id=\"oKQ0rm\"\n description=\"Button text to sign out of all other devices\"\n />\n </Button>\n </Flex>\n </Card>\n )}\n\n {sessionToSignOut && (\n <LogoutDialog\n session={sessionToSignOut}\n open={openLogoutDialog}\n onOpenChange={setOpenLogoutDialog}\n />\n )}\n\n <LogoutAllSessionsDialog\n open={openLogoutAllSessionsDialog}\n onOpenChange={setOpenLogoutAllSessionsDialog}\n currentSessionId={currentSessionId}\n />\n </Flex>\n );\n};\n\ninterface UserSessionsLoadingProps extends WidgetRootDomProps {}\n\nconst UserSessionsLoading: React.FC<UserSessionsLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>\n <Translation\n defaultMessage=\"The location\"\n id=\"+7UnNu\"\n description=\"Loading placeholder text for session location\"\n />\n </Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface UserSessionsErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSessionsError: React.FC<UserSessionsErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSessionProps {\n session: SessionFieldsFragment;\n isCurrentSession?: boolean;\n onSignOut?: (session: SessionFieldsFragment) => void;\n}\n\nconst UserSession: React.FC<UserSessionProps> = ({\n session,\n isCurrentSession = false,\n onSignOut,\n}) => {\n const translate = useTranslation();\n const userAgent = parseUserAgent(session.userAgent);\n const userLocation =\n getUserLocation(session.currentLocation, session.ipAddress) ||\n translate({\n defaultMessage: \"Unknown location\",\n description:\n \"Text for a session whose location could not be determined from its user agent\",\n id: \"uMbGX5\",\n });\n const timeAgo = useComparativeReadableDate({\n date: session.lastActivityAt ? new Date(session.lastActivityAt) : null,\n });\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel>\n {userAgent?.isMobile ? <MobileIcon /> : <LaptopIcon />}\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n {userAgent?.pretty ?? (\n <Translation\n defaultMessage=\"Unknown device\"\n id=\"nF+P+T\"\n description=\"Label for a session whose device could not be determined from its user agent\"\n />\n )}\n </Text>\n\n <Flex gap=\"1\" align=\"center\">\n <Text size=\"2\" color=\"gray\" as=\"p\">\n {userLocation}\n </Text>\n\n {isCurrentSession && (\n <Badge ml=\"2\">\n <Translation\n defaultMessage=\"This device\"\n id=\"Wz8T8u\"\n description=\"Badge label indicating the current device session\"\n />\n </Badge>\n )}\n\n {!isCurrentSession &&\n session.lastActivityAt &&\n timeAgo.state === \"valid\" && (\n <>\n <Text size=\"2\" color=\"gray\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last seen {timeAgo}\"\n id=\"gF+kUw\"\n description=\"Text showing when the session was last active\"\n values={{ timeAgo: timeAgo.formatted }}\n />\n </Text>\n </>\n )}\n </Flex>\n </Flex>\n\n {!isCurrentSession && (\n <Flex ml=\"auto\">\n <Button variant=\"secondary\" onClick={() => onSignOut?.(session)}>\n <Translation\n defaultMessage=\"Sign out\"\n id=\"sT1L78\"\n description=\"Button text to sign out of a session\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getWidgetDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-sessions\",\n widgetState: state,\n });\n}\n\nfunction getUserLocation(\n location?: {\n cityName: string;\n countryISOCode: string;\n } | null,\n ipAddress?: string | null,\n): string | null {\n if (location) {\n return (\n [location.cityName, location.countryISOCode].filter(Boolean).join(\", \") ||\n null\n );\n }\n\n return ipAddress || null;\n}\n\nexport type { UserSessionsLoadingProps, UserSessionsErrorProps };\nexport { UserSessions, UserSessionsLoading, UserSessionsError };\n"],"mappings":"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"}
@@ -22,13 +22,13 @@ const OrganizationSwitcher = ({ organizations, switchToOrganization, variant, or
22
22
  variant,
23
23
  ...domProps,
24
24
  message: translate({
25
- id: "XimGbo",
25
+ id: "aZ7eyn",
26
26
  defaultMessage: "No organizations found",
27
27
  description: "Shown in the disabled organization switcher when the user belongs to no organizations"
28
28
  })
29
29
  });
30
30
  const currentOrganizationName = currentOrganization?.name ?? translate({
31
- id: "aZ7eyn",
31
+ id: "OLi4Va",
32
32
  defaultMessage: "Select an organization",
33
33
  description: "Placeholder in the organization switcher trigger when the user has organizations but none is active"
34
34
  });
@@ -1 +1 @@
1
- {"version":3,"file":"organization-switcher.js","names":["DropdownMenu.Root","DropdownMenu.Trigger","Button","DropdownMenu.TriggerIcon","DropdownMenu.Content","DropdownMenu.Group","DropdownMenu.Label","DropdownMenu.Item","Skeleton"],"sources":["../../../../src/widgets/organization-switcher/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n ChevronDownIcon,\n Flex,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport cx from \"clsx\";\nimport type { ListUserOrganizationsQuery } from \"../../api/client-graphql/generated.js\";\nimport { Button, DropdownMenu, Skeleton } from \"../../components/elements.js\";\nimport type { ButtonProps } from \"../../components/elements.js\";\nimport { getErrorMessage } from \"../../components/generic-error.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { useWidgetsInvalidator } from \"../../lib/use-widgets-invalidator.js\";\nimport { isPromiseLike } from \"../../lib/utils.js\";\nimport { getWidgetDomProps } from \"../../lib/widget-dom-props.js\";\nimport type {\n WidgetRootDomProps,\n WidgetRootState,\n} from \"../../lib/widget-types.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void | Promise<void>;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ntype UserOrganization = ListUserOrganizationsQuery[\"organizations\"][number];\n\ninterface OrganizationSwitcherProps extends OrganizationSwitcherPassthroughProps {\n organizations: UserOrganization[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant,\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.isCurrent,\n );\n const invalidateAllWidgets = useWidgetsInvalidator();\n const translate = useTranslation();\n\n if (organizations.length === 0) {\n return (\n <OrganizationSwitcherError\n variant={variant}\n {...domProps}\n message={translate({\n id: \"XimGbo\",\n defaultMessage: \"No organizations found\",\n description:\n \"Shown in the disabled organization switcher when the user belongs to no organizations\",\n })}\n />\n );\n }\n\n const currentOrganizationName =\n currentOrganization?.name ??\n translate({\n id: \"aZ7eyn\",\n defaultMessage: \"Select an organization\",\n description:\n \"Placeholder in the organization switcher trigger when the user has organizations but none is active\",\n });\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n variant=\"secondary\"\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO(v2): Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganizationName}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (\n !currentOrganization ||\n organization.id !== currentOrganization.id\n ) {\n const result = switchToOrganization({\n organizationId: organization.id,\n });\n if (isPromiseLike(result)) {\n result.then(invalidateAllWidgets);\n } else {\n invalidateAllWidgets();\n }\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.isCurrent && (\n <VisuallyHidden>\n <Translation\n defaultMessage=\"(current)\"\n id=\"daFXTP\"\n description=\"Label for screen readers indicating current organization\"\n />\n </VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.isCurrent ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = ({ variant, ...props }: OrganizationSwitcherLoadingProps) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n <Text>\n <Translation\n defaultMessage=\"Loading...\"\n id=\"MPkIXK\"\n description=\"Placeholder text while organizations load\"\n />\n </Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error?: unknown;\n message?: string;\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherError: React.FC<OrganizationSwitcherErrorProps> = ({\n error,\n variant,\n message,\n ...domProps\n}) => {\n const translate = useTranslation();\n const heading = message || getErrorMessage(error, translate).heading;\n\n return (\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\ninterface TruncatedOrganizationNameProps {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}\n\nconst TruncatedOrganizationName: React.FC<TruncatedOrganizationNameProps> = ({\n organizationName,\n truncateBehavior,\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction mapVariantProps(variant?: OrganizationSwitcherVariant): ButtonProps {\n const variantProps: ButtonProps = {};\n // Passing `undefined` to the variant prop will result in overrides to props we\n // set internally. This should be addressed in Radix Themes, but we can\n // explicitly set it only when it's provided and _not_ undefined.\n if (variant) {\n variantProps.unsafe_radixVariant = variant;\n }\n return variantProps;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getWidgetDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\nexport type {\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n OrganizationSwitcherPassthroughProps,\n UserOrganization,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"organization-switcher.js","names":["DropdownMenu.Root","DropdownMenu.Trigger","Button","DropdownMenu.TriggerIcon","DropdownMenu.Content","DropdownMenu.Group","DropdownMenu.Label","DropdownMenu.Item","Skeleton"],"sources":["../../../../src/widgets/organization-switcher/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n ChevronDownIcon,\n Flex,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport cx from \"clsx\";\nimport type { ListUserOrganizationsQuery } from \"../../api/client-graphql/generated.js\";\nimport { Button, DropdownMenu, Skeleton } from \"../../components/elements.js\";\nimport type { ButtonProps } from \"../../components/elements.js\";\nimport { getErrorMessage } from \"../../components/generic-error.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { useWidgetsInvalidator } from \"../../lib/use-widgets-invalidator.js\";\nimport { isPromiseLike } from \"../../lib/utils.js\";\nimport { getWidgetDomProps } from \"../../lib/widget-dom-props.js\";\nimport type {\n WidgetRootDomProps,\n WidgetRootState,\n} from \"../../lib/widget-types.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void | Promise<void>;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ntype UserOrganization = ListUserOrganizationsQuery[\"organizations\"][number];\n\ninterface OrganizationSwitcherProps extends OrganizationSwitcherPassthroughProps {\n organizations: UserOrganization[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant,\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.isCurrent,\n );\n const invalidateAllWidgets = useWidgetsInvalidator();\n const translate = useTranslation();\n\n if (organizations.length === 0) {\n return (\n <OrganizationSwitcherError\n variant={variant}\n {...domProps}\n message={translate({\n id: \"aZ7eyn\",\n defaultMessage: \"No organizations found\",\n description:\n \"Shown in the disabled organization switcher when the user belongs to no organizations\",\n })}\n />\n );\n }\n\n const currentOrganizationName =\n currentOrganization?.name ??\n translate({\n id: \"OLi4Va\",\n defaultMessage: \"Select an organization\",\n description:\n \"Placeholder in the organization switcher trigger when the user has organizations but none is active\",\n });\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n variant=\"secondary\"\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO(v2): Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganizationName}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (\n !currentOrganization ||\n organization.id !== currentOrganization.id\n ) {\n const result = switchToOrganization({\n organizationId: organization.id,\n });\n if (isPromiseLike(result)) {\n result.then(invalidateAllWidgets);\n } else {\n invalidateAllWidgets();\n }\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.isCurrent && (\n <VisuallyHidden>\n <Translation\n defaultMessage=\"(current)\"\n id=\"daFXTP\"\n description=\"Label for screen readers indicating current organization\"\n />\n </VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.isCurrent ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = ({ variant, ...props }: OrganizationSwitcherLoadingProps) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n <Text>\n <Translation\n defaultMessage=\"Loading...\"\n id=\"MPkIXK\"\n description=\"Placeholder text while organizations load\"\n />\n </Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error?: unknown;\n message?: string;\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherError: React.FC<OrganizationSwitcherErrorProps> = ({\n error,\n variant,\n message,\n ...domProps\n}) => {\n const translate = useTranslation();\n const heading = message || getErrorMessage(error, translate).heading;\n\n return (\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\ninterface TruncatedOrganizationNameProps {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}\n\nconst TruncatedOrganizationName: React.FC<TruncatedOrganizationNameProps> = ({\n organizationName,\n truncateBehavior,\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction mapVariantProps(variant?: OrganizationSwitcherVariant): ButtonProps {\n const variantProps: ButtonProps = {};\n // Passing `undefined` to the variant prop will result in overrides to props we\n // set internally. This should be addressed in Radix Themes, but we can\n // explicitly set it only when it's provided and _not_ undefined.\n if (variant) {\n variantProps.unsafe_radixVariant = variant;\n }\n return variantProps;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getWidgetDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\nexport type {\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n OrganizationSwitcherPassthroughProps,\n UserOrganization,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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"}
@@ -136,7 +136,7 @@ function toAccountDisplayNameInput(name) {
136
136
  const ConnectionNameField = ({ id, value, onChange }) => {
137
137
  const placeholder = useTranslation()({
138
138
  defaultMessage: "e.g. Marketing",
139
- id: "Rn4cLp",
139
+ id: "pWC98E",
140
140
  description: "Placeholder for the connection name input"
141
141
  });
142
142
  return /* @__PURE__ */ jsxs(Flex, {
@@ -149,7 +149,7 @@ const ConnectionNameField = ({ id, value, onChange }) => {
149
149
  htmlFor: id,
150
150
  children: /* @__PURE__ */ jsx(Translation, {
151
151
  defaultMessage: "Name",
152
- id: "Rn1lNm",
152
+ id: "KdgU9T",
153
153
  description: "Label for the connection name input"
154
154
  })
155
155
  }), /* @__PURE__ */ jsx(Text, {
@@ -157,7 +157,7 @@ const ConnectionNameField = ({ id, value, onChange }) => {
157
157
  color: "gray",
158
158
  children: /* @__PURE__ */ jsx(Translation, {
159
159
  defaultMessage: "Optional",
160
- id: "Rn0oPt",
160
+ id: "2Yy441",
161
161
  description: "Hint beside the connection name input saying it can be left empty"
162
162
  })
163
163
  })]
@@ -189,7 +189,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
189
189
  const errorMessage = error instanceof ApiError && error.message ? error.message : null;
190
190
  const placeholder = translate({
191
191
  defaultMessage: "e.g. Marketing",
192
- id: "Rn4cLp",
192
+ id: "pWC98E",
193
193
  description: "Placeholder for the connection name input"
194
194
  });
195
195
  return /* @__PURE__ */ jsx(Root, {
@@ -203,7 +203,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
203
203
  weight: "bold",
204
204
  children: /* @__PURE__ */ jsx(Translation, {
205
205
  defaultMessage: "Rename {integrationName} connection",
206
- id: "Rn7tTl",
206
+ id: "c1jT5Q",
207
207
  description: "Dialog title for renaming one connection to a provider",
208
208
  values: { integrationName }
209
209
  })
@@ -213,7 +213,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
213
213
  mt: "1",
214
214
  children: /* @__PURE__ */ jsx(Translation, {
215
215
  defaultMessage: "Give this connection a name to tell it apart from your other {integrationName} connections.",
216
- id: "Rn2dSc",
216
+ id: "Ptf2r1",
217
217
  description: "Explains what a connection name is for",
218
218
  values: { integrationName }
219
219
  })
@@ -224,7 +224,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
224
224
  role: "alert",
225
225
  children: /* @__PURE__ */ jsx(Callout.Text, { children: errorMessage ?? /* @__PURE__ */ jsx(Translation, {
226
226
  defaultMessage: "An error occurred while renaming this connection. Please try again.",
227
- id: "Rn9eRr",
227
+ id: "0grPwn",
228
228
  description: "Error message when renaming a connection fails"
229
229
  }) })
230
230
  }),
@@ -234,7 +234,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
234
234
  role: "status",
235
235
  children: /* @__PURE__ */ jsx(Callout.Text, { children: warning.code === DUPLICATE_LABEL_WARNING ? /* @__PURE__ */ jsx(Translation, {
236
236
  defaultMessage: "Saved. Another {integrationName} connection already uses this name, so you may want to pick one that tells them apart.",
237
- id: "Rn2wDp",
237
+ id: "eB4eyQ",
238
238
  description: "Notice after renaming a connection to a name another connection to the same provider already has",
239
239
  values: { integrationName }
240
240
  }) : warning.message })
@@ -258,7 +258,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
258
258
  htmlFor: `rename-connection-${installation.id}`,
259
259
  children: /* @__PURE__ */ jsx(Translation, {
260
260
  defaultMessage: "Name",
261
- id: "Rn1lNm",
261
+ id: "KdgU9T",
262
262
  description: "Label for the connection name input"
263
263
  })
264
264
  }), /* @__PURE__ */ jsx(TextFieldRoot, {
@@ -278,7 +278,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
278
278
  variant: "secondary",
279
279
  children: warnings.length > 0 ? /* @__PURE__ */ jsx(Translation, {
280
280
  defaultMessage: "Done",
281
- id: "Rn6dDn",
281
+ id: "YlARFG",
282
282
  description: "Button to close the rename dialog after a name was saved with a warning"
283
283
  }) : /* @__PURE__ */ jsx(Translation, {
284
284
  defaultMessage: "Cancel",
@@ -291,7 +291,7 @@ const RenameConnectionDialog = ({ integrationName, installation, owner = "user",
291
291
  loading: isPending,
292
292
  children: /* @__PURE__ */ jsx(Translation, {
293
293
  defaultMessage: "Save",
294
- id: "Rn5sVe",
294
+ id: "JmvID+",
295
295
  description: "Button to save a connection's new name"
296
296
  })
297
297
  })]
@@ -311,7 +311,7 @@ const ConnectionCountStatus = ({ count }) => {
311
311
  state: "neutral",
312
312
  children: /* @__PURE__ */ jsx(Translation, {
313
313
  defaultMessage: "{count} connections",
314
- id: "Rn3cCt",
314
+ id: "ZarniP",
315
315
  description: "Status for a provider grouping two or more connections, giving how many",
316
316
  values: { count }
317
317
  })
@@ -320,21 +320,21 @@ const ConnectionCountStatus = ({ count }) => {
320
320
  const RenameMenuLabel = () => {
321
321
  return /* @__PURE__ */ jsx(Translation, {
322
322
  defaultMessage: "Rename",
323
- id: "Rn6mRn",
323
+ id: "iiQbUM",
324
324
  description: "Menu option to rename one connection"
325
325
  });
326
326
  };
327
327
  const ConnectAnotherAccountMenuLabel = () => {
328
328
  return /* @__PURE__ */ jsx(Translation, {
329
329
  defaultMessage: "Connect another account",
330
- id: "Rn8mCa",
330
+ id: "SNK0to",
331
331
  description: "Menu option to add another connection to the same provider"
332
332
  });
333
333
  };
334
334
  const AddConnectionButtonLabel = () => {
335
335
  return /* @__PURE__ */ jsx(Translation, {
336
336
  defaultMessage: "Add connection",
337
- id: "Rn0bAc",
337
+ id: "DFzo7c",
338
338
  description: "Button to add another connection to a provider that already has several"
339
339
  });
340
340
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pipes-connections.js","names":["TextField.Root","Dialog.Root","Dialog.Content","Dialog.Title","Dialog.Description","Dialog.Close","Button"],"sources":["../../../../src/widgets/pipes/pipes-connections.tsx"],"sourcesContent":["\"use client\";\nimport { Callout, Flex, Text } from \"@radix-ui/themes\";\nimport { useEffect, useState } from \"react\";\nimport type {\n ConnectionIntent,\n DataProviderConnectionLabelResultFieldsFragment,\n UpdateDataProviderConnectionLabelInput,\n} from \"../../api/client-graphql/generated.js\";\nimport { useClientGraphqlMutation } from \"../../api/client-graphql/hooks.js\";\nimport { ApiError } from \"../../api/errors.js\";\nimport { Button, Dialog, Label, TextField } from \"../../components/elements.js\";\nimport { Status } from \"../../components/status.js\";\nimport { useInvalidateConnections } from \"../../lib/api/pipes.js\";\nimport type { DataInstallation } from \"../../lib/api/types.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport type { ConnectionOwner } from \"./pipes.js\";\n\n/**\n * Multiple connections per provider, shared by the member and administrator\n * widgets: naming a connection, targeting the connect flows at one exact\n * connection (or at a new one), and renaming.\n */\n\n/**\n * How one connection is named within its provider's group: the label someone\n * gave it, then the provider account it disclosed, then the provider itself.\n */\nfunction getConnectionLabel(\n integrationName: string,\n installation: DataInstallation,\n): string {\n return (\n installation.account_display_name?.trim() ||\n installation.account_identifier ||\n integrationName\n );\n}\n\n/**\n * Which connection a connect flow writes. Left unset, the flows keep the API's\n * compatibility behavior: they write the owner's single compatibility\n * connection, creating it if there is none.\n */\ntype ConnectionTarget =\n /**\n * Create another connection alongside the owner's existing ones.\n * `idempotencyKey` identifies one logical Add, so a retry after an\n * ambiguous failure returns the connection the first attempt created\n * instead of creating a second (see {@link createAddConnectionTarget}).\n */\n | { intent: \"Add\"; idempotencyKey?: string }\n /** Re-authorize, or replace the credentials of, one exact connection. */\n | { intent: \"Reauthorize\"; connectedAccountId: string };\n\n/** Requests an Add; the flow that runs it mints the idempotency key. */\nconst ADD_CONNECTION: ConnectionTarget = { intent: \"Add\" };\n\n/**\n * A random key for one logical Add. `crypto.randomUUID` needs a secure\n * context, so plain-HTTP hosts fall back to `getRandomValues`, which doesn't.\n */\nfunction createIdempotencyKey(): string {\n if (typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\n/**\n * The target for one logical Add, carrying a fresh idempotency key. Mint it\n * once when the Add starts and reuse it for every retry of that Add; a\n * deliberate second Add gets its own. The key is only honored with the Add\n * intent, and within 24 hours of the first attempt.\n */\nfunction createAddConnectionTarget(): ConnectionTarget {\n return { intent: \"Add\", idempotencyKey: createIdempotencyKey() };\n}\n\n/**\n * The target for writing an existing connection's credentials. Standard\n * connections are only reachable by naming them; the compatibility connection\n * is what an untargeted write already means, and leaving the intent off keeps\n * working where the environment has multiple connections turned off (the API\n * refuses explicit intents there).\n */\nfunction getConnectionTarget(\n installation: DataInstallation | null | undefined,\n): ConnectionTarget | undefined {\n return installation?.connection_role === \"standard\"\n ? { intent: \"Reauthorize\", connectedAccountId: installation.id }\n : undefined;\n}\n\n/**\n * Whether a provider's connections can be renamed: only once it can hold more\n * than one, since a lone connection's name is never shown beside another's.\n * The API reports no setting for this, so it's inferred: either an add is\n * available, or a standard connection exists, which only multiple connections\n * create (and which any provider with several connections has, at the cap\n * too).\n */\nfunction canRenameConnections(integration: {\n capabilities: { canAddConnection: boolean };\n connected_accounts: DataInstallation[];\n}): boolean {\n return (\n integration.capabilities.canAddConnection ||\n integration.connected_accounts.some(\n (connection) => connection.connection_role === \"standard\",\n )\n );\n}\n\n/**\n * The `connectionIntent` / `connectedAccountId` fields of a connect input.\n * Every connect input takes these, including OAuth authorization, which has\n * no idempotency key — see {@link toCreationTargetInput} for the inputs that do.\n */\nfunction toConnectionTargetInput(target: ConnectionTarget | undefined): {\n connectionIntent?: ConnectionIntent;\n connectedAccountId?: string;\n} {\n if (!target) {\n return {};\n }\n return target.intent === \"Add\"\n ? { connectionIntent: \"Add\" }\n : {\n connectionIntent: \"Reauthorize\",\n connectedAccountId: target.connectedAccountId,\n };\n}\n\n/**\n * {@link toConnectionTargetInput} plus the Add's `idempotencyKey`, for the\n * synchronous creation inputs (API key and client credentials) that accept it.\n * Never spread this into an authorization input: the API rejects the field.\n */\nfunction toCreationTargetInput(target: ConnectionTarget | undefined): {\n connectionIntent?: ConnectionIntent;\n connectedAccountId?: string;\n idempotencyKey?: string;\n} {\n const input = toConnectionTargetInput(target);\n return target?.intent === \"Add\" && target.idempotencyKey\n ? { ...input, idempotencyKey: target.idempotencyKey }\n : input;\n}\n\n/**\n * Saves a connection's label through the owner's mutation (`null` clears it\n * back to the computed fallback) and refreshes the owner's lists.\n */\nfunction useRenameConnection(owner: ConnectionOwner) {\n const invalidateConnections = useInvalidateConnections(owner);\n return useClientGraphqlMutation({\n mutationFn: async (\n sdk,\n input: UpdateDataProviderConnectionLabelInput,\n ): Promise<DataProviderConnectionLabelResultFieldsFragment> => {\n if (owner === \"organization\") {\n const { updateOrganizationDataProviderConnectionLabel } =\n await sdk.UpdateOrganizationDataProviderConnectionLabel({ input });\n return updateOrganizationDataProviderConnectionLabel;\n }\n const { updateDataProviderConnectionLabel } =\n await sdk.UpdateDataProviderConnectionLabel({ input });\n return updateDataProviderConnectionLabel;\n },\n onSuccess: invalidateConnections,\n });\n}\n\n/** The label code the API warns with when a sibling already uses the name. */\nconst DUPLICATE_LABEL_WARNING = \"duplicate_account_display_name\";\n\n/** Maximum label length the API accepts (PVIT-904). */\nconst MAX_LABEL_LENGTH = 255;\n\n/**\n * The `accountDisplayName` field of a creation input: the trimmed name when\n * one was entered, otherwise nothing, so an untouched field never sends an\n * empty label.\n */\nfunction toAccountDisplayNameInput(name: string | undefined): {\n accountDisplayName?: string;\n} {\n const trimmed = name?.trim();\n return trimmed ? { accountDisplayName: trimmed } : {};\n}\n\ninterface ConnectionNameFieldProps {\n id: string;\n value: string;\n onChange: (value: string) => void;\n}\n\n/**\n * The optional name a connect dialog collects for the connection it creates,\n * so it can be told apart from the owner's other connections to the provider.\n * Only the sectioned experiences ask for it, and only when creating.\n */\nconst ConnectionNameField: React.FC<ConnectionNameFieldProps> = ({\n id,\n value,\n onChange,\n}) => {\n const translate = useTranslation();\n const placeholder = translate({\n defaultMessage: \"e.g. Marketing\",\n id: \"Rn4cLp\",\n description: \"Placeholder for the connection name input\",\n });\n\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Flex align=\"baseline\" gap=\"2\">\n <Label htmlFor={id}>\n <Translation\n defaultMessage=\"Name\"\n id=\"Rn1lNm\"\n description=\"Label for the connection name input\"\n />\n </Label>\n <Text size=\"1\" color=\"gray\">\n <Translation\n defaultMessage=\"Optional\"\n id=\"Rn0oPt\"\n description=\"Hint beside the connection name input saying it can be left empty\"\n />\n </Text>\n </Flex>\n <TextField.Root\n id={id}\n value={value}\n maxLength={MAX_LABEL_LENGTH}\n autoComplete=\"off\"\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n />\n </Flex>\n );\n};\n\ninterface RenameConnectionDialogProps {\n integrationName: string;\n installation: DataInstallation;\n owner?: ConnectionOwner;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\n/**\n * Renames one connection. A duplicate name never blocks the save; when the API\n * warns about one, the dialog stays open on the saved name to say so, and the\n * field stays editable so a distinct name can be saved right away.\n */\nconst RenameConnectionDialog: React.FC<RenameConnectionDialogProps> = ({\n integrationName,\n installation,\n owner = \"user\",\n open,\n onOpenChange,\n}) => {\n const [label, setLabel] = useState(installation.account_display_name ?? \"\");\n const translate = useTranslation();\n const { mutate, data, error, reset, isPending } = useRenameConnection(owner);\n\n // Mounted only while open, so the field starts from the saved label.\n useEffect(() => {\n reset();\n }, [reset]);\n\n const trimmed = label.trim();\n // After a save that warned, the name to compare against is the one just\n // saved, so the warning can be answered with another name straight away.\n const savedLabel = data\n ? (data.connection.accountDisplayName ?? \"\")\n : (installation.account_display_name ?? \"\");\n const unchanged = trimmed === savedLabel;\n // A save's warnings describe the name it saved, so they only stand while\n // the field still shows that name. Once it's edited they (and \"Done\") give\n // way to Cancel, so closing can't be mistaken for keeping the new text.\n const warnings = unchanged ? (data?.warnings ?? []) : [];\n const errorMessage =\n error instanceof ApiError && error.message ? error.message : null;\n\n const placeholder = translate({\n defaultMessage: \"e.g. Marketing\",\n id: \"Rn4cLp\",\n description: \"Placeholder for the connection name input\",\n });\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n <Translation\n defaultMessage=\"Rename {integrationName} connection\"\n id=\"Rn7tTl\"\n description=\"Dialog title for renaming one connection to a provider\"\n values={{ integrationName }}\n />\n </Dialog.Title>\n <Dialog.Description color=\"gray\" mt=\"1\">\n <Translation\n defaultMessage=\"Give this connection a name to tell it apart from your other {integrationName} connections.\"\n id=\"Rn2dSc\"\n description=\"Explains what a connection name is for\"\n values={{ integrationName }}\n />\n </Dialog.Description>\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred while renaming this connection. Please try again.\"\n id=\"Rn9eRr\"\n description=\"Error message when renaming a connection fails\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n {warnings.map((warning) => (\n <Callout.Root key={warning.code} my=\"3\" color=\"amber\" role=\"status\">\n <Callout.Text>\n {warning.code === DUPLICATE_LABEL_WARNING ? (\n <Translation\n defaultMessage=\"Saved. Another {integrationName} connection already uses this name, so you may want to pick one that tells them apart.\"\n id=\"Rn2wDp\"\n description=\"Notice after renaming a connection to a name another connection to the same provider already has\"\n values={{ integrationName }}\n />\n ) : (\n warning.message\n )}\n </Callout.Text>\n </Callout.Root>\n ))}\n\n <form\n onSubmit={(event) => {\n event.preventDefault();\n if (unchanged) {\n return;\n }\n mutate(\n { id: installation.id, accountDisplayName: trimmed || null },\n {\n onSuccess: (result) => {\n if (result.warnings.length === 0) {\n onOpenChange(false);\n }\n },\n },\n );\n }}\n >\n <Flex direction=\"column\" gap=\"1\" mt=\"4\">\n <Label htmlFor={`rename-connection-${installation.id}`}>\n <Translation\n defaultMessage=\"Name\"\n id=\"Rn1lNm\"\n description=\"Label for the connection name input\"\n />\n </Label>\n <TextField.Root\n id={`rename-connection-${installation.id}`}\n value={label}\n maxLength={MAX_LABEL_LENGTH}\n autoComplete=\"off\"\n placeholder={placeholder}\n onChange={(event) => setLabel(event.target.value)}\n />\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button type=\"button\" variant=\"secondary\">\n {/* With a saved name shown (and warned about), closing keeps it. */}\n {warnings.length > 0 ? (\n <Translation\n defaultMessage=\"Done\"\n id=\"Rn6dDn\"\n description=\"Button to close the rename dialog after a name was saved with a warning\"\n />\n ) : (\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n )}\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n disabled={isPending || unchanged}\n loading={isPending}\n >\n <Translation\n defaultMessage=\"Save\"\n id=\"Rn5sVe\"\n description=\"Button to save a connection's new name\"\n />\n </Button>\n </Flex>\n </form>\n </Dialog.Content>\n </Dialog.Root>\n );\n};\n\ninterface ConnectionCountStatusProps {\n count: number;\n}\n\n/**\n * A provider row's status once it groups its connections, which it only does\n * for two or more — hence no singular form (plurals also need the optional\n * I18nProvider to format).\n */\nconst ConnectionCountStatus: React.FC<ConnectionCountStatusProps> = ({\n count,\n}) => {\n return (\n <Status state=\"neutral\">\n <Translation\n defaultMessage=\"{count} connections\"\n id=\"Rn3cCt\"\n description=\"Status for a provider grouping two or more connections, giving how many\"\n values={{ count }}\n />\n </Status>\n );\n};\n\nconst RenameMenuLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Rename\"\n id=\"Rn6mRn\"\n description=\"Menu option to rename one connection\"\n />\n );\n};\n\nconst ConnectAnotherAccountMenuLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Connect another account\"\n id=\"Rn8mCa\"\n description=\"Menu option to add another connection to the same provider\"\n />\n );\n};\n\nconst AddConnectionButtonLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Add connection\"\n id=\"Rn0bAc\"\n description=\"Button to add another connection to a provider that already has several\"\n />\n );\n};\nexport type { ConnectionTarget };\nexport {\n getConnectionLabel,\n ADD_CONNECTION,\n createAddConnectionTarget,\n getConnectionTarget,\n canRenameConnections,\n toConnectionTargetInput,\n toCreationTargetInput,\n toAccountDisplayNameInput,\n ConnectionNameField,\n RenameConnectionDialog,\n ConnectionCountStatus,\n RenameMenuLabel,\n ConnectAnotherAccountMenuLabel,\n AddConnectionButtonLabel,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"pipes-connections.js","names":["TextField.Root","Dialog.Root","Dialog.Content","Dialog.Title","Dialog.Description","Dialog.Close","Button"],"sources":["../../../../src/widgets/pipes/pipes-connections.tsx"],"sourcesContent":["\"use client\";\nimport { Callout, Flex, Text } from \"@radix-ui/themes\";\nimport { useEffect, useState } from \"react\";\nimport type {\n ConnectionIntent,\n DataProviderConnectionLabelResultFieldsFragment,\n UpdateDataProviderConnectionLabelInput,\n} from \"../../api/client-graphql/generated.js\";\nimport { useClientGraphqlMutation } from \"../../api/client-graphql/hooks.js\";\nimport { ApiError } from \"../../api/errors.js\";\nimport { Button, Dialog, Label, TextField } from \"../../components/elements.js\";\nimport { Status } from \"../../components/status.js\";\nimport { useInvalidateConnections } from \"../../lib/api/pipes.js\";\nimport type { DataInstallation } from \"../../lib/api/types.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport type { ConnectionOwner } from \"./pipes.js\";\n\n/**\n * Multiple connections per provider, shared by the member and administrator\n * widgets: naming a connection, targeting the connect flows at one exact\n * connection (or at a new one), and renaming.\n */\n\n/**\n * How one connection is named within its provider's group: the label someone\n * gave it, then the provider account it disclosed, then the provider itself.\n */\nfunction getConnectionLabel(\n integrationName: string,\n installation: DataInstallation,\n): string {\n return (\n installation.account_display_name?.trim() ||\n installation.account_identifier ||\n integrationName\n );\n}\n\n/**\n * Which connection a connect flow writes. Left unset, the flows keep the API's\n * compatibility behavior: they write the owner's single compatibility\n * connection, creating it if there is none.\n */\ntype ConnectionTarget =\n /**\n * Create another connection alongside the owner's existing ones.\n * `idempotencyKey` identifies one logical Add, so a retry after an\n * ambiguous failure returns the connection the first attempt created\n * instead of creating a second (see {@link createAddConnectionTarget}).\n */\n | { intent: \"Add\"; idempotencyKey?: string }\n /** Re-authorize, or replace the credentials of, one exact connection. */\n | { intent: \"Reauthorize\"; connectedAccountId: string };\n\n/** Requests an Add; the flow that runs it mints the idempotency key. */\nconst ADD_CONNECTION: ConnectionTarget = { intent: \"Add\" };\n\n/**\n * A random key for one logical Add. `crypto.randomUUID` needs a secure\n * context, so plain-HTTP hosts fall back to `getRandomValues`, which doesn't.\n */\nfunction createIdempotencyKey(): string {\n if (typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\n/**\n * The target for one logical Add, carrying a fresh idempotency key. Mint it\n * once when the Add starts and reuse it for every retry of that Add; a\n * deliberate second Add gets its own. The key is only honored with the Add\n * intent, and within 24 hours of the first attempt.\n */\nfunction createAddConnectionTarget(): ConnectionTarget {\n return { intent: \"Add\", idempotencyKey: createIdempotencyKey() };\n}\n\n/**\n * The target for writing an existing connection's credentials. Standard\n * connections are only reachable by naming them; the compatibility connection\n * is what an untargeted write already means, and leaving the intent off keeps\n * working where the environment has multiple connections turned off (the API\n * refuses explicit intents there).\n */\nfunction getConnectionTarget(\n installation: DataInstallation | null | undefined,\n): ConnectionTarget | undefined {\n return installation?.connection_role === \"standard\"\n ? { intent: \"Reauthorize\", connectedAccountId: installation.id }\n : undefined;\n}\n\n/**\n * Whether a provider's connections can be renamed: only once it can hold more\n * than one, since a lone connection's name is never shown beside another's.\n * The API reports no setting for this, so it's inferred: either an add is\n * available, or a standard connection exists, which only multiple connections\n * create (and which any provider with several connections has, at the cap\n * too).\n */\nfunction canRenameConnections(integration: {\n capabilities: { canAddConnection: boolean };\n connected_accounts: DataInstallation[];\n}): boolean {\n return (\n integration.capabilities.canAddConnection ||\n integration.connected_accounts.some(\n (connection) => connection.connection_role === \"standard\",\n )\n );\n}\n\n/**\n * The `connectionIntent` / `connectedAccountId` fields of a connect input.\n * Every connect input takes these, including OAuth authorization, which has\n * no idempotency key — see {@link toCreationTargetInput} for the inputs that do.\n */\nfunction toConnectionTargetInput(target: ConnectionTarget | undefined): {\n connectionIntent?: ConnectionIntent;\n connectedAccountId?: string;\n} {\n if (!target) {\n return {};\n }\n return target.intent === \"Add\"\n ? { connectionIntent: \"Add\" }\n : {\n connectionIntent: \"Reauthorize\",\n connectedAccountId: target.connectedAccountId,\n };\n}\n\n/**\n * {@link toConnectionTargetInput} plus the Add's `idempotencyKey`, for the\n * synchronous creation inputs (API key and client credentials) that accept it.\n * Never spread this into an authorization input: the API rejects the field.\n */\nfunction toCreationTargetInput(target: ConnectionTarget | undefined): {\n connectionIntent?: ConnectionIntent;\n connectedAccountId?: string;\n idempotencyKey?: string;\n} {\n const input = toConnectionTargetInput(target);\n return target?.intent === \"Add\" && target.idempotencyKey\n ? { ...input, idempotencyKey: target.idempotencyKey }\n : input;\n}\n\n/**\n * Saves a connection's label through the owner's mutation (`null` clears it\n * back to the computed fallback) and refreshes the owner's lists.\n */\nfunction useRenameConnection(owner: ConnectionOwner) {\n const invalidateConnections = useInvalidateConnections(owner);\n return useClientGraphqlMutation({\n mutationFn: async (\n sdk,\n input: UpdateDataProviderConnectionLabelInput,\n ): Promise<DataProviderConnectionLabelResultFieldsFragment> => {\n if (owner === \"organization\") {\n const { updateOrganizationDataProviderConnectionLabel } =\n await sdk.UpdateOrganizationDataProviderConnectionLabel({ input });\n return updateOrganizationDataProviderConnectionLabel;\n }\n const { updateDataProviderConnectionLabel } =\n await sdk.UpdateDataProviderConnectionLabel({ input });\n return updateDataProviderConnectionLabel;\n },\n onSuccess: invalidateConnections,\n });\n}\n\n/** The label code the API warns with when a sibling already uses the name. */\nconst DUPLICATE_LABEL_WARNING = \"duplicate_account_display_name\";\n\n/** Maximum label length the API accepts (PVIT-904). */\nconst MAX_LABEL_LENGTH = 255;\n\n/**\n * The `accountDisplayName` field of a creation input: the trimmed name when\n * one was entered, otherwise nothing, so an untouched field never sends an\n * empty label.\n */\nfunction toAccountDisplayNameInput(name: string | undefined): {\n accountDisplayName?: string;\n} {\n const trimmed = name?.trim();\n return trimmed ? { accountDisplayName: trimmed } : {};\n}\n\ninterface ConnectionNameFieldProps {\n id: string;\n value: string;\n onChange: (value: string) => void;\n}\n\n/**\n * The optional name a connect dialog collects for the connection it creates,\n * so it can be told apart from the owner's other connections to the provider.\n * Only the sectioned experiences ask for it, and only when creating.\n */\nconst ConnectionNameField: React.FC<ConnectionNameFieldProps> = ({\n id,\n value,\n onChange,\n}) => {\n const translate = useTranslation();\n const placeholder = translate({\n defaultMessage: \"e.g. Marketing\",\n id: \"pWC98E\",\n description: \"Placeholder for the connection name input\",\n });\n\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Flex align=\"baseline\" gap=\"2\">\n <Label htmlFor={id}>\n <Translation\n defaultMessage=\"Name\"\n id=\"KdgU9T\"\n description=\"Label for the connection name input\"\n />\n </Label>\n <Text size=\"1\" color=\"gray\">\n <Translation\n defaultMessage=\"Optional\"\n id=\"2Yy441\"\n description=\"Hint beside the connection name input saying it can be left empty\"\n />\n </Text>\n </Flex>\n <TextField.Root\n id={id}\n value={value}\n maxLength={MAX_LABEL_LENGTH}\n autoComplete=\"off\"\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n />\n </Flex>\n );\n};\n\ninterface RenameConnectionDialogProps {\n integrationName: string;\n installation: DataInstallation;\n owner?: ConnectionOwner;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\n/**\n * Renames one connection. A duplicate name never blocks the save; when the API\n * warns about one, the dialog stays open on the saved name to say so, and the\n * field stays editable so a distinct name can be saved right away.\n */\nconst RenameConnectionDialog: React.FC<RenameConnectionDialogProps> = ({\n integrationName,\n installation,\n owner = \"user\",\n open,\n onOpenChange,\n}) => {\n const [label, setLabel] = useState(installation.account_display_name ?? \"\");\n const translate = useTranslation();\n const { mutate, data, error, reset, isPending } = useRenameConnection(owner);\n\n // Mounted only while open, so the field starts from the saved label.\n useEffect(() => {\n reset();\n }, [reset]);\n\n const trimmed = label.trim();\n // After a save that warned, the name to compare against is the one just\n // saved, so the warning can be answered with another name straight away.\n const savedLabel = data\n ? (data.connection.accountDisplayName ?? \"\")\n : (installation.account_display_name ?? \"\");\n const unchanged = trimmed === savedLabel;\n // A save's warnings describe the name it saved, so they only stand while\n // the field still shows that name. Once it's edited they (and \"Done\") give\n // way to Cancel, so closing can't be mistaken for keeping the new text.\n const warnings = unchanged ? (data?.warnings ?? []) : [];\n const errorMessage =\n error instanceof ApiError && error.message ? error.message : null;\n\n const placeholder = translate({\n defaultMessage: \"e.g. Marketing\",\n id: \"pWC98E\",\n description: \"Placeholder for the connection name input\",\n });\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n <Translation\n defaultMessage=\"Rename {integrationName} connection\"\n id=\"c1jT5Q\"\n description=\"Dialog title for renaming one connection to a provider\"\n values={{ integrationName }}\n />\n </Dialog.Title>\n <Dialog.Description color=\"gray\" mt=\"1\">\n <Translation\n defaultMessage=\"Give this connection a name to tell it apart from your other {integrationName} connections.\"\n id=\"Ptf2r1\"\n description=\"Explains what a connection name is for\"\n values={{ integrationName }}\n />\n </Dialog.Description>\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred while renaming this connection. Please try again.\"\n id=\"0grPwn\"\n description=\"Error message when renaming a connection fails\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n {warnings.map((warning) => (\n <Callout.Root key={warning.code} my=\"3\" color=\"amber\" role=\"status\">\n <Callout.Text>\n {warning.code === DUPLICATE_LABEL_WARNING ? (\n <Translation\n defaultMessage=\"Saved. Another {integrationName} connection already uses this name, so you may want to pick one that tells them apart.\"\n id=\"eB4eyQ\"\n description=\"Notice after renaming a connection to a name another connection to the same provider already has\"\n values={{ integrationName }}\n />\n ) : (\n warning.message\n )}\n </Callout.Text>\n </Callout.Root>\n ))}\n\n <form\n onSubmit={(event) => {\n event.preventDefault();\n if (unchanged) {\n return;\n }\n mutate(\n { id: installation.id, accountDisplayName: trimmed || null },\n {\n onSuccess: (result) => {\n if (result.warnings.length === 0) {\n onOpenChange(false);\n }\n },\n },\n );\n }}\n >\n <Flex direction=\"column\" gap=\"1\" mt=\"4\">\n <Label htmlFor={`rename-connection-${installation.id}`}>\n <Translation\n defaultMessage=\"Name\"\n id=\"KdgU9T\"\n description=\"Label for the connection name input\"\n />\n </Label>\n <TextField.Root\n id={`rename-connection-${installation.id}`}\n value={label}\n maxLength={MAX_LABEL_LENGTH}\n autoComplete=\"off\"\n placeholder={placeholder}\n onChange={(event) => setLabel(event.target.value)}\n />\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button type=\"button\" variant=\"secondary\">\n {/* With a saved name shown (and warned about), closing keeps it. */}\n {warnings.length > 0 ? (\n <Translation\n defaultMessage=\"Done\"\n id=\"YlARFG\"\n description=\"Button to close the rename dialog after a name was saved with a warning\"\n />\n ) : (\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n )}\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n disabled={isPending || unchanged}\n loading={isPending}\n >\n <Translation\n defaultMessage=\"Save\"\n id=\"JmvID+\"\n description=\"Button to save a connection's new name\"\n />\n </Button>\n </Flex>\n </form>\n </Dialog.Content>\n </Dialog.Root>\n );\n};\n\ninterface ConnectionCountStatusProps {\n count: number;\n}\n\n/**\n * A provider row's status once it groups its connections, which it only does\n * for two or more — hence no singular form (plurals also need the optional\n * I18nProvider to format).\n */\nconst ConnectionCountStatus: React.FC<ConnectionCountStatusProps> = ({\n count,\n}) => {\n return (\n <Status state=\"neutral\">\n <Translation\n defaultMessage=\"{count} connections\"\n id=\"ZarniP\"\n description=\"Status for a provider grouping two or more connections, giving how many\"\n values={{ count }}\n />\n </Status>\n );\n};\n\nconst RenameMenuLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Rename\"\n id=\"iiQbUM\"\n description=\"Menu option to rename one connection\"\n />\n );\n};\n\nconst ConnectAnotherAccountMenuLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Connect another account\"\n id=\"SNK0to\"\n description=\"Menu option to add another connection to the same provider\"\n />\n );\n};\n\nconst AddConnectionButtonLabel: React.FC = () => {\n return (\n <Translation\n defaultMessage=\"Add connection\"\n id=\"DFzo7c\"\n description=\"Button to add another connection to a provider that already has several\"\n />\n );\n};\nexport type { ConnectionTarget };\nexport {\n getConnectionLabel,\n ADD_CONNECTION,\n createAddConnectionTarget,\n getConnectionTarget,\n canRenameConnections,\n toConnectionTargetInput,\n toCreationTargetInput,\n toAccountDisplayNameInput,\n ConnectionNameField,\n RenameConnectionDialog,\n ConnectionCountStatus,\n RenameMenuLabel,\n ConnectAnotherAccountMenuLabel,\n AddConnectionButtonLabel,\n};\n"],"mappings":"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"}
@@ -18,11 +18,11 @@ function usePipesCredentialAttribution() {
18
18
  error: sessionUserId && hostUserId && hostUserId !== sessionUserId ? translate({
19
19
  defaultMessage: "Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.",
20
20
  description: "Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user",
21
- id: "pipesCredentialUserMismatch"
21
+ id: "jhlRXY"
22
22
  }) : !userId ? translate({
23
23
  defaultMessage: "Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.",
24
24
  description: "Configuration guidance for shared credential writes without an acting user; no user ID entry is requested",
25
- id: "pipesCredentialUserRequired"
25
+ id: "LXD0s/"
26
26
  }) : void 0
27
27
  };
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pipes-credential-attribution.js","names":[],"sources":["../../../../src/widgets/pipes/pipes-credential-attribution.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { useApi } from \"../../api/api-provider.js\";\nimport { getAuthenticatedUserId, getClaims } from \"../../api/claims.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\n\nconst PipesCredentialUserIdContext = createContext<string | undefined>(\n undefined,\n);\nPipesCredentialUserIdContext.displayName = \"PipesCredentialUserIdContext\";\n\nfunction usePipesCredentialAttribution() {\n const hostUserId = useContext(PipesCredentialUserIdContext)?.trim();\n const { authToken } = useApi();\n const translate = useTranslation();\n const claims = authToken ? getClaims(authToken) : undefined;\n const sessionUserId = claims && getAuthenticatedUserId(claims);\n const userId =\n sessionUserId ??\n (claims?.sub_type === \"client_api_credential\" &&\n hostUserId?.startsWith(\"user_\")\n ? hostUserId\n : undefined);\n\n const error =\n sessionUserId && hostUserId && hostUserId !== sessionUserId\n ? translate({\n defaultMessage:\n \"Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.\",\n description:\n \"Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user\",\n id: \"pipesCredentialUserMismatch\",\n })\n : !userId\n ? translate({\n defaultMessage:\n \"Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.\",\n description:\n \"Configuration guidance for shared credential writes without an acting user; no user ID entry is requested\",\n id: \"pipesCredentialUserRequired\",\n })\n : undefined;\n\n return { userId, error };\n}\nexport { PipesCredentialUserIdContext, usePipesCredentialAttribution };\n"],"mappings":";;;;;;AAOA,MAAM,+BAA+B,cACnC,MACF;AACA,6BAA6B,cAAc;AAE3C,SAAS,gCAAgC;CACvC,MAAM,aAAa,WAAW,4BAA4B,CAAC,EAAE,KAAK;CAClE,MAAM,EAAE,cAAc,OAAO;CAC7B,MAAM,YAAY,eAAe;CACjC,MAAM,SAAS,YAAY,UAAU,SAAS,IAAI;CAClD,MAAM,gBAAgB,UAAU,uBAAuB,MAAM;CAC7D,MAAM,SACJ,kBACC,QAAQ,aAAa,2BACtB,YAAY,WAAW,OAAO,IAC1B,aACA;CAqBN,OAAO;EAAE;EAAQ,OAlBf,iBAAiB,cAAc,eAAe,gBAC1C,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD,CAAC,SACC,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD;CAEe;AACzB"}
1
+ {"version":3,"file":"pipes-credential-attribution.js","names":[],"sources":["../../../../src/widgets/pipes/pipes-credential-attribution.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { useApi } from \"../../api/api-provider.js\";\nimport { getAuthenticatedUserId, getClaims } from \"../../api/claims.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\n\nconst PipesCredentialUserIdContext = createContext<string | undefined>(\n undefined,\n);\nPipesCredentialUserIdContext.displayName = \"PipesCredentialUserIdContext\";\n\nfunction usePipesCredentialAttribution() {\n const hostUserId = useContext(PipesCredentialUserIdContext)?.trim();\n const { authToken } = useApi();\n const translate = useTranslation();\n const claims = authToken ? getClaims(authToken) : undefined;\n const sessionUserId = claims && getAuthenticatedUserId(claims);\n const userId =\n sessionUserId ??\n (claims?.sub_type === \"client_api_credential\" &&\n hostUserId?.startsWith(\"user_\")\n ? hostUserId\n : undefined);\n\n const error =\n sessionUserId && hostUserId && hostUserId !== sessionUserId\n ? translate({\n defaultMessage:\n \"Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.\",\n description:\n \"Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user\",\n id: \"jhlRXY\",\n })\n : !userId\n ? translate({\n defaultMessage:\n \"Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.\",\n description:\n \"Configuration guidance for shared credential writes without an acting user; no user ID entry is requested\",\n id: \"LXD0s/\",\n })\n : undefined;\n\n return { userId, error };\n}\nexport { PipesCredentialUserIdContext, usePipesCredentialAttribution };\n"],"mappings":";;;;;;AAOA,MAAM,+BAA+B,cACnC,MACF;AACA,6BAA6B,cAAc;AAE3C,SAAS,gCAAgC;CACvC,MAAM,aAAa,WAAW,4BAA4B,CAAC,EAAE,KAAK;CAClE,MAAM,EAAE,cAAc,OAAO;CAC7B,MAAM,YAAY,eAAe;CACjC,MAAM,SAAS,YAAY,UAAU,SAAS,IAAI;CAClD,MAAM,gBAAgB,UAAU,uBAAuB,MAAM;CAC7D,MAAM,SACJ,kBACC,QAAQ,aAAa,2BACtB,YAAY,WAAW,OAAO,IAC1B,aACA;CAqBN,OAAO;EAAE;EAAQ,OAlBf,iBAAiB,cAAc,eAAe,gBAC1C,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD,CAAC,SACC,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD;CAEe;AACzB"}
@@ -1718,7 +1718,7 @@ const SharedConnectionStatus = ({ connection }) => {
1718
1718
  state: "success",
1719
1719
  children: /* @__PURE__ */ jsx(Translation, {
1720
1720
  defaultMessage: "Available",
1721
- id: "_jQjSu",
1721
+ id: "/jQjSu",
1722
1722
  description: "Status text for a shared connection the member can use"
1723
1723
  })
1724
1724
  }) : /* @__PURE__ */ jsx(Status, {
@@ -1812,7 +1812,7 @@ const MemberConnectionStatus = ({ installation, connectionError }) => {
1812
1812
  description: "Status text for a connection established with client credentials"
1813
1813
  }) : /* @__PURE__ */ jsx(Translation, {
1814
1814
  defaultMessage: "Connected via OAuth",
1815
- id: "pJcK_M",
1815
+ id: "pJcK/M",
1816
1816
  description: "Status text for a connection established with OAuth"
1817
1817
  })
1818
1818
  });
@@ -1820,7 +1820,7 @@ const MemberConnectionStatus = ({ installation, connectionError }) => {
1820
1820
  state: "warning",
1821
1821
  children: installation.auth_method === "api_key" ? /* @__PURE__ */ jsx(Translation, {
1822
1822
  defaultMessage: "Update your API key",
1823
- id: "-YLPTk",
1823
+ id: "+YLPTk",
1824
1824
  description: "Status text for a connection whose API key stopped working"
1825
1825
  }) : /* @__PURE__ */ jsx(Translation, {
1826
1826
  defaultMessage: "Requires reauthorization",
@@ -1919,7 +1919,7 @@ const MemberConnectionActions = ({ integration, installation, label, onConnect,
1919
1919
  onClick: openApiKey,
1920
1920
  children: /* @__PURE__ */ jsx(Translation, {
1921
1921
  defaultMessage: "Update key",
1922
- id: "MP-aOE",
1922
+ id: "MP+aOE",
1923
1923
  description: "Button to replace the API key of a connection that stopped working"
1924
1924
  })
1925
1925
  }) : isClientCredentialsInstallation ? /* @__PURE__ */ jsx(Button$1, {
@@ -2127,7 +2127,7 @@ const PipesSections = ({ integrations, hasUnfilteredIntegrations, sharedConnecti
2127
2127
  children: [(isSharedLoading || sharedConnections.length > 0 || hasUnfilteredSharedConnections) && /* @__PURE__ */ jsx(PipesSection, {
2128
2128
  title: /* @__PURE__ */ jsx(Translation, {
2129
2129
  defaultMessage: "Shared connections",
2130
- id: "Fcd-bK",
2130
+ id: "Fcd+bK",
2131
2131
  description: "Heading for the section listing connections the organization owns"
2132
2132
  }),
2133
2133
  description: organizationName ? /* @__PURE__ */ jsx(Translation, {
@@ -2144,7 +2144,7 @@ const PipesSections = ({ integrations, hasUnfilteredIntegrations, sharedConnecti
2144
2144
  }), /* @__PURE__ */ jsx(PipesSection, {
2145
2145
  title: /* @__PURE__ */ jsx(Translation, {
2146
2146
  defaultMessage: "Your connections",
2147
- id: "-VDI3G",
2147
+ id: "+VDI3G",
2148
2148
  description: "Heading for the section listing the member's own connections"
2149
2149
  }),
2150
2150
  description: /* @__PURE__ */ jsx(Translation, {