@shipfox/client-integrations 14.0.0 → 16.0.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 (85) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +35 -0
  3. package/dist/application/complete-integration-callback.d.ts +2 -2
  4. package/dist/components/callback-status-shell.js +3 -3
  5. package/dist/components/callback-status-shell.js.map +1 -1
  6. package/dist/components/connection-picker.js +3 -3
  7. package/dist/components/connection-picker.js.map +1 -1
  8. package/dist/components/installed-integrations-section.js +9 -9
  9. package/dist/components/installed-integrations-section.js.map +1 -1
  10. package/dist/components/integration-delete-confirm-modal.js +1 -1
  11. package/dist/components/integration-delete-confirm-modal.js.map +1 -1
  12. package/dist/components/integration-gallery-for-workspace.js +3 -3
  13. package/dist/components/integration-gallery-for-workspace.js.map +1 -1
  14. package/dist/components/integration-gallery.stories.d.ts +1 -0
  15. package/dist/components/integration-gallery.stories.d.ts.map +1 -1
  16. package/dist/components/integration-gallery.stories.js +28 -0
  17. package/dist/components/integration-gallery.stories.js.map +1 -1
  18. package/dist/components/integration-usage-modal.d.ts +1 -1
  19. package/dist/components/integration-usage-modal.d.ts.map +1 -1
  20. package/dist/components/integration-usage-modal.js +8 -7
  21. package/dist/components/integration-usage-modal.js.map +1 -1
  22. package/dist/components/provider-grid.d.ts +1 -1
  23. package/dist/components/provider-grid.d.ts.map +1 -1
  24. package/dist/components/provider-grid.js +10 -10
  25. package/dist/components/provider-grid.js.map +1 -1
  26. package/dist/components/redirect-install-page.js +1 -1
  27. package/dist/components/redirect-install-page.js.map +1 -1
  28. package/dist/components/repository-picker.js +4 -4
  29. package/dist/components/repository-picker.js.map +1 -1
  30. package/dist/components/webhook/copyable-value.js +3 -3
  31. package/dist/components/webhook/copyable-value.js.map +1 -1
  32. package/dist/components/webhook/webhook-create-modal.js +1 -1
  33. package/dist/components/webhook/webhook-create-modal.js.map +1 -1
  34. package/dist/components/webhook/webhook-modals.stories.d.ts.map +1 -1
  35. package/dist/components/webhook/webhook-usage-details.js +2 -2
  36. package/dist/components/webhook/webhook-usage-details.js.map +1 -1
  37. package/dist/feature.d.ts +8 -8
  38. package/dist/feature.d.ts.map +1 -1
  39. package/dist/hooks/api/integrations.d.ts +4 -4
  40. package/dist/hooks/api/integrations.d.ts.map +1 -1
  41. package/dist/hooks/api/webhook-connections.d.ts +1 -1
  42. package/dist/hooks/api/webhook-connections.d.ts.map +1 -1
  43. package/dist/pages/gitea-install-page.js +4 -4
  44. package/dist/pages/gitea-install-page.js.map +1 -1
  45. package/dist/pages/jira-callback-page.js +7 -7
  46. package/dist/pages/jira-callback-page.js.map +1 -1
  47. package/dist/pages/sentry-callback-page.js +7 -7
  48. package/dist/pages/sentry-callback-page.js.map +1 -1
  49. package/dist/pages/source-control-onboarding-page.js +2 -2
  50. package/dist/pages/source-control-onboarding-page.js.map +1 -1
  51. package/dist/routes/gitea.d.ts.map +1 -1
  52. package/dist/routes/github-callback.d.ts.map +1 -1
  53. package/dist/routes/github.d.ts.map +1 -1
  54. package/dist/routes/integrations-settings.d.ts.map +1 -1
  55. package/dist/routes/integrations.d.ts.map +1 -1
  56. package/dist/routes/jira-callback.d.ts.map +1 -1
  57. package/dist/routes/jira.d.ts.map +1 -1
  58. package/dist/routes/linear-callback.d.ts.map +1 -1
  59. package/dist/routes/linear.d.ts.map +1 -1
  60. package/dist/routes/sentry-callback.d.ts.map +1 -1
  61. package/dist/routes/sentry.d.ts.map +1 -1
  62. package/dist/routes/slack-callback.d.ts.map +1 -1
  63. package/dist/routes/slack.d.ts.map +1 -1
  64. package/dist/tsconfig.test.tsbuildinfo +1 -1
  65. package/package.json +14 -14
  66. package/src/components/callback-status-shell.tsx +3 -3
  67. package/src/components/connection-picker.tsx +3 -3
  68. package/src/components/installed-integrations-section.tsx +9 -9
  69. package/src/components/integration-delete-confirm-modal.tsx +1 -1
  70. package/src/components/integration-gallery-for-workspace.tsx +3 -3
  71. package/src/components/integration-gallery.stories.tsx +20 -0
  72. package/src/components/integration-gallery.test.tsx +21 -0
  73. package/src/components/integration-usage-modal.tsx +9 -7
  74. package/src/components/provider-grid.tsx +10 -10
  75. package/src/components/redirect-install-page.tsx +1 -1
  76. package/src/components/repository-picker.test.tsx +2 -2
  77. package/src/components/repository-picker.tsx +6 -4
  78. package/src/components/webhook/copyable-value.tsx +3 -3
  79. package/src/components/webhook/webhook-create-modal.tsx +1 -1
  80. package/src/components/webhook/webhook-usage-details.tsx +2 -2
  81. package/src/pages/gitea-install-page.tsx +4 -4
  82. package/src/pages/jira-callback-page.tsx +7 -7
  83. package/src/pages/sentry-callback-page.tsx +7 -7
  84. package/src/pages/source-control-onboarding-page.tsx +2 -2
  85. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 59 files with swc (445.33ms)
2
+ Successfully compiled: 59 files with swc (583.69ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @shipfox/client-integrations
2
2
 
3
+ ## 16.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 654da7f: Restores page interaction immediately after closing the integration usage modal.
8
+ - Updated dependencies [7901a60]
9
+ - Updated dependencies [80cde6b]
10
+ - @shipfox/api-integration-core-dto@12.2.0
11
+ - @shipfox/react-ui@1.1.0
12
+ - @shipfox/client-ui@16.0.0
13
+ - @shipfox/api-integration-gitea-dto@12.2.0
14
+ - @shipfox/api-integration-github-dto@12.2.0
15
+ - @shipfox/api-integration-jira-dto@12.2.0
16
+ - @shipfox/api-integration-linear-dto@12.2.0
17
+ - @shipfox/api-integration-sentry-dto@12.2.0
18
+ - @shipfox/api-integration-slack-dto@12.2.0
19
+ - @shipfox/api-integration-webhook-dto@12.2.0
20
+ - @shipfox/client-auth@16.0.0
21
+ - @shipfox/client-shell@16.0.0
22
+ - @shipfox/integration-icons@0.3.2
23
+
24
+ ## 14.0.1
25
+
26
+ ### Patch Changes
27
+
28
+ - 6aa6c7a: Migrates the integrations, triggers, runners, and projects client surfaces to semantic spacing roles and enables `no-raw-spacing` for them. Adds the `gap-x-*` and `gap-y-*` axis roles and the `-mx-inline` bleed role so grids with differing column and row rhythm, and rows that cancel their own `px-tight`, stay on the density-aware scale.
29
+ - Updated dependencies [88bf8e8]
30
+ - Updated dependencies [6aa6c7a]
31
+ - Updated dependencies [5c56ba6]
32
+ - @shipfox/react-ui@1.0.0
33
+ - @shipfox/client-shell@14.0.1
34
+ - @shipfox/client-auth@14.0.1
35
+ - @shipfox/client-ui@14.0.1
36
+ - @shipfox/integration-icons@0.3.1
37
+
3
38
  ## 14.0.0
4
39
 
5
40
  ### Minor Changes
@@ -19,6 +19,6 @@ export interface CompleteIntegrationCallbackResultOptions<TInput, TResult> {
19
19
  }
20
20
  export declare function completeIntegrationCallback<TInput>({ input, refreshAuth, complete, queryClient, }: CompleteIntegrationCallbackOptions<TInput>): Promise<IntegrationConnection>;
21
21
  export declare function completeIntegrationCallbackResult<TInput, TResult>({ input, refreshAuth, complete, getConnection, queryClient, }: CompleteIntegrationCallbackResultOptions<TInput, TResult>): Promise<TResult>;
22
- export declare function useCompleteIntegrationCallback(): <TInput>(options: Omit<CompleteIntegrationCallbackOptions<TInput>, "queryClient">) => Promise<IntegrationConnection>;
23
- export declare function useCompleteIntegrationCallbackResult(): <TInput, TResult>(options: Omit<CompleteIntegrationCallbackResultOptions<TInput, TResult>, "queryClient">) => Promise<TResult>;
22
+ export declare function useCompleteIntegrationCallback(): <TInput>(options: Omit<CompleteIntegrationCallbackOptions<TInput>, 'queryClient'>) => Promise<IntegrationConnection>;
23
+ export declare function useCompleteIntegrationCallbackResult(): <TInput, TResult>(options: Omit<CompleteIntegrationCallbackResultOptions<TInput, TResult>, 'queryClient'>) => Promise<TResult>;
24
24
  //# sourceMappingURL=complete-integration-callback.d.ts.map
@@ -30,9 +30,9 @@ export function CallbackStatusShell({ title, message, status = 'error', startOve
30
30
  });
31
31
  const logoutRedirect = workspaceSlug ? installPath.replace('$workspaceSlug', workspaceSlug) : undefined;
32
32
  return /*#__PURE__*/ _jsx("main", {
33
- className: "flex min-h-screen bg-background-subtle-base px-16 py-32",
33
+ className: "flex min-h-screen bg-background-subtle-base px-row py-frame",
34
34
  children: /*#__PURE__*/ _jsxs("div", {
35
- className: "mx-auto flex w-full max-w-[480px] flex-col justify-center gap-20",
35
+ className: "mx-auto flex w-full max-w-[480px] flex-col justify-center gap-section",
36
36
  children: [
37
37
  /*#__PURE__*/ _jsx("h2", {
38
38
  ref: headingRef,
@@ -49,7 +49,7 @@ export function CallbackStatusShell({ title, message, status = 'error', startOve
49
49
  })
50
50
  }),
51
51
  /*#__PURE__*/ _jsxs("div", {
52
- className: "flex flex-col gap-8 sm:flex-row sm:items-center",
52
+ className: "flex flex-col gap-inline sm:flex-row sm:items-center",
53
53
  children: [
54
54
  switchAccount ? /*#__PURE__*/ _jsx(ButtonLink, {
55
55
  asChild: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/callback-status-shell.tsx"],"sourcesContent":["import {ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useRef} from 'react';\n\nexport function CallbackStatusShell({\n title,\n message,\n status = 'error',\n startOver,\n switchAccount,\n workspaceSlug,\n installPath,\n}: {\n title: string;\n message: string;\n status?: 'error' | 'success';\n startOver?: boolean;\n switchAccount?: boolean;\n workspaceSlug?: string | undefined;\n installPath:\n | '/w/$workspaceSlug/integrations/linear'\n | '/w/$workspaceSlug/integrations/slack'\n | '/w/$workspaceSlug/integrations/jira';\n}) {\n const headingRef = useRef<HTMLHeadingElement>(null);\n useEffect(() => headingRef.current?.focus(), []);\n const recoveryVariant = startOver || switchAccount ? 'muted' : 'base';\n const settings = workspaceSlug ? (\n <ButtonLink asChild variant={recoveryVariant} className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/settings/integrations\" params={{workspaceSlug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n ) : (\n <ButtonLink asChild variant={recoveryVariant} className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n );\n const logoutRedirect = workspaceSlug\n ? installPath.replace('$workspaceSlug', workspaceSlug)\n : undefined;\n\n return (\n <main className=\"flex min-h-screen bg-background-subtle-base px-16 py-32\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-20\">\n <h2 ref={headingRef} tabIndex={-1} className=\"text-24 font-semibold outline-none\">\n {title}\n </h2>\n <Callout role={status === 'error' ? 'alert' : 'status'} type={status}>\n <Text size=\"sm\">{message}</Text>\n </Callout>\n <div className=\"flex flex-col gap-8 sm:flex-row sm:items-center\">\n {switchAccount ? (\n <ButtonLink asChild className=\"min-h-44 w-full sm:w-fit\">\n <Link\n to=\"/auth/logout\"\n search={logoutRedirect ? {redirect: logoutRedirect} : undefined}\n >\n Switch account\n </Link>\n </ButtonLink>\n ) : null}\n {startOver && workspaceSlug ? (\n <ButtonLink asChild className=\"min-h-44 w-full sm:w-fit\">\n <Link to={installPath} params={{workspaceSlug}}>\n Start over\n </Link>\n </ButtonLink>\n ) : null}\n {settings}\n </div>\n </div>\n </main>\n );\n}\n"],"names":["ButtonLink","Callout","Text","Link","useEffect","useRef","CallbackStatusShell","title","message","status","startOver","switchAccount","workspaceSlug","installPath","headingRef","current","focus","recoveryVariant","settings","asChild","variant","className","to","params","logoutRedirect","replace","undefined","main","div","h2","ref","tabIndex","role","type","size","search","redirect"],"mappings":";AAAA,SAAQA,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,SAAS,EAAEC,MAAM,QAAO,QAAQ;AAExC,OAAO,SAASC,oBAAoB,EAClCC,KAAK,EACLC,OAAO,EACPC,SAAS,OAAO,EAChBC,SAAS,EACTC,aAAa,EACbC,aAAa,EACbC,WAAW,EAYZ;IACC,MAAMC,aAAaT,OAA2B;IAC9CD,UAAU,IAAMU,WAAWC,OAAO,EAAEC,SAAS,EAAE;IAC/C,MAAMC,kBAAkBP,aAAaC,gBAAgB,UAAU;IAC/D,MAAMO,WAAWN,8BACf,KAACZ;QAAWmB,OAAO;QAACC,SAASH;QAAiBI,WAAU;kBACtD,cAAA,KAAClB;YAAKmB,IAAG;YAA0CC,QAAQ;gBAACX;YAAa;sBAAG;;uBAK9E,KAACZ;QAAWmB,OAAO;QAACC,SAASH;QAAiBI,WAAU;kBACtD,cAAA,KAAClB;YAAKmB,IAAG;sBAAI;;;IAGjB,MAAME,iBAAiBZ,gBACnBC,YAAYY,OAAO,CAAC,kBAAkBb,iBACtCc;IAEJ,qBACE,KAACC;QAAKN,WAAU;kBACd,cAAA,MAACO;YAAIP,WAAU;;8BACb,KAACQ;oBAAGC,KAAKhB;oBAAYiB,UAAU,CAAC;oBAAGV,WAAU;8BAC1Cd;;8BAEH,KAACN;oBAAQ+B,MAAMvB,WAAW,UAAU,UAAU;oBAAUwB,MAAMxB;8BAC5D,cAAA,KAACP;wBAAKgC,MAAK;kCAAM1B;;;8BAEnB,MAACoB;oBAAIP,WAAU;;wBACZV,8BACC,KAACX;4BAAWmB,OAAO;4BAACE,WAAU;sCAC5B,cAAA,KAAClB;gCACCmB,IAAG;gCACHa,QAAQX,iBAAiB;oCAACY,UAAUZ;gCAAc,IAAIE;0CACvD;;6BAID;wBACHhB,aAAaE,8BACZ,KAACZ;4BAAWmB,OAAO;4BAACE,WAAU;sCAC5B,cAAA,KAAClB;gCAAKmB,IAAIT;gCAAaU,QAAQ;oCAACX;gCAAa;0CAAG;;6BAIhD;wBACHM;;;;;;AAKX"}
1
+ {"version":3,"sources":["../../src/components/callback-status-shell.tsx"],"sourcesContent":["import {ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useRef} from 'react';\n\nexport function CallbackStatusShell({\n title,\n message,\n status = 'error',\n startOver,\n switchAccount,\n workspaceSlug,\n installPath,\n}: {\n title: string;\n message: string;\n status?: 'error' | 'success';\n startOver?: boolean;\n switchAccount?: boolean;\n workspaceSlug?: string | undefined;\n installPath:\n | '/w/$workspaceSlug/integrations/linear'\n | '/w/$workspaceSlug/integrations/slack'\n | '/w/$workspaceSlug/integrations/jira';\n}) {\n const headingRef = useRef<HTMLHeadingElement>(null);\n useEffect(() => headingRef.current?.focus(), []);\n const recoveryVariant = startOver || switchAccount ? 'muted' : 'base';\n const settings = workspaceSlug ? (\n <ButtonLink asChild variant={recoveryVariant} className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/settings/integrations\" params={{workspaceSlug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n ) : (\n <ButtonLink asChild variant={recoveryVariant} className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n );\n const logoutRedirect = workspaceSlug\n ? installPath.replace('$workspaceSlug', workspaceSlug)\n : undefined;\n\n return (\n <main className=\"flex min-h-screen bg-background-subtle-base px-row py-frame\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-section\">\n <h2 ref={headingRef} tabIndex={-1} className=\"text-24 font-semibold outline-none\">\n {title}\n </h2>\n <Callout role={status === 'error' ? 'alert' : 'status'} type={status}>\n <Text size=\"sm\">{message}</Text>\n </Callout>\n <div className=\"flex flex-col gap-inline sm:flex-row sm:items-center\">\n {switchAccount ? (\n <ButtonLink asChild className=\"min-h-44 w-full sm:w-fit\">\n <Link\n to=\"/auth/logout\"\n search={logoutRedirect ? {redirect: logoutRedirect} : undefined}\n >\n Switch account\n </Link>\n </ButtonLink>\n ) : null}\n {startOver && workspaceSlug ? (\n <ButtonLink asChild className=\"min-h-44 w-full sm:w-fit\">\n <Link to={installPath} params={{workspaceSlug}}>\n Start over\n </Link>\n </ButtonLink>\n ) : null}\n {settings}\n </div>\n </div>\n </main>\n );\n}\n"],"names":["ButtonLink","Callout","Text","Link","useEffect","useRef","CallbackStatusShell","title","message","status","startOver","switchAccount","workspaceSlug","installPath","headingRef","current","focus","recoveryVariant","settings","asChild","variant","className","to","params","logoutRedirect","replace","undefined","main","div","h2","ref","tabIndex","role","type","size","search","redirect"],"mappings":";AAAA,SAAQA,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,SAAS,EAAEC,MAAM,QAAO,QAAQ;AAExC,OAAO,SAASC,oBAAoB,EAClCC,KAAK,EACLC,OAAO,EACPC,SAAS,OAAO,EAChBC,SAAS,EACTC,aAAa,EACbC,aAAa,EACbC,WAAW,EAYZ;IACC,MAAMC,aAAaT,OAA2B;IAC9CD,UAAU,IAAMU,WAAWC,OAAO,EAAEC,SAAS,EAAE;IAC/C,MAAMC,kBAAkBP,aAAaC,gBAAgB,UAAU;IAC/D,MAAMO,WAAWN,8BACf,KAACZ;QAAWmB,OAAO;QAACC,SAASH;QAAiBI,WAAU;kBACtD,cAAA,KAAClB;YAAKmB,IAAG;YAA0CC,QAAQ;gBAACX;YAAa;sBAAG;;uBAK9E,KAACZ;QAAWmB,OAAO;QAACC,SAASH;QAAiBI,WAAU;kBACtD,cAAA,KAAClB;YAAKmB,IAAG;sBAAI;;;IAGjB,MAAME,iBAAiBZ,gBACnBC,YAAYY,OAAO,CAAC,kBAAkBb,iBACtCc;IAEJ,qBACE,KAACC;QAAKN,WAAU;kBACd,cAAA,MAACO;YAAIP,WAAU;;8BACb,KAACQ;oBAAGC,KAAKhB;oBAAYiB,UAAU,CAAC;oBAAGV,WAAU;8BAC1Cd;;8BAEH,KAACN;oBAAQ+B,MAAMvB,WAAW,UAAU,UAAU;oBAAUwB,MAAMxB;8BAC5D,cAAA,KAACP;wBAAKgC,MAAK;kCAAM1B;;;8BAEnB,MAACoB;oBAAIP,WAAU;;wBACZV,8BACC,KAACX;4BAAWmB,OAAO;4BAACE,WAAU;sCAC5B,cAAA,KAAClB;gCACCmB,IAAG;gCACHa,QAAQX,iBAAiB;oCAACY,UAAUZ;gCAAc,IAAIE;0CACvD;;6BAID;wBACHhB,aAAaE,8BACZ,KAACZ;4BAAWmB,OAAO;4BAACE,WAAU;sCAC5B,cAAA,KAAClB;gCAAKmB,IAAIT;gCAAaU,QAAQ;oCAACX;gCAAa;0CAAG;;6BAIhD;wBACHM;;;;;;AAKX"}
@@ -9,7 +9,7 @@ import { useId } from 'react';
9
9
  export function ConnectionPicker({ connections, selectedConnectionId, onSelect }) {
10
10
  const labelId = useId();
11
11
  return /*#__PURE__*/ _jsxs("div", {
12
- className: "flex flex-col gap-10",
12
+ className: "flex flex-col gap-inline",
13
13
  children: [
14
14
  /*#__PURE__*/ _jsx(Label, {
15
15
  id: labelId,
@@ -20,7 +20,7 @@ export function ConnectionPicker({ connections, selectedConnectionId, onSelect }
20
20
  "aria-labelledby": labelId,
21
21
  value: selectedConnectionId ?? '',
22
22
  onValueChange: onSelect,
23
- className: "grid grid-cols-2 gap-8 max-[760px]:grid-cols-1",
23
+ className: "grid grid-cols-2 gap-inline max-[760px]:grid-cols-1",
24
24
  children: connections.map((connection)=>/*#__PURE__*/ _jsx(RadioGroupItem, {
25
25
  value: connection.id,
26
26
  children: /*#__PURE__*/ _jsx(ConnectionOption, {
@@ -34,7 +34,7 @@ export function ConnectionPicker({ connections, selectedConnectionId, onSelect }
34
34
  function ConnectionOption({ connection }) {
35
35
  const { ref: nameRef, isTruncated } = useIsTextTruncated(connection.displayName);
36
36
  return /*#__PURE__*/ _jsxs("span", {
37
- className: "flex min-w-0 items-center gap-10",
37
+ className: "flex min-w-0 items-center gap-inline",
38
38
  children: [
39
39
  /*#__PURE__*/ _jsxs(Tooltip, {
40
40
  children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/connection-picker.tsx"],"sourcesContent":["import {IntegrationIcon} from '@shipfox/integration-icons';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport function ConnectionPicker({\n connections,\n selectedConnectionId,\n onSelect,\n}: {\n connections: IntegrationConnection[];\n selectedConnectionId: string | undefined;\n onSelect: (connectionId: string) => void;\n}) {\n const labelId = useId();\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Source integration\n </Label>\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedConnectionId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-8 max-[760px]:grid-cols-1\"\n >\n {connections.map((connection) => (\n <RadioGroupItem key={connection.id} value={connection.id}>\n <ConnectionOption connection={connection} />\n </RadioGroupItem>\n ))}\n </RadioGroup>\n </div>\n );\n}\n\nfunction ConnectionOption({connection}: {connection: IntegrationConnection}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(connection.displayName);\n\n return (\n <span className=\"flex min-w-0 items-center gap-10\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className=\"size-20 text-foreground-neutral-base\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{integrationName(connection.provider)}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={nameRef} className=\"min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {connection.displayName}\n </Text>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{connection.displayName}</TooltipContent> : null}\n </Tooltip>\n </span>\n );\n}\n\nfunction integrationName(provider: string): string {\n switch (provider) {\n case 'github':\n return 'GitHub';\n case 'gitea':\n return 'Gitea';\n case 'sentry':\n return 'Sentry';\n case 'webhook':\n return 'Webhook';\n case 'debug':\n return 'Debug';\n default:\n return provider;\n }\n}\n"],"names":["IntegrationIcon","useIsTextTruncated","Label","RadioGroup","RadioGroupItem","Tooltip","TooltipContent","TooltipTrigger","Text","useId","ConnectionPicker","connections","selectedConnectionId","onSelect","labelId","div","className","id","aria-labelledby","value","onValueChange","map","connection","ConnectionOption","ref","nameRef","isTruncated","displayName","span","asChild","source","provider","aria-hidden","integrationName","as","size","bold"],"mappings":";AAAA,SAAQA,eAAe,QAAO,6BAA6B;AAC3D,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,OAAO,SAASC,iBAAiB,EAC/BC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EAKT;IACC,MAAMC,UAAUL;IAEhB,qBACE,MAACM;QAAIC,WAAU;;0BACb,KAACd;gBAAMe,IAAIH;gBAASE,WAAU;0BAAU;;0BAGxC,KAACb;gBACCe,mBAAiBJ;gBACjBK,OAAOP,wBAAwB;gBAC/BQ,eAAeP;gBACfG,WAAU;0BAETL,YAAYU,GAAG,CAAC,CAACC,2BAChB,KAAClB;wBAAmCe,OAAOG,WAAWL,EAAE;kCACtD,cAAA,KAACM;4BAAiBD,YAAYA;;uBADXA,WAAWL,EAAE;;;;AAO5C;AAEA,SAASM,iBAAiB,EAACD,UAAU,EAAsC;IACzE,MAAM,EAACE,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGzB,mBAAoCqB,WAAWK,WAAW;IAE9F,qBACE,MAACC;QAAKZ,WAAU;;0BACd,MAACX;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKZ,WAAU;sCACd,cAAA,KAAChB;gCACC8B,QAAQR,WAAWS,QAAQ;gCAC3BC,aAAW;gCACXhB,WAAU;;;;kCAIhB,KAACV;kCAAgB2B,gBAAgBX,WAAWS,QAAQ;;;;0BAGtD,MAAC1B;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKJ,KAAKC;4BAAST,WAAU;sCAC5B,cAAA,KAACR;gCAAK0B,IAAG;gCAAOC,MAAK;gCAAKC,IAAI;0CAC3Bd,WAAWK,WAAW;;;;oBAI5BD,4BAAc,KAACpB;kCAAgBgB,WAAWK,WAAW;yBAAqB;;;;;AAInF;AAEA,SAASM,gBAAgBF,QAAgB;IACvC,OAAQA;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,OAAOA;IACX;AACF"}
1
+ {"version":3,"sources":["../../src/components/connection-picker.tsx"],"sourcesContent":["import {IntegrationIcon} from '@shipfox/integration-icons';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport function ConnectionPicker({\n connections,\n selectedConnectionId,\n onSelect,\n}: {\n connections: IntegrationConnection[];\n selectedConnectionId: string | undefined;\n onSelect: (connectionId: string) => void;\n}) {\n const labelId = useId();\n\n return (\n <div className=\"flex flex-col gap-inline\">\n <Label id={labelId} className=\"sr-only\">\n Source integration\n </Label>\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedConnectionId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-inline max-[760px]:grid-cols-1\"\n >\n {connections.map((connection) => (\n <RadioGroupItem key={connection.id} value={connection.id}>\n <ConnectionOption connection={connection} />\n </RadioGroupItem>\n ))}\n </RadioGroup>\n </div>\n );\n}\n\nfunction ConnectionOption({connection}: {connection: IntegrationConnection}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(connection.displayName);\n\n return (\n <span className=\"flex min-w-0 items-center gap-inline\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className=\"size-20 text-foreground-neutral-base\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{integrationName(connection.provider)}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={nameRef} className=\"min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {connection.displayName}\n </Text>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{connection.displayName}</TooltipContent> : null}\n </Tooltip>\n </span>\n );\n}\n\nfunction integrationName(provider: string): string {\n switch (provider) {\n case 'github':\n return 'GitHub';\n case 'gitea':\n return 'Gitea';\n case 'sentry':\n return 'Sentry';\n case 'webhook':\n return 'Webhook';\n case 'debug':\n return 'Debug';\n default:\n return provider;\n }\n}\n"],"names":["IntegrationIcon","useIsTextTruncated","Label","RadioGroup","RadioGroupItem","Tooltip","TooltipContent","TooltipTrigger","Text","useId","ConnectionPicker","connections","selectedConnectionId","onSelect","labelId","div","className","id","aria-labelledby","value","onValueChange","map","connection","ConnectionOption","ref","nameRef","isTruncated","displayName","span","asChild","source","provider","aria-hidden","integrationName","as","size","bold"],"mappings":";AAAA,SAAQA,eAAe,QAAO,6BAA6B;AAC3D,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,OAAO,SAASC,iBAAiB,EAC/BC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EAKT;IACC,MAAMC,UAAUL;IAEhB,qBACE,MAACM;QAAIC,WAAU;;0BACb,KAACd;gBAAMe,IAAIH;gBAASE,WAAU;0BAAU;;0BAGxC,KAACb;gBACCe,mBAAiBJ;gBACjBK,OAAOP,wBAAwB;gBAC/BQ,eAAeP;gBACfG,WAAU;0BAETL,YAAYU,GAAG,CAAC,CAACC,2BAChB,KAAClB;wBAAmCe,OAAOG,WAAWL,EAAE;kCACtD,cAAA,KAACM;4BAAiBD,YAAYA;;uBADXA,WAAWL,EAAE;;;;AAO5C;AAEA,SAASM,iBAAiB,EAACD,UAAU,EAAsC;IACzE,MAAM,EAACE,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGzB,mBAAoCqB,WAAWK,WAAW;IAE9F,qBACE,MAACC;QAAKZ,WAAU;;0BACd,MAACX;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKZ,WAAU;sCACd,cAAA,KAAChB;gCACC8B,QAAQR,WAAWS,QAAQ;gCAC3BC,aAAW;gCACXhB,WAAU;;;;kCAIhB,KAACV;kCAAgB2B,gBAAgBX,WAAWS,QAAQ;;;;0BAGtD,MAAC1B;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKJ,KAAKC;4BAAST,WAAU;sCAC5B,cAAA,KAACR;gCAAK0B,IAAG;gCAAOC,MAAK;gCAAKC,IAAI;0CAC3Bd,WAAWK,WAAW;;;;oBAI5BD,4BAAc,KAACpB;kCAAgBgB,WAAWK,WAAW;yBAAqB;;;;;AAInF;AAEA,SAASM,gBAAgBF,QAAgB;IACvC,OAAQA;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,OAAOA;IACX;AACF"}
@@ -14,11 +14,11 @@ import { usageEventsForConnection } from './integration-usage-events.js';
14
14
  const INSTALLED_SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
15
15
  export function InstalledIntegrationsSection({ workspaceSlug, connections, isPending, isFetching, error, onRetry, isMutating, onUse, onSetActive, onDelete, providerDisplayName }) {
16
16
  return /*#__PURE__*/ _jsxs("section", {
17
- className: "flex flex-col gap-16",
17
+ className: "flex flex-col gap-group",
18
18
  "aria-label": "Installed integrations",
19
19
  children: [
20
20
  /*#__PURE__*/ _jsxs("div", {
21
- className: "flex flex-col gap-4",
21
+ className: "flex flex-col gap-tight",
22
22
  children: [
23
23
  /*#__PURE__*/ _jsx(Header, {
24
24
  variant: "h3",
@@ -35,7 +35,7 @@ export function InstalledIntegrationsSection({ workspaceSlug, connections, isPen
35
35
  label: "Loading integrations"
36
36
  }) : null,
37
37
  error ? /*#__PURE__*/ _jsx("div", {
38
- className: cn(INSTALLED_SURFACE_CLASS, 'px-16'),
38
+ className: cn(INSTALLED_SURFACE_CLASS, 'px-row'),
39
39
  children: /*#__PURE__*/ _jsx(QueryLoadError, {
40
40
  query: {
41
41
  isError: true,
@@ -48,7 +48,7 @@ export function InstalledIntegrationsSection({ workspaceSlug, connections, isPen
48
48
  })
49
49
  }) : null,
50
50
  !isPending && !error && connections.length === 0 ? /*#__PURE__*/ _jsx("div", {
51
- className: cn(INSTALLED_SURFACE_CLASS, 'px-16'),
51
+ className: cn(INSTALLED_SURFACE_CLASS, 'px-row'),
52
52
  children: /*#__PURE__*/ _jsx(EmptyState, {
53
53
  icon: "componentLine",
54
54
  title: "No integrations installed yet",
@@ -76,7 +76,7 @@ function InstalledRow({ connection, workspaceSlug, isMutating, onUse, onSetActiv
76
76
  const recentEventsEvent = usageEventsForConnection(connection)[0]?.value ?? 'received';
77
77
  const providerName = providerDisplayName(connection.provider);
78
78
  return /*#__PURE__*/ _jsxs("li", {
79
- className: "flex items-center gap-12 px-16 py-12 transition-colors hover:bg-background-components-hover",
79
+ className: "flex items-center gap-cluster px-row py-row transition-colors hover:bg-background-components-hover",
80
80
  children: [
81
81
  /*#__PURE__*/ _jsx(IntegrationIcon, {
82
82
  source: connection.provider,
@@ -84,10 +84,10 @@ function InstalledRow({ connection, workspaceSlug, isMutating, onUse, onSetActiv
84
84
  className: cn('size-24 shrink-0', muted ? 'text-foreground-neutral-disabled' : 'text-foreground-neutral-base')
85
85
  }),
86
86
  /*#__PURE__*/ _jsxs("div", {
87
- className: "flex min-w-0 flex-1 flex-col gap-2",
87
+ className: "flex min-w-0 flex-1 flex-col gap-tight",
88
88
  children: [
89
89
  /*#__PURE__*/ _jsxs("div", {
90
- className: "flex min-w-0 items-center gap-8",
90
+ className: "flex min-w-0 items-center gap-inline",
91
91
  children: [
92
92
  /*#__PURE__*/ _jsx(Text, {
93
93
  size: "md",
@@ -184,13 +184,13 @@ function InstalledSkeleton({ label }) {
184
184
  1,
185
185
  2
186
186
  ].map((row)=>/*#__PURE__*/ _jsxs("li", {
187
- className: "flex items-center gap-12 px-16 py-12",
187
+ className: "flex items-center gap-cluster px-row py-row",
188
188
  children: [
189
189
  /*#__PURE__*/ _jsx(Skeleton, {
190
190
  className: "size-24 shrink-0"
191
191
  }),
192
192
  /*#__PURE__*/ _jsxs("div", {
193
- className: "flex min-w-0 flex-1 flex-col gap-2",
193
+ className: "flex min-w-0 flex-1 flex-col gap-tight",
194
194
  children: [
195
195
  /*#__PURE__*/ _jsx(Skeleton, {
196
196
  className: "h-16 w-120"
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/installed-integrations-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IntegrationIcon} from '@shipfox/integration-icons';\nimport {IconButton} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn, formatDate} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {ConnectionStatusBadge} from '#connection-status-badge.js';\nimport {type IntegrationConnection, isUsableConnection} from '#core/models.js';\nimport {usageEventsForConnection} from './integration-usage-events.js';\n\ninterface InstalledIntegrationsSectionProps {\n workspaceSlug?: string | undefined;\n connections: IntegrationConnection[];\n isPending: boolean;\n isFetching: boolean;\n error?: Error | null | undefined;\n onRetry: () => void;\n isMutating: boolean;\n onUse: (connectionId: string) => void;\n onSetActive: (connection: IntegrationConnection, active: boolean) => void;\n onDelete: (connectionId: string) => void;\n providerDisplayName: (provider: string) => string | undefined;\n}\n\nconst INSTALLED_SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function InstalledIntegrationsSection({\n workspaceSlug,\n connections,\n isPending,\n isFetching,\n error,\n onRetry,\n isMutating,\n onUse,\n onSetActive,\n onDelete,\n providerDisplayName,\n}: InstalledIntegrationsSectionProps) {\n return (\n <section className=\"flex flex-col gap-16\" aria-label=\"Installed integrations\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Installed integrations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Provider accounts installed in this workspace.\n </Text>\n </div>\n\n {isPending ? <InstalledSkeleton label=\"Loading integrations\" /> : null}\n\n {error ? (\n <div className={cn(INSTALLED_SURFACE_CLASS, 'px-16')}>\n <QueryLoadError\n query={{isError: true, isFetching, data: undefined, error, refetch: onRetry}}\n subject=\"integrations\"\n />\n </div>\n ) : null}\n\n {!isPending && !error && connections.length === 0 ? (\n <div className={cn(INSTALLED_SURFACE_CLASS, 'px-16')}>\n <EmptyState\n icon=\"componentLine\"\n title=\"No integrations installed yet\"\n description=\"Install a provider below to get started.\"\n />\n </div>\n ) : null}\n\n {connections.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS)}>\n {connections.map((connection) => (\n <InstalledRow\n key={connection.id}\n connection={connection}\n workspaceSlug={workspaceSlug}\n isMutating={isMutating}\n onUse={onUse}\n onSetActive={(nextActive) => onSetActive(connection, nextActive)}\n onDelete={onDelete}\n providerDisplayName={providerDisplayName}\n />\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nfunction InstalledRow({\n connection,\n workspaceSlug,\n isMutating,\n onUse,\n onSetActive,\n onDelete,\n providerDisplayName,\n}: {\n connection: IntegrationConnection;\n workspaceSlug?: string | undefined;\n isMutating: boolean;\n onUse: (connectionId: string) => void;\n onSetActive: (active: boolean) => void;\n onDelete: (connectionId: string) => void;\n providerDisplayName: (provider: string) => string | undefined;\n}) {\n const muted = connection.lifecycleStatus === 'disabled';\n const active = isUsableConnection(connection);\n const recentEventsEvent = usageEventsForConnection(connection)[0]?.value ?? 'received';\n const providerName = providerDisplayName(connection.provider);\n\n return (\n <li className=\"flex items-center gap-12 px-16 py-12 transition-colors hover:bg-background-components-hover\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className={cn(\n 'size-24 shrink-0',\n muted ? 'text-foreground-neutral-disabled' : 'text-foreground-neutral-base',\n )}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <div className=\"flex min-w-0 items-center gap-8\">\n <Text\n size=\"md\"\n bold\n className={cn('truncate', muted ? 'text-foreground-neutral-disabled' : undefined)}\n >\n {connection.displayName}\n </Text>\n <ConnectionStatusBadge status={connection.lifecycleStatus} className=\"shrink-0\" />\n </div>\n <Text size=\"sm\" className=\"truncate text-foreground-neutral-muted\">\n Added {formatDate(connection.createdAt)}\n </Text>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Open ${connection.displayName} integration actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {connection.externalUrl ? (\n <DropdownMenuItem asChild>\n <a href={connection.externalUrl} target=\"_blank\" rel=\"noreferrer noopener\">\n {providerName ? `Open in ${providerName}` : 'Open provider settings'}\n </a>\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onSelect={() => onUse(connection.id)}>\n Use this integration\n </DropdownMenuItem>\n {workspaceSlug ? (\n <DropdownMenuItem asChild>\n <Link\n to=\"/w/$workspaceSlug/settings/events\"\n params={{workspaceSlug}}\n search={{source: [connection.slug], event: [recentEventsEvent]}}\n >\n View recent events\n </Link>\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuSeparator />\n <DropdownMenuItem disabled={isMutating} onSelect={() => onSetActive(!active)}>\n {active ? 'Disable integration' : 'Enable integration'}\n </DropdownMenuItem>\n <DropdownMenuItem disabled={isMutating} onSelect={() => onDelete(connection.id)}>\n Delete integration\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </li>\n );\n}\n\nfunction InstalledSkeleton({label}: {label: string}) {\n return (\n <ul\n role=\"status\"\n aria-label={label}\n className={cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS)}\n >\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-12 px-16 py-12\">\n <Skeleton className=\"size-24 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-12 w-80\" />\n </div>\n <Skeleton className=\"h-20 w-72 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IntegrationIcon","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","EmptyState","Skeleton","Header","Text","cn","formatDate","Link","ConnectionStatusBadge","isUsableConnection","usageEventsForConnection","INSTALLED_SURFACE_CLASS","InstalledIntegrationsSection","workspaceSlug","connections","isPending","isFetching","error","onRetry","isMutating","onUse","onSetActive","onDelete","providerDisplayName","section","className","aria-label","div","variant","size","InstalledSkeleton","label","query","isError","data","undefined","refetch","subject","length","icon","title","description","ul","map","connection","InstalledRow","nextActive","id","muted","lifecycleStatus","active","recentEventsEvent","value","providerName","provider","li","source","aria-hidden","bold","displayName","status","createdAt","asChild","align","externalUrl","a","href","target","rel","onSelect","to","params","search","slug","event","disabled","role","row"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/installed-integrations-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IntegrationIcon} from '@shipfox/integration-icons';\nimport {IconButton} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn, formatDate} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {ConnectionStatusBadge} from '#connection-status-badge.js';\nimport {type IntegrationConnection, isUsableConnection} from '#core/models.js';\nimport {usageEventsForConnection} from './integration-usage-events.js';\n\ninterface InstalledIntegrationsSectionProps {\n workspaceSlug?: string | undefined;\n connections: IntegrationConnection[];\n isPending: boolean;\n isFetching: boolean;\n error?: Error | null | undefined;\n onRetry: () => void;\n isMutating: boolean;\n onUse: (connectionId: string) => void;\n onSetActive: (connection: IntegrationConnection, active: boolean) => void;\n onDelete: (connectionId: string) => void;\n providerDisplayName: (provider: string) => string | undefined;\n}\n\nconst INSTALLED_SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function InstalledIntegrationsSection({\n workspaceSlug,\n connections,\n isPending,\n isFetching,\n error,\n onRetry,\n isMutating,\n onUse,\n onSetActive,\n onDelete,\n providerDisplayName,\n}: InstalledIntegrationsSectionProps) {\n return (\n <section className=\"flex flex-col gap-group\" aria-label=\"Installed integrations\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Installed integrations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Provider accounts installed in this workspace.\n </Text>\n </div>\n\n {isPending ? <InstalledSkeleton label=\"Loading integrations\" /> : null}\n\n {error ? (\n <div className={cn(INSTALLED_SURFACE_CLASS, 'px-row')}>\n <QueryLoadError\n query={{isError: true, isFetching, data: undefined, error, refetch: onRetry}}\n subject=\"integrations\"\n />\n </div>\n ) : null}\n\n {!isPending && !error && connections.length === 0 ? (\n <div className={cn(INSTALLED_SURFACE_CLASS, 'px-row')}>\n <EmptyState\n icon=\"componentLine\"\n title=\"No integrations installed yet\"\n description=\"Install a provider below to get started.\"\n />\n </div>\n ) : null}\n\n {connections.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS)}>\n {connections.map((connection) => (\n <InstalledRow\n key={connection.id}\n connection={connection}\n workspaceSlug={workspaceSlug}\n isMutating={isMutating}\n onUse={onUse}\n onSetActive={(nextActive) => onSetActive(connection, nextActive)}\n onDelete={onDelete}\n providerDisplayName={providerDisplayName}\n />\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nfunction InstalledRow({\n connection,\n workspaceSlug,\n isMutating,\n onUse,\n onSetActive,\n onDelete,\n providerDisplayName,\n}: {\n connection: IntegrationConnection;\n workspaceSlug?: string | undefined;\n isMutating: boolean;\n onUse: (connectionId: string) => void;\n onSetActive: (active: boolean) => void;\n onDelete: (connectionId: string) => void;\n providerDisplayName: (provider: string) => string | undefined;\n}) {\n const muted = connection.lifecycleStatus === 'disabled';\n const active = isUsableConnection(connection);\n const recentEventsEvent = usageEventsForConnection(connection)[0]?.value ?? 'received';\n const providerName = providerDisplayName(connection.provider);\n\n return (\n <li className=\"flex items-center gap-cluster px-row py-row transition-colors hover:bg-background-components-hover\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className={cn(\n 'size-24 shrink-0',\n muted ? 'text-foreground-neutral-disabled' : 'text-foreground-neutral-base',\n )}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Text\n size=\"md\"\n bold\n className={cn('truncate', muted ? 'text-foreground-neutral-disabled' : undefined)}\n >\n {connection.displayName}\n </Text>\n <ConnectionStatusBadge status={connection.lifecycleStatus} className=\"shrink-0\" />\n </div>\n <Text size=\"sm\" className=\"truncate text-foreground-neutral-muted\">\n Added {formatDate(connection.createdAt)}\n </Text>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Open ${connection.displayName} integration actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {connection.externalUrl ? (\n <DropdownMenuItem asChild>\n <a href={connection.externalUrl} target=\"_blank\" rel=\"noreferrer noopener\">\n {providerName ? `Open in ${providerName}` : 'Open provider settings'}\n </a>\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onSelect={() => onUse(connection.id)}>\n Use this integration\n </DropdownMenuItem>\n {workspaceSlug ? (\n <DropdownMenuItem asChild>\n <Link\n to=\"/w/$workspaceSlug/settings/events\"\n params={{workspaceSlug}}\n search={{source: [connection.slug], event: [recentEventsEvent]}}\n >\n View recent events\n </Link>\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuSeparator />\n <DropdownMenuItem disabled={isMutating} onSelect={() => onSetActive(!active)}>\n {active ? 'Disable integration' : 'Enable integration'}\n </DropdownMenuItem>\n <DropdownMenuItem disabled={isMutating} onSelect={() => onDelete(connection.id)}>\n Delete integration\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </li>\n );\n}\n\nfunction InstalledSkeleton({label}: {label: string}) {\n return (\n <ul\n role=\"status\"\n aria-label={label}\n className={cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS)}\n >\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-cluster px-row py-row\">\n <Skeleton className=\"size-24 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight\">\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-12 w-80\" />\n </div>\n <Skeleton className=\"h-20 w-72 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IntegrationIcon","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","EmptyState","Skeleton","Header","Text","cn","formatDate","Link","ConnectionStatusBadge","isUsableConnection","usageEventsForConnection","INSTALLED_SURFACE_CLASS","InstalledIntegrationsSection","workspaceSlug","connections","isPending","isFetching","error","onRetry","isMutating","onUse","onSetActive","onDelete","providerDisplayName","section","className","aria-label","div","variant","size","InstalledSkeleton","label","query","isError","data","undefined","refetch","subject","length","icon","title","description","ul","map","connection","InstalledRow","nextActive","id","muted","lifecycleStatus","active","recentEventsEvent","value","providerName","provider","li","source","aria-hidden","bold","displayName","status","createdAt","asChild","align","externalUrl","a","href","target","rel","onSelect","to","params","search","slug","event","disabled","role","row"],"mappings":"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"}
@@ -22,7 +22,7 @@ export function IntegrationDeleteConfirmModal({ connectionName, open, isPending,
22
22
  showClose: !isPending
23
23
  }),
24
24
  /*#__PURE__*/ _jsx(ModalBody, {
25
- className: "gap-16",
25
+ className: "gap-group",
26
26
  children: /*#__PURE__*/ _jsxs(Text, {
27
27
  size: "sm",
28
28
  children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/integration-delete-confirm-modal.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Text} from '@shipfox/react-ui/typography';\n\ninterface IntegrationDeleteConfirmModalProps {\n connectionName: string | undefined;\n open: boolean;\n isPending: boolean;\n onOpenChange: (open: boolean) => void;\n onConfirm: () => void;\n}\n\nexport function IntegrationDeleteConfirmModal({\n connectionName,\n open,\n isPending,\n onOpenChange,\n onConfirm,\n}: IntegrationDeleteConfirmModalProps) {\n const name = connectionName ?? 'this integration';\n return (\n <Modal\n open={open}\n onOpenChange={(nextOpen) => {\n if (isPending && !nextOpen) return;\n onOpenChange(nextOpen);\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Delete integration</ModalTitle>\n <ModalHeader title=\"Delete integration\" showClose={!isPending} />\n <ModalBody className=\"gap-16\">\n <Text size=\"sm\">\n Are you sure you want to delete <strong className=\"font-medium\">{name}</strong>? Once\n deleted, Shipfox will immediately stop processing events from this integration. This\n cannot be undone.\n </Text>\n </ModalBody>\n <ModalFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={isPending}\n onClick={() => onOpenChange(false)}\n >\n Cancel\n </Button>\n <Button type=\"button\" variant=\"danger\" isLoading={isPending} onClick={onConfirm}>\n Delete integration\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n"],"names":["Button","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Text","IntegrationDeleteConfirmModal","connectionName","open","isPending","onOpenChange","onConfirm","name","nextOpen","aria-describedby","undefined","className","title","showClose","size","strong","type","variant","disabled","onClick","isLoading"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,UAAU,QACL,0BAA0B;AACjC,SAAQC,IAAI,QAAO,+BAA+B;AAUlD,OAAO,SAASC,8BAA8B,EAC5CC,cAAc,EACdC,IAAI,EACJC,SAAS,EACTC,YAAY,EACZC,SAAS,EAC0B;IACnC,MAAMC,OAAOL,kBAAkB;IAC/B,qBACE,KAACR;QACCS,MAAMA;QACNE,cAAc,CAACG;YACb,IAAIJ,aAAa,CAACI,UAAU;YAC5BH,aAAaG;QACf;kBAEA,cAAA,MAACZ;YAAaa,oBAAkBC;;8BAC9B,KAACX;oBAAWY,WAAU;8BAAU;;8BAChC,KAACb;oBAAYc,OAAM;oBAAqBC,WAAW,CAACT;;8BACpD,KAACT;oBAAUgB,WAAU;8BACnB,cAAA,MAACX;wBAAKc,MAAK;;4BAAK;0CACkB,KAACC;gCAAOJ,WAAU;0CAAeJ;;4BAAc;;;;8BAKnF,MAACV;;sCACC,KAACJ;4BACCuB,MAAK;4BACLC,SAAQ;4BACRC,UAAUd;4BACVe,SAAS,IAAMd,aAAa;sCAC7B;;sCAGD,KAACZ;4BAAOuB,MAAK;4BAASC,SAAQ;4BAASG,WAAWhB;4BAAWe,SAASb;sCAAW;;;;;;;AAO3F"}
1
+ {"version":3,"sources":["../../src/components/integration-delete-confirm-modal.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Text} from '@shipfox/react-ui/typography';\n\ninterface IntegrationDeleteConfirmModalProps {\n connectionName: string | undefined;\n open: boolean;\n isPending: boolean;\n onOpenChange: (open: boolean) => void;\n onConfirm: () => void;\n}\n\nexport function IntegrationDeleteConfirmModal({\n connectionName,\n open,\n isPending,\n onOpenChange,\n onConfirm,\n}: IntegrationDeleteConfirmModalProps) {\n const name = connectionName ?? 'this integration';\n return (\n <Modal\n open={open}\n onOpenChange={(nextOpen) => {\n if (isPending && !nextOpen) return;\n onOpenChange(nextOpen);\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Delete integration</ModalTitle>\n <ModalHeader title=\"Delete integration\" showClose={!isPending} />\n <ModalBody className=\"gap-group\">\n <Text size=\"sm\">\n Are you sure you want to delete <strong className=\"font-medium\">{name}</strong>? Once\n deleted, Shipfox will immediately stop processing events from this integration. This\n cannot be undone.\n </Text>\n </ModalBody>\n <ModalFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={isPending}\n onClick={() => onOpenChange(false)}\n >\n Cancel\n </Button>\n <Button type=\"button\" variant=\"danger\" isLoading={isPending} onClick={onConfirm}>\n Delete integration\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n"],"names":["Button","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Text","IntegrationDeleteConfirmModal","connectionName","open","isPending","onOpenChange","onConfirm","name","nextOpen","aria-describedby","undefined","className","title","showClose","size","strong","type","variant","disabled","onClick","isLoading"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,UAAU,QACL,0BAA0B;AACjC,SAAQC,IAAI,QAAO,+BAA+B;AAUlD,OAAO,SAASC,8BAA8B,EAC5CC,cAAc,EACdC,IAAI,EACJC,SAAS,EACTC,YAAY,EACZC,SAAS,EAC0B;IACnC,MAAMC,OAAOL,kBAAkB;IAC/B,qBACE,KAACR;QACCS,MAAMA;QACNE,cAAc,CAACG;YACb,IAAIJ,aAAa,CAACI,UAAU;YAC5BH,aAAaG;QACf;kBAEA,cAAA,MAACZ;YAAaa,oBAAkBC;;8BAC9B,KAACX;oBAAWY,WAAU;8BAAU;;8BAChC,KAACb;oBAAYc,OAAM;oBAAqBC,WAAW,CAACT;;8BACpD,KAACT;oBAAUgB,WAAU;8BACnB,cAAA,MAACX;wBAAKc,MAAK;;4BAAK;0CACkB,KAACC;gCAAOJ,WAAU;0CAAeJ;;4BAAc;;;;8BAKnF,MAACV;;sCACC,KAACJ;4BACCuB,MAAK;4BACLC,SAAQ;4BACRC,UAAUd;4BACVe,SAAS,IAAMd,aAAa;sCAC7B;;sCAGD,KAACZ;4BAAOuB,MAAK;4BAASC,SAAQ;4BAASG,WAAWhB;4BAAWe,SAASb;sCAAW;;;;;;;AAO3F"}
@@ -91,7 +91,7 @@ export function IntegrationGalleryForWorkspace({ capability, emptyProvidersMessa
91
91
  }
92
92
  }
93
93
  return /*#__PURE__*/ _jsxs("div", {
94
- className: "flex flex-col gap-24",
94
+ className: "flex flex-col gap-section",
95
95
  children: [
96
96
  /*#__PURE__*/ _jsx(InstalledIntegrationsSection, {
97
97
  workspaceSlug: workspaceSlug,
@@ -109,11 +109,11 @@ export function IntegrationGalleryForWorkspace({ capability, emptyProvidersMessa
109
109
  providerDisplayName: providerDisplayName
110
110
  }),
111
111
  /*#__PURE__*/ _jsxs("section", {
112
- className: "flex flex-col gap-16",
112
+ className: "flex flex-col gap-group",
113
113
  "aria-label": "Available integrations",
114
114
  children: [
115
115
  /*#__PURE__*/ _jsxs("div", {
116
- className: "flex flex-col gap-4",
116
+ className: "flex flex-col gap-tight",
117
117
  children: [
118
118
  /*#__PURE__*/ _jsx(Header, {
119
119
  variant: "h3",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/integration-gallery-for-workspace.tsx"],"sourcesContent":["import {useAuthState} from '@shipfox/client-auth';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport type {\n IntegrationCapability,\n IntegrationConnection,\n IntegrationProvider,\n} from '#core/models.js';\nimport {\n useDeleteIntegrationConnectionMutation,\n useIntegrationConnectionsQuery,\n useIntegrationProvidersQuery,\n useUpdateIntegrationConnectionMutation,\n} from '#hooks/api/integrations.js';\nimport {\n useDeleteWebhookConnectionMutation,\n useUpdateWebhookConnectionMutation,\n} from '#hooks/api/webhook-connections.js';\nimport {InstalledIntegrationsSection} from './installed-integrations-section.js';\nimport {IntegrationDeleteConfirmModal} from './integration-delete-confirm-modal.js';\nimport {usageEventsForConnection} from './integration-usage-events.js';\nimport {IntegrationUsageModal} from './integration-usage-modal.js';\nimport {ProviderGrid} from './provider-grid.js';\nimport {WebhookCreateModal} from './webhook/webhook-create-modal.js';\nimport {WebhookUsageDetails} from './webhook/webhook-usage-details.js';\n\ninterface IntegrationGalleryForWorkspaceProps {\n capability: IntegrationCapability | undefined;\n emptyProvidersMessage: string;\n workspaceId: string;\n}\n\nexport function IntegrationGalleryForWorkspace({\n capability,\n emptyProvidersMessage,\n workspaceId,\n}: IntegrationGalleryForWorkspaceProps) {\n const {workspaces} = useAuthState();\n const workspaceSlug = workspaces.find((workspace) => workspace.id === workspaceId)?.slug;\n const [createProvider, setCreateProvider] = useState<string | undefined>();\n const [usageConnectionId, setUsageConnectionId] = useState<string | undefined>();\n const [createdUsageConnection, setCreatedUsageConnection] = useState<\n IntegrationConnection | undefined\n >();\n const [deleteConnectionId, setDeleteConnectionId] = useState<string | undefined>();\n const providersQuery = useIntegrationProvidersQuery(capability ? {capability} : undefined);\n const connectionsQuery = useIntegrationConnectionsQuery(workspaceId);\n const updateConnection = useUpdateIntegrationConnectionMutation();\n const deleteConnection = useDeleteIntegrationConnectionMutation();\n const updateWebhookConnection = useUpdateWebhookConnectionMutation();\n const deleteWebhookConnection = useDeleteWebhookConnectionMutation();\n\n const providers = providersQuery.data ?? [];\n const providersMap = new Map<string, IntegrationProvider>(\n providers.map((provider) => [provider.provider, provider]),\n );\n\n const allConnections = connectionsQuery.data ?? [];\n // Filter in memory so the all-status cache key stays shared; passing capability\n // into the hook would collide with the active-only `source_control` key used\n // elsewhere.\n const connections = capability\n ? allConnections.filter((connection) => connection.capabilities.includes(capability))\n : allConnections;\n\n const providerDisplayName = (provider: string) => providersMap.get(provider)?.displayName;\n const providerLabel = (provider: string) => providerDisplayName(provider) ?? provider;\n\n const sortedConnections = [...connections].sort((a, b) => {\n const byProvider = providerLabel(a.provider).localeCompare(providerLabel(b.provider));\n if (byProvider !== 0) return byProvider;\n return a.createdAt.localeCompare(b.createdAt);\n });\n const usageConnection =\n sortedConnections.find((connection) => connection.id === usageConnectionId) ??\n (createdUsageConnection?.id === usageConnectionId ? createdUsageConnection : null) ??\n null;\n const deleteConnectionTarget = sortedConnections.find(\n (connection) => connection.id === deleteConnectionId,\n );\n\n async function setConnectionActive(connection: IntegrationConnection, active: boolean) {\n try {\n const body = {lifecycle_status: active ? 'active' : 'disabled'} as const;\n if (connection.provider === 'webhook') {\n await updateWebhookConnection.mutateAsync({\n workspaceId,\n connectionId: connection.id,\n body,\n });\n } else {\n await updateConnection.mutateAsync({\n connectionId: connection.id,\n body,\n });\n }\n toast.success(active ? 'Integration enabled.' : 'Integration disabled.');\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Could not update integration.');\n }\n }\n\n async function confirmDeleteConnection() {\n if (!deleteConnectionTarget) return;\n try {\n if (deleteConnectionTarget.provider === 'webhook') {\n await deleteWebhookConnection.mutateAsync({\n workspaceId,\n connectionId: deleteConnectionTarget.id,\n });\n } else {\n await deleteConnection.mutateAsync({\n workspaceId,\n connectionId: deleteConnectionTarget.id,\n });\n }\n toast.success('Integration deleted.');\n setDeleteConnectionId(undefined);\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Could not delete integration.');\n }\n }\n\n return (\n <div className=\"flex flex-col gap-24\">\n <InstalledIntegrationsSection\n workspaceSlug={workspaceSlug}\n connections={sortedConnections}\n isPending={connectionsQuery.isPending}\n isFetching={connectionsQuery.isFetching}\n error={connectionsQuery.isError ? connectionsQuery.error : undefined}\n onRetry={() => void connectionsQuery.refetch()}\n isMutating={\n updateConnection.isPending ||\n deleteConnection.isPending ||\n updateWebhookConnection.isPending ||\n deleteWebhookConnection.isPending\n }\n onUse={setUsageConnectionId}\n onSetActive={(connection, active) => {\n void setConnectionActive(connection, active);\n }}\n onDelete={setDeleteConnectionId}\n providerDisplayName={providerDisplayName}\n />\n\n <section className=\"flex flex-col gap-16\" aria-label=\"Available integrations\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Available integrations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers available to install in this workspace.\n </Text>\n </div>\n\n {workspaceSlug ? (\n <ProviderGrid\n workspaceSlug={workspaceSlug}\n providers={providers}\n isPending={providersQuery.isPending}\n isFetching={providersQuery.isFetching}\n error={providersQuery.isError ? providersQuery.error : undefined}\n onRetry={() => void providersQuery.refetch()}\n emptyMessage={emptyProvidersMessage}\n onOpenProvider={setCreateProvider}\n />\n ) : (\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\" aria-live=\"polite\">\n Loading workspace details…\n </Text>\n )}\n </section>\n <WebhookCreateModal\n workspaceId={workspaceId}\n open={createProvider === 'webhook'}\n onOpenChange={(open) => setCreateProvider(open ? 'webhook' : undefined)}\n onCreated={(connection) => {\n setCreatedUsageConnection(connection);\n setUsageConnectionId(connection.id);\n }}\n />\n <IntegrationUsageModal\n connection={usageConnection}\n events={usageConnection ? usageEventsForConnection(usageConnection) : []}\n open={usageConnection !== null}\n onOpenChange={(open) => {\n if (!open) {\n setUsageConnectionId(undefined);\n setCreatedUsageConnection(undefined);\n }\n }}\n >\n {usageConnection?.provider === 'webhook' ? (\n <WebhookUsageDetails workspaceId={workspaceId} connectionId={usageConnection.id} />\n ) : null}\n </IntegrationUsageModal>\n <IntegrationDeleteConfirmModal\n connectionName={deleteConnectionTarget?.displayName}\n open={deleteConnectionId !== undefined}\n isPending={deleteConnection.isPending || deleteWebhookConnection.isPending}\n onOpenChange={(open) => {\n if (!open) setDeleteConnectionId(undefined);\n }}\n onConfirm={() => {\n void confirmDeleteConnection();\n }}\n />\n </div>\n );\n}\n"],"names":["useAuthState","toast","Header","Text","useState","useDeleteIntegrationConnectionMutation","useIntegrationConnectionsQuery","useIntegrationProvidersQuery","useUpdateIntegrationConnectionMutation","useDeleteWebhookConnectionMutation","useUpdateWebhookConnectionMutation","InstalledIntegrationsSection","IntegrationDeleteConfirmModal","usageEventsForConnection","IntegrationUsageModal","ProviderGrid","WebhookCreateModal","WebhookUsageDetails","IntegrationGalleryForWorkspace","capability","emptyProvidersMessage","workspaceId","workspaces","workspaceSlug","find","workspace","id","slug","createProvider","setCreateProvider","usageConnectionId","setUsageConnectionId","createdUsageConnection","setCreatedUsageConnection","deleteConnectionId","setDeleteConnectionId","providersQuery","undefined","connectionsQuery","updateConnection","deleteConnection","updateWebhookConnection","deleteWebhookConnection","providers","data","providersMap","Map","map","provider","allConnections","connections","filter","connection","capabilities","includes","providerDisplayName","get","displayName","providerLabel","sortedConnections","sort","a","b","byProvider","localeCompare","createdAt","usageConnection","deleteConnectionTarget","setConnectionActive","active","body","lifecycle_status","mutateAsync","connectionId","success","error","Error","message","confirmDeleteConnection","div","className","isPending","isFetching","isError","onRetry","refetch","isMutating","onUse","onSetActive","onDelete","section","aria-label","variant","size","emptyMessage","onOpenProvider","aria-live","open","onOpenChange","onCreated","events","connectionName","onConfirm"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/integration-gallery-for-workspace.tsx"],"sourcesContent":["import {useAuthState} from '@shipfox/client-auth';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport type {\n IntegrationCapability,\n IntegrationConnection,\n IntegrationProvider,\n} from '#core/models.js';\nimport {\n useDeleteIntegrationConnectionMutation,\n useIntegrationConnectionsQuery,\n useIntegrationProvidersQuery,\n useUpdateIntegrationConnectionMutation,\n} from '#hooks/api/integrations.js';\nimport {\n useDeleteWebhookConnectionMutation,\n useUpdateWebhookConnectionMutation,\n} from '#hooks/api/webhook-connections.js';\nimport {InstalledIntegrationsSection} from './installed-integrations-section.js';\nimport {IntegrationDeleteConfirmModal} from './integration-delete-confirm-modal.js';\nimport {usageEventsForConnection} from './integration-usage-events.js';\nimport {IntegrationUsageModal} from './integration-usage-modal.js';\nimport {ProviderGrid} from './provider-grid.js';\nimport {WebhookCreateModal} from './webhook/webhook-create-modal.js';\nimport {WebhookUsageDetails} from './webhook/webhook-usage-details.js';\n\ninterface IntegrationGalleryForWorkspaceProps {\n capability: IntegrationCapability | undefined;\n emptyProvidersMessage: string;\n workspaceId: string;\n}\n\nexport function IntegrationGalleryForWorkspace({\n capability,\n emptyProvidersMessage,\n workspaceId,\n}: IntegrationGalleryForWorkspaceProps) {\n const {workspaces} = useAuthState();\n const workspaceSlug = workspaces.find((workspace) => workspace.id === workspaceId)?.slug;\n const [createProvider, setCreateProvider] = useState<string | undefined>();\n const [usageConnectionId, setUsageConnectionId] = useState<string | undefined>();\n const [createdUsageConnection, setCreatedUsageConnection] = useState<\n IntegrationConnection | undefined\n >();\n const [deleteConnectionId, setDeleteConnectionId] = useState<string | undefined>();\n const providersQuery = useIntegrationProvidersQuery(capability ? {capability} : undefined);\n const connectionsQuery = useIntegrationConnectionsQuery(workspaceId);\n const updateConnection = useUpdateIntegrationConnectionMutation();\n const deleteConnection = useDeleteIntegrationConnectionMutation();\n const updateWebhookConnection = useUpdateWebhookConnectionMutation();\n const deleteWebhookConnection = useDeleteWebhookConnectionMutation();\n\n const providers = providersQuery.data ?? [];\n const providersMap = new Map<string, IntegrationProvider>(\n providers.map((provider) => [provider.provider, provider]),\n );\n\n const allConnections = connectionsQuery.data ?? [];\n // Filter in memory so the all-status cache key stays shared; passing capability\n // into the hook would collide with the active-only `source_control` key used\n // elsewhere.\n const connections = capability\n ? allConnections.filter((connection) => connection.capabilities.includes(capability))\n : allConnections;\n\n const providerDisplayName = (provider: string) => providersMap.get(provider)?.displayName;\n const providerLabel = (provider: string) => providerDisplayName(provider) ?? provider;\n\n const sortedConnections = [...connections].sort((a, b) => {\n const byProvider = providerLabel(a.provider).localeCompare(providerLabel(b.provider));\n if (byProvider !== 0) return byProvider;\n return a.createdAt.localeCompare(b.createdAt);\n });\n const usageConnection =\n sortedConnections.find((connection) => connection.id === usageConnectionId) ??\n (createdUsageConnection?.id === usageConnectionId ? createdUsageConnection : null) ??\n null;\n const deleteConnectionTarget = sortedConnections.find(\n (connection) => connection.id === deleteConnectionId,\n );\n\n async function setConnectionActive(connection: IntegrationConnection, active: boolean) {\n try {\n const body = {lifecycle_status: active ? 'active' : 'disabled'} as const;\n if (connection.provider === 'webhook') {\n await updateWebhookConnection.mutateAsync({\n workspaceId,\n connectionId: connection.id,\n body,\n });\n } else {\n await updateConnection.mutateAsync({\n connectionId: connection.id,\n body,\n });\n }\n toast.success(active ? 'Integration enabled.' : 'Integration disabled.');\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Could not update integration.');\n }\n }\n\n async function confirmDeleteConnection() {\n if (!deleteConnectionTarget) return;\n try {\n if (deleteConnectionTarget.provider === 'webhook') {\n await deleteWebhookConnection.mutateAsync({\n workspaceId,\n connectionId: deleteConnectionTarget.id,\n });\n } else {\n await deleteConnection.mutateAsync({\n workspaceId,\n connectionId: deleteConnectionTarget.id,\n });\n }\n toast.success('Integration deleted.');\n setDeleteConnectionId(undefined);\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Could not delete integration.');\n }\n }\n\n return (\n <div className=\"flex flex-col gap-section\">\n <InstalledIntegrationsSection\n workspaceSlug={workspaceSlug}\n connections={sortedConnections}\n isPending={connectionsQuery.isPending}\n isFetching={connectionsQuery.isFetching}\n error={connectionsQuery.isError ? connectionsQuery.error : undefined}\n onRetry={() => void connectionsQuery.refetch()}\n isMutating={\n updateConnection.isPending ||\n deleteConnection.isPending ||\n updateWebhookConnection.isPending ||\n deleteWebhookConnection.isPending\n }\n onUse={setUsageConnectionId}\n onSetActive={(connection, active) => {\n void setConnectionActive(connection, active);\n }}\n onDelete={setDeleteConnectionId}\n providerDisplayName={providerDisplayName}\n />\n\n <section className=\"flex flex-col gap-group\" aria-label=\"Available integrations\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Available integrations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers available to install in this workspace.\n </Text>\n </div>\n\n {workspaceSlug ? (\n <ProviderGrid\n workspaceSlug={workspaceSlug}\n providers={providers}\n isPending={providersQuery.isPending}\n isFetching={providersQuery.isFetching}\n error={providersQuery.isError ? providersQuery.error : undefined}\n onRetry={() => void providersQuery.refetch()}\n emptyMessage={emptyProvidersMessage}\n onOpenProvider={setCreateProvider}\n />\n ) : (\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\" aria-live=\"polite\">\n Loading workspace details…\n </Text>\n )}\n </section>\n <WebhookCreateModal\n workspaceId={workspaceId}\n open={createProvider === 'webhook'}\n onOpenChange={(open) => setCreateProvider(open ? 'webhook' : undefined)}\n onCreated={(connection) => {\n setCreatedUsageConnection(connection);\n setUsageConnectionId(connection.id);\n }}\n />\n <IntegrationUsageModal\n connection={usageConnection}\n events={usageConnection ? usageEventsForConnection(usageConnection) : []}\n open={usageConnection !== null}\n onOpenChange={(open) => {\n if (!open) {\n setUsageConnectionId(undefined);\n setCreatedUsageConnection(undefined);\n }\n }}\n >\n {usageConnection?.provider === 'webhook' ? (\n <WebhookUsageDetails workspaceId={workspaceId} connectionId={usageConnection.id} />\n ) : null}\n </IntegrationUsageModal>\n <IntegrationDeleteConfirmModal\n connectionName={deleteConnectionTarget?.displayName}\n open={deleteConnectionId !== undefined}\n isPending={deleteConnection.isPending || deleteWebhookConnection.isPending}\n onOpenChange={(open) => {\n if (!open) setDeleteConnectionId(undefined);\n }}\n onConfirm={() => {\n void confirmDeleteConnection();\n }}\n />\n </div>\n );\n}\n"],"names":["useAuthState","toast","Header","Text","useState","useDeleteIntegrationConnectionMutation","useIntegrationConnectionsQuery","useIntegrationProvidersQuery","useUpdateIntegrationConnectionMutation","useDeleteWebhookConnectionMutation","useUpdateWebhookConnectionMutation","InstalledIntegrationsSection","IntegrationDeleteConfirmModal","usageEventsForConnection","IntegrationUsageModal","ProviderGrid","WebhookCreateModal","WebhookUsageDetails","IntegrationGalleryForWorkspace","capability","emptyProvidersMessage","workspaceId","workspaces","workspaceSlug","find","workspace","id","slug","createProvider","setCreateProvider","usageConnectionId","setUsageConnectionId","createdUsageConnection","setCreatedUsageConnection","deleteConnectionId","setDeleteConnectionId","providersQuery","undefined","connectionsQuery","updateConnection","deleteConnection","updateWebhookConnection","deleteWebhookConnection","providers","data","providersMap","Map","map","provider","allConnections","connections","filter","connection","capabilities","includes","providerDisplayName","get","displayName","providerLabel","sortedConnections","sort","a","b","byProvider","localeCompare","createdAt","usageConnection","deleteConnectionTarget","setConnectionActive","active","body","lifecycle_status","mutateAsync","connectionId","success","error","Error","message","confirmDeleteConnection","div","className","isPending","isFetching","isError","onRetry","refetch","isMutating","onUse","onSetActive","onDelete","section","aria-label","variant","size","emptyMessage","onOpenProvider","aria-live","open","onOpenChange","onCreated","events","connectionName","onConfirm"],"mappings":"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"}
@@ -23,4 +23,5 @@ export declare const ConnectionsError: Story;
23
23
  export declare const ProvidersError: Story;
24
24
  export declare const NoProvidersAvailable: Story;
25
25
  export declare const LongNames: Story;
26
+ export declare const UsageModalCloseRestoresInteraction: Story;
26
27
  //# sourceMappingURL=integration-gallery.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration-gallery.stories.d.ts","sourceRoot":"","sources":["../../src/components/integration-gallery.stories.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAyBrD,KAAK,QAAQ,GACT,OAAO,GACP,mBAAmB,GACnB,SAAS,GACT,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,YAAY,CAAC;AAEjB,UAAU,4BAA4B;IACpC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAWD,iBAAS,uBAAuB,CAAC,EAAC,QAAQ,EAAC,EAAE,4BAA4B,+BA0DxE;AAED,QAAA,MAAM,IAAI;;;;;;;;;CAKsC,CAAC;AAEjD,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAElC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC"}
1
+ {"version":3,"file":"integration-gallery.stories.d.ts","sourceRoot":"","sources":["../../src/components/integration-gallery.stories.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AA0BrD,KAAK,QAAQ,GACT,OAAO,GACP,mBAAmB,GACnB,SAAS,GACT,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,YAAY,CAAC;AAEjB,UAAU,4BAA4B;IACpC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAWD,iBAAS,uBAAuB,CAAC,EAAC,QAAQ,EAAC,EAAE,4BAA4B,+BA0DxE;AAED,QAAA,MAAM,IAAI;;;;QAGK,MAAM;;;;;CAE2B,CAAC;eAElC,IAAI;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAElC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AAEF,eAAO,MAAM,kCAAkC,EAAE,KAiBhD,CAAC"}
@@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
6
  import { createMemoryHistory, createRootRoute, createRoute, createRouter, Outlet, RouterProvider } from '@tanstack/react-router';
7
7
  import { createStore, Provider as JotaiProvider } from 'jotai';
8
8
  import { useMemo } from 'react';
9
+ import { expect, screen, userEvent, within } from 'storybook/test';
9
10
  import { IntegrationGallery } from './integration-gallery.js';
10
11
  const WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';
11
12
  const WORKSPACE_PATH = '/w/acme/settings/integrations';
@@ -177,6 +178,33 @@ export const LongNames = {
177
178
  scenario: 'long-names'
178
179
  }
179
180
  };
181
+ export const UsageModalCloseRestoresInteraction = {
182
+ play: async ({ canvasElement })=>{
183
+ const user = userEvent.setup();
184
+ const canvas = within(canvasElement);
185
+ const actionsButton = await canvas.findByRole('button', {
186
+ name: 'Open acme-corp integration actions'
187
+ });
188
+ await user.click(actionsButton);
189
+ await user.click(await screen.findByRole('menuitem', {
190
+ name: 'Use this integration'
191
+ }));
192
+ await screen.findByRole('dialog', {
193
+ name: 'Use acme-corp'
194
+ });
195
+ await user.click(await screen.findByRole('button', {
196
+ name: 'Done'
197
+ }));
198
+ expect(screen.queryByRole('dialog', {
199
+ name: 'Use acme-corp'
200
+ })).not.toBeInTheDocument();
201
+ expect(document.body.style.pointerEvents).not.toBe('none');
202
+ await user.click(actionsButton);
203
+ await screen.findByRole('menuitem', {
204
+ name: 'Use this integration'
205
+ });
206
+ }
207
+ };
180
208
  function fetchForScenario(scenario) {
181
209
  return (input, init)=>{
182
210
  const url = requestUrl(input);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/integration-gallery.stories.tsx"],"sourcesContent":["import type {\n IntegrationConnectionDto,\n IntegrationProviderDto,\n} from '@shipfox/api-integration-core-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {authStateAtom} from '@shipfox/client-auth';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {\n createMemoryHistory,\n createRootRoute,\n createRoute,\n createRouter,\n Outlet,\n RouterProvider,\n} from '@tanstack/react-router';\nimport {createStore, Provider as JotaiProvider} from 'jotai';\nimport {useMemo} from 'react';\nimport {IntegrationGallery} from './integration-gallery.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\nconst WORKSPACE_PATH = '/w/acme/settings/integrations';\nconst SETUP_PATHS = [\n '/w/$workspaceSlug/integrations/github',\n '/w/$workspaceSlug/integrations/sentry',\n '/w/$workspaceSlug/integrations/linear',\n '/w/$workspaceSlug/integrations/slack',\n '/w/$workspaceSlug/integrations/gitea',\n '/w/$workspaceSlug/settings/events',\n] as const;\n\ntype Scenario =\n | 'mixed'\n | 'empty-connections'\n | 'loading'\n | 'connections-error'\n | 'providers-error'\n | 'no-providers'\n | 'long-names';\n\ninterface IntegrationGalleryStoryProps {\n scenario: Scenario;\n}\n\nconst PROVIDERS: IntegrationProviderDto[] = [\n {provider: 'github', display_name: 'GitHub', capabilities: ['source_control']},\n {provider: 'sentry', display_name: 'Sentry', capabilities: []},\n {provider: 'linear', display_name: 'Linear', capabilities: ['agent_tools']},\n {provider: 'slack', display_name: 'Slack', capabilities: ['agent_tools']},\n {provider: 'gitea', display_name: 'Gitea', capabilities: ['source_control']},\n {provider: 'webhook', display_name: 'Webhook', capabilities: []},\n];\n\nfunction IntegrationGalleryStory({scenario}: IntegrationGalleryStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n const store = useMemo(() => {\n const nextStore = createStore();\n nextStore.set(authStateAtom, {\n status: 'authenticated',\n workspaces: [{id: WORKSPACE_ID, name: 'Acme', slug: 'acme', membershipId: 'membership-1'}],\n });\n return nextStore;\n }, []);\n const router = useMemo(() => {\n const rootRoute = createRootRoute({component: Outlet});\n const workspaceRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/w/$workspaceSlug',\n component: Outlet,\n });\n const galleryRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/integrations',\n component: () => (\n <div className=\"mx-auto w-full max-w-[760px] bg-background-neutral-background p-24\">\n <IntegrationGallery workspaceId={WORKSPACE_ID} />\n </div>\n ),\n });\n const setupRoutes = SETUP_PATHS.map((path) =>\n createRoute({\n getParentRoute: () => workspaceRoute,\n path: path.replace('/w/$workspaceSlug/', ''),\n component: () => <div />,\n }),\n );\n\n return createRouter({\n history: createMemoryHistory({initialEntries: [WORKSPACE_PATH]}),\n routeTree: rootRoute.addChildren([\n workspaceRoute.addChildren([galleryRoute, ...setupRoutes]),\n ]),\n });\n }, []);\n\n return (\n <QueryClientProvider client={queryClient}>\n <JotaiProvider store={store}>\n <RouterProvider router={router} />\n <Toaster />\n </JotaiProvider>\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Integrations/Gallery',\n component: IntegrationGalleryStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'mixed'},\n} satisfies Meta<typeof IntegrationGalleryStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const EmptyConnections: Story = {\n args: {scenario: 'empty-connections'},\n};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const ConnectionsError: Story = {\n args: {scenario: 'connections-error'},\n};\n\nexport const ProvidersError: Story = {\n args: {scenario: 'providers-error'},\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input, init) => {\n const url = requestUrl(input);\n const method = init?.method ?? 'GET';\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname === '/integration-providers') {\n if (scenario === 'providers-error') return Promise.resolve(errorResponse());\n return Promise.resolve(\n jsonResponse({providers: scenario === 'no-providers' ? [] : PROVIDERS}),\n );\n }\n if (url.pathname.startsWith('/integration-connections/') && method === 'PATCH') {\n return Promise.resolve(\n jsonResponse({\n ...connection(),\n id: url.pathname.split('/').at(-1),\n lifecycle_status: 'disabled',\n }),\n );\n }\n if (url.pathname.startsWith('/integration-connections/') && method === 'DELETE') {\n return Promise.resolve(jsonResponse(undefined, {status: 204}));\n }\n if (url.pathname.startsWith('/integrations/webhook/connections/') && method === 'PATCH') {\n return Promise.resolve(\n jsonResponse({\n id: url.pathname.split('/').at(-1),\n workspace_id: WORKSPACE_ID,\n name: 'Stripe production',\n slug: 'stripe-prod',\n lifecycle_status: 'disabled',\n inbound_url: 'https://api.example.test/webhook/77777777-7777-4777-8777-777777777777',\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n }),\n );\n }\n if (url.pathname.startsWith('/integrations/webhook/connections/') && method === 'DELETE') {\n return Promise.resolve(jsonResponse(undefined, {status: 204}));\n }\n if (url.pathname === '/integration-connections') {\n if (scenario === 'connections-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse({connections: connectionsForScenario(scenario)}));\n }\n if (url.pathname === '/integrations/webhook/connections') {\n return Promise.resolve(\n jsonResponse({\n connections: [\n {\n id: '77777777-7777-4777-8777-777777777777',\n workspace_id: WORKSPACE_ID,\n name: 'Stripe production',\n slug: 'stripe-prod',\n lifecycle_status: 'active',\n inbound_url: 'https://api.example.test/webhook/77777777-7777-4777-8777-777777777777',\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n },\n ],\n }),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction connectionsForScenario(scenario: Scenario): IntegrationConnectionDto[] {\n if (scenario === 'empty-connections' || scenario === 'no-providers') return [];\n if (scenario === 'long-names') {\n return [\n connection({\n display_name: 'acme-production-observability-and-source-control-organization',\n lifecycle_status: 'active',\n }),\n connection({\n id: '55555555-5555-4555-8555-555555555555',\n provider: 'sentry',\n display_name: 'sentry-team-with-a-very-long-connected-account-name',\n lifecycle_status: 'error',\n }),\n ];\n }\n return [\n connection({display_name: 'acme-corp', lifecycle_status: 'active'}),\n connection({\n id: '99999999-9999-4999-8999-999999999999',\n provider: 'slack',\n display_name: 'Slack Acme',\n lifecycle_status: 'active',\n capabilities: ['agent_tools'],\n external_url: 'https://app.slack.com/client/T123',\n }),\n connection({\n id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa',\n provider: 'slack',\n display_name: 'Slack disabled',\n lifecycle_status: 'disabled',\n capabilities: ['agent_tools'],\n external_url: undefined,\n }),\n connection({\n id: '88888888-8888-4888-8888-888888888888',\n provider: 'linear',\n display_name: 'linear-acme',\n lifecycle_status: 'active',\n external_url: 'https://linear.app/acme/settings',\n }),\n connection({\n id: '55555555-5555-4555-8555-555555555555',\n provider: 'linear',\n display_name: 'linear-disabled',\n lifecycle_status: 'disabled',\n external_url: undefined,\n }),\n connection({\n id: '66666666-6666-4666-8666-666666666666',\n provider: 'linear',\n display_name: 'linear-error',\n lifecycle_status: 'error',\n external_url: undefined,\n }),\n connection({\n id: '77777777-7777-4777-8777-777777777777',\n provider: 'webhook',\n external_account_id: 'stripe-prod',\n slug: 'stripe-prod',\n display_name: 'Stripe production',\n capabilities: [],\n lifecycle_status: 'active',\n external_url: undefined,\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n }),\n ];\n}\n\nfunction connection(overrides: Partial<IntegrationConnectionDto> = {}): IntegrationConnectionDto {\n return {\n id: '44444444-4444-4444-8444-444444444444',\n workspace_id: WORKSPACE_ID,\n provider: 'github',\n external_account_id: 'installation-1',\n slug: 'github_acme_corp',\n display_name: 'acme-corp',\n lifecycle_status: 'active',\n capabilities: ['source_control'],\n external_url: 'https://github.com/organizations/acme-corp/settings/installations/1',\n created_at: '2026-03-12T00:00:00.000Z',\n updated_at: '2026-03-12T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","authStateAtom","Toaster","QueryClient","QueryClientProvider","createMemoryHistory","createRootRoute","createRoute","createRouter","Outlet","RouterProvider","createStore","Provider","JotaiProvider","useMemo","IntegrationGallery","WORKSPACE_ID","WORKSPACE_PATH","SETUP_PATHS","PROVIDERS","provider","display_name","capabilities","IntegrationGalleryStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","store","nextStore","set","status","workspaces","id","name","slug","membershipId","router","rootRoute","component","workspaceRoute","getParentRoute","path","galleryRoute","div","className","workspaceId","setupRoutes","map","replace","history","initialEntries","routeTree","addChildren","client","meta","title","parameters","layout","args","Playground","EmptyConnections","Loading","ConnectionsError","ProvidersError","NoProvidersAvailable","LongNames","input","init","url","requestUrl","method","Promise","undefined","pathname","resolve","errorResponse","jsonResponse","providers","startsWith","connection","split","at","lifecycle_status","workspace_id","inbound_url","created_at","updated_at","connections","connectionsForScenario","external_url","external_account_id","overrides","URL","body","Response","JSON","stringify","headers","code","statusText"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/integration-gallery.stories.tsx"],"sourcesContent":["import type {\n IntegrationConnectionDto,\n IntegrationProviderDto,\n} from '@shipfox/api-integration-core-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {authStateAtom} from '@shipfox/client-auth';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {\n createMemoryHistory,\n createRootRoute,\n createRoute,\n createRouter,\n Outlet,\n RouterProvider,\n} from '@tanstack/react-router';\nimport {createStore, Provider as JotaiProvider} from 'jotai';\nimport {useMemo} from 'react';\nimport {expect, screen, userEvent, within} from 'storybook/test';\nimport {IntegrationGallery} from './integration-gallery.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\nconst WORKSPACE_PATH = '/w/acme/settings/integrations';\nconst SETUP_PATHS = [\n '/w/$workspaceSlug/integrations/github',\n '/w/$workspaceSlug/integrations/sentry',\n '/w/$workspaceSlug/integrations/linear',\n '/w/$workspaceSlug/integrations/slack',\n '/w/$workspaceSlug/integrations/gitea',\n '/w/$workspaceSlug/settings/events',\n] as const;\n\ntype Scenario =\n | 'mixed'\n | 'empty-connections'\n | 'loading'\n | 'connections-error'\n | 'providers-error'\n | 'no-providers'\n | 'long-names';\n\ninterface IntegrationGalleryStoryProps {\n scenario: Scenario;\n}\n\nconst PROVIDERS: IntegrationProviderDto[] = [\n {provider: 'github', display_name: 'GitHub', capabilities: ['source_control']},\n {provider: 'sentry', display_name: 'Sentry', capabilities: []},\n {provider: 'linear', display_name: 'Linear', capabilities: ['agent_tools']},\n {provider: 'slack', display_name: 'Slack', capabilities: ['agent_tools']},\n {provider: 'gitea', display_name: 'Gitea', capabilities: ['source_control']},\n {provider: 'webhook', display_name: 'Webhook', capabilities: []},\n];\n\nfunction IntegrationGalleryStory({scenario}: IntegrationGalleryStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n const store = useMemo(() => {\n const nextStore = createStore();\n nextStore.set(authStateAtom, {\n status: 'authenticated',\n workspaces: [{id: WORKSPACE_ID, name: 'Acme', slug: 'acme', membershipId: 'membership-1'}],\n });\n return nextStore;\n }, []);\n const router = useMemo(() => {\n const rootRoute = createRootRoute({component: Outlet});\n const workspaceRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/w/$workspaceSlug',\n component: Outlet,\n });\n const galleryRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/integrations',\n component: () => (\n <div className=\"mx-auto w-full max-w-[760px] bg-background-neutral-background p-24\">\n <IntegrationGallery workspaceId={WORKSPACE_ID} />\n </div>\n ),\n });\n const setupRoutes = SETUP_PATHS.map((path) =>\n createRoute({\n getParentRoute: () => workspaceRoute,\n path: path.replace('/w/$workspaceSlug/', ''),\n component: () => <div />,\n }),\n );\n\n return createRouter({\n history: createMemoryHistory({initialEntries: [WORKSPACE_PATH]}),\n routeTree: rootRoute.addChildren([\n workspaceRoute.addChildren([galleryRoute, ...setupRoutes]),\n ]),\n });\n }, []);\n\n return (\n <QueryClientProvider client={queryClient}>\n <JotaiProvider store={store}>\n <RouterProvider router={router} />\n <Toaster />\n </JotaiProvider>\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Integrations/Gallery',\n component: IntegrationGalleryStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'mixed'},\n} satisfies Meta<typeof IntegrationGalleryStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const EmptyConnections: Story = {\n args: {scenario: 'empty-connections'},\n};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const ConnectionsError: Story = {\n args: {scenario: 'connections-error'},\n};\n\nexport const ProvidersError: Story = {\n args: {scenario: 'providers-error'},\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n};\n\nexport const UsageModalCloseRestoresInteraction: Story = {\n play: async ({canvasElement}) => {\n const user = userEvent.setup();\n const canvas = within(canvasElement);\n const actionsButton = await canvas.findByRole('button', {\n name: 'Open acme-corp integration actions',\n });\n\n await user.click(actionsButton);\n await user.click(await screen.findByRole('menuitem', {name: 'Use this integration'}));\n await screen.findByRole('dialog', {name: 'Use acme-corp'});\n await user.click(await screen.findByRole('button', {name: 'Done'}));\n expect(screen.queryByRole('dialog', {name: 'Use acme-corp'})).not.toBeInTheDocument();\n expect(document.body.style.pointerEvents).not.toBe('none');\n await user.click(actionsButton);\n await screen.findByRole('menuitem', {name: 'Use this integration'});\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input, init) => {\n const url = requestUrl(input);\n const method = init?.method ?? 'GET';\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname === '/integration-providers') {\n if (scenario === 'providers-error') return Promise.resolve(errorResponse());\n return Promise.resolve(\n jsonResponse({providers: scenario === 'no-providers' ? [] : PROVIDERS}),\n );\n }\n if (url.pathname.startsWith('/integration-connections/') && method === 'PATCH') {\n return Promise.resolve(\n jsonResponse({\n ...connection(),\n id: url.pathname.split('/').at(-1),\n lifecycle_status: 'disabled',\n }),\n );\n }\n if (url.pathname.startsWith('/integration-connections/') && method === 'DELETE') {\n return Promise.resolve(jsonResponse(undefined, {status: 204}));\n }\n if (url.pathname.startsWith('/integrations/webhook/connections/') && method === 'PATCH') {\n return Promise.resolve(\n jsonResponse({\n id: url.pathname.split('/').at(-1),\n workspace_id: WORKSPACE_ID,\n name: 'Stripe production',\n slug: 'stripe-prod',\n lifecycle_status: 'disabled',\n inbound_url: 'https://api.example.test/webhook/77777777-7777-4777-8777-777777777777',\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n }),\n );\n }\n if (url.pathname.startsWith('/integrations/webhook/connections/') && method === 'DELETE') {\n return Promise.resolve(jsonResponse(undefined, {status: 204}));\n }\n if (url.pathname === '/integration-connections') {\n if (scenario === 'connections-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse({connections: connectionsForScenario(scenario)}));\n }\n if (url.pathname === '/integrations/webhook/connections') {\n return Promise.resolve(\n jsonResponse({\n connections: [\n {\n id: '77777777-7777-4777-8777-777777777777',\n workspace_id: WORKSPACE_ID,\n name: 'Stripe production',\n slug: 'stripe-prod',\n lifecycle_status: 'active',\n inbound_url: 'https://api.example.test/webhook/77777777-7777-4777-8777-777777777777',\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n },\n ],\n }),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction connectionsForScenario(scenario: Scenario): IntegrationConnectionDto[] {\n if (scenario === 'empty-connections' || scenario === 'no-providers') return [];\n if (scenario === 'long-names') {\n return [\n connection({\n display_name: 'acme-production-observability-and-source-control-organization',\n lifecycle_status: 'active',\n }),\n connection({\n id: '55555555-5555-4555-8555-555555555555',\n provider: 'sentry',\n display_name: 'sentry-team-with-a-very-long-connected-account-name',\n lifecycle_status: 'error',\n }),\n ];\n }\n return [\n connection({display_name: 'acme-corp', lifecycle_status: 'active'}),\n connection({\n id: '99999999-9999-4999-8999-999999999999',\n provider: 'slack',\n display_name: 'Slack Acme',\n lifecycle_status: 'active',\n capabilities: ['agent_tools'],\n external_url: 'https://app.slack.com/client/T123',\n }),\n connection({\n id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa',\n provider: 'slack',\n display_name: 'Slack disabled',\n lifecycle_status: 'disabled',\n capabilities: ['agent_tools'],\n external_url: undefined,\n }),\n connection({\n id: '88888888-8888-4888-8888-888888888888',\n provider: 'linear',\n display_name: 'linear-acme',\n lifecycle_status: 'active',\n external_url: 'https://linear.app/acme/settings',\n }),\n connection({\n id: '55555555-5555-4555-8555-555555555555',\n provider: 'linear',\n display_name: 'linear-disabled',\n lifecycle_status: 'disabled',\n external_url: undefined,\n }),\n connection({\n id: '66666666-6666-4666-8666-666666666666',\n provider: 'linear',\n display_name: 'linear-error',\n lifecycle_status: 'error',\n external_url: undefined,\n }),\n connection({\n id: '77777777-7777-4777-8777-777777777777',\n provider: 'webhook',\n external_account_id: 'stripe-prod',\n slug: 'stripe-prod',\n display_name: 'Stripe production',\n capabilities: [],\n lifecycle_status: 'active',\n external_url: undefined,\n created_at: '2026-04-12T00:00:00.000Z',\n updated_at: '2026-04-12T00:00:00.000Z',\n }),\n ];\n}\n\nfunction connection(overrides: Partial<IntegrationConnectionDto> = {}): IntegrationConnectionDto {\n return {\n id: '44444444-4444-4444-8444-444444444444',\n workspace_id: WORKSPACE_ID,\n provider: 'github',\n external_account_id: 'installation-1',\n slug: 'github_acme_corp',\n display_name: 'acme-corp',\n lifecycle_status: 'active',\n capabilities: ['source_control'],\n external_url: 'https://github.com/organizations/acme-corp/settings/installations/1',\n created_at: '2026-03-12T00:00:00.000Z',\n updated_at: '2026-03-12T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","authStateAtom","Toaster","QueryClient","QueryClientProvider","createMemoryHistory","createRootRoute","createRoute","createRouter","Outlet","RouterProvider","createStore","Provider","JotaiProvider","useMemo","expect","screen","userEvent","within","IntegrationGallery","WORKSPACE_ID","WORKSPACE_PATH","SETUP_PATHS","PROVIDERS","provider","display_name","capabilities","IntegrationGalleryStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","store","nextStore","set","status","workspaces","id","name","slug","membershipId","router","rootRoute","component","workspaceRoute","getParentRoute","path","galleryRoute","div","className","workspaceId","setupRoutes","map","replace","history","initialEntries","routeTree","addChildren","client","meta","title","parameters","layout","args","Playground","EmptyConnections","Loading","ConnectionsError","ProvidersError","NoProvidersAvailable","LongNames","UsageModalCloseRestoresInteraction","play","canvasElement","user","setup","canvas","actionsButton","findByRole","click","queryByRole","not","toBeInTheDocument","document","body","style","pointerEvents","toBe","input","init","url","requestUrl","method","Promise","undefined","pathname","resolve","errorResponse","jsonResponse","providers","startsWith","connection","split","at","lifecycle_status","workspace_id","inbound_url","created_at","updated_at","connections","connectionsForScenario","external_url","external_account_id","overrides","URL","Response","JSON","stringify","headers","code","statusText"],"mappings":"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"}
@@ -11,6 +11,6 @@ interface IntegrationUsageModalProps {
11
11
  onOpenChange: (open: boolean) => void;
12
12
  children?: ReactNode;
13
13
  }
14
- export declare function IntegrationUsageModal({ connection, events, open, onOpenChange, children, }: IntegrationUsageModalProps): import("react").JSX.Element;
14
+ export declare function IntegrationUsageModal({ connection, events, open, onOpenChange, children, }: IntegrationUsageModalProps): import("react").JSX.Element | null;
15
15
  export {};
16
16
  //# sourceMappingURL=integration-usage-modal.d.ts.map