@shipfox/client-integrations 17.0.0 → 21.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 +20 -0
- package/dist/components/callback-status-shell.js +2 -2
- package/dist/components/callback-status-shell.js.map +1 -1
- package/dist/components/integration-gallery.stories.js +1 -1
- package/dist/components/integration-gallery.stories.js.map +1 -1
- package/dist/components/provider-grid.js +4 -4
- package/dist/components/provider-grid.js.map +1 -1
- package/dist/components/repository-picker.js +1 -1
- package/dist/components/repository-picker.js.map +1 -1
- package/dist/components/webhook/webhook-modals.stories.js +1 -1
- package/dist/components/webhook/webhook-modals.stories.js.map +1 -1
- package/dist/pages/gitea-install-page.js +1 -1
- package/dist/pages/gitea-install-page.js.map +1 -1
- package/dist/pages/jira-callback-page.js +4 -4
- package/dist/pages/jira-callback-page.js.map +1 -1
- package/dist/pages/sentry-callback-page.js +4 -4
- package/dist/pages/sentry-callback-page.js.map +1 -1
- package/dist/pages/source-control-onboarding-page.js +1 -1
- package/dist/pages/source-control-onboarding-page.js.map +1 -1
- package/dist/routes/gitea.d.ts +3 -0
- package/dist/routes/gitea.js +3 -0
- package/dist/routes/gitea.js.map +1 -1
- package/dist/routes/github-callback.d.ts +3 -0
- package/dist/routes/github-callback.d.ts.map +1 -1
- package/dist/routes/github-callback.js +3 -0
- package/dist/routes/github-callback.js.map +1 -1
- package/dist/routes/github.d.ts +3 -0
- package/dist/routes/github.js +3 -0
- package/dist/routes/github.js.map +1 -1
- package/dist/routes/integrations-settings.d.ts +3 -0
- package/dist/routes/integrations-settings.js +3 -0
- package/dist/routes/integrations-settings.js.map +1 -1
- package/dist/routes/integrations.d.ts +3 -0
- package/dist/routes/integrations.js +3 -0
- package/dist/routes/integrations.js.map +1 -1
- package/dist/routes/jira-callback.d.ts +3 -0
- package/dist/routes/jira-callback.js +3 -0
- package/dist/routes/jira-callback.js.map +1 -1
- package/dist/routes/jira.d.ts +3 -0
- package/dist/routes/jira.js +3 -0
- package/dist/routes/jira.js.map +1 -1
- package/dist/routes/linear-callback.d.ts +3 -0
- package/dist/routes/linear-callback.js +3 -0
- package/dist/routes/linear-callback.js.map +1 -1
- package/dist/routes/linear.d.ts +3 -0
- package/dist/routes/linear.js +3 -0
- package/dist/routes/linear.js.map +1 -1
- package/dist/routes/sentry-callback.d.ts +3 -0
- package/dist/routes/sentry-callback.js +3 -0
- package/dist/routes/sentry-callback.js.map +1 -1
- package/dist/routes/sentry.d.ts +3 -0
- package/dist/routes/sentry.js +3 -0
- package/dist/routes/sentry.js.map +1 -1
- package/dist/routes/slack-callback.d.ts +3 -0
- package/dist/routes/slack-callback.js +3 -0
- package/dist/routes/slack-callback.js.map +1 -1
- package/dist/routes/slack.d.ts +3 -0
- package/dist/routes/slack.js +3 -0
- package/dist/routes/slack.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/callback-status-shell.tsx +2 -2
- package/src/components/integration-gallery.stories.tsx +1 -1
- package/src/components/integration-gallery.test.tsx +1 -0
- package/src/components/provider-grid.tsx +5 -5
- package/src/components/repository-picker.tsx +1 -1
- package/src/components/webhook/webhook-modals.stories.tsx +1 -1
- package/src/pages/gitea-install-page.tsx +1 -1
- package/src/pages/jira-callback-page.tsx +5 -5
- package/src/pages/sentry-callback-page.tsx +5 -7
- package/src/pages/source-control-onboarding-page.tsx +1 -1
- package/src/routes/gitea.tsx +4 -1
- package/src/routes/github-callback.tsx +1 -0
- package/src/routes/github.tsx +4 -1
- package/src/routes/integrations-settings.tsx +4 -1
- package/src/routes/integrations.tsx +4 -1
- package/src/routes/jira-callback.tsx +1 -0
- package/src/routes/jira.tsx +4 -1
- package/src/routes/linear-callback.tsx +1 -0
- package/src/routes/linear.tsx +4 -1
- package/src/routes/sentry-callback.tsx +1 -0
- package/src/routes/sentry.tsx +4 -1
- package/src/routes/slack-callback.tsx +1 -0
- package/src/routes/slack.tsx +4 -1
- 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 (132.01ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @shipfox/client-integrations
|
|
2
2
|
|
|
3
|
+
## 21.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [0f4abe4]
|
|
8
|
+
- Updated dependencies [71d0c44]
|
|
9
|
+
- Updated dependencies [9c21429]
|
|
10
|
+
- Updated dependencies [30beb8f]
|
|
11
|
+
- Updated dependencies [16733a7]
|
|
12
|
+
- Updated dependencies [163c40a]
|
|
13
|
+
- Updated dependencies [c4376a1]
|
|
14
|
+
- Updated dependencies [6703982]
|
|
15
|
+
- Updated dependencies [f1d127e]
|
|
16
|
+
- Updated dependencies [0e860d7]
|
|
17
|
+
- @shipfox/react-ui@2.0.0
|
|
18
|
+
- @shipfox/client-shell@21.0.0
|
|
19
|
+
- @shipfox/client-auth@21.0.0
|
|
20
|
+
- @shipfox/client-ui@21.0.0
|
|
21
|
+
- @shipfox/integration-icons@0.3.4
|
|
22
|
+
|
|
3
23
|
## 17.0.0
|
|
4
24
|
|
|
5
25
|
### Patch 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
|
|
33
|
+
className: "flex min-h-screen px-row py-frame",
|
|
34
34
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
35
|
-
className: "mx-auto flex w-full
|
|
35
|
+
className: "mx-auto flex w-full flex-col justify-center gap-section",
|
|
36
36
|
children: [
|
|
37
37
|
/*#__PURE__*/ _jsx("h2", {
|
|
38
38
|
ref: headingRef,
|
|
@@ -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
|
|
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 px-row py-frame\">\n <div className=\"mx-auto flex w-full 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"}
|
|
@@ -98,7 +98,7 @@ function IntegrationGalleryStory({ scenario }) {
|
|
|
98
98
|
getParentRoute: ()=>workspaceRoute,
|
|
99
99
|
path: 'settings/integrations',
|
|
100
100
|
component: ()=>/*#__PURE__*/ _jsx("div", {
|
|
101
|
-
className: "mx-auto w-full max-w-[760px] bg-background-
|
|
101
|
+
className: "mx-auto w-full max-w-[760px] bg-background-subtle-base p-24",
|
|
102
102
|
children: /*#__PURE__*/ _jsx(IntegrationGallery, {
|
|
103
103
|
workspaceId: WORKSPACE_ID
|
|
104
104
|
})
|
|
@@ -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 {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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"}
|
|
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-subtle-base 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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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { QueryLoadError } from '@shipfox/client-ui';
|
|
3
3
|
import { IntegrationIcon } from '@shipfox/integration-icons';
|
|
4
|
-
import { Card } from '@shipfox/react-ui/card';
|
|
5
4
|
import { EmptyState } from '@shipfox/react-ui/empty-state';
|
|
6
5
|
import { Icon } from '@shipfox/react-ui/icon';
|
|
6
|
+
import { Panel } from '@shipfox/react-ui/panel';
|
|
7
7
|
import { Skeleton } from '@shipfox/react-ui/skeleton';
|
|
8
8
|
import { Text } from '@shipfox/react-ui/typography';
|
|
9
9
|
import { cn } from '@shipfox/react-ui/utils';
|
|
@@ -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-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",
|
|
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 shadow-button-neutral 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-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",
|
|
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 shadow-button-neutral 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"
|
|
@@ -128,7 +128,7 @@ function ProviderGridSkeleton({ label }) {
|
|
|
128
128
|
2,
|
|
129
129
|
3
|
|
130
130
|
].map((tile)=>/*#__PURE__*/ _jsx("li", {
|
|
131
|
-
children: /*#__PURE__*/ _jsx(
|
|
131
|
+
children: /*#__PURE__*/ _jsx(Panel, {
|
|
132
132
|
className: "h-full p-panel-compact",
|
|
133
133
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
134
134
|
className: "flex items-center justify-between gap-cluster",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/provider-grid.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IntegrationIcon} from '@shipfox/integration-icons';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/components/provider-grid.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IntegrationIcon} from '@shipfox/integration-icons';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport type {IntegrationProvider} from '#core/models.js';\nimport {PROVIDER_CATALOG} from '#provider-catalog.js';\n\nexport interface ProviderGridProps {\n workspaceSlug: string;\n providers: IntegrationProvider[];\n isPending: boolean;\n isFetching?: boolean;\n error?: Error | null | undefined;\n onRetry?: () => void;\n emptyMessage: string;\n loadingLabel?: string;\n errorSubject?: string;\n onOpenProvider?: ((provider: string) => void) | undefined;\n}\n\nexport const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1';\n\nexport const PROVIDER_SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function ProviderGrid({\n workspaceSlug,\n providers,\n isPending,\n isFetching = false,\n error,\n onRetry,\n emptyMessage,\n loadingLabel = 'Loading providers',\n errorSubject = 'available integrations',\n onOpenProvider,\n}: ProviderGridProps) {\n const installableProviders = providers.filter((provider) => PROVIDER_CATALOG[provider.provider]);\n\n if (isPending) return <ProviderGridSkeleton label={loadingLabel} />;\n\n if (error) {\n return (\n <div className={cn(PROVIDER_SURFACE_CLASS, 'px-row')}>\n <QueryLoadError\n query={{\n isError: true,\n isFetching,\n data: undefined,\n error,\n refetch: onRetry ?? (() => undefined),\n }}\n subject={errorSubject}\n />\n </div>\n );\n }\n\n if (installableProviders.length === 0) {\n return (\n <div className={cn(PROVIDER_SURFACE_CLASS, 'px-row')}>\n <EmptyState\n icon=\"componentLine\"\n title=\"No integrations available\"\n description={emptyMessage}\n />\n </div>\n );\n }\n\n return (\n <ul className={PROVIDER_GRID_CLASS}>\n {installableProviders.map((provider) => (\n <li key={provider.provider}>\n <ProviderCard\n provider={provider}\n workspaceSlug={workspaceSlug}\n onOpenProvider={onOpenProvider}\n />\n </li>\n ))}\n </ul>\n );\n}\n\nfunction ProviderCard({\n provider,\n workspaceSlug,\n onOpenProvider,\n}: {\n provider: IntegrationProvider;\n workspaceSlug: string;\n onOpenProvider?: ((provider: string) => void) | undefined;\n}) {\n const catalog = PROVIDER_CATALOG[provider.provider];\n if (!catalog) return null;\n\n if (catalog.kind === 'modal-connect') {\n return (\n <button\n type=\"button\"\n aria-label={`Add ${provider.displayName}`}\n onClick={() => onOpenProvider?.(provider.provider)}\n 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 shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none\"\n >\n <ProviderCardContent provider={provider} action=\"Add\" />\n </button>\n );\n }\n\n return (\n <Link\n to={catalog.setupPath}\n params={{workspaceSlug}}\n aria-label={`Install ${provider.displayName}`}\n 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 shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none\"\n >\n <ProviderCardContent provider={provider} action=\"Install\" />\n </Link>\n );\n}\n\nfunction ProviderCardContent({\n provider,\n action,\n}: {\n provider: IntegrationProvider;\n action: 'Add' | 'Install';\n}) {\n return (\n <>\n <span className=\"flex min-w-0 items-center gap-cluster\">\n <IntegrationIcon\n source={provider.provider}\n aria-hidden\n className=\"size-24 shrink-0 text-foreground-neutral-base\"\n />\n <Text as=\"span\" size=\"md\" bold className=\"truncate\">\n {provider.displayName}\n </Text>\n </span>\n <span className=\"flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text as=\"span\" size=\"sm\">\n {action}\n </Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </span>\n </>\n );\n}\n\nfunction ProviderGridSkeleton({label}: {label: string}) {\n return (\n <ul role=\"status\" aria-label={label} className={PROVIDER_GRID_CLASS}>\n {[0, 1, 2, 3].map((tile) => (\n <li key={tile}>\n <Panel className=\"h-full p-panel-compact\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-cluster\">\n <Skeleton className=\"size-24 shrink-0\" />\n <Skeleton className=\"h-16 w-100\" />\n </div>\n <Skeleton className=\"h-16 w-64 shrink-0\" />\n </div>\n </Panel>\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IntegrationIcon","EmptyState","Icon","Panel","Skeleton","Text","cn","Link","PROVIDER_CATALOG","PROVIDER_GRID_CLASS","PROVIDER_SURFACE_CLASS","ProviderGrid","workspaceSlug","providers","isPending","isFetching","error","onRetry","emptyMessage","loadingLabel","errorSubject","onOpenProvider","installableProviders","filter","provider","ProviderGridSkeleton","label","div","className","query","isError","data","undefined","refetch","subject","length","icon","title","description","ul","map","li","ProviderCard","catalog","kind","button","type","aria-label","displayName","onClick","ProviderCardContent","action","to","setupPath","params","span","source","aria-hidden","as","size","bold","name","role","tile"],"mappings":"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"}
|
|
@@ -36,7 +36,7 @@ export function RepositoryPicker({ repositories, selectedRepositoryId, onSelect,
|
|
|
36
36
|
}) : null,
|
|
37
37
|
isLoading ? /*#__PURE__*/ _jsx(RepositoryLoadingState, {}) : null,
|
|
38
38
|
!isLoading && repositories.length === 0 ? /*#__PURE__*/ _jsx("div", {
|
|
39
|
-
className: "rounded-8 border border-border-neutral-base bg-background-
|
|
39
|
+
className: "rounded-8 border border-border-neutral-base bg-background-neutral-base p-panel-compact",
|
|
40
40
|
children: /*#__PURE__*/ _jsx(Text, {
|
|
41
41
|
size: "sm",
|
|
42
42
|
children: emptyMessage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/repository-picker.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Input} from '@shipfox/react-ui/input';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {Repository} from '#core/models.js';\n\nconst REPOSITORY_GRID_CLASS_NAME = 'grid grid-cols-2 gap-inline max-[760px]:grid-cols-1';\nconst REPOSITORY_SKELETON_WIDTHS = ['w-64', 'w-96', 'w-80', 'w-112'] as const;\n\nexport function RepositoryPicker({\n repositories,\n selectedRepositoryId,\n onSelect,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n emptyMessage = 'No repositories found.',\n searchValue,\n onSearchChange,\n searchDisabled,\n}: {\n repositories: Repository[];\n selectedRepositoryId: string | undefined;\n onSelect: (repositoryId: string) => void;\n isLoading: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void;\n emptyMessage?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n searchDisabled?: boolean;\n}) {\n const labelId = useId();\n const showSearch = onSearchChange !== undefined;\n\n return (\n <div className=\"flex flex-col gap-inline\">\n <Label id={labelId} className=\"sr-only\">\n Repository\n </Label>\n\n {showSearch ? (\n <Input\n type=\"search\"\n placeholder=\"Search repositories…\"\n aria-label=\"Search repositories\"\n value={searchValue ?? ''}\n onChange={(event) => onSearchChange?.(event.target.value)}\n disabled={searchDisabled}\n />\n ) : null}\n\n {isLoading ? <RepositoryLoadingState /> : null}\n\n {!isLoading && repositories.length === 0 ? (\n <div className=\"rounded-8 border border-border-neutral-base bg-background-
|
|
1
|
+
{"version":3,"sources":["../../src/components/repository-picker.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Input} from '@shipfox/react-ui/input';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {Repository} from '#core/models.js';\n\nconst REPOSITORY_GRID_CLASS_NAME = 'grid grid-cols-2 gap-inline max-[760px]:grid-cols-1';\nconst REPOSITORY_SKELETON_WIDTHS = ['w-64', 'w-96', 'w-80', 'w-112'] as const;\n\nexport function RepositoryPicker({\n repositories,\n selectedRepositoryId,\n onSelect,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n emptyMessage = 'No repositories found.',\n searchValue,\n onSearchChange,\n searchDisabled,\n}: {\n repositories: Repository[];\n selectedRepositoryId: string | undefined;\n onSelect: (repositoryId: string) => void;\n isLoading: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void;\n emptyMessage?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n searchDisabled?: boolean;\n}) {\n const labelId = useId();\n const showSearch = onSearchChange !== undefined;\n\n return (\n <div className=\"flex flex-col gap-inline\">\n <Label id={labelId} className=\"sr-only\">\n Repository\n </Label>\n\n {showSearch ? (\n <Input\n type=\"search\"\n placeholder=\"Search repositories…\"\n aria-label=\"Search repositories\"\n value={searchValue ?? ''}\n onChange={(event) => onSearchChange?.(event.target.value)}\n disabled={searchDisabled}\n />\n ) : null}\n\n {isLoading ? <RepositoryLoadingState /> : null}\n\n {!isLoading && repositories.length === 0 ? (\n <div className=\"rounded-8 border border-border-neutral-base bg-background-neutral-base p-panel-compact\">\n <Text size=\"sm\">{emptyMessage}</Text>\n </div>\n ) : null}\n\n {repositories.length > 0 ? (\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedRepositoryId ?? ''}\n onValueChange={onSelect}\n className={REPOSITORY_GRID_CLASS_NAME}\n >\n {repositories.map((repository) => (\n <RepositoryCard key={repository.externalRepositoryId} repository={repository} />\n ))}\n </RadioGroup>\n ) : null}\n\n {hasNextPage && onLoadMore ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n isLoading={isFetchingNextPage ?? false}\n onClick={onLoadMore}\n >\n Load more\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction RepositoryCard({repository}: {repository: Repository}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(repository.name);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <RadioGroupItem value={repository.externalRepositoryId} className=\"min-w-0\">\n <span ref={nameRef} className=\"block min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {repository.name}\n </Text>\n </span>\n </RadioGroupItem>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{repository.name}</TooltipContent> : null}\n </Tooltip>\n );\n}\n\nfunction RepositoryLoadingState() {\n return (\n <>\n <div role=\"status\" className=\"sr-only\">\n Loading repositories.\n </div>\n <div aria-hidden=\"true\" className={REPOSITORY_GRID_CLASS_NAME}>\n {/* The skeleton mirrors RadioGroupItem's own 14px padding contract so the\n placeholder and the loaded card stay the same height. */}\n {REPOSITORY_SKELETON_WIDTHS.map((width) => (\n <div\n key={width}\n className=\"h-50 min-w-0 rounded-8 border border-border-neutral-base bg-background-neutral-base p-[14px]\"\n >\n <Skeleton className={`h-20 ${width}`} />\n </div>\n ))}\n </div>\n </>\n );\n}\n"],"names":["Button","useIsTextTruncated","Input","Label","RadioGroup","RadioGroupItem","Skeleton","Tooltip","TooltipContent","TooltipTrigger","Text","useId","REPOSITORY_GRID_CLASS_NAME","REPOSITORY_SKELETON_WIDTHS","RepositoryPicker","repositories","selectedRepositoryId","onSelect","isLoading","isFetchingNextPage","hasNextPage","onLoadMore","emptyMessage","searchValue","onSearchChange","searchDisabled","labelId","showSearch","undefined","div","className","id","type","placeholder","aria-label","value","onChange","event","target","disabled","RepositoryLoadingState","length","size","aria-labelledby","onValueChange","map","repository","RepositoryCard","externalRepositoryId","variant","onClick","ref","nameRef","isTruncated","name","asChild","span","as","bold","role","aria-hidden","width"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,MAAMC,6BAA6B;AACnC,MAAMC,6BAA6B;IAAC;IAAQ;IAAQ;IAAQ;CAAQ;AAEpE,OAAO,SAASC,iBAAiB,EAC/BC,YAAY,EACZC,oBAAoB,EACpBC,QAAQ,EACRC,SAAS,EACTC,kBAAkB,EAClBC,WAAW,EACXC,UAAU,EACVC,eAAe,wBAAwB,EACvCC,WAAW,EACXC,cAAc,EACdC,cAAc,EAaf;IACC,MAAMC,UAAUf;IAChB,MAAMgB,aAAaH,mBAAmBI;IAEtC,qBACE,MAACC;QAAIC,WAAU;;0BACb,KAAC3B;gBAAM4B,IAAIL;gBAASI,WAAU;0BAAU;;YAIvCH,2BACC,KAACzB;gBACC8B,MAAK;gBACLC,aAAY;gBACZC,cAAW;gBACXC,OAAOZ,eAAe;gBACtBa,UAAU,CAACC,QAAUb,iBAAiBa,MAAMC,MAAM,CAACH,KAAK;gBACxDI,UAAUd;iBAEV;YAEHP,0BAAY,KAACsB,8BAA4B;YAEzC,CAACtB,aAAaH,aAAa0B,MAAM,KAAK,kBACrC,KAACZ;gBAAIC,WAAU;0BACb,cAAA,KAACpB;oBAAKgC,MAAK;8BAAMpB;;iBAEjB;YAEHP,aAAa0B,MAAM,GAAG,kBACrB,KAACrC;gBACCuC,mBAAiBjB;gBACjBS,OAAOnB,wBAAwB;gBAC/B4B,eAAe3B;gBACfa,WAAWlB;0BAEVG,aAAa8B,GAAG,CAAC,CAACC,2BACjB,KAACC;wBAAqDD,YAAYA;uBAA7CA,WAAWE,oBAAoB;iBAGtD;YAEH5B,eAAeC,2BACd,KAACrB;gBACCgC,MAAK;gBACLiB,SAAQ;gBACRP,MAAK;gBACLxB,WAAWC,sBAAsB;gBACjC+B,SAAS7B;0BACV;iBAGC;;;AAGV;AAEA,SAAS0B,eAAe,EAACD,UAAU,EAA2B;IAC5D,MAAM,EAACK,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGpD,mBAAoC6C,WAAWQ,IAAI;IAEvF,qBACE,MAAC/C;;0BACC,KAACE;gBAAe8C,OAAO;0BACrB,cAAA,KAAClD;oBAAe8B,OAAOW,WAAWE,oBAAoB;oBAAElB,WAAU;8BAChE,cAAA,KAAC0B;wBAAKL,KAAKC;wBAAStB,WAAU;kCAC5B,cAAA,KAACpB;4BAAK+C,IAAG;4BAAOf,MAAK;4BAAKgB,IAAI;sCAC3BZ,WAAWQ,IAAI;;;;;YAKvBD,4BAAc,KAAC7C;0BAAgBsC,WAAWQ,IAAI;iBAAqB;;;AAG1E;AAEA,SAASd;IACP,qBACE;;0BACE,KAACX;gBAAI8B,MAAK;gBAAS7B,WAAU;0BAAU;;0BAGvC,KAACD;gBAAI+B,eAAY;gBAAO9B,WAAWlB;0BAGhCC,2BAA2BgC,GAAG,CAAC,CAACgB,sBAC/B,KAAChC;wBAECC,WAAU;kCAEV,cAAA,KAACxB;4BAASwB,WAAW,CAAC,KAAK,EAAE+B,OAAO;;uBAH/BA;;;;AASjB"}
|
|
@@ -108,7 +108,7 @@ export const CopyableValueState = {
|
|
|
108
108
|
};
|
|
109
109
|
function StorySurface({ scenario }) {
|
|
110
110
|
return /*#__PURE__*/ _jsxs("div", {
|
|
111
|
-
className: "min-h-screen bg-background-
|
|
111
|
+
className: "min-h-screen bg-background-subtle-base p-24",
|
|
112
112
|
children: [
|
|
113
113
|
scenario === 'create-form' ? /*#__PURE__*/ _jsx(WebhookCreateModal, {
|
|
114
114
|
workspaceId: WORKSPACE_ID,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/webhook/webhook-modals.stories.tsx"],"sourcesContent":["import type {WebhookConnectionDto} from '@shipfox/api-integration-webhook-dto';\nimport {WEBHOOK_RECEIVED_EVENT} from '@shipfox/api-integration-webhook-dto';\nimport {configureApiClient} from '@shipfox/client-api';\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 {useMemo} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\nimport {IntegrationDeleteConfirmModal} from '../integration-delete-confirm-modal.js';\nimport {IntegrationUsageModal} from '../integration-usage-modal.js';\nimport {CopyableValue} from './copyable-value.js';\nimport {WebhookCreateModal} from './webhook-create-modal.js';\nimport {WebhookPublicEndpointAlert} from './webhook-public-endpoint-alert.js';\nimport {WebhookUsageDetails} from './webhook-usage-details.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\nconst CONNECTION_ID = '77777777-7777-4777-8777-777777777777';\n\ntype Scenario =\n | 'create-form'\n | 'create-success'\n | 'usage-active'\n | 'usage-disabled'\n | 'delete-confirm'\n | 'copyable-value';\n\ninterface WebhookModalStoryProps {\n scenario: Scenario;\n}\n\nconst activeConnection: WebhookConnectionDto = {\n id: CONNECTION_ID,\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\nconst disabledConnection: WebhookConnectionDto = {\n ...activeConnection,\n lifecycle_status: 'disabled',\n};\n\nconst activeIntegrationConnection: IntegrationConnection = {\n id: CONNECTION_ID,\n workspaceId: WORKSPACE_ID,\n provider: 'webhook',\n externalAccountId: activeConnection.slug,\n slug: activeConnection.slug,\n displayName: activeConnection.name,\n lifecycleStatus: activeConnection.lifecycle_status,\n capabilities: [],\n createdAt: activeConnection.created_at,\n updatedAt: activeConnection.updated_at,\n};\n\nconst disabledIntegrationConnection: IntegrationConnection = {\n ...activeIntegrationConnection,\n lifecycleStatus: 'disabled',\n};\n\nfunction WebhookModalStory({scenario}: WebhookModalStoryProps) {\n const connection = scenario === 'usage-disabled' ? disabledConnection : activeConnection;\n\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForConnection(connection),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n const router = useMemo(() => createStoryRouter(scenario), [scenario]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={router} />\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Integrations/WebhookModals',\n component: WebhookModalStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'create-form'},\n} satisfies Meta<typeof WebhookModalStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const CreateSuccess: Story = {\n args: {scenario: 'create-success'},\n};\n\nexport const UsageActive: Story = {\n args: {scenario: 'usage-active'},\n};\n\nexport const UsageDisabled: Story = {\n args: {scenario: 'usage-disabled'},\n};\n\nexport const DeleteConfirm: Story = {\n args: {scenario: 'delete-confirm'},\n};\n\nexport const CopyableValueState: Story = {\n args: {scenario: 'copyable-value'},\n};\n\nfunction StorySurface({scenario}: {scenario: Scenario}) {\n return (\n <div className=\"min-h-screen bg-background-neutral-background p-24\">\n {scenario === 'create-form' ? (\n <WebhookCreateModal\n workspaceId={WORKSPACE_ID}\n open\n onOpenChange={() => undefined}\n onCreated={() => undefined}\n />\n ) : null}\n {scenario === 'create-success' ||\n scenario === 'usage-active' ||\n scenario === 'usage-disabled' ? (\n <IntegrationUsageModal\n connection={\n scenario === 'usage-disabled'\n ? disabledIntegrationConnection\n : activeIntegrationConnection\n }\n events={[{value: WEBHOOK_RECEIVED_EVENT, label: WEBHOOK_RECEIVED_EVENT}]}\n open\n onOpenChange={() => undefined}\n >\n <WebhookUsageDetails workspaceId={WORKSPACE_ID} connectionId={CONNECTION_ID} />\n </IntegrationUsageModal>\n ) : null}\n {scenario === 'delete-confirm' ? (\n <IntegrationDeleteConfirmModal\n connectionName={activeConnection.name}\n open\n isPending={false}\n onOpenChange={() => undefined}\n onConfirm={() => undefined}\n />\n ) : null}\n {scenario === 'copyable-value' ? (\n <div className=\"mx-auto max-w-[560px] rounded-8 border border-border-neutral-base bg-background-neutral-base p-24\">\n <div className=\"flex flex-col gap-12\">\n <CopyableValue label=\"inbound URL\" value={activeConnection.inbound_url} />\n <WebhookPublicEndpointAlert />\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction createStoryRouter(scenario: Scenario) {\n const rootRoute = createRootRoute({component: Outlet});\n const workspaceRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/w/$workspaceSlug',\n component: Outlet,\n });\n const integrationsRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/integrations',\n component: () => <StorySurface scenario={scenario} />,\n });\n const eventsRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/events',\n component: () => <div />,\n });\n\n return createRouter({\n history: createMemoryHistory({\n initialEntries: ['/w/acme/settings/integrations'],\n }),\n routeTree: rootRoute.addChildren([\n workspaceRoute.addChildren([integrationsRoute, eventsRoute]),\n ]),\n });\n}\n\nfunction fetchForConnection(connection: WebhookConnectionDto): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n if (url.pathname === '/integrations/webhook/connections') {\n return Promise.resolve(jsonResponse({connections: [connection]}));\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\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"],"names":["WEBHOOK_RECEIVED_EVENT","configureApiClient","Toaster","QueryClient","QueryClientProvider","createMemoryHistory","createRootRoute","createRoute","createRouter","Outlet","RouterProvider","useMemo","IntegrationDeleteConfirmModal","IntegrationUsageModal","CopyableValue","WebhookCreateModal","WebhookPublicEndpointAlert","WebhookUsageDetails","WORKSPACE_ID","CONNECTION_ID","activeConnection","id","workspace_id","name","slug","lifecycle_status","inbound_url","created_at","updated_at","disabledConnection","activeIntegrationConnection","workspaceId","provider","externalAccountId","displayName","lifecycleStatus","capabilities","createdAt","updatedAt","disabledIntegrationConnection","WebhookModalStory","scenario","connection","baseUrl","fetchImpl","fetchForConnection","queryClient","defaultOptions","queries","retry","router","createStoryRouter","client","meta","title","component","parameters","layout","args","Playground","CreateSuccess","UsageActive","UsageDisabled","DeleteConfirm","CopyableValueState","StorySurface","div","className","open","onOpenChange","undefined","onCreated","events","value","label","connectionId","connectionName","isPending","onConfirm","rootRoute","workspaceRoute","getParentRoute","path","integrationsRoute","eventsRoute","history","initialEntries","routeTree","addChildren","input","url","requestUrl","pathname","Promise","resolve","jsonResponse","connections","status","URL","body","init","Response","JSON","stringify","headers"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/webhook/webhook-modals.stories.tsx"],"sourcesContent":["import type {WebhookConnectionDto} from '@shipfox/api-integration-webhook-dto';\nimport {WEBHOOK_RECEIVED_EVENT} from '@shipfox/api-integration-webhook-dto';\nimport {configureApiClient} from '@shipfox/client-api';\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 {useMemo} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\nimport {IntegrationDeleteConfirmModal} from '../integration-delete-confirm-modal.js';\nimport {IntegrationUsageModal} from '../integration-usage-modal.js';\nimport {CopyableValue} from './copyable-value.js';\nimport {WebhookCreateModal} from './webhook-create-modal.js';\nimport {WebhookPublicEndpointAlert} from './webhook-public-endpoint-alert.js';\nimport {WebhookUsageDetails} from './webhook-usage-details.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\nconst CONNECTION_ID = '77777777-7777-4777-8777-777777777777';\n\ntype Scenario =\n | 'create-form'\n | 'create-success'\n | 'usage-active'\n | 'usage-disabled'\n | 'delete-confirm'\n | 'copyable-value';\n\ninterface WebhookModalStoryProps {\n scenario: Scenario;\n}\n\nconst activeConnection: WebhookConnectionDto = {\n id: CONNECTION_ID,\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\nconst disabledConnection: WebhookConnectionDto = {\n ...activeConnection,\n lifecycle_status: 'disabled',\n};\n\nconst activeIntegrationConnection: IntegrationConnection = {\n id: CONNECTION_ID,\n workspaceId: WORKSPACE_ID,\n provider: 'webhook',\n externalAccountId: activeConnection.slug,\n slug: activeConnection.slug,\n displayName: activeConnection.name,\n lifecycleStatus: activeConnection.lifecycle_status,\n capabilities: [],\n createdAt: activeConnection.created_at,\n updatedAt: activeConnection.updated_at,\n};\n\nconst disabledIntegrationConnection: IntegrationConnection = {\n ...activeIntegrationConnection,\n lifecycleStatus: 'disabled',\n};\n\nfunction WebhookModalStory({scenario}: WebhookModalStoryProps) {\n const connection = scenario === 'usage-disabled' ? disabledConnection : activeConnection;\n\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForConnection(connection),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n const router = useMemo(() => createStoryRouter(scenario), [scenario]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={router} />\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Integrations/WebhookModals',\n component: WebhookModalStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'create-form'},\n} satisfies Meta<typeof WebhookModalStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const CreateSuccess: Story = {\n args: {scenario: 'create-success'},\n};\n\nexport const UsageActive: Story = {\n args: {scenario: 'usage-active'},\n};\n\nexport const UsageDisabled: Story = {\n args: {scenario: 'usage-disabled'},\n};\n\nexport const DeleteConfirm: Story = {\n args: {scenario: 'delete-confirm'},\n};\n\nexport const CopyableValueState: Story = {\n args: {scenario: 'copyable-value'},\n};\n\nfunction StorySurface({scenario}: {scenario: Scenario}) {\n return (\n <div className=\"min-h-screen bg-background-subtle-base p-24\">\n {scenario === 'create-form' ? (\n <WebhookCreateModal\n workspaceId={WORKSPACE_ID}\n open\n onOpenChange={() => undefined}\n onCreated={() => undefined}\n />\n ) : null}\n {scenario === 'create-success' ||\n scenario === 'usage-active' ||\n scenario === 'usage-disabled' ? (\n <IntegrationUsageModal\n connection={\n scenario === 'usage-disabled'\n ? disabledIntegrationConnection\n : activeIntegrationConnection\n }\n events={[{value: WEBHOOK_RECEIVED_EVENT, label: WEBHOOK_RECEIVED_EVENT}]}\n open\n onOpenChange={() => undefined}\n >\n <WebhookUsageDetails workspaceId={WORKSPACE_ID} connectionId={CONNECTION_ID} />\n </IntegrationUsageModal>\n ) : null}\n {scenario === 'delete-confirm' ? (\n <IntegrationDeleteConfirmModal\n connectionName={activeConnection.name}\n open\n isPending={false}\n onOpenChange={() => undefined}\n onConfirm={() => undefined}\n />\n ) : null}\n {scenario === 'copyable-value' ? (\n <div className=\"mx-auto max-w-[560px] rounded-8 border border-border-neutral-base bg-background-neutral-base p-24\">\n <div className=\"flex flex-col gap-12\">\n <CopyableValue label=\"inbound URL\" value={activeConnection.inbound_url} />\n <WebhookPublicEndpointAlert />\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction createStoryRouter(scenario: Scenario) {\n const rootRoute = createRootRoute({component: Outlet});\n const workspaceRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/w/$workspaceSlug',\n component: Outlet,\n });\n const integrationsRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/integrations',\n component: () => <StorySurface scenario={scenario} />,\n });\n const eventsRoute = createRoute({\n getParentRoute: () => workspaceRoute,\n path: 'settings/events',\n component: () => <div />,\n });\n\n return createRouter({\n history: createMemoryHistory({\n initialEntries: ['/w/acme/settings/integrations'],\n }),\n routeTree: rootRoute.addChildren([\n workspaceRoute.addChildren([integrationsRoute, eventsRoute]),\n ]),\n });\n}\n\nfunction fetchForConnection(connection: WebhookConnectionDto): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n if (url.pathname === '/integrations/webhook/connections') {\n return Promise.resolve(jsonResponse({connections: [connection]}));\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\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"],"names":["WEBHOOK_RECEIVED_EVENT","configureApiClient","Toaster","QueryClient","QueryClientProvider","createMemoryHistory","createRootRoute","createRoute","createRouter","Outlet","RouterProvider","useMemo","IntegrationDeleteConfirmModal","IntegrationUsageModal","CopyableValue","WebhookCreateModal","WebhookPublicEndpointAlert","WebhookUsageDetails","WORKSPACE_ID","CONNECTION_ID","activeConnection","id","workspace_id","name","slug","lifecycle_status","inbound_url","created_at","updated_at","disabledConnection","activeIntegrationConnection","workspaceId","provider","externalAccountId","displayName","lifecycleStatus","capabilities","createdAt","updatedAt","disabledIntegrationConnection","WebhookModalStory","scenario","connection","baseUrl","fetchImpl","fetchForConnection","queryClient","defaultOptions","queries","retry","router","createStoryRouter","client","meta","title","component","parameters","layout","args","Playground","CreateSuccess","UsageActive","UsageDisabled","DeleteConfirm","CopyableValueState","StorySurface","div","className","open","onOpenChange","undefined","onCreated","events","value","label","connectionId","connectionName","isPending","onConfirm","rootRoute","workspaceRoute","getParentRoute","path","integrationsRoute","eventsRoute","history","initialEntries","routeTree","addChildren","input","url","requestUrl","pathname","Promise","resolve","jsonResponse","connections","status","URL","body","init","Response","JSON","stringify","headers"],"mappings":"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"}
|
|
@@ -51,7 +51,7 @@ export function GiteaInstallPage() {
|
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
return /*#__PURE__*/ _jsxs("div", {
|
|
54
|
-
className: "mx-auto flex w-full
|
|
54
|
+
className: "mx-auto flex w-full flex-col gap-section",
|
|
55
55
|
children: [
|
|
56
56
|
/*#__PURE__*/ _jsxs("header", {
|
|
57
57
|
className: "flex flex-col gap-inline",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/gitea-install-page.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useState} from 'react';\nimport {useCreateGiteaConnectionMutation} from '#hooks/api/integrations.js';\nimport {giteaConnectErrorToFormError} from './gitea-form-errors.js';\n\nexport function GiteaInstallPage() {\n const workspace = useActiveWorkspace();\n const connect = useCreateGiteaConnectionMutation();\n const navigate = useNavigate();\n const [formError, setFormError] = useState<string | undefined>();\n\n const form = useForm({\n defaultValues: {org: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n const workspaceId = workspace.id;\n try {\n await connect.mutateAsync({workspace_id: workspaceId, org: value.org.trim()});\n toast.success('Gitea organization installed.');\n await navigate({to: '/w/$workspaceSlug', params: {workspaceSlug: workspace.slug}});\n } catch (error) {\n const mapped = giteaConnectErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n return (\n <div className=\"mx-auto flex w-full
|
|
1
|
+
{"version":3,"sources":["../../src/pages/gitea-install-page.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useState} from 'react';\nimport {useCreateGiteaConnectionMutation} from '#hooks/api/integrations.js';\nimport {giteaConnectErrorToFormError} from './gitea-form-errors.js';\n\nexport function GiteaInstallPage() {\n const workspace = useActiveWorkspace();\n const connect = useCreateGiteaConnectionMutation();\n const navigate = useNavigate();\n const [formError, setFormError] = useState<string | undefined>();\n\n const form = useForm({\n defaultValues: {org: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n const workspaceId = workspace.id;\n try {\n await connect.mutateAsync({workspace_id: workspaceId, org: value.org.trim()});\n toast.success('Gitea organization installed.');\n await navigate({to: '/w/$workspaceSlug', params: {workspaceSlug: workspace.slug}});\n } catch (error) {\n const mapped = giteaConnectErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n return (\n <div className=\"mx-auto flex w-full flex-col gap-section\">\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h1\">Install Gitea</Header>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n Enter the Gitea organization to install in this workspace.\n </Text>\n </header>\n\n <form\n className=\"flex flex-col gap-group\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"org\"\n validators={{\n onBlur: ({value}) =>\n value.trim().length > 0 ? undefined : 'Enter your Gitea organization.',\n onSubmit: ({value}) =>\n value.trim().length > 0 ? undefined : 'Enter your Gitea organization.',\n }}\n >\n {(field) => (\n <FormField label=\"Organization\" id=\"gitea-org\" error={fieldError(field)}>\n <FormFieldInput\n placeholder=\"my-org\"\n autoComplete=\"off\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n <div className=\"flex items-center gap-cluster\">\n <Button type=\"submit\" isLoading={connect.isPending}>\n Install\n </Button>\n <ButtonLink asChild variant=\"muted\">\n <Link to=\"/w/$workspaceSlug/integrations\" params={{workspaceSlug: workspace.slug}}>\n Cancel\n </Link>\n </ButtonLink>\n </div>\n </form>\n </div>\n );\n}\n"],"names":["useActiveWorkspace","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","toast","Header","Text","useForm","Link","useNavigate","useState","useCreateGiteaConnectionMutation","giteaConnectErrorToFormError","GiteaInstallPage","workspace","connect","navigate","formError","setFormError","form","defaultValues","org","onSubmit","value","undefined","workspaceId","id","mutateAsync","workspace_id","trim","success","to","params","workspaceSlug","slug","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","div","className","header","variant","size","noValidate","event","preventDefault","stopPropagation","handleSubmit","role","type","Field","name","validators","onBlur","length","label","placeholder","autoComplete","state","onChange","handleChange","target","handleBlur","isLoading","isPending","asChild"],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ import { useRouteSearch } from '@shipfox/client-shell/runtime';
|
|
|
4
4
|
import { sessionStorageOrUndefined } from '@shipfox/client-ui';
|
|
5
5
|
import { Button, ButtonLink } from '@shipfox/react-ui/button';
|
|
6
6
|
import { Callout } from '@shipfox/react-ui/callout';
|
|
7
|
-
import { Card } from '@shipfox/react-ui/card';
|
|
8
7
|
import { FullPageLoader } from '@shipfox/react-ui/loader';
|
|
8
|
+
import { Panel } from '@shipfox/react-ui/panel';
|
|
9
9
|
import { toast } from '@shipfox/react-ui/toast';
|
|
10
10
|
import { Header, Text } from '@shipfox/react-ui/typography';
|
|
11
11
|
import { useQueryClient } from '@tanstack/react-query';
|
|
@@ -235,9 +235,9 @@ function JiraCallbackFailurePage({ failure, workspaceSlug }) {
|
|
|
235
235
|
}
|
|
236
236
|
function JiraSiteSelectionPage({ sites, selectedCloudId, failure, workspaceSlug, onSelect }) {
|
|
237
237
|
return /*#__PURE__*/ _jsx("main", {
|
|
238
|
-
className: "flex min-h-screen
|
|
238
|
+
className: "flex min-h-screen px-row py-frame",
|
|
239
239
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
240
|
-
className: "mx-auto flex w-full
|
|
240
|
+
className: "mx-auto flex w-full flex-col justify-center gap-section",
|
|
241
241
|
children: [
|
|
242
242
|
/*#__PURE__*/ _jsxs("header", {
|
|
243
243
|
className: "flex flex-col gap-inline",
|
|
@@ -264,7 +264,7 @@ function JiraSiteSelectionPage({ sites, selectedCloudId, failure, workspaceSlug,
|
|
|
264
264
|
/*#__PURE__*/ _jsx("section", {
|
|
265
265
|
className: "flex flex-col gap-inline",
|
|
266
266
|
"aria-label": "Choose a Jira site",
|
|
267
|
-
children: sites.map((site)=>/*#__PURE__*/ _jsx(
|
|
267
|
+
children: sites.map((site)=>/*#__PURE__*/ _jsx(Panel, {
|
|
268
268
|
className: "p-panel-compact",
|
|
269
269
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
270
270
|
className: "flex items-center justify-between gap-cluster",
|