@workos-inc/widgets 1.20.2-next.1792708307096 → 1.20.2

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 (123) hide show
  1. package/CHANGELOG.md +4 -12
  2. package/dist/cjs/admin-portal-audit-log-streaming.client.cjs +2 -1
  3. package/dist/cjs/admin-portal-audit-log-streaming.client.cjs.map +1 -1
  4. package/dist/cjs/admin-portal-domain-verification.client.cjs +3 -2
  5. package/dist/cjs/admin-portal-domain-verification.client.cjs.map +1 -1
  6. package/dist/cjs/admin-portal-sso-connection.client.cjs +2 -1
  7. package/dist/cjs/admin-portal-sso-connection.client.cjs.map +1 -1
  8. package/dist/cjs/api/api-provider.cjs +23 -1
  9. package/dist/cjs/api/api-provider.cjs.map +1 -1
  10. package/dist/cjs/api/api-provider.d.cts.map +1 -1
  11. package/dist/cjs/api/claims.cjs.map +1 -1
  12. package/dist/cjs/api/claims.d.cts +2 -1
  13. package/dist/cjs/api/claims.d.cts.map +1 -1
  14. package/dist/cjs/api/client-graphql/hooks.cjs +3 -20
  15. package/dist/cjs/api/client-graphql/hooks.cjs.map +1 -1
  16. package/dist/cjs/api/client-graphql/hooks.d.cts +3 -12
  17. package/dist/cjs/api/client-graphql/hooks.d.cts.map +1 -1
  18. package/dist/cjs/api/client-graphql/query-keys.cjs +25 -0
  19. package/dist/cjs/api/client-graphql/query-keys.cjs.map +1 -0
  20. package/dist/cjs/api/client-graphql/query-keys.d.cts +16 -0
  21. package/dist/cjs/api/client-graphql/query-keys.d.cts.map +1 -0
  22. package/dist/cjs/components/copy-text.cjs +1 -1
  23. package/dist/cjs/components/copy-text.cjs.map +1 -1
  24. package/dist/cjs/components/otp-input.cjs +1 -0
  25. package/dist/cjs/components/otp-input.cjs.map +1 -1
  26. package/dist/cjs/directory-sync.client.cjs +2 -1
  27. package/dist/cjs/directory-sync.client.cjs.map +1 -1
  28. package/dist/cjs/lib/api/api-key.cjs +4 -3
  29. package/dist/cjs/lib/api/api-key.cjs.map +1 -1
  30. package/dist/cjs/lib/api/me.cjs +2 -1
  31. package/dist/cjs/lib/api/me.cjs.map +1 -1
  32. package/dist/cjs/lib/api/pipes.cjs +7 -6
  33. package/dist/cjs/lib/api/pipes.cjs.map +1 -1
  34. package/dist/cjs/lib/api/user-api-key.cjs +3 -2
  35. package/dist/cjs/lib/api/user-api-key.cjs.map +1 -1
  36. package/dist/cjs/lib/use-widgets-invalidator.cjs +3 -2
  37. package/dist/cjs/lib/use-widgets-invalidator.cjs.map +1 -1
  38. package/dist/cjs/organization-switcher.client.cjs +2 -1
  39. package/dist/cjs/organization-switcher.client.cjs.map +1 -1
  40. package/dist/cjs/pipes-admin.client.cjs +2 -1
  41. package/dist/cjs/pipes-admin.client.cjs.map +1 -1
  42. package/dist/cjs/pipes.client.cjs +2 -1
  43. package/dist/cjs/pipes.client.cjs.map +1 -1
  44. package/dist/cjs/user-security.client.cjs +2 -1
  45. package/dist/cjs/user-security.client.cjs.map +1 -1
  46. package/dist/cjs/user-sessions.client.cjs +2 -1
  47. package/dist/cjs/user-sessions.client.cjs.map +1 -1
  48. package/dist/cjs/widgets/organization-switcher/organization-switcher.cjs +9 -4
  49. package/dist/cjs/widgets/organization-switcher/organization-switcher.cjs.map +1 -1
  50. package/dist/cjs/widgets/organization-switcher/organization-switcher.d.cts.map +1 -1
  51. package/dist/cjs/widgets/pipes/pipes.cjs +3 -2
  52. package/dist/cjs/widgets/pipes/pipes.cjs.map +1 -1
  53. package/dist/cjs/widgets/user-sessions/logout-all-sessions-dialog.cjs +2 -1
  54. package/dist/cjs/widgets/user-sessions/logout-all-sessions-dialog.cjs.map +1 -1
  55. package/dist/cjs/widgets/user-sessions/logout-dialog.cjs +2 -1
  56. package/dist/cjs/widgets/user-sessions/logout-dialog.cjs.map +1 -1
  57. package/dist/cjs/widgets/users-management/users-management-utils.cjs +4 -3
  58. package/dist/cjs/widgets/users-management/users-management-utils.cjs.map +1 -1
  59. package/dist/esm/admin-portal-audit-log-streaming.client.js +2 -1
  60. package/dist/esm/admin-portal-audit-log-streaming.client.js.map +1 -1
  61. package/dist/esm/admin-portal-domain-verification.client.js +2 -1
  62. package/dist/esm/admin-portal-domain-verification.client.js.map +1 -1
  63. package/dist/esm/admin-portal-sso-connection.client.js +2 -1
  64. package/dist/esm/admin-portal-sso-connection.client.js.map +1 -1
  65. package/dist/esm/api/api-provider.d.ts.map +1 -1
  66. package/dist/esm/api/api-provider.js +23 -1
  67. package/dist/esm/api/api-provider.js.map +1 -1
  68. package/dist/esm/api/claims.d.ts +2 -1
  69. package/dist/esm/api/claims.d.ts.map +1 -1
  70. package/dist/esm/api/claims.js.map +1 -1
  71. package/dist/esm/api/client-graphql/hooks.d.ts +3 -12
  72. package/dist/esm/api/client-graphql/hooks.d.ts.map +1 -1
  73. package/dist/esm/api/client-graphql/hooks.js +1 -18
  74. package/dist/esm/api/client-graphql/hooks.js.map +1 -1
  75. package/dist/esm/api/client-graphql/query-keys.d.ts +16 -0
  76. package/dist/esm/api/client-graphql/query-keys.d.ts.map +1 -0
  77. package/dist/esm/api/client-graphql/query-keys.js +23 -0
  78. package/dist/esm/api/client-graphql/query-keys.js.map +1 -0
  79. package/dist/esm/components/copy-text.js +1 -1
  80. package/dist/esm/components/copy-text.js.map +1 -1
  81. package/dist/esm/components/otp-input.js +1 -0
  82. package/dist/esm/components/otp-input.js.map +1 -1
  83. package/dist/esm/directory-sync.client.js +2 -1
  84. package/dist/esm/directory-sync.client.js.map +1 -1
  85. package/dist/esm/lib/api/api-key.js +2 -1
  86. package/dist/esm/lib/api/api-key.js.map +1 -1
  87. package/dist/esm/lib/api/me.js +2 -1
  88. package/dist/esm/lib/api/me.js.map +1 -1
  89. package/dist/esm/lib/api/pipes.js +2 -1
  90. package/dist/esm/lib/api/pipes.js.map +1 -1
  91. package/dist/esm/lib/api/user-api-key.js +2 -1
  92. package/dist/esm/lib/api/user-api-key.js.map +1 -1
  93. package/dist/esm/lib/use-widgets-invalidator.js +2 -1
  94. package/dist/esm/lib/use-widgets-invalidator.js.map +1 -1
  95. package/dist/esm/organization-switcher.client.js +2 -1
  96. package/dist/esm/organization-switcher.client.js.map +1 -1
  97. package/dist/esm/pipes-admin.client.js +2 -1
  98. package/dist/esm/pipes-admin.client.js.map +1 -1
  99. package/dist/esm/pipes.client.js +2 -1
  100. package/dist/esm/pipes.client.js.map +1 -1
  101. package/dist/esm/user-security.client.js +2 -1
  102. package/dist/esm/user-security.client.js.map +1 -1
  103. package/dist/esm/user-sessions.client.js +2 -1
  104. package/dist/esm/user-sessions.client.js.map +1 -1
  105. package/dist/esm/widgets/organization-switcher/organization-switcher.d.ts.map +1 -1
  106. package/dist/esm/widgets/organization-switcher/organization-switcher.js +9 -4
  107. package/dist/esm/widgets/organization-switcher/organization-switcher.js.map +1 -1
  108. package/dist/esm/widgets/pipes/pipes.js +2 -1
  109. package/dist/esm/widgets/pipes/pipes.js.map +1 -1
  110. package/dist/esm/widgets/user-sessions/logout-all-sessions-dialog.js +2 -1
  111. package/dist/esm/widgets/user-sessions/logout-all-sessions-dialog.js.map +1 -1
  112. package/dist/esm/widgets/user-sessions/logout-dialog.js +2 -1
  113. package/dist/esm/widgets/user-sessions/logout-dialog.js.map +1 -1
  114. package/dist/esm/widgets/users-management/users-management-utils.js +2 -1
  115. package/dist/esm/widgets/users-management/users-management-utils.js.map +1 -1
  116. package/package.json +1 -1
  117. package/src/api/api-provider.tsx +39 -1
  118. package/src/api/claims.ts +2 -1
  119. package/src/api/client-graphql/hooks.ts +8 -27
  120. package/src/api/client-graphql/query-keys.ts +29 -0
  121. package/src/components/copy-text.tsx +1 -1
  122. package/src/components/otp-input.tsx +2 -0
  123. package/src/widgets/organization-switcher/organization-switcher.tsx +16 -6
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { clientGraphqlQueryKey, useClientGraphqlMutation } from "../../api/client-graphql/hooks.js";
2
+ import { clientGraphqlQueryKey } from "../../api/client-graphql/query-keys.js";
3
+ import { useClientGraphqlMutation } from "../../api/client-graphql/hooks.js";
3
4
  import { Button as Button$1 } from "../../components/elements/button.js";
4
5
  import { Cancel, Content as AlertDialogContent, Description as AlertDialogDescription, Root, Title } from "../../components/elements/alert-dialog.js";
5
6
  import "../../components/elements.js";
@@ -1 +1 @@
1
- {"version":3,"file":"logout-all-sessions-dialog.js","names":["AlertDialog.Root","AlertDialog.Content","AlertDialog.Title","AlertDialog.Description","AlertDialog.Cancel","Button"],"sources":["../../../../src/widgets/user-sessions/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlMutation,\n} from \"../../api/client-graphql/hooks.js\";\nimport { AlertDialog, Button } from \"../../components/elements.js\";\nimport { SaveButton } from \"../../components/save-button.js\";\nimport { expectResultMember } from \"../../lib/client-graphql-result.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\n\ninterface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {\n currentSessionId?: string;\n children?: ReactNode;\n}\n\nconst LogoutAllSessionsDialog: React.FC<LogoutAllSessionsDialogProps> = ({\n open,\n onOpenChange,\n currentSessionId,\n children,\n ...props\n}) => {\n const client = useQueryClient();\n\n const revokeAllSessions = useClientGraphqlMutation({\n mutationFn: async (sdk) =>\n expectResultMember(\n (\n await sdk.RevokeAllSessions({\n input: { currentSessionId: currentSessionId || null },\n })\n ).revokeAllSessions,\n \"AllSessionsRevoked\",\n ),\n });\n\n const onSubmitForm = () => {\n revokeAllSessions.mutate();\n };\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"Sessions\"),\n });\n }, [client, onOpenChange]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of all other devices?\"\n id=\"x//BWg\"\n description=\"Dialog title asking to confirm signing out of all other devices\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be logged out of all other active sessions on other devices, except this one.\"\n id=\"GftsX9\"\n description=\"Description explaining all other sessions will be logged out\"\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={\n revokeAllSessions.isPending || revokeAllSessions.isSuccess\n }\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"Pnmy4H\"\n description=\"Button to cancel signing out of all devices\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeAllSessions.isPending}\n done={revokeAllSessions.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"1Fb48o\"\n description=\"Button to confirm signing out of all other devices\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n};\nexport { LogoutAllSessionsDialog };\n"],"mappings":";;;;;;;;;;;;;AAoBA,MAAM,2BAAmE,EACvE,MACA,cACA,kBACA,UACA,GAAG,YACC;CACJ,MAAM,SAAS,eAAe;CAE9B,MAAM,oBAAoB,yBAAyB,EACjD,YAAY,OAAO,QACjB,oBAEI,MAAM,IAAI,kBAAkB,EAC1B,OAAO,EAAE,kBAAkB,oBAAoB,KAAK,EACtD,CAAC,EAAA,CACD,mBACF,oBACF,EACJ,CAAC;CAED,MAAM,qBAAqB;EACzB,kBAAkB,OAAO;CAC3B;CAEA,MAAM,aAAa,MAAM,kBAAkB;EACzC,eAAe,KAAK;EAEpB,OAAO,kBAAkB,EACvB,UAAU,sBAAsB,UAAU,EAC5C,CAAC;CACH,GAAG,CAAC,QAAQ,YAAY,CAAC;CAEzB,OACE,oBAACA,MAAD;EAAwB;EAAoB;EAAc,GAAI;EAC5D,UAAA,qBAACC,oBAAD;GAAqB,UAAS;GAA9B,UAAA;IACE,oBAACC,OAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACgB,CAAA;IACnB,oBAACC,wBAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACsB,CAAA;IAEzB,oBAAC,MAAD;KAAM,KAAI;KAAI,SAAQ;KAAM,IAAG;KAAI,SAAA;KACjC,UAAA,qBAAC,QAAD;MACE,WAAW,UAAU;OACnB,MAAM,eAAe;OACrB,aAAa;MACf;MAJF,UAAA,CAME,oBAACC,QAAD,EAAA,UACE,oBAACC,UAAD;OACE,SAAQ;OACR,UACE,kBAAkB,aAAa,kBAAkB;OAGnD,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACK,CAAA,EACU,CAAA,GAEpB,oBAAC,YAAD;OACE,SAAA;OACA,SAAS,kBAAkB;OAC3B,MAAM,kBAAkB;OACxB,QAAQ;OAER,UAAA,oBAACA,UAAD;QAAQ,SAAQ;QAAc,MAAK;QACjC,UAAA,oBAAC,aAAD;SACE,gBAAe;SACf,IAAG;SACH,aAAY;QACb,CAAA;OACK,CAAA;MACE,CAAA,CACR;;IACF,CAAA;GACa;;CACL,CAAA;AAEtB"}
1
+ {"version":3,"file":"logout-all-sessions-dialog.js","names":["AlertDialog.Root","AlertDialog.Content","AlertDialog.Title","AlertDialog.Description","AlertDialog.Cancel","Button"],"sources":["../../../../src/widgets/user-sessions/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlMutation,\n} from \"../../api/client-graphql/hooks.js\";\nimport { AlertDialog, Button } from \"../../components/elements.js\";\nimport { SaveButton } from \"../../components/save-button.js\";\nimport { expectResultMember } from \"../../lib/client-graphql-result.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\n\ninterface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {\n currentSessionId?: string;\n children?: ReactNode;\n}\n\nconst LogoutAllSessionsDialog: React.FC<LogoutAllSessionsDialogProps> = ({\n open,\n onOpenChange,\n currentSessionId,\n children,\n ...props\n}) => {\n const client = useQueryClient();\n\n const revokeAllSessions = useClientGraphqlMutation({\n mutationFn: async (sdk) =>\n expectResultMember(\n (\n await sdk.RevokeAllSessions({\n input: { currentSessionId: currentSessionId || null },\n })\n ).revokeAllSessions,\n \"AllSessionsRevoked\",\n ),\n });\n\n const onSubmitForm = () => {\n revokeAllSessions.mutate();\n };\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"Sessions\"),\n });\n }, [client, onOpenChange]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of all other devices?\"\n id=\"x//BWg\"\n description=\"Dialog title asking to confirm signing out of all other devices\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be logged out of all other active sessions on other devices, except this one.\"\n id=\"GftsX9\"\n description=\"Description explaining all other sessions will be logged out\"\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={\n revokeAllSessions.isPending || revokeAllSessions.isSuccess\n }\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"Pnmy4H\"\n description=\"Button to cancel signing out of all devices\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeAllSessions.isPending}\n done={revokeAllSessions.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"1Fb48o\"\n description=\"Button to confirm signing out of all other devices\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n};\nexport { LogoutAllSessionsDialog };\n"],"mappings":";;;;;;;;;;;;;;AAoBA,MAAM,2BAAmE,EACvE,MACA,cACA,kBACA,UACA,GAAG,YACC;CACJ,MAAM,SAAS,eAAe;CAE9B,MAAM,oBAAoB,yBAAyB,EACjD,YAAY,OAAO,QACjB,oBAEI,MAAM,IAAI,kBAAkB,EAC1B,OAAO,EAAE,kBAAkB,oBAAoB,KAAK,EACtD,CAAC,EAAA,CACD,mBACF,oBACF,EACJ,CAAC;CAED,MAAM,qBAAqB;EACzB,kBAAkB,OAAO;CAC3B;CAEA,MAAM,aAAa,MAAM,kBAAkB;EACzC,eAAe,KAAK;EAEpB,OAAO,kBAAkB,EACvB,UAAU,sBAAsB,UAAU,EAC5C,CAAC;CACH,GAAG,CAAC,QAAQ,YAAY,CAAC;CAEzB,OACE,oBAACA,MAAD;EAAwB;EAAoB;EAAc,GAAI;EAC5D,UAAA,qBAACC,oBAAD;GAAqB,UAAS;GAA9B,UAAA;IACE,oBAACC,OAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACgB,CAAA;IACnB,oBAACC,wBAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACsB,CAAA;IAEzB,oBAAC,MAAD;KAAM,KAAI;KAAI,SAAQ;KAAM,IAAG;KAAI,SAAA;KACjC,UAAA,qBAAC,QAAD;MACE,WAAW,UAAU;OACnB,MAAM,eAAe;OACrB,aAAa;MACf;MAJF,UAAA,CAME,oBAACC,QAAD,EAAA,UACE,oBAACC,UAAD;OACE,SAAQ;OACR,UACE,kBAAkB,aAAa,kBAAkB;OAGnD,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACK,CAAA,EACU,CAAA,GAEpB,oBAAC,YAAD;OACE,SAAA;OACA,SAAS,kBAAkB;OAC3B,MAAM,kBAAkB;OACxB,QAAQ;OAER,UAAA,oBAACA,UAAD;QAAQ,SAAQ;QAAc,MAAK;QACjC,UAAA,oBAAC,aAAD;SACE,gBAAe;SACf,IAAG;SACH,aAAY;QACb,CAAA;OACK,CAAA;MACE,CAAA,CACR;;IACF,CAAA;GACa;;CACL,CAAA;AAEtB"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { clientGraphqlQueryKey, useClientGraphqlMutation } from "../../api/client-graphql/hooks.js";
2
+ import { clientGraphqlQueryKey } from "../../api/client-graphql/query-keys.js";
3
+ import { useClientGraphqlMutation } from "../../api/client-graphql/hooks.js";
3
4
  import { Button as Button$1 } from "../../components/elements/button.js";
4
5
  import { useTranslation } from "../../lib/i18n/use-translation.js";
5
6
  import { Cancel, Content as AlertDialogContent, Description as AlertDialogDescription, Root, Title } from "../../components/elements/alert-dialog.js";
@@ -1 +1 @@
1
- {"version":3,"file":"logout-dialog.js","names":["AlertDialog.Root","AlertDialog.Content","AlertDialog.Title","AlertDialog.Description","AlertDialog.Cancel","Button"],"sources":["../../../../src/widgets/user-sessions/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex, Strong } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { SessionFieldsFragment } from \"../../api/client-graphql/generated.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlMutation,\n} from \"../../api/client-graphql/hooks.js\";\nimport { AlertDialog, Button } from \"../../components/elements.js\";\nimport { SaveButton } from \"../../components/save-button.js\";\nimport { expectResultMember } from \"../../lib/client-graphql-result.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { parseUserAgent } from \"../../lib/parse-user-agent.js\";\n\ninterface LogoutDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n session: SessionFieldsFragment;\n}\n\nconst LogoutDialog: React.FC<LogoutDialogProps> = ({\n children,\n session,\n open,\n onOpenChange,\n ...props\n}) => {\n const client = useQueryClient();\n const translate = useTranslation();\n const device =\n parseUserAgent(session.userAgent)?.pretty ??\n translate({\n defaultMessage: \"Unknown device\",\n id: \"nF+P+T\",\n description:\n \"Label for a session whose device could not be determined from its user agent\",\n });\n\n const revokeSession = useClientGraphqlMutation({\n mutationFn: async (sdk, sessionId: string) =>\n expectResultMember(\n (await sdk.RevokeSession({ input: { sessionId } })).revokeSession,\n \"SessionRevoked\",\n ),\n });\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"Sessions\"),\n exact: false,\n });\n }, [onOpenChange, client]);\n\n const onSubmitForm = () => {\n revokeSession.mutate(session.id);\n };\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of device?\"\n id=\"Jic5nB\"\n description=\"Dialog title asking to confirm signing out of a device\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be signed out of {device}.\"\n id=\"diFnRK\"\n description=\"Description explaining the user will be signed out of a specific device\"\n values={{ device: <Strong>{device}</Strong> }}\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={revokeSession.isPending || revokeSession.isSuccess}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"KjY2RX\"\n description=\"Button to cancel the logout action\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeSession.isPending}\n done={revokeSession.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"tRJt/S\"\n description=\"Button to confirm signing out of device\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n};\nexport { LogoutDialog };\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAM,gBAA6C,EACjD,UACA,SACA,MACA,cACA,GAAG,YACC;CACJ,MAAM,SAAS,eAAe;CAC9B,MAAM,YAAY,eAAe;CACjC,MAAM,SACJ,eAAe,QAAQ,SAAS,CAAC,EAAE,UACnC,UAAU;EACR,gBAAgB;EAChB,IAAI;EACJ,aACE;CACJ,CAAC;CAEH,MAAM,gBAAgB,yBAAyB,EAC7C,YAAY,OAAO,KAAK,cACtB,oBACG,MAAM,IAAI,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,EAAA,CAAG,eACpD,gBACF,EACJ,CAAC;CAED,MAAM,aAAa,MAAM,kBAAkB;EACzC,eAAe,KAAK;EAEpB,OAAO,kBAAkB;GACvB,UAAU,sBAAsB,UAAU;GAC1C,OAAO;EACT,CAAC;CACH,GAAG,CAAC,cAAc,MAAM,CAAC;CAEzB,MAAM,qBAAqB;EACzB,cAAc,OAAO,QAAQ,EAAE;CACjC;CAEA,OACE,oBAACA,MAAD;EAAwB;EAAoB;EAAc,GAAI;EAC5D,UAAA,qBAACC,oBAAD;GAAqB,UAAS;GAA9B,UAAA;IACE,oBAACC,OAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACgB,CAAA;IACnB,oBAACC,wBAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;KACZ,QAAQ,EAAE,QAAQ,oBAAC,QAAD,EAAA,UAAS,OAAe,CAAA,EAAE;IAC7C,CAAA,EACsB,CAAA;IAEzB,oBAAC,MAAD;KAAM,KAAI;KAAI,SAAQ;KAAM,IAAG;KAAI,SAAA;KACjC,UAAA,qBAAC,QAAD;MACE,WAAW,UAAU;OACnB,MAAM,eAAe;OACrB,aAAa;MACf;MAJF,UAAA,CAME,oBAACC,QAAD,EAAA,UACE,oBAACC,UAAD;OACE,SAAQ;OACR,UAAU,cAAc,aAAa,cAAc;OAEnD,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACK,CAAA,EACU,CAAA,GAEpB,oBAAC,YAAD;OACE,SAAA;OACA,SAAS,cAAc;OACvB,MAAM,cAAc;OACpB,QAAQ;OAER,UAAA,oBAACA,UAAD;QAAQ,SAAQ;QAAc,MAAK;QACjC,UAAA,oBAAC,aAAD;SACE,gBAAe;SACf,IAAG;SACH,aAAY;QACb,CAAA;OACK,CAAA;MACE,CAAA,CACR;;IACF,CAAA;GACa;;CACL,CAAA;AAEtB"}
1
+ {"version":3,"file":"logout-dialog.js","names":["AlertDialog.Root","AlertDialog.Content","AlertDialog.Title","AlertDialog.Description","AlertDialog.Cancel","Button"],"sources":["../../../../src/widgets/user-sessions/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex, Strong } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { SessionFieldsFragment } from \"../../api/client-graphql/generated.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlMutation,\n} from \"../../api/client-graphql/hooks.js\";\nimport { AlertDialog, Button } from \"../../components/elements.js\";\nimport { SaveButton } from \"../../components/save-button.js\";\nimport { expectResultMember } from \"../../lib/client-graphql-result.js\";\nimport { Translation } from \"../../lib/i18n/translation.js\";\nimport { useTranslation } from \"../../lib/i18n/use-translation.js\";\nimport { parseUserAgent } from \"../../lib/parse-user-agent.js\";\n\ninterface LogoutDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n session: SessionFieldsFragment;\n}\n\nconst LogoutDialog: React.FC<LogoutDialogProps> = ({\n children,\n session,\n open,\n onOpenChange,\n ...props\n}) => {\n const client = useQueryClient();\n const translate = useTranslation();\n const device =\n parseUserAgent(session.userAgent)?.pretty ??\n translate({\n defaultMessage: \"Unknown device\",\n id: \"nF+P+T\",\n description:\n \"Label for a session whose device could not be determined from its user agent\",\n });\n\n const revokeSession = useClientGraphqlMutation({\n mutationFn: async (sdk, sessionId: string) =>\n expectResultMember(\n (await sdk.RevokeSession({ input: { sessionId } })).revokeSession,\n \"SessionRevoked\",\n ),\n });\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"Sessions\"),\n exact: false,\n });\n }, [onOpenChange, client]);\n\n const onSubmitForm = () => {\n revokeSession.mutate(session.id);\n };\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of device?\"\n id=\"Jic5nB\"\n description=\"Dialog title asking to confirm signing out of a device\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be signed out of {device}.\"\n id=\"diFnRK\"\n description=\"Description explaining the user will be signed out of a specific device\"\n values={{ device: <Strong>{device}</Strong> }}\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={revokeSession.isPending || revokeSession.isSuccess}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"KjY2RX\"\n description=\"Button to cancel the logout action\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeSession.isPending}\n done={revokeSession.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"tRJt/S\"\n description=\"Button to confirm signing out of device\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n};\nexport { LogoutDialog };\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,MAAM,gBAA6C,EACjD,UACA,SACA,MACA,cACA,GAAG,YACC;CACJ,MAAM,SAAS,eAAe;CAC9B,MAAM,YAAY,eAAe;CACjC,MAAM,SACJ,eAAe,QAAQ,SAAS,CAAC,EAAE,UACnC,UAAU;EACR,gBAAgB;EAChB,IAAI;EACJ,aACE;CACJ,CAAC;CAEH,MAAM,gBAAgB,yBAAyB,EAC7C,YAAY,OAAO,KAAK,cACtB,oBACG,MAAM,IAAI,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,EAAA,CAAG,eACpD,gBACF,EACJ,CAAC;CAED,MAAM,aAAa,MAAM,kBAAkB;EACzC,eAAe,KAAK;EAEpB,OAAO,kBAAkB;GACvB,UAAU,sBAAsB,UAAU;GAC1C,OAAO;EACT,CAAC;CACH,GAAG,CAAC,cAAc,MAAM,CAAC;CAEzB,MAAM,qBAAqB;EACzB,cAAc,OAAO,QAAQ,EAAE;CACjC;CAEA,OACE,oBAACA,MAAD;EAAwB;EAAoB;EAAc,GAAI;EAC5D,UAAA,qBAACC,oBAAD;GAAqB,UAAS;GAA9B,UAAA;IACE,oBAACC,OAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;IACb,CAAA,EACgB,CAAA;IACnB,oBAACC,wBAAD,EAAA,UACE,oBAAC,aAAD;KACE,gBAAe;KACf,IAAG;KACH,aAAY;KACZ,QAAQ,EAAE,QAAQ,oBAAC,QAAD,EAAA,UAAS,OAAe,CAAA,EAAE;IAC7C,CAAA,EACsB,CAAA;IAEzB,oBAAC,MAAD;KAAM,KAAI;KAAI,SAAQ;KAAM,IAAG;KAAI,SAAA;KACjC,UAAA,qBAAC,QAAD;MACE,WAAW,UAAU;OACnB,MAAM,eAAe;OACrB,aAAa;MACf;MAJF,UAAA,CAME,oBAACC,QAAD,EAAA,UACE,oBAACC,UAAD;OACE,SAAQ;OACR,UAAU,cAAc,aAAa,cAAc;OAEnD,UAAA,oBAAC,aAAD;QACE,gBAAe;QACf,IAAG;QACH,aAAY;OACb,CAAA;MACK,CAAA,EACU,CAAA,GAEpB,oBAAC,YAAD;OACE,SAAA;OACA,SAAS,cAAc;OACvB,MAAM,cAAc;OACpB,QAAQ;OAER,UAAA,oBAACA,UAAD;QAAQ,SAAQ;QAAc,MAAK;QACjC,UAAA,oBAAC,aAAD;SACE,gBAAe;SACf,IAAG;SACH,aAAY;QACb,CAAA;OACK,CAAA;MACE,CAAA,CACR;;IACF,CAAA;GACa;;CACL,CAAA;AAEtB"}
@@ -1,6 +1,7 @@
1
1
  import "../../lib/constants.js";
2
+ import { clientGraphqlQueryKey } from "../../api/client-graphql/query-keys.js";
2
3
  import { ApiError } from "../../api/errors.js";
3
- import { clientGraphqlQueryKey, useClientGraphqlQuery } from "../../api/client-graphql/hooks.js";
4
+ import { useClientGraphqlQuery } from "../../api/client-graphql/hooks.js";
4
5
  import { useUsersManagementContext } from "./users-management-context.js";
5
6
  import { keepPreviousData, useQueryClient } from "@tanstack/react-query";
6
7
  //#region src/widgets/users-management/users-management-utils.ts
@@ -1 +1 @@
1
- {"version":3,"file":"users-management-utils.js","names":[],"sources":["../../../../src/widgets/users-management/users-management-utils.ts"],"sourcesContent":["import type { UseQueryResult } from \"@tanstack/react-query\";\nimport { keepPreviousData, useQueryClient } from \"@tanstack/react-query\";\nimport type {\n InviteUserMutation,\n ListOrganizationMembershipsQuery,\n ListRolesQuery,\n OrganizationMemberAction,\n OrganizationMemberFieldsFragment,\n RemoveMemberMutation,\n ResendInvitationMutation,\n RevokeInvitationMutation,\n RoleFieldsFragment,\n UpdateMemberRoleMutation,\n} from \"../../api/client-graphql/generated.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlQuery,\n} from \"../../api/client-graphql/hooks.js\";\nimport { ApiError } from \"../../api/errors.js\";\nimport type { ListMetadata } from \"../../lib/api/types.js\";\nimport { USER_ROW_LIMIT } from \"../../lib/constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport type { UsersManagementContextValue } from \"./users-management-context.js\";\n\nexport type Role = RoleFieldsFragment;\n\nexport type RolesAndConfig = ListRolesQuery[\"roles\"];\n\nexport interface Member extends Omit<\n OrganizationMemberFieldsFragment,\n \"actions\"\n> {\n actions: MemberAction[];\n isLoggedInUser: boolean;\n}\n\nexport interface MembersQueryResult {\n data: Member[];\n listMetadata: ListMetadata;\n}\n\nconst MemberActions = {\n EditRole: \"edit-role\",\n ResendInvite: \"resend-invite\",\n RevokeInvite: \"revoke-invite\",\n RevokeMembership: \"revoke-membership\",\n} as const satisfies Record<OrganizationMemberAction, string>;\n\ntype MemberAction = (typeof MemberActions)[keyof typeof MemberActions];\n\nfunction toMember(member: OrganizationMemberFieldsFragment): Member {\n return {\n ...member,\n actions: member.actions.map((action) => MemberActions[action]),\n isLoggedInUser: member.isCurrentUser,\n };\n}\n\nfunction toMembersQueryResult(\n data: ListOrganizationMembershipsQuery,\n): MembersQueryResult {\n const { organizationMemberships } = data;\n return {\n data: organizationMemberships.data.map(toMember),\n listMetadata: {\n before: organizationMemberships.listMetadata.before ?? null,\n after: organizationMemberships.listMetadata.after ?? null,\n },\n };\n}\n\nexport const EMPTY_ROLES_AND_CONFIG: Readonly<ListRolesQuery> = {\n roles: { multipleRolesEnabled: false, roles: [] },\n};\n\nexport function useRolesAndConfig(): UseQueryResult<RolesAndConfig> {\n return useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListRoles\"),\n queryFn: (sdk) => sdk.ListRoles(),\n select: (data) => data.roles,\n initialData: EMPTY_ROLES_AND_CONFIG,\n });\n}\n\nexport function useUsers(context?: UsersManagementContextValue) {\n const {\n state: { pagination, role, searchQuery },\n } = useUsersManagementContext(context);\n const { before, after } = pagination || {};\n const variables = {\n after: after ?? null,\n before: before ?? null,\n limit: USER_ROW_LIMIT,\n roleSlug: role ?? null,\n search: searchQuery ?? null,\n };\n\n return useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListOrganizationMemberships\", variables),\n queryFn: (sdk) => sdk.ListOrganizationMemberships(variables),\n select: toMembersQueryResult,\n placeholderData: keepPreviousData,\n });\n}\n\nexport function useInvalidateMembers() {\n const queryClient = useQueryClient();\n return () =>\n queryClient.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"ListOrganizationMemberships\"),\n });\n}\n\nfunction mutationFailure(typename: string, message: string): ApiError {\n return new ApiError({\n message,\n status: 400,\n queryType: \"mutation\",\n context: { typename },\n });\n}\n\nexport function unwrapUpdateMemberRole(\n result: UpdateMemberRoleMutation[\"updateMemberRole\"],\n) {\n switch (result.__typename) {\n case \"MemberRoleUpdated\":\n return result.member;\n case \"MemberNotFound\":\n throw mutationFailure(result.__typename, \"Cannot edit role for user\");\n case \"RoleNotFound\":\n throw mutationFailure(result.__typename, \"Invalid role\");\n }\n}\n\nexport function unwrapInviteUser(result: InviteUserMutation[\"inviteUser\"]) {\n switch (result.__typename) {\n case \"UserInvited\":\n return result.invitation;\n case \"InviteeAlreadyMember\":\n throw mutationFailure(result.__typename, \"User already exists\");\n case \"InviteeAlreadyInvited\":\n throw mutationFailure(result.__typename, \"User already invited\");\n case \"InvalidInviteeEmail\":\n case \"InviteeEmailNotDeliverable\":\n throw mutationFailure(result.__typename, \"Invalid email\");\n case \"InvalidInviteeRole\":\n throw mutationFailure(result.__typename, \"Invalid role\");\n case \"InvalidInvitationExpiry\":\n throw mutationFailure(result.__typename, \"Invalid input\");\n case \"OrganizationBlockedFromSendingInvites\":\n throw mutationFailure(\n result.__typename,\n \"This organization is not allowed to send invites.\",\n );\n }\n}\n\nexport function unwrapRemoveMember(\n result: RemoveMemberMutation[\"removeMember\"],\n) {\n switch (result.__typename) {\n case \"MemberRemoved\":\n return result;\n case \"MemberNotFound\":\n case \"MemberIsManagedByDirectory\":\n throw mutationFailure(result.__typename, \"Cannot revoke membership\");\n }\n}\n\nexport function unwrapRevokeInvitation(\n result: RevokeInvitationMutation[\"revokeInvitation\"],\n) {\n switch (result.__typename) {\n case \"InvitationRevoked\":\n return result.invitation;\n case \"InvitationNotFound\":\n throw mutationFailure(result.__typename, \"User not invited\");\n case \"InvitationNotPending\":\n throw mutationFailure(result.__typename, \"User already accepted invite\");\n }\n}\n\nexport function unwrapResendInvitation(\n result: ResendInvitationMutation[\"resendInvitation\"],\n) {\n switch (result.__typename) {\n case \"InvitationResent\":\n return result.invitation;\n case \"ResendInvitationNotFound\":\n throw mutationFailure(result.__typename, \"User not invited\");\n case \"InviteeAlreadyAccepted\":\n throw mutationFailure(result.__typename, \"User already accepted invite\");\n case \"InviteeEmailNotDeliverable\":\n throw mutationFailure(result.__typename, \"Invalid email\");\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"users-management-utils.js","names":[],"sources":["../../../../src/widgets/users-management/users-management-utils.ts"],"sourcesContent":["import type { UseQueryResult } from \"@tanstack/react-query\";\nimport { keepPreviousData, useQueryClient } from \"@tanstack/react-query\";\nimport type {\n InviteUserMutation,\n ListOrganizationMembershipsQuery,\n ListRolesQuery,\n OrganizationMemberAction,\n OrganizationMemberFieldsFragment,\n RemoveMemberMutation,\n ResendInvitationMutation,\n RevokeInvitationMutation,\n RoleFieldsFragment,\n UpdateMemberRoleMutation,\n} from \"../../api/client-graphql/generated.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlQuery,\n} from \"../../api/client-graphql/hooks.js\";\nimport { ApiError } from \"../../api/errors.js\";\nimport type { ListMetadata } from \"../../lib/api/types.js\";\nimport { USER_ROW_LIMIT } from \"../../lib/constants.js\";\nimport { useUsersManagementContext } from \"./users-management-context.js\";\nimport type { UsersManagementContextValue } from \"./users-management-context.js\";\n\nexport type Role = RoleFieldsFragment;\n\nexport type RolesAndConfig = ListRolesQuery[\"roles\"];\n\nexport interface Member extends Omit<\n OrganizationMemberFieldsFragment,\n \"actions\"\n> {\n actions: MemberAction[];\n isLoggedInUser: boolean;\n}\n\nexport interface MembersQueryResult {\n data: Member[];\n listMetadata: ListMetadata;\n}\n\nconst MemberActions = {\n EditRole: \"edit-role\",\n ResendInvite: \"resend-invite\",\n RevokeInvite: \"revoke-invite\",\n RevokeMembership: \"revoke-membership\",\n} as const satisfies Record<OrganizationMemberAction, string>;\n\ntype MemberAction = (typeof MemberActions)[keyof typeof MemberActions];\n\nfunction toMember(member: OrganizationMemberFieldsFragment): Member {\n return {\n ...member,\n actions: member.actions.map((action) => MemberActions[action]),\n isLoggedInUser: member.isCurrentUser,\n };\n}\n\nfunction toMembersQueryResult(\n data: ListOrganizationMembershipsQuery,\n): MembersQueryResult {\n const { organizationMemberships } = data;\n return {\n data: organizationMemberships.data.map(toMember),\n listMetadata: {\n before: organizationMemberships.listMetadata.before ?? null,\n after: organizationMemberships.listMetadata.after ?? null,\n },\n };\n}\n\nexport const EMPTY_ROLES_AND_CONFIG: Readonly<ListRolesQuery> = {\n roles: { multipleRolesEnabled: false, roles: [] },\n};\n\nexport function useRolesAndConfig(): UseQueryResult<RolesAndConfig> {\n return useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListRoles\"),\n queryFn: (sdk) => sdk.ListRoles(),\n select: (data) => data.roles,\n initialData: EMPTY_ROLES_AND_CONFIG,\n });\n}\n\nexport function useUsers(context?: UsersManagementContextValue) {\n const {\n state: { pagination, role, searchQuery },\n } = useUsersManagementContext(context);\n const { before, after } = pagination || {};\n const variables = {\n after: after ?? null,\n before: before ?? null,\n limit: USER_ROW_LIMIT,\n roleSlug: role ?? null,\n search: searchQuery ?? null,\n };\n\n return useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListOrganizationMemberships\", variables),\n queryFn: (sdk) => sdk.ListOrganizationMemberships(variables),\n select: toMembersQueryResult,\n placeholderData: keepPreviousData,\n });\n}\n\nexport function useInvalidateMembers() {\n const queryClient = useQueryClient();\n return () =>\n queryClient.invalidateQueries({\n queryKey: clientGraphqlQueryKey(\"ListOrganizationMemberships\"),\n });\n}\n\nfunction mutationFailure(typename: string, message: string): ApiError {\n return new ApiError({\n message,\n status: 400,\n queryType: \"mutation\",\n context: { typename },\n });\n}\n\nexport function unwrapUpdateMemberRole(\n result: UpdateMemberRoleMutation[\"updateMemberRole\"],\n) {\n switch (result.__typename) {\n case \"MemberRoleUpdated\":\n return result.member;\n case \"MemberNotFound\":\n throw mutationFailure(result.__typename, \"Cannot edit role for user\");\n case \"RoleNotFound\":\n throw mutationFailure(result.__typename, \"Invalid role\");\n }\n}\n\nexport function unwrapInviteUser(result: InviteUserMutation[\"inviteUser\"]) {\n switch (result.__typename) {\n case \"UserInvited\":\n return result.invitation;\n case \"InviteeAlreadyMember\":\n throw mutationFailure(result.__typename, \"User already exists\");\n case \"InviteeAlreadyInvited\":\n throw mutationFailure(result.__typename, \"User already invited\");\n case \"InvalidInviteeEmail\":\n case \"InviteeEmailNotDeliverable\":\n throw mutationFailure(result.__typename, \"Invalid email\");\n case \"InvalidInviteeRole\":\n throw mutationFailure(result.__typename, \"Invalid role\");\n case \"InvalidInvitationExpiry\":\n throw mutationFailure(result.__typename, \"Invalid input\");\n case \"OrganizationBlockedFromSendingInvites\":\n throw mutationFailure(\n result.__typename,\n \"This organization is not allowed to send invites.\",\n );\n }\n}\n\nexport function unwrapRemoveMember(\n result: RemoveMemberMutation[\"removeMember\"],\n) {\n switch (result.__typename) {\n case \"MemberRemoved\":\n return result;\n case \"MemberNotFound\":\n case \"MemberIsManagedByDirectory\":\n throw mutationFailure(result.__typename, \"Cannot revoke membership\");\n }\n}\n\nexport function unwrapRevokeInvitation(\n result: RevokeInvitationMutation[\"revokeInvitation\"],\n) {\n switch (result.__typename) {\n case \"InvitationRevoked\":\n return result.invitation;\n case \"InvitationNotFound\":\n throw mutationFailure(result.__typename, \"User not invited\");\n case \"InvitationNotPending\":\n throw mutationFailure(result.__typename, \"User already accepted invite\");\n }\n}\n\nexport function unwrapResendInvitation(\n result: ResendInvitationMutation[\"resendInvitation\"],\n) {\n switch (result.__typename) {\n case \"InvitationResent\":\n return result.invitation;\n case \"ResendInvitationNotFound\":\n throw mutationFailure(result.__typename, \"User not invited\");\n case \"InviteeAlreadyAccepted\":\n throw mutationFailure(result.__typename, \"User already accepted invite\");\n case \"InviteeEmailNotDeliverable\":\n throw mutationFailure(result.__typename, \"Invalid email\");\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos-inc/widgets",
3
- "version": "1.20.2-next.1792708307096",
3
+ "version": "1.20.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -2,6 +2,8 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
2
2
  import * as React from "react";
3
3
  import { useIsHydrated } from "../lib/use-is-hydrated.js";
4
4
  import { getClaims } from "./claims.js";
5
+ import type { Claims } from "./claims.js";
6
+ import { isClientGraphqlQueryKey } from "./client-graphql/query-keys.js";
5
7
 
6
8
  type WidgetType =
7
9
  | "admin-portal-audit-log-streaming"
@@ -69,6 +71,7 @@ const ApiProvider: React.FC<ApiProviderProps> = ({
69
71
  widgetType,
70
72
  }) => {
71
73
  const queryClient = useQueryClient();
74
+ const queryKey = authTokenQueryKey(widgetType);
72
75
  const authTokenQuery = useQuery<AuthTokenQueryData>({
73
76
  initialData: () => {
74
77
  if (typeof authToken !== "string") {
@@ -93,9 +96,40 @@ const ApiProvider: React.FC<ApiProviderProps> = ({
93
96
  exp: claims.exp,
94
97
  };
95
98
  },
96
- queryKey: authTokenQueryKey(widgetType),
99
+ queryKey,
97
100
  });
98
101
 
102
+ // `initialData` only seeds the cache on first mount, so a new string token
103
+ // has to be written to the cache explicitly. A token for a different session,
104
+ // user or organization (e.g. after switching organizations) also invalidates
105
+ // data fetched with the previous token.
106
+ React.useEffect(() => {
107
+ if (typeof authToken !== "string") {
108
+ return;
109
+ }
110
+
111
+ const cached = queryClient.getQueryData<AuthTokenQueryData>(queryKey);
112
+ if (cached?.authToken === authToken) {
113
+ return;
114
+ }
115
+
116
+ // Keep an in-flight fetch holding the previous token from overwriting the
117
+ // new one.
118
+ void queryClient.cancelQueries({ queryKey });
119
+ const claims = getClaims(authToken);
120
+ queryClient.setQueryData<AuthTokenQueryData>(queryKey, {
121
+ authToken,
122
+ permissions: claims.permissions,
123
+ exp: claims.exp,
124
+ });
125
+
126
+ if (cached && !isSameSubject(getClaims(cached.authToken), claims)) {
127
+ void queryClient.invalidateQueries({
128
+ predicate: (query) => isClientGraphqlQueryKey(query.queryKey),
129
+ });
130
+ }
131
+ }, [authToken, queryClient, queryKey]);
132
+
99
133
  // Keep the token "fresh" until ~30s before it expires, so window-focus
100
134
  // re-fetches re-mint before data queries use a stale Bearer.
101
135
  //
@@ -179,6 +213,10 @@ const ApiProvider: React.FC<ApiProviderProps> = ({
179
213
  return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;
180
214
  };
181
215
 
216
+ function isSameSubject(a: Claims, b: Claims) {
217
+ return a.sid === b.sid && a.sub === b.sub && a.org_id === b.org_id;
218
+ }
219
+
182
220
  const useApi = () => {
183
221
  const context = React.useContext(ApiContext);
184
222
 
package/src/api/claims.ts CHANGED
@@ -1,8 +1,9 @@
1
- interface Claims {
1
+ export interface Claims {
2
2
  sid?: string;
3
3
  sub?: string;
4
4
  sub_type?: string;
5
5
  sub_profile?: string;
6
+ org_id?: string;
6
7
  auth_time?: number;
7
8
  permissions?: string[];
8
9
  exp?: number;
@@ -1,6 +1,5 @@
1
1
  import { useMutation, useQuery } from "@tanstack/react-query";
2
2
  import type {
3
- QueryKey,
4
3
  UseMutationOptions,
5
4
  UseQueryOptions,
6
5
  } from "@tanstack/react-query";
@@ -8,32 +7,14 @@ import { useApiReady } from "../api-provider.js";
8
7
  import { useClientGraphql } from "./client.js";
9
8
  import type { Sdk } from "./generated.js";
10
9
 
11
- export type ClientGraphqlOperation = keyof Sdk;
12
-
13
- export type ClientGraphqlVariables<K extends ClientGraphqlOperation> =
14
- Parameters<Sdk[K]>[0];
15
-
16
- const CLIENT_GRAPHQL_KEY_PREFIX = "client-graphql";
17
-
18
- export function isClientGraphqlQueryKey(queryKey: QueryKey): boolean {
19
- return queryKey[0] === CLIENT_GRAPHQL_KEY_PREFIX;
20
- }
21
-
22
- /**
23
- * React Query key for a Client GraphQL operation. Omit `variables` to address
24
- * every cached page/variant of an operation, e.g. when invalidating after a
25
- * mutation:
26
- *
27
- * queryClient.invalidateQueries({ queryKey: clientGraphqlQueryKey("Sessions") });
28
- */
29
- export function clientGraphqlQueryKey<K extends ClientGraphqlOperation>(
30
- operation: K,
31
- variables?: ClientGraphqlVariables<K>,
32
- ): QueryKey {
33
- return variables === undefined
34
- ? [CLIENT_GRAPHQL_KEY_PREFIX, operation]
35
- : [CLIENT_GRAPHQL_KEY_PREFIX, operation, variables];
36
- }
10
+ export {
11
+ clientGraphqlQueryKey,
12
+ isClientGraphqlQueryKey,
13
+ } from "./query-keys.js";
14
+ export type {
15
+ ClientGraphqlOperation,
16
+ ClientGraphqlVariables,
17
+ } from "./query-keys.js";
37
18
 
38
19
  type ClientGraphqlQueryOptions<TResult, TData> = Omit<
39
20
  UseQueryOptions<TResult, Error, TData>,
@@ -0,0 +1,29 @@
1
+ import type { QueryKey } from "@tanstack/react-query";
2
+ import type { Sdk } from "./generated.js";
3
+
4
+ export type ClientGraphqlOperation = keyof Sdk;
5
+
6
+ export type ClientGraphqlVariables<K extends ClientGraphqlOperation> =
7
+ Parameters<Sdk[K]>[0];
8
+
9
+ const CLIENT_GRAPHQL_KEY_PREFIX = "client-graphql";
10
+
11
+ export function isClientGraphqlQueryKey(queryKey: QueryKey): boolean {
12
+ return queryKey[0] === CLIENT_GRAPHQL_KEY_PREFIX;
13
+ }
14
+
15
+ /**
16
+ * React Query key for a Client GraphQL operation. Omit `variables` to address
17
+ * every cached page/variant of an operation, e.g. when invalidating after a
18
+ * mutation:
19
+ *
20
+ * queryClient.invalidateQueries({ queryKey: clientGraphqlQueryKey("Sessions") });
21
+ */
22
+ export function clientGraphqlQueryKey<K extends ClientGraphqlOperation>(
23
+ operation: K,
24
+ variables?: ClientGraphqlVariables<K>,
25
+ ): QueryKey {
26
+ return variables === undefined
27
+ ? [CLIENT_GRAPHQL_KEY_PREFIX, operation]
28
+ : [CLIENT_GRAPHQL_KEY_PREFIX, operation, variables];
29
+ }
@@ -56,7 +56,7 @@ const CopyText: React.FC<CopyTextProps> = ({ value, label }) => {
56
56
  title={copyLabel}
57
57
  variant="ghost"
58
58
  size="1"
59
- aria-labelledby={copyLabel}
59
+ aria-label={copyLabel}
60
60
  className={namespaceClassName("copy-text__copy")}
61
61
  onClick={async (event) => {
62
62
  const button = event.currentTarget;
@@ -243,6 +243,8 @@ const OtpInput = React.forwardRef<HTMLInputElement, OtpInputProps>(
243
243
  otpContext.onEnterPressed();
244
244
  }
245
245
  }}
246
+ // TODO(v2): remove; we're no longer using it
247
+ data-index={index}
246
248
  {...props}
247
249
  />
248
250
  </Form.Control>
@@ -68,9 +68,7 @@ const OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({
68
68
  const invalidateAllWidgets = useWidgetsInvalidator();
69
69
  const translate = useTranslation();
70
70
 
71
- // TODO: Possible if the user has no organizations - we should figure out what
72
- // to do in this case
73
- if (!currentOrganization) {
71
+ if (organizations.length === 0) {
74
72
  return (
75
73
  <OrganizationSwitcherError
76
74
  variant={variant}
@@ -79,12 +77,21 @@ const OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({
79
77
  id: "XimGbo",
80
78
  defaultMessage: "No organizations found",
81
79
  description:
82
- "Message for screen readers when no organizations are found",
80
+ "Shown in the disabled organization switcher when the user belongs to no organizations",
83
81
  })}
84
82
  />
85
83
  );
86
84
  }
87
85
 
86
+ const currentOrganizationName =
87
+ currentOrganization?.name ??
88
+ translate({
89
+ id: "aZ7eyn",
90
+ defaultMessage: "Select an organization",
91
+ description:
92
+ "Placeholder in the organization switcher trigger when the user has organizations but none is active",
93
+ });
94
+
88
95
  return (
89
96
  <DropdownMenu.Root>
90
97
  <DropdownMenu.Trigger>
@@ -108,7 +115,7 @@ const OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({
108
115
  minWidth="0"
109
116
  >
110
117
  <TruncatedOrganizationName
111
- organizationName={currentOrganization.name}
118
+ organizationName={currentOrganizationName}
112
119
  truncateBehavior={truncateBehavior}
113
120
  />
114
121
  <Flex asChild flexShrink="0">
@@ -134,7 +141,10 @@ const OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({
134
141
  >
135
142
  <DropdownMenu.Item
136
143
  onClick={() => {
137
- if (organization.id !== currentOrganization.id) {
144
+ if (
145
+ !currentOrganization ||
146
+ organization.id !== currentOrganization.id
147
+ ) {
138
148
  const result = switchToOrganization({
139
149
  organizationId: organization.id,
140
150
  });