@shipfox/client-integrations 14.0.0 → 14.0.1
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 +14 -0
- 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-usage-modal.js +6 -6
- 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-usage-details.js +2 -2
- package/dist/components/webhook/webhook-usage-details.js.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/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +6 -6
- 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-usage-modal.tsx +6 -6
- 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 (306.48ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @shipfox/client-integrations
|
|
2
2
|
|
|
3
|
+
## 14.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
- Updated dependencies [88bf8e8]
|
|
9
|
+
- Updated dependencies [6aa6c7a]
|
|
10
|
+
- Updated dependencies [5c56ba6]
|
|
11
|
+
- @shipfox/react-ui@1.0.0
|
|
12
|
+
- @shipfox/client-shell@14.0.1
|
|
13
|
+
- @shipfox/client-auth@14.0.1
|
|
14
|
+
- @shipfox/client-ui@14.0.1
|
|
15
|
+
- @shipfox/integration-icons@0.3.1
|
|
16
|
+
|
|
3
17
|
## 14.0.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
|
@@ -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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"}
|
|
@@ -43,10 +43,10 @@ export function IntegrationUsageModal({ connection, events, open, onOpenChange,
|
|
|
43
43
|
}),
|
|
44
44
|
/*#__PURE__*/ _jsx(ModalHeader, {
|
|
45
45
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
46
|
-
className: "flex min-w-0 flex-col gap-
|
|
46
|
+
className: "flex min-w-0 flex-col gap-tight",
|
|
47
47
|
children: [
|
|
48
48
|
/*#__PURE__*/ _jsxs("div", {
|
|
49
|
-
className: "flex min-w-0 items-center gap-
|
|
49
|
+
className: "flex min-w-0 items-center gap-inline",
|
|
50
50
|
children: [
|
|
51
51
|
/*#__PURE__*/ _jsx(Text, {
|
|
52
52
|
size: "lg",
|
|
@@ -71,10 +71,10 @@ export function IntegrationUsageModal({ connection, events, open, onOpenChange,
|
|
|
71
71
|
connection ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
72
72
|
children: [
|
|
73
73
|
/*#__PURE__*/ _jsxs(ModalBody, {
|
|
74
|
-
className: "min-h-0 flex-1 gap-
|
|
74
|
+
className: "min-h-0 flex-1 gap-section overflow-y-auto overflow-x-clip scrollbar",
|
|
75
75
|
children: [
|
|
76
76
|
/*#__PURE__*/ _jsxs("section", {
|
|
77
|
-
className: "flex w-full flex-col gap-
|
|
77
|
+
className: "flex w-full flex-col gap-cluster",
|
|
78
78
|
children: [
|
|
79
79
|
/*#__PURE__*/ _jsx(Text, {
|
|
80
80
|
size: "md",
|
|
@@ -82,7 +82,7 @@ export function IntegrationUsageModal({ connection, events, open, onOpenChange,
|
|
|
82
82
|
children: "Usage"
|
|
83
83
|
}),
|
|
84
84
|
events.length > 1 ? /*#__PURE__*/ _jsxs("div", {
|
|
85
|
-
className: "flex flex-col gap-
|
|
85
|
+
className: "flex flex-col gap-inline",
|
|
86
86
|
children: [
|
|
87
87
|
/*#__PURE__*/ _jsx("label", {
|
|
88
88
|
htmlFor: "integration-usage-event",
|
|
@@ -143,7 +143,7 @@ export function IntegrationUsageModal({ connection, events, open, onOpenChange,
|
|
|
143
143
|
]
|
|
144
144
|
}),
|
|
145
145
|
children ? /*#__PURE__*/ _jsxs("section", {
|
|
146
|
-
className: "flex w-full flex-col gap-
|
|
146
|
+
className: "flex w-full flex-col gap-cluster",
|
|
147
147
|
children: [
|
|
148
148
|
/*#__PURE__*/ _jsx(Text, {
|
|
149
149
|
size: "md",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/integration-usage-modal.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n CodeBlock,\n CodeBlockBody,\n CodeBlockContent,\n CodeBlockCopyButton,\n CodeBlockFilename,\n CodeBlockFiles,\n CodeBlockHeader,\n CodeBlockItem,\n} from '@shipfox/react-ui/code-block';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@shipfox/react-ui/select';\nimport {Text} from '@shipfox/react-ui/typography';\nimport type {ReactNode} from 'react';\nimport {useEffect, useMemo, useState} from 'react';\nimport {ConnectionStatusBadge} from '#connection-status-badge.js';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport interface IntegrationUsageEvent {\n value: string;\n label: string;\n}\n\ninterface IntegrationUsageModalProps {\n connection: IntegrationConnection | null;\n events: IntegrationUsageEvent[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n children?: ReactNode;\n}\n\nconst WORKFLOW_FILENAME = '.shipfox/workflows/integration.yml';\n\nexport function IntegrationUsageModal({\n connection,\n events,\n open,\n onOpenChange,\n children,\n}: IntegrationUsageModalProps) {\n const [selectedEvent, setSelectedEvent] = useState('');\n const eventValuesKey = events.map((event) => event.value).join('\\u0000');\n\n useEffect(() => {\n const eventValues = eventValuesKey ? eventValuesKey.split('\\u0000') : [];\n setSelectedEvent((current) =>\n eventValues.includes(current) ? current : (eventValues[0] ?? ''),\n );\n }, [eventValuesKey]);\n\n const workflowExample = connection\n ? buildWorkflowExample({source: connection.slug, event: selectedEvent})\n : '';\n const data = useMemo(\n () => [{language: 'yaml', filename: WORKFLOW_FILENAME, code: workflowExample}],\n [workflowExample],\n );\n const title = connection ? `Use ${connection.displayName}` : 'Use integration';\n\n return (\n <Modal open={open && connection !== null} onOpenChange={onOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-h-[calc(100vh-32px)] max-w-[640px]\">\n <ModalTitle className=\"sr-only\">{title}</ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/integration-usage-modal.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n CodeBlock,\n CodeBlockBody,\n CodeBlockContent,\n CodeBlockCopyButton,\n CodeBlockFilename,\n CodeBlockFiles,\n CodeBlockHeader,\n CodeBlockItem,\n} from '@shipfox/react-ui/code-block';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@shipfox/react-ui/select';\nimport {Text} from '@shipfox/react-ui/typography';\nimport type {ReactNode} from 'react';\nimport {useEffect, useMemo, useState} from 'react';\nimport {ConnectionStatusBadge} from '#connection-status-badge.js';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport interface IntegrationUsageEvent {\n value: string;\n label: string;\n}\n\ninterface IntegrationUsageModalProps {\n connection: IntegrationConnection | null;\n events: IntegrationUsageEvent[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n children?: ReactNode;\n}\n\nconst WORKFLOW_FILENAME = '.shipfox/workflows/integration.yml';\n\nexport function IntegrationUsageModal({\n connection,\n events,\n open,\n onOpenChange,\n children,\n}: IntegrationUsageModalProps) {\n const [selectedEvent, setSelectedEvent] = useState('');\n const eventValuesKey = events.map((event) => event.value).join('\\u0000');\n\n useEffect(() => {\n const eventValues = eventValuesKey ? eventValuesKey.split('\\u0000') : [];\n setSelectedEvent((current) =>\n eventValues.includes(current) ? current : (eventValues[0] ?? ''),\n );\n }, [eventValuesKey]);\n\n const workflowExample = connection\n ? buildWorkflowExample({source: connection.slug, event: selectedEvent})\n : '';\n const data = useMemo(\n () => [{language: 'yaml', filename: WORKFLOW_FILENAME, code: workflowExample}],\n [workflowExample],\n );\n const title = connection ? `Use ${connection.displayName}` : 'Use integration';\n\n return (\n <Modal open={open && connection !== null} onOpenChange={onOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-h-[calc(100vh-32px)] max-w-[640px]\">\n <ModalTitle className=\"sr-only\">{title}</ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Text size=\"lg\" aria-hidden=\"true\" className=\"truncate\">\n {title}\n </Text>\n {connection ? (\n <ConnectionStatusBadge status={connection.lifecycleStatus} className=\"shrink-0\" />\n ) : null}\n </div>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Reference this connection from a workflow trigger.\n </Text>\n </div>\n </ModalHeader>\n {connection ? (\n <>\n <ModalBody className=\"min-h-0 flex-1 gap-section overflow-y-auto overflow-x-clip scrollbar\">\n <section className=\"flex w-full flex-col gap-cluster\">\n <Text size=\"md\" bold>\n Usage\n </Text>\n {events.length > 1 ? (\n <div className=\"flex flex-col gap-inline\">\n <label\n htmlFor=\"integration-usage-event\"\n className=\"font-display text-sm font-medium text-foreground-neutral-base\"\n >\n Event\n </label>\n <Select value={selectedEvent} onValueChange={setSelectedEvent}>\n <SelectTrigger id=\"integration-usage-event\">\n <SelectValue placeholder=\"Select event\" />\n </SelectTrigger>\n <SelectContent>\n {events.map((event) => (\n <SelectItem key={event.value} value={event.value}>\n {event.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n <CodeBlock data={data} className=\"h-auto min-h-0 rounded-8\">\n <CodeBlockHeader>\n <CodeBlockFiles>\n {(item) => (\n <CodeBlockFilename value={item.filename}>{item.filename}</CodeBlockFilename>\n )}\n </CodeBlockFiles>\n <CodeBlockCopyButton />\n </CodeBlockHeader>\n <CodeBlockBody>\n {(item) => (\n <CodeBlockItem value={item.filename}>\n <CodeBlockContent\n language=\"yaml\"\n syntaxHighlighting\n highlightedLineRange={{startLine: 3, endLine: 4}}\n >\n {item.code}\n </CodeBlockContent>\n </CodeBlockItem>\n )}\n </CodeBlockBody>\n </CodeBlock>\n </section>\n {children ? (\n <section className=\"flex w-full flex-col gap-cluster\">\n <Text size=\"md\" bold>\n Details\n </Text>\n {children}\n </section>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button type=\"button\" onClick={() => onOpenChange(false)}>\n Done\n </Button>\n </ModalFooter>\n </>\n ) : null}\n </ModalContent>\n </Modal>\n );\n}\n\nfunction buildWorkflowExample({source, event}: {source: string; event: string}) {\n return [\n 'triggers:',\n ' integration:',\n ` source: ${source}`,\n ` event: ${event}`,\n 'jobs:',\n ' handle-event:',\n ' steps:',\n ' - run: echo \"Received event\"',\n ].join('\\n');\n}\n"],"names":["Button","CodeBlock","CodeBlockBody","CodeBlockContent","CodeBlockCopyButton","CodeBlockFilename","CodeBlockFiles","CodeBlockHeader","CodeBlockItem","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","Text","useEffect","useMemo","useState","ConnectionStatusBadge","WORKFLOW_FILENAME","IntegrationUsageModal","connection","events","open","onOpenChange","children","selectedEvent","setSelectedEvent","eventValuesKey","map","event","value","join","eventValues","split","current","includes","workflowExample","buildWorkflowExample","source","slug","data","language","filename","code","title","displayName","aria-describedby","undefined","className","div","size","aria-hidden","status","lifecycleStatus","section","bold","length","label","htmlFor","onValueChange","id","placeholder","item","syntaxHighlighting","highlightedLineRange","startLine","endLine","type","onClick"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ export interface ProviderGridProps {
|
|
|
11
11
|
errorSubject?: string;
|
|
12
12
|
onOpenProvider?: ((provider: string) => void) | undefined;
|
|
13
13
|
}
|
|
14
|
-
export declare const PROVIDER_GRID_CLASS = "grid grid-cols-2 gap-
|
|
14
|
+
export declare const PROVIDER_GRID_CLASS = "grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1";
|
|
15
15
|
export declare const PROVIDER_SURFACE_CLASS = "overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base";
|
|
16
16
|
export declare function ProviderGrid({ workspaceSlug, providers, isPending, isFetching, error, onRetry, emptyMessage, loadingLabel, errorSubject, onOpenProvider, }: ProviderGridProps): import("react").JSX.Element;
|
|
17
17
|
//# sourceMappingURL=provider-grid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-grid.d.ts","sourceRoot":"","sources":["../../src/components/provider-grid.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AAGzD,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3D;AAED,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"provider-grid.d.ts","sourceRoot":"","sources":["../../src/components/provider-grid.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AAGzD,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3D;AAED,eAAO,MAAM,mBAAmB,yDAAyD,CAAC;AAE1F,eAAO,MAAM,sBAAsB,2FACuD,CAAC;AAE3F,wBAAgB,YAAY,CAAC,EAC3B,aAAa,EACb,SAAS,EACT,SAAS,EACT,UAAkB,EAClB,KAAK,EACL,OAAO,EACP,YAAY,EACZ,YAAkC,EAClC,YAAuC,EACvC,cAAc,GACf,EAAE,iBAAiB,+BA+CnB"}
|
|
@@ -9,7 +9,7 @@ import { Text } from '@shipfox/react-ui/typography';
|
|
|
9
9
|
import { cn } from '@shipfox/react-ui/utils';
|
|
10
10
|
import { Link } from '@tanstack/react-router';
|
|
11
11
|
import { PROVIDER_CATALOG } from '#provider-catalog.js';
|
|
12
|
-
export const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-
|
|
12
|
+
export const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1';
|
|
13
13
|
export const PROVIDER_SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
|
|
14
14
|
export function ProviderGrid({ workspaceSlug, providers, isPending, isFetching = false, error, onRetry, emptyMessage, loadingLabel = 'Loading providers', errorSubject = 'available integrations', onOpenProvider }) {
|
|
15
15
|
const installableProviders = providers.filter((provider)=>PROVIDER_CATALOG[provider.provider]);
|
|
@@ -18,7 +18,7 @@ export function ProviderGrid({ workspaceSlug, providers, isPending, isFetching =
|
|
|
18
18
|
});
|
|
19
19
|
if (error) {
|
|
20
20
|
return /*#__PURE__*/ _jsx("div", {
|
|
21
|
-
className: cn(PROVIDER_SURFACE_CLASS, 'px-
|
|
21
|
+
className: cn(PROVIDER_SURFACE_CLASS, 'px-row'),
|
|
22
22
|
children: /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
23
23
|
query: {
|
|
24
24
|
isError: true,
|
|
@@ -33,7 +33,7 @@ export function ProviderGrid({ workspaceSlug, providers, isPending, isFetching =
|
|
|
33
33
|
}
|
|
34
34
|
if (installableProviders.length === 0) {
|
|
35
35
|
return /*#__PURE__*/ _jsx("div", {
|
|
36
|
-
className: cn(PROVIDER_SURFACE_CLASS, 'px-
|
|
36
|
+
className: cn(PROVIDER_SURFACE_CLASS, 'px-row'),
|
|
37
37
|
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
38
38
|
icon: "componentLine",
|
|
39
39
|
title: "No integrations available",
|
|
@@ -60,7 +60,7 @@ function ProviderCard({ provider, workspaceSlug, onOpenProvider }) {
|
|
|
60
60
|
type: "button",
|
|
61
61
|
"aria-label": `Add ${provider.displayName}`,
|
|
62
62
|
onClick: ()=>onOpenProvider?.(provider.provider),
|
|
63
|
-
className: "group flex h-full w-full min-w-0 items-center justify-between gap-
|
|
63
|
+
className: "group flex h-full w-full min-w-0 items-center justify-between gap-cluster rounded-8 border border-border-neutral-base bg-background-neutral-base p-panel-compact text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none",
|
|
64
64
|
children: /*#__PURE__*/ _jsx(ProviderCardContent, {
|
|
65
65
|
provider: provider,
|
|
66
66
|
action: "Add"
|
|
@@ -73,7 +73,7 @@ function ProviderCard({ provider, workspaceSlug, onOpenProvider }) {
|
|
|
73
73
|
workspaceSlug
|
|
74
74
|
},
|
|
75
75
|
"aria-label": `Install ${provider.displayName}`,
|
|
76
|
-
className: "group flex h-full min-w-0 items-center justify-between gap-
|
|
76
|
+
className: "group flex h-full min-w-0 items-center justify-between gap-cluster rounded-8 border border-border-neutral-base bg-background-neutral-base p-panel-compact transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none",
|
|
77
77
|
children: /*#__PURE__*/ _jsx(ProviderCardContent, {
|
|
78
78
|
provider: provider,
|
|
79
79
|
action: "Install"
|
|
@@ -84,7 +84,7 @@ function ProviderCardContent({ provider, action }) {
|
|
|
84
84
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
85
85
|
children: [
|
|
86
86
|
/*#__PURE__*/ _jsxs("span", {
|
|
87
|
-
className: "flex min-w-0 items-center gap-
|
|
87
|
+
className: "flex min-w-0 items-center gap-cluster",
|
|
88
88
|
children: [
|
|
89
89
|
/*#__PURE__*/ _jsx(IntegrationIcon, {
|
|
90
90
|
source: provider.provider,
|
|
@@ -101,7 +101,7 @@ function ProviderCardContent({ provider, action }) {
|
|
|
101
101
|
]
|
|
102
102
|
}),
|
|
103
103
|
/*#__PURE__*/ _jsxs("span", {
|
|
104
|
-
className: "flex shrink-0 items-center gap-
|
|
104
|
+
className: "flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
|
|
105
105
|
children: [
|
|
106
106
|
/*#__PURE__*/ _jsx(Text, {
|
|
107
107
|
as: "span",
|
|
@@ -129,12 +129,12 @@ function ProviderGridSkeleton({ label }) {
|
|
|
129
129
|
3
|
|
130
130
|
].map((tile)=>/*#__PURE__*/ _jsx("li", {
|
|
131
131
|
children: /*#__PURE__*/ _jsx(Card, {
|
|
132
|
-
className: "h-full p-
|
|
132
|
+
className: "h-full p-panel-compact",
|
|
133
133
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
134
|
-
className: "flex items-center justify-between gap-
|
|
134
|
+
className: "flex items-center justify-between gap-cluster",
|
|
135
135
|
children: [
|
|
136
136
|
/*#__PURE__*/ _jsxs("div", {
|
|
137
|
-
className: "flex min-w-0 items-center gap-
|
|
137
|
+
className: "flex min-w-0 items-center gap-cluster",
|
|
138
138
|
children: [
|
|
139
139
|
/*#__PURE__*/ _jsx(Skeleton, {
|
|
140
140
|
className: "size-24 shrink-0"
|