@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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +35 -0
- package/dist/application/complete-integration-callback.d.ts +2 -2
- package/dist/components/callback-status-shell.js +3 -3
- package/dist/components/callback-status-shell.js.map +1 -1
- package/dist/components/connection-picker.js +3 -3
- package/dist/components/connection-picker.js.map +1 -1
- package/dist/components/installed-integrations-section.js +9 -9
- package/dist/components/installed-integrations-section.js.map +1 -1
- package/dist/components/integration-delete-confirm-modal.js +1 -1
- package/dist/components/integration-delete-confirm-modal.js.map +1 -1
- package/dist/components/integration-gallery-for-workspace.js +3 -3
- package/dist/components/integration-gallery-for-workspace.js.map +1 -1
- package/dist/components/integration-gallery.stories.d.ts +1 -0
- package/dist/components/integration-gallery.stories.d.ts.map +1 -1
- package/dist/components/integration-gallery.stories.js +28 -0
- package/dist/components/integration-gallery.stories.js.map +1 -1
- package/dist/components/integration-usage-modal.d.ts +1 -1
- package/dist/components/integration-usage-modal.d.ts.map +1 -1
- package/dist/components/integration-usage-modal.js +8 -7
- package/dist/components/integration-usage-modal.js.map +1 -1
- package/dist/components/provider-grid.d.ts +1 -1
- package/dist/components/provider-grid.d.ts.map +1 -1
- package/dist/components/provider-grid.js +10 -10
- package/dist/components/provider-grid.js.map +1 -1
- package/dist/components/redirect-install-page.js +1 -1
- package/dist/components/redirect-install-page.js.map +1 -1
- package/dist/components/repository-picker.js +4 -4
- package/dist/components/repository-picker.js.map +1 -1
- package/dist/components/webhook/copyable-value.js +3 -3
- package/dist/components/webhook/copyable-value.js.map +1 -1
- package/dist/components/webhook/webhook-create-modal.js +1 -1
- package/dist/components/webhook/webhook-create-modal.js.map +1 -1
- package/dist/components/webhook/webhook-modals.stories.d.ts.map +1 -1
- package/dist/components/webhook/webhook-usage-details.js +2 -2
- package/dist/components/webhook/webhook-usage-details.js.map +1 -1
- package/dist/feature.d.ts +8 -8
- package/dist/feature.d.ts.map +1 -1
- package/dist/hooks/api/integrations.d.ts +4 -4
- package/dist/hooks/api/integrations.d.ts.map +1 -1
- package/dist/hooks/api/webhook-connections.d.ts +1 -1
- package/dist/hooks/api/webhook-connections.d.ts.map +1 -1
- package/dist/pages/gitea-install-page.js +4 -4
- package/dist/pages/gitea-install-page.js.map +1 -1
- package/dist/pages/jira-callback-page.js +7 -7
- package/dist/pages/jira-callback-page.js.map +1 -1
- package/dist/pages/sentry-callback-page.js +7 -7
- package/dist/pages/sentry-callback-page.js.map +1 -1
- package/dist/pages/source-control-onboarding-page.js +2 -2
- package/dist/pages/source-control-onboarding-page.js.map +1 -1
- package/dist/routes/gitea.d.ts.map +1 -1
- package/dist/routes/github-callback.d.ts.map +1 -1
- package/dist/routes/github.d.ts.map +1 -1
- package/dist/routes/integrations-settings.d.ts.map +1 -1
- package/dist/routes/integrations.d.ts.map +1 -1
- package/dist/routes/jira-callback.d.ts.map +1 -1
- package/dist/routes/jira.d.ts.map +1 -1
- package/dist/routes/linear-callback.d.ts.map +1 -1
- package/dist/routes/linear.d.ts.map +1 -1
- package/dist/routes/sentry-callback.d.ts.map +1 -1
- package/dist/routes/sentry.d.ts.map +1 -1
- package/dist/routes/slack-callback.d.ts.map +1 -1
- package/dist/routes/slack.d.ts.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +14 -14
- package/src/components/callback-status-shell.tsx +3 -3
- package/src/components/connection-picker.tsx +3 -3
- package/src/components/installed-integrations-section.tsx +9 -9
- package/src/components/integration-delete-confirm-modal.tsx +1 -1
- package/src/components/integration-gallery-for-workspace.tsx +3 -3
- package/src/components/integration-gallery.stories.tsx +20 -0
- package/src/components/integration-gallery.test.tsx +21 -0
- package/src/components/integration-usage-modal.tsx +9 -7
- package/src/components/provider-grid.tsx +10 -10
- package/src/components/redirect-install-page.tsx +1 -1
- package/src/components/repository-picker.test.tsx +2 -2
- package/src/components/repository-picker.tsx +6 -4
- package/src/components/webhook/copyable-value.tsx +3 -3
- package/src/components/webhook/webhook-create-modal.tsx +1 -1
- package/src/components/webhook/webhook-usage-details.tsx +2 -2
- package/src/pages/gitea-install-page.tsx +4 -4
- package/src/pages/jira-callback-page.tsx +7 -7
- package/src/pages/sentry-callback-page.tsx +7 -7
- package/src/pages/source-control-onboarding-page.tsx +2 -2
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled: 59 files with swc (
|
|
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>,
|
|
23
|
-
export declare function useCompleteIntegrationCallbackResult(): <TInput, TResult>(options: Omit<CompleteIntegrationCallbackResultOptions<TInput, 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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;
|
|
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
|