@shipfox/client-integrations 17.0.0 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +39 -0
  3. package/dist/components/callback-status-shell.d.ts.map +1 -1
  4. package/dist/components/callback-status-shell.js +4 -3
  5. package/dist/components/callback-status-shell.js.map +1 -1
  6. package/dist/components/connection-picker.js +2 -2
  7. package/dist/components/connection-picker.js.map +1 -1
  8. package/dist/components/installed-integrations-section.d.ts.map +1 -1
  9. package/dist/components/installed-integrations-section.js +155 -141
  10. package/dist/components/installed-integrations-section.js.map +1 -1
  11. package/dist/components/integration-gallery.stories.d.ts.map +1 -1
  12. package/dist/components/integration-gallery.stories.js +8 -3
  13. package/dist/components/integration-gallery.stories.js.map +1 -1
  14. package/dist/components/provider-grid.d.ts +0 -2
  15. package/dist/components/provider-grid.d.ts.map +1 -1
  16. package/dist/components/provider-grid.js +88 -104
  17. package/dist/components/provider-grid.js.map +1 -1
  18. package/dist/components/redirect-install-page.d.ts.map +1 -1
  19. package/dist/components/redirect-install-page.js +3 -2
  20. package/dist/components/redirect-install-page.js.map +1 -1
  21. package/dist/components/repository-picker.d.ts +1 -4
  22. package/dist/components/repository-picker.d.ts.map +1 -1
  23. package/dist/components/repository-picker.js +24 -37
  24. package/dist/components/repository-picker.js.map +1 -1
  25. package/dist/components/webhook/webhook-modals.stories.js +1 -1
  26. package/dist/components/webhook/webhook-modals.stories.js.map +1 -1
  27. package/dist/pages/gitea-install-page.js +1 -1
  28. package/dist/pages/gitea-install-page.js.map +1 -1
  29. package/dist/pages/jira-callback-page.js +6 -6
  30. package/dist/pages/jira-callback-page.js.map +1 -1
  31. package/dist/pages/sentry-callback-page.js +6 -6
  32. package/dist/pages/sentry-callback-page.js.map +1 -1
  33. package/dist/pages/source-control-onboarding-page.js +1 -1
  34. package/dist/pages/source-control-onboarding-page.js.map +1 -1
  35. package/dist/routes/gitea.d.ts +3 -0
  36. package/dist/routes/gitea.js +3 -0
  37. package/dist/routes/gitea.js.map +1 -1
  38. package/dist/routes/github-callback.d.ts +3 -0
  39. package/dist/routes/github-callback.d.ts.map +1 -1
  40. package/dist/routes/github-callback.js +3 -0
  41. package/dist/routes/github-callback.js.map +1 -1
  42. package/dist/routes/github.d.ts +3 -0
  43. package/dist/routes/github.js +3 -0
  44. package/dist/routes/github.js.map +1 -1
  45. package/dist/routes/integrations-settings.d.ts +3 -0
  46. package/dist/routes/integrations-settings.js +3 -0
  47. package/dist/routes/integrations-settings.js.map +1 -1
  48. package/dist/routes/integrations.d.ts +3 -0
  49. package/dist/routes/integrations.js +3 -0
  50. package/dist/routes/integrations.js.map +1 -1
  51. package/dist/routes/jira-callback.d.ts +3 -0
  52. package/dist/routes/jira-callback.js +3 -0
  53. package/dist/routes/jira-callback.js.map +1 -1
  54. package/dist/routes/jira.d.ts +3 -0
  55. package/dist/routes/jira.js +3 -0
  56. package/dist/routes/jira.js.map +1 -1
  57. package/dist/routes/linear-callback.d.ts +3 -0
  58. package/dist/routes/linear-callback.js +3 -0
  59. package/dist/routes/linear-callback.js.map +1 -1
  60. package/dist/routes/linear.d.ts +3 -0
  61. package/dist/routes/linear.js +3 -0
  62. package/dist/routes/linear.js.map +1 -1
  63. package/dist/routes/sentry-callback.d.ts +3 -0
  64. package/dist/routes/sentry-callback.js +3 -0
  65. package/dist/routes/sentry-callback.js.map +1 -1
  66. package/dist/routes/sentry.d.ts +3 -0
  67. package/dist/routes/sentry.js +3 -0
  68. package/dist/routes/sentry.js.map +1 -1
  69. package/dist/routes/slack-callback.d.ts +3 -0
  70. package/dist/routes/slack-callback.js +3 -0
  71. package/dist/routes/slack-callback.js.map +1 -1
  72. package/dist/routes/slack.d.ts +3 -0
  73. package/dist/routes/slack.js +3 -0
  74. package/dist/routes/slack.js.map +1 -1
  75. package/dist/tsconfig.test.tsbuildinfo +1 -1
  76. package/package.json +8 -8
  77. package/src/components/callback-status-shell.tsx +4 -3
  78. package/src/components/connection-picker.tsx +2 -2
  79. package/src/components/installed-integrations-section.tsx +110 -98
  80. package/src/components/integration-gallery.stories.tsx +8 -3
  81. package/src/components/integration-gallery.test.tsx +3 -1
  82. package/src/components/provider-grid.tsx +69 -79
  83. package/src/components/redirect-install-page.test.tsx +4 -0
  84. package/src/components/redirect-install-page.tsx +3 -2
  85. package/src/components/repository-picker.test.tsx +27 -13
  86. package/src/components/repository-picker.tsx +22 -47
  87. package/src/components/webhook/webhook-modals.stories.tsx +1 -1
  88. package/src/pages/gitea-install-page.tsx +1 -1
  89. package/src/pages/jira-callback-page.tsx +7 -7
  90. package/src/pages/sentry-callback-page.tsx +6 -8
  91. package/src/pages/slack-callback-page.test.tsx +7 -0
  92. package/src/pages/source-control-onboarding-page.tsx +1 -1
  93. package/src/routes/gitea.tsx +4 -1
  94. package/src/routes/github-callback.tsx +1 -0
  95. package/src/routes/github.tsx +4 -1
  96. package/src/routes/integrations-settings.tsx +4 -1
  97. package/src/routes/integrations.tsx +4 -1
  98. package/src/routes/jira-callback.tsx +1 -0
  99. package/src/routes/jira.tsx +4 -1
  100. package/src/routes/linear-callback.tsx +1 -0
  101. package/src/routes/linear.tsx +4 -1
  102. package/src/routes/sentry-callback.tsx +1 -0
  103. package/src/routes/sentry.tsx +4 -1
  104. package/src/routes/slack-callback.tsx +1 -0
  105. package/src/routes/slack.tsx +4 -1
  106. package/tsconfig.build.tsbuildinfo +1 -1
@@ -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":";AAIA,SAAQA,kBAAkB,QAAO,sBAAsB;AACvD,SAAQC,aAAa,QAAO,uBAAuB;AACnD,SAAQC,OAAO,QAAO,0BAA0B;AAEhD,SAAQC,WAAW,EAAEC,mBAAmB,QAAO,wBAAwB;AACvE,SACEC,mBAAmB,EACnBC,eAAe,EACfC,WAAW,EACXC,YAAY,EACZC,MAAM,EACNC,cAAc,QACT,yBAAyB;AAChC,SAAQC,WAAW,EAAEC,YAAYC,aAAa,QAAO,QAAQ;AAC7D,SAAQC,OAAO,QAAO,QAAQ;AAC9B,SAAQC,MAAM,EAAEC,MAAM,EAAEC,SAAS,EAAEC,MAAM,QAAO,iBAAiB;AACjE,SAAQC,kBAAkB,QAAO,2BAA2B;AAE5D,MAAMC,eAAe;AACrB,MAAMC,iBAAiB;AACvB,MAAMC,cAAc;IAClB;IACA;IACA;IACA;IACA;IACA;CACD;AAeD,MAAMC,YAAsC;IAC1C;QAACC,UAAU;QAAUC,cAAc;QAAUC,cAAc;YAAC;SAAiB;IAAA;IAC7E;QAACF,UAAU;QAAUC,cAAc;QAAUC,cAAc,EAAE;IAAA;IAC7D;QAACF,UAAU;QAAUC,cAAc;QAAUC,cAAc;YAAC;SAAc;IAAA;IAC1E;QAACF,UAAU;QAASC,cAAc;QAASC,cAAc;YAAC;SAAc;IAAA;IACxE;QAACF,UAAU;QAASC,cAAc;QAASC,cAAc;YAAC;SAAiB;IAAA;IAC3E;QAACF,UAAU;QAAWC,cAAc;QAAWC,cAAc,EAAE;IAAA;CAChE;AAED,SAASC,wBAAwB,EAACC,QAAQ,EAA+B;IACvE5B,mBAAmB;QACjB6B,SAAS;QACTC,WAAWC,iBAAiBH;IAC9B;IAEA,MAAMI,cAAclB,QAClB,IAAM,IAAIX,YAAY;YAAC8B,gBAAgB;gBAACC,SAAS;oBAACC,OAAO;gBAAK;YAAC;QAAC,IAChE,EAAE;IAEJ,MAAMC,QAAQtB,QAAQ;QACpB,MAAMuB,YAAY1B;QAClB0B,UAAUC,GAAG,CAACrC,eAAe;YAC3BsC,QAAQ;YACRC,YAAY;gBAAC;oBAACC,IAAIrB;oBAAcsB,MAAM;oBAAQC,MAAM;oBAAQC,cAAc;gBAAc;aAAE;QAC5F;QACA,OAAOP;IACT,GAAG,EAAE;IACL,MAAMQ,SAAS/B,QAAQ;QACrB,MAAMgC,YAAYxC,gBAAgB;YAACyC,WAAWtC;QAAM;QACpD,MAAMuC,iBAAiBzC,YAAY;YACjC0C,gBAAgB,IAAMH;YACtBI,MAAM;YACNH,WAAWtC;QACb;QACA,MAAM0C,eAAe5C,YAAY;YAC/B0C,gBAAgB,IAAMD;YACtBE,MAAM;YACNH,WAAW,kBACT,KAACK;oBAAIC,WAAU;8BACb,cAAA,KAAClC;wBAAmBmC,aAAalC;;;QAGvC;QACA,MAAMmC,cAAcjC,YAAYkC,GAAG,CAAC,CAACN,OACnC3C,YAAY;gBACV0C,gBAAgB,IAAMD;gBACtBE,MAAMA,KAAKO,OAAO,CAAC,sBAAsB;gBACzCV,WAAW,kBAAM,KAACK;YACpB;QAGF,OAAO5C,aAAa;YAClBkD,SAASrD,oBAAoB;gBAACsD,gBAAgB;oBAACtC;iBAAe;YAAA;YAC9DuC,WAAWd,UAAUe,WAAW,CAAC;gBAC/Bb,eAAea,WAAW,CAAC;oBAACV;uBAAiBI;iBAAY;aAC1D;QACH;IACF,GAAG,EAAE;IAEL,qBACE,KAACnD;QAAoB0D,QAAQ9B;kBAC3B,cAAA,MAACnB;YAAcuB,OAAOA;;8BACpB,KAAC1B;oBAAemC,QAAQA;;8BACxB,KAAC3C;;;;AAIT;AAEA,MAAM6D,OAAO;IACXC,OAAO;IACPjB,WAAWpB;IACXsC,YAAY;QAACC,QAAQ;IAAY;IACjCC,MAAM;QAACvC,UAAU;IAAO;AAC1B;AAEA,eAAemC,KAAK;AAGpB,OAAO,MAAMK,aAAoB,CAAC,EAAE;AAEpC,OAAO,MAAMC,mBAA0B;IACrCF,MAAM;QAACvC,UAAU;IAAmB;AACtC,EAAE;AAEF,OAAO,MAAM0C,UAAiB;IAC5BH,MAAM;QAACvC,UAAU;IAAS;AAC5B,EAAE;AAEF,OAAO,MAAM2C,mBAA0B;IACrCJ,MAAM;QAACvC,UAAU;IAAmB;AACtC,EAAE;AAEF,OAAO,MAAM4C,iBAAwB;IACnCL,MAAM;QAACvC,UAAU;IAAiB;AACpC,EAAE;AAEF,OAAO,MAAM6C,uBAA8B;IACzCN,MAAM;QAACvC,UAAU;IAAc;AACjC,EAAE;AAEF,OAAO,MAAM8C,YAAmB;IAC9BP,MAAM;QAACvC,UAAU;IAAY;AAC/B,EAAE;AAEF,OAAO,MAAM+C,qCAA4C;IACvDC,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,OAAO7D,UAAU8D,KAAK;QAC5B,MAAMC,SAAS9D,OAAO2D;QACtB,MAAMI,gBAAgB,MAAMD,OAAOE,UAAU,CAAC,UAAU;YACtDxC,MAAM;QACR;QAEA,MAAMoC,KAAKK,KAAK,CAACF;QACjB,MAAMH,KAAKK,KAAK,CAAC,MAAMnE,OAAOkE,UAAU,CAAC,YAAY;YAACxC,MAAM;QAAsB;QAClF,MAAM1B,OAAOkE,UAAU,CAAC,UAAU;YAACxC,MAAM;QAAe;QACxD,MAAMoC,KAAKK,KAAK,CAAC,MAAMnE,OAAOkE,UAAU,CAAC,UAAU;YAACxC,MAAM;QAAM;QAChE3B,OAAOC,OAAOoE,WAAW,CAAC,UAAU;YAAC1C,MAAM;QAAe,IAAI2C,GAAG,CAACC,iBAAiB;QACnFvE,OAAOwE,SAASC,IAAI,CAACC,KAAK,CAACC,aAAa,EAAEL,GAAG,CAACM,IAAI,CAAC;QACnD,MAAMb,KAAKK,KAAK,CAACF;QACjB,MAAMjE,OAAOkE,UAAU,CAAC,YAAY;YAACxC,MAAM;QAAsB;IACnE;AACF,EAAE;AAEF,SAASX,iBAAiBH,QAAkB;IAC1C,OAAO,CAACgE,OAAOC;QACb,MAAMC,MAAMC,WAAWH;QACvB,MAAMI,SAASH,MAAMG,UAAU;QAC/B,IAAIpE,aAAa,WAAW,OAAO,IAAIqE,QAAkB,IAAMC;QAC/D,IAAIJ,IAAIK,QAAQ,KAAK,0BAA0B;YAC7C,IAAIvE,aAAa,mBAAmB,OAAOqE,QAAQG,OAAO,CAACC;YAC3D,OAAOJ,QAAQG,OAAO,CACpBE,aAAa;gBAACC,WAAW3E,aAAa,iBAAiB,EAAE,GAAGL;YAAS;QAEzE;QACA,IAAIuE,IAAIK,QAAQ,CAACK,UAAU,CAAC,gCAAgCR,WAAW,SAAS;YAC9E,OAAOC,QAAQG,OAAO,CACpBE,aAAa;gBACX,GAAGG,YAAY;gBACfhE,IAAIqD,IAAIK,QAAQ,CAACO,KAAK,CAAC,KAAKC,EAAE,CAAC,CAAC;gBAChCC,kBAAkB;YACpB;QAEJ;QACA,IAAId,IAAIK,QAAQ,CAACK,UAAU,CAAC,gCAAgCR,WAAW,UAAU;YAC/E,OAAOC,QAAQG,OAAO,CAACE,aAAaJ,WAAW;gBAAC3D,QAAQ;YAAG;QAC7D;QACA,IAAIuD,IAAIK,QAAQ,CAACK,UAAU,CAAC,yCAAyCR,WAAW,SAAS;YACvF,OAAOC,QAAQG,OAAO,CACpBE,aAAa;gBACX7D,IAAIqD,IAAIK,QAAQ,CAACO,KAAK,CAAC,KAAKC,EAAE,CAAC,CAAC;gBAChCE,cAAczF;gBACdsB,MAAM;gBACNC,MAAM;gBACNiE,kBAAkB;gBAClBE,aAAa;gBACbC,YAAY;gBACZC,YAAY;YACd;QAEJ;QACA,IAAIlB,IAAIK,QAAQ,CAACK,UAAU,CAAC,yCAAyCR,WAAW,UAAU;YACxF,OAAOC,QAAQG,OAAO,CAACE,aAAaJ,WAAW;gBAAC3D,QAAQ;YAAG;QAC7D;QACA,IAAIuD,IAAIK,QAAQ,KAAK,4BAA4B;YAC/C,IAAIvE,aAAa,qBAAqB,OAAOqE,QAAQG,OAAO,CAACC;YAC7D,OAAOJ,QAAQG,OAAO,CAACE,aAAa;gBAACW,aAAaC,uBAAuBtF;YAAS;QACpF;QACA,IAAIkE,IAAIK,QAAQ,KAAK,qCAAqC;YACxD,OAAOF,QAAQG,OAAO,CACpBE,aAAa;gBACXW,aAAa;oBACX;wBACExE,IAAI;wBACJoE,cAAczF;wBACdsB,MAAM;wBACNC,MAAM;wBACNiE,kBAAkB;wBAClBE,aAAa;wBACbC,YAAY;wBACZC,YAAY;oBACd;iBACD;YACH;QAEJ;QACA,OAAOf,QAAQG,OAAO,CAACE,aAAa,CAAC,GAAG;YAAC/D,QAAQ;QAAG;IACtD;AACF;AAEA,SAAS2E,uBAAuBtF,QAAkB;IAChD,IAAIA,aAAa,uBAAuBA,aAAa,gBAAgB,OAAO,EAAE;IAC9E,IAAIA,aAAa,cAAc;QAC7B,OAAO;YACL6E,WAAW;gBACThF,cAAc;gBACdmF,kBAAkB;YACpB;YACAH,WAAW;gBACThE,IAAI;gBACJjB,UAAU;gBACVC,cAAc;gBACdmF,kBAAkB;YACpB;SACD;IACH;IACA,OAAO;QACLH,WAAW;YAAChF,cAAc;YAAamF,kBAAkB;QAAQ;QACjEH,WAAW;YACThE,IAAI;YACJjB,UAAU;YACVC,cAAc;YACdmF,kBAAkB;YAClBlF,cAAc;gBAAC;aAAc;YAC7ByF,cAAc;QAChB;QACAV,WAAW;YACThE,IAAI;YACJjB,UAAU;YACVC,cAAc;YACdmF,kBAAkB;YAClBlF,cAAc;gBAAC;aAAc;YAC7ByF,cAAcjB;QAChB;QACAO,WAAW;YACThE,IAAI;YACJjB,UAAU;YACVC,cAAc;YACdmF,kBAAkB;YAClBO,cAAc;QAChB;QACAV,WAAW;YACThE,IAAI;YACJjB,UAAU;YACVC,cAAc;YACdmF,kBAAkB;YAClBO,cAAcjB;QAChB;QACAO,WAAW;YACThE,IAAI;YACJjB,UAAU;YACVC,cAAc;YACdmF,kBAAkB;YAClBO,cAAcjB;QAChB;QACAO,WAAW;YACThE,IAAI;YACJjB,UAAU;YACV4F,qBAAqB;YACrBzE,MAAM;YACNlB,cAAc;YACdC,cAAc,EAAE;YAChBkF,kBAAkB;YAClBO,cAAcjB;YACda,YAAY;YACZC,YAAY;QACd;KACD;AACH;AAEA,SAASP,WAAWY,YAA+C,CAAC,CAAC;IACnE,OAAO;QACL5E,IAAI;QACJoE,cAAczF;QACdI,UAAU;QACV4F,qBAAqB;QACrBzE,MAAM;QACNlB,cAAc;QACdmF,kBAAkB;QAClBlF,cAAc;YAAC;SAAiB;QAChCyF,cAAc;QACdJ,YAAY;QACZC,YAAY;QACZ,GAAGK,SAAS;IACd;AACF;AAEA,SAAStB,WAAWH,KAAwB;IAC1C,IAAI,OAAOA,UAAU,UAAU,OAAO,IAAI0B,IAAI1B;IAC9C,IAAIA,iBAAiB0B,KAAK,OAAO1B;IACjC,OAAO,IAAI0B,IAAI1B,MAAME,GAAG;AAC1B;AAEA,SAASQ,aAAad,IAAa,EAAEK,OAAqB,CAAC,CAAC;IAC1D,OAAO,IAAI0B,SAASC,KAAKC,SAAS,CAACjC,OAAO;QACxCjD,QAAQ;QACRmF,SAAS;YAAC,gBAAgB;QAAkB;QAC5C,GAAG7B,IAAI;IACT;AACF;AAEA,SAASQ;IACP,OAAOC,aAAa;QAACqB,MAAM;IAAc,GAAG;QAACpF,QAAQ;QAAKqF,YAAY;IAAc;AACtF"}
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, waitFor, 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 // The dialog unmounts before its dismissable layer releases the body, so\n // wait for the release rather than asserting it on the same tick: clicking\n // while `pointer-events: none` is still set is swallowed silently.\n await waitFor(() => {\n expect(document.body.style.pointerEvents).not.toBe('none');\n });\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","waitFor","within","IntegrationGallery","WORKSPACE_ID","WORKSPACE_PATH","SETUP_PATHS","PROVIDERS","provider","display_name","capabilities","IntegrationGalleryStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","store","nextStore","set","status","workspaces","id","name","slug","membershipId","router","rootRoute","component","workspaceRoute","getParentRoute","path","galleryRoute","div","className","workspaceId","setupRoutes","map","replace","history","initialEntries","routeTree","addChildren","client","meta","title","parameters","layout","args","Playground","EmptyConnections","Loading","ConnectionsError","ProvidersError","NoProvidersAvailable","LongNames","UsageModalCloseRestoresInteraction","play","canvasElement","user","setup","canvas","actionsButton","findByRole","click","queryByRole","not","toBeInTheDocument","document","body","style","pointerEvents","toBe","input","init","url","requestUrl","method","Promise","undefined","pathname","resolve","errorResponse","jsonResponse","providers","startsWith","connection","split","at","lifecycle_status","workspace_id","inbound_url","created_at","updated_at","connections","connectionsForScenario","external_url","external_account_id","overrides","URL","Response","JSON","stringify","headers","code","statusText"],"mappings":"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"}
@@ -11,7 +11,5 @@ 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-cluster max-[760px]:grid-cols-1";
15
- export declare const PROVIDER_SURFACE_CLASS = "overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base";
16
14
  export declare function ProviderGrid({ workspaceSlug, providers, isPending, isFetching, error, onRetry, emptyMessage, loadingLabel, errorSubject, onOpenProvider, }: ProviderGridProps): import("react").JSX.Element;
17
15
  //# 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,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"}
1
+ {"version":3,"file":"provider-grid.d.ts","sourceRoot":"","sources":["../../src/components/provider-grid.tsx"],"names":[],"mappings":"AAOA,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,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,+BAoDnB"}
@@ -1,24 +1,19 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } 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
- import { Icon } from '@shipfox/react-ui/icon';
5
+ import { Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid } from '@shipfox/react-ui/panel';
7
6
  import { Skeleton } from '@shipfox/react-ui/skeleton';
8
7
  import { Text } from '@shipfox/react-ui/typography';
9
- import { cn } from '@shipfox/react-ui/utils';
10
8
  import { Link } from '@tanstack/react-router';
11
9
  import { PROVIDER_CATALOG } from '#provider-catalog.js';
12
- export const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1';
13
- export const PROVIDER_SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
14
10
  export function ProviderGrid({ workspaceSlug, providers, isPending, isFetching = false, error, onRetry, emptyMessage, loadingLabel = 'Loading providers', errorSubject = 'available integrations', onOpenProvider }) {
15
11
  const installableProviders = providers.filter((provider)=>PROVIDER_CATALOG[provider.provider]);
16
12
  if (isPending) return /*#__PURE__*/ _jsx(ProviderGridSkeleton, {
17
13
  label: loadingLabel
18
14
  });
19
15
  if (error) {
20
- return /*#__PURE__*/ _jsx("div", {
21
- className: cn(PROVIDER_SURFACE_CLASS, 'px-row'),
16
+ return /*#__PURE__*/ _jsx(Panel, {
22
17
  children: /*#__PURE__*/ _jsx(QueryLoadError, {
23
18
  query: {
24
19
  isError: true,
@@ -27,130 +22,119 @@ export function ProviderGrid({ workspaceSlug, providers, isPending, isFetching =
27
22
  error,
28
23
  refetch: onRetry ?? (()=>undefined)
29
24
  },
30
- subject: errorSubject
25
+ subject: errorSubject,
26
+ variant: "panel"
31
27
  })
32
28
  });
33
29
  }
34
30
  if (installableProviders.length === 0) {
35
- return /*#__PURE__*/ _jsx("div", {
36
- className: cn(PROVIDER_SURFACE_CLASS, 'px-row'),
31
+ return /*#__PURE__*/ _jsx(Panel, {
37
32
  children: /*#__PURE__*/ _jsx(EmptyState, {
38
33
  icon: "componentLine",
39
34
  title: "No integrations available",
40
- description: emptyMessage
35
+ description: emptyMessage,
36
+ variant: "panel"
41
37
  })
42
38
  });
43
39
  }
44
- return /*#__PURE__*/ _jsx("ul", {
45
- className: PROVIDER_GRID_CLASS,
46
- children: installableProviders.map((provider)=>/*#__PURE__*/ _jsx("li", {
47
- children: /*#__PURE__*/ _jsx(ProviderCard, {
48
- provider: provider,
49
- workspaceSlug: workspaceSlug,
50
- onOpenProvider: onOpenProvider
51
- })
52
- }, provider.provider))
40
+ return /*#__PURE__*/ _jsx(Panel, {
41
+ children: /*#__PURE__*/ _jsx(PanelBody, {
42
+ children: /*#__PURE__*/ _jsx(PanelGrid, {
43
+ "aria-label": "Available integrations",
44
+ children: installableProviders.map((provider)=>/*#__PURE__*/ _jsx(ProviderCell, {
45
+ provider: provider,
46
+ workspaceSlug: workspaceSlug,
47
+ onOpenProvider: onOpenProvider
48
+ }, provider.provider))
49
+ })
50
+ })
53
51
  });
54
52
  }
55
- function ProviderCard({ provider, workspaceSlug, onOpenProvider }) {
53
+ function ProviderCell({ provider, workspaceSlug, onOpenProvider }) {
56
54
  const catalog = PROVIDER_CATALOG[provider.provider];
57
55
  if (!catalog) return null;
58
56
  if (catalog.kind === 'modal-connect') {
59
- return /*#__PURE__*/ _jsx("button", {
60
- type: "button",
61
- "aria-label": `Add ${provider.displayName}`,
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",
64
- children: /*#__PURE__*/ _jsx(ProviderCardContent, {
65
- provider: provider,
66
- action: "Add"
57
+ return /*#__PURE__*/ _jsx(PanelCell, {
58
+ children: /*#__PURE__*/ _jsx(PanelCellAction, {
59
+ action: "Add",
60
+ "aria-label": `Add ${provider.displayName}`,
61
+ onClick: ()=>onOpenProvider?.(provider.provider),
62
+ children: /*#__PURE__*/ _jsx(ProviderCellContent, {
63
+ provider: provider
64
+ })
67
65
  })
68
66
  });
69
67
  }
70
- return /*#__PURE__*/ _jsx(Link, {
71
- to: catalog.setupPath,
72
- params: {
73
- workspaceSlug
74
- },
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",
77
- children: /*#__PURE__*/ _jsx(ProviderCardContent, {
78
- provider: provider,
79
- action: "Install"
68
+ return /*#__PURE__*/ _jsx(PanelCell, {
69
+ children: /*#__PURE__*/ _jsx(PanelCellAction, {
70
+ asChild: true,
71
+ action: "Install",
72
+ children: /*#__PURE__*/ _jsx(Link, {
73
+ to: catalog.setupPath,
74
+ params: {
75
+ workspaceSlug
76
+ },
77
+ "aria-label": `Install ${provider.displayName}`,
78
+ children: /*#__PURE__*/ _jsx(ProviderCellContent, {
79
+ provider: provider
80
+ })
81
+ })
80
82
  })
81
83
  });
82
84
  }
83
- function ProviderCardContent({ provider, action }) {
84
- return /*#__PURE__*/ _jsxs(_Fragment, {
85
+ function ProviderCellContent({ provider }) {
86
+ return /*#__PURE__*/ _jsxs("span", {
87
+ className: "flex min-w-0 items-center gap-cluster",
85
88
  children: [
86
- /*#__PURE__*/ _jsxs("span", {
87
- className: "flex min-w-0 items-center gap-cluster",
88
- children: [
89
- /*#__PURE__*/ _jsx(IntegrationIcon, {
90
- source: provider.provider,
91
- "aria-hidden": true,
92
- className: "size-24 shrink-0 text-foreground-neutral-base"
93
- }),
94
- /*#__PURE__*/ _jsx(Text, {
95
- as: "span",
96
- size: "md",
97
- bold: true,
98
- className: "truncate",
99
- children: provider.displayName
100
- })
101
- ]
89
+ /*#__PURE__*/ _jsx(IntegrationIcon, {
90
+ source: provider.provider,
91
+ "aria-hidden": true,
92
+ className: "size-24 shrink-0 text-foreground-neutral-base"
102
93
  }),
103
- /*#__PURE__*/ _jsxs("span", {
104
- className: "flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
105
- children: [
106
- /*#__PURE__*/ _jsx(Text, {
107
- as: "span",
108
- size: "sm",
109
- children: action
110
- }),
111
- /*#__PURE__*/ _jsx(Icon, {
112
- name: "chevronRight",
113
- className: "size-16"
114
- })
115
- ]
94
+ /*#__PURE__*/ _jsx(Text, {
95
+ as: "span",
96
+ size: "md",
97
+ bold: true,
98
+ className: "truncate",
99
+ children: provider.displayName
116
100
  })
117
101
  ]
118
102
  });
119
103
  }
120
104
  function ProviderGridSkeleton({ label }) {
121
- return /*#__PURE__*/ _jsx("ul", {
122
- role: "status",
123
- "aria-label": label,
124
- className: PROVIDER_GRID_CLASS,
125
- children: [
126
- 0,
127
- 1,
128
- 2,
129
- 3
130
- ].map((tile)=>/*#__PURE__*/ _jsx("li", {
131
- children: /*#__PURE__*/ _jsx(Card, {
132
- className: "h-full p-panel-compact",
133
- children: /*#__PURE__*/ _jsxs("div", {
134
- className: "flex items-center justify-between gap-cluster",
135
- children: [
136
- /*#__PURE__*/ _jsxs("div", {
137
- className: "flex min-w-0 items-center gap-cluster",
138
- children: [
139
- /*#__PURE__*/ _jsx(Skeleton, {
140
- className: "size-24 shrink-0"
141
- }),
142
- /*#__PURE__*/ _jsx(Skeleton, {
143
- className: "h-16 w-100"
144
- })
145
- ]
146
- }),
147
- /*#__PURE__*/ _jsx(Skeleton, {
148
- className: "h-16 w-64 shrink-0"
149
- })
150
- ]
151
- })
152
- })
153
- }, tile))
105
+ return /*#__PURE__*/ _jsx(Panel, {
106
+ children: /*#__PURE__*/ _jsx(PanelBody, {
107
+ children: /*#__PURE__*/ _jsx(PanelGrid, {
108
+ role: "status",
109
+ "aria-label": label,
110
+ children: [
111
+ 0,
112
+ 1,
113
+ 2,
114
+ 3
115
+ ].map((tile)=>/*#__PURE__*/ _jsx(PanelCell, {
116
+ children: /*#__PURE__*/ _jsxs("div", {
117
+ className: "flex items-center justify-between gap-cluster px-row py-row",
118
+ children: [
119
+ /*#__PURE__*/ _jsxs("div", {
120
+ className: "flex min-w-0 items-center gap-cluster",
121
+ children: [
122
+ /*#__PURE__*/ _jsx(Skeleton, {
123
+ className: "size-24 shrink-0"
124
+ }),
125
+ /*#__PURE__*/ _jsx(Skeleton, {
126
+ className: "h-16 w-100"
127
+ })
128
+ ]
129
+ }),
130
+ /*#__PURE__*/ _jsx(Skeleton, {
131
+ className: "h-16 w-64 shrink-0"
132
+ })
133
+ ]
134
+ })
135
+ }, tile))
136
+ })
137
+ })
154
138
  });
155
139
  }
156
140
 
@@ -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 {Card} from '@shipfox/react-ui/card';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\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 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 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 <Card 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 </Card>\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IntegrationIcon","Card","EmptyState","Icon","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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"}
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 {Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\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 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 <Panel>\n <QueryLoadError\n query={{\n isError: true,\n isFetching,\n data: undefined,\n error,\n refetch: onRetry ?? (() => undefined),\n }}\n subject={errorSubject}\n variant=\"panel\"\n />\n </Panel>\n );\n }\n\n if (installableProviders.length === 0) {\n return (\n <Panel>\n <EmptyState\n icon=\"componentLine\"\n title=\"No integrations available\"\n description={emptyMessage}\n variant=\"panel\"\n />\n </Panel>\n );\n }\n\n return (\n <Panel>\n <PanelBody>\n <PanelGrid aria-label=\"Available integrations\">\n {installableProviders.map((provider) => (\n <ProviderCell\n key={provider.provider}\n provider={provider}\n workspaceSlug={workspaceSlug}\n onOpenProvider={onOpenProvider}\n />\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n\nfunction ProviderCell({\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 <PanelCell>\n <PanelCellAction\n action=\"Add\"\n aria-label={`Add ${provider.displayName}`}\n onClick={() => onOpenProvider?.(provider.provider)}\n >\n <ProviderCellContent provider={provider} />\n </PanelCellAction>\n </PanelCell>\n );\n }\n\n return (\n <PanelCell>\n <PanelCellAction asChild action=\"Install\">\n <Link\n to={catalog.setupPath}\n params={{workspaceSlug}}\n aria-label={`Install ${provider.displayName}`}\n >\n <ProviderCellContent provider={provider} />\n </Link>\n </PanelCellAction>\n </PanelCell>\n );\n}\n\nfunction ProviderCellContent({provider}: {provider: IntegrationProvider}) {\n return (\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 );\n}\n\nfunction ProviderGridSkeleton({label}: {label: string}) {\n return (\n <Panel>\n <PanelBody>\n <PanelGrid role=\"status\" aria-label={label}>\n {[0, 1, 2, 3].map((tile) => (\n <PanelCell key={tile}>\n <div className=\"flex items-center justify-between gap-cluster px-row py-row\">\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 </PanelCell>\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["QueryLoadError","IntegrationIcon","EmptyState","Panel","PanelBody","PanelCell","PanelCellAction","PanelGrid","Skeleton","Text","Link","PROVIDER_CATALOG","ProviderGrid","workspaceSlug","providers","isPending","isFetching","error","onRetry","emptyMessage","loadingLabel","errorSubject","onOpenProvider","installableProviders","filter","provider","ProviderGridSkeleton","label","query","isError","data","undefined","refetch","subject","variant","length","icon","title","description","aria-label","map","ProviderCell","catalog","kind","action","displayName","onClick","ProviderCellContent","asChild","to","setupPath","params","span","className","source","aria-hidden","as","size","bold","role","tile","div"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-install-page.d.ts","sourceRoot":"","sources":["../../src/components/redirect-install-page.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iBAAiB,CAAC;AAErD,UAAU,wBAAwB;IAChC,cAAc,EAAE,CAAC,IAAI,EAAE;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,cAAc,EACd,oBAAoB,EACpB,YAAsC,EACtC,cAAc,EACd,cAAqD,GACtD,EAAE,wBAAwB,+BAwC1B"}
1
+ {"version":3,"file":"redirect-install-page.d.ts","sourceRoot":"","sources":["../../src/components/redirect-install-page.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iBAAiB,CAAC;AAErD,UAAU,wBAAwB;IAChC,cAAc,EAAE,CAAC,IAAI,EAAE;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,cAAc,EACd,oBAAoB,EACpB,YAAsC,EACtC,cAAc,EACd,cAAqD,GACtD,EAAE,wBAAwB,+BAwC1B"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ApiError } from '@shipfox/client-api';
3
3
  import { useActiveWorkspace } from '@shipfox/client-auth';
4
+ import { FocusedFrame } from '@shipfox/client-shell/runtime';
4
5
  import { ButtonLink } from '@shipfox/react-ui/button';
5
6
  import { Callout } from '@shipfox/react-ui/callout';
6
7
  import { FullPageLoader } from '@shipfox/react-ui/loader';
@@ -36,8 +37,8 @@ export function RedirectInstallPage({ installRequest, errorFallbackMessage, load
36
37
  assignLocation
37
38
  ]);
38
39
  if (errorMessage) {
39
- return /*#__PURE__*/ _jsxs("div", {
40
- className: "mx-auto flex w-full max-w-[480px] flex-col gap-group",
40
+ return /*#__PURE__*/ _jsxs(FocusedFrame, {
41
+ className: "flex flex-col gap-group",
41
42
  children: [
42
43
  /*#__PURE__*/ _jsx(Callout, {
43
44
  role: "alert",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/redirect-install-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {useActiveWorkspace} from '@shipfox/client-auth';\nimport {ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useRef, useState} from 'react';\nimport type {InstallRedirect} from '#core/models.js';\n\ninterface RedirectInstallPageProps {\n installRequest: (body: {workspace_id: string}) => Promise<InstallRedirect>;\n errorFallbackMessage: string;\n loadingLabel?: string;\n /**\n * Runs before leaving the app (e.g. to persist the workspace id for a\n * state-less provider callback. It must not throw. A failed side effect\n * should never block the redirect.\n */\n beforeRedirect?: (workspaceId: string) => void;\n /** Injectable for tests: jsdom's window.location cannot be stubbed. */\n assignLocation?: (url: string) => void;\n}\n\nexport function RedirectInstallPage({\n installRequest,\n errorFallbackMessage,\n loadingLabel = 'Starting installation',\n beforeRedirect,\n assignLocation = (url) => window.location.assign(url),\n}: RedirectInstallPageProps) {\n const workspace = useActiveWorkspace();\n const startedRef = useRef(false);\n const [errorMessage, setErrorMessage] = useState<string | undefined>();\n\n useEffect(() => {\n if (startedRef.current) return;\n startedRef.current = true;\n // The side effect is best-effort persistence; a throw here must never\n // block the install redirect, so swallow it and continue.\n try {\n beforeRedirect?.(workspace.id);\n } catch {\n // ignore\n }\n installRequest({workspace_id: workspace.id})\n .then((response) => {\n assignLocation(response.installUrl);\n })\n .catch((error: unknown) => {\n setErrorMessage(error instanceof ApiError ? error.message : errorFallbackMessage);\n });\n }, [workspace, installRequest, beforeRedirect, errorFallbackMessage, assignLocation]);\n\n if (errorMessage) {\n return (\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col gap-group\">\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{errorMessage}</Text>\n </Callout>\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/w/$workspaceSlug/integrations\" params={{workspaceSlug: workspace.slug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n </div>\n );\n }\n\n return <FullPageLoader aria-label={loadingLabel} />;\n}\n"],"names":["ApiError","useActiveWorkspace","ButtonLink","Callout","FullPageLoader","Text","Link","useEffect","useRef","useState","RedirectInstallPage","installRequest","errorFallbackMessage","loadingLabel","beforeRedirect","assignLocation","url","window","location","assign","workspace","startedRef","errorMessage","setErrorMessage","current","id","workspace_id","then","response","installUrl","catch","error","message","div","className","role","type","size","asChild","variant","to","params","workspaceSlug","slug","aria-label"],"mappings":";AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAC7C,SAAQC,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAiBlD,OAAO,SAASC,oBAAoB,EAClCC,cAAc,EACdC,oBAAoB,EACpBC,eAAe,uBAAuB,EACtCC,cAAc,EACdC,iBAAiB,CAACC,MAAQC,OAAOC,QAAQ,CAACC,MAAM,CAACH,IAAI,EAC5B;IACzB,MAAMI,YAAYnB;IAClB,MAAMoB,aAAab,OAAO;IAC1B,MAAM,CAACc,cAAcC,gBAAgB,GAAGd;IAExCF,UAAU;QACR,IAAIc,WAAWG,OAAO,EAAE;QACxBH,WAAWG,OAAO,GAAG;QACrB,sEAAsE;QACtE,0DAA0D;QAC1D,IAAI;YACFV,iBAAiBM,UAAUK,EAAE;QAC/B,EAAE,OAAM;QACN,SAAS;QACX;QACAd,eAAe;YAACe,cAAcN,UAAUK,EAAE;QAAA,GACvCE,IAAI,CAAC,CAACC;YACLb,eAAea,SAASC,UAAU;QACpC,GACCC,KAAK,CAAC,CAACC;YACNR,gBAAgBQ,iBAAiB/B,WAAW+B,MAAMC,OAAO,GAAGpB;QAC9D;IACJ,GAAG;QAACQ;QAAWT;QAAgBG;QAAgBF;QAAsBG;KAAe;IAEpF,IAAIO,cAAc;QAChB,qBACE,MAACW;YAAIC,WAAU;;8BACb,KAAC/B;oBAAQgC,MAAK;oBAAQC,MAAK;8BACzB,cAAA,KAAC/B;wBAAKgC,MAAK;kCAAMf;;;8BAEnB,KAACpB;oBAAWoC,OAAO;oBAACC,SAAQ;oBAAQL,WAAU;8BAC5C,cAAA,KAAC5B;wBAAKkC,IAAG;wBAAiCC,QAAQ;4BAACC,eAAetB,UAAUuB,IAAI;wBAAA;kCAAG;;;;;IAM3F;IAEA,qBAAO,KAACvC;QAAewC,cAAY/B;;AACrC"}
1
+ {"version":3,"sources":["../../src/components/redirect-install-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {useActiveWorkspace} from '@shipfox/client-auth';\nimport {FocusedFrame} from '@shipfox/client-shell/runtime';\nimport {ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useRef, useState} from 'react';\nimport type {InstallRedirect} from '#core/models.js';\n\ninterface RedirectInstallPageProps {\n installRequest: (body: {workspace_id: string}) => Promise<InstallRedirect>;\n errorFallbackMessage: string;\n loadingLabel?: string;\n /**\n * Runs before leaving the app (e.g. to persist the workspace id for a\n * state-less provider callback. It must not throw. A failed side effect\n * should never block the redirect.\n */\n beforeRedirect?: (workspaceId: string) => void;\n /** Injectable for tests: jsdom's window.location cannot be stubbed. */\n assignLocation?: (url: string) => void;\n}\n\nexport function RedirectInstallPage({\n installRequest,\n errorFallbackMessage,\n loadingLabel = 'Starting installation',\n beforeRedirect,\n assignLocation = (url) => window.location.assign(url),\n}: RedirectInstallPageProps) {\n const workspace = useActiveWorkspace();\n const startedRef = useRef(false);\n const [errorMessage, setErrorMessage] = useState<string | undefined>();\n\n useEffect(() => {\n if (startedRef.current) return;\n startedRef.current = true;\n // The side effect is best-effort persistence; a throw here must never\n // block the install redirect, so swallow it and continue.\n try {\n beforeRedirect?.(workspace.id);\n } catch {\n // ignore\n }\n installRequest({workspace_id: workspace.id})\n .then((response) => {\n assignLocation(response.installUrl);\n })\n .catch((error: unknown) => {\n setErrorMessage(error instanceof ApiError ? error.message : errorFallbackMessage);\n });\n }, [workspace, installRequest, beforeRedirect, errorFallbackMessage, assignLocation]);\n\n if (errorMessage) {\n return (\n <FocusedFrame className=\"flex flex-col gap-group\">\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{errorMessage}</Text>\n </Callout>\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/w/$workspaceSlug/integrations\" params={{workspaceSlug: workspace.slug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n </FocusedFrame>\n );\n }\n\n return <FullPageLoader aria-label={loadingLabel} />;\n}\n"],"names":["ApiError","useActiveWorkspace","FocusedFrame","ButtonLink","Callout","FullPageLoader","Text","Link","useEffect","useRef","useState","RedirectInstallPage","installRequest","errorFallbackMessage","loadingLabel","beforeRedirect","assignLocation","url","window","location","assign","workspace","startedRef","errorMessage","setErrorMessage","current","id","workspace_id","then","response","installUrl","catch","error","message","className","role","type","size","asChild","variant","to","params","workspaceSlug","slug","aria-label"],"mappings":";AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAC7C,SAAQC,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,YAAY,QAAO,gCAAgC;AAC3D,SAAQC,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAiBlD,OAAO,SAASC,oBAAoB,EAClCC,cAAc,EACdC,oBAAoB,EACpBC,eAAe,uBAAuB,EACtCC,cAAc,EACdC,iBAAiB,CAACC,MAAQC,OAAOC,QAAQ,CAACC,MAAM,CAACH,IAAI,EAC5B;IACzB,MAAMI,YAAYpB;IAClB,MAAMqB,aAAab,OAAO;IAC1B,MAAM,CAACc,cAAcC,gBAAgB,GAAGd;IAExCF,UAAU;QACR,IAAIc,WAAWG,OAAO,EAAE;QACxBH,WAAWG,OAAO,GAAG;QACrB,sEAAsE;QACtE,0DAA0D;QAC1D,IAAI;YACFV,iBAAiBM,UAAUK,EAAE;QAC/B,EAAE,OAAM;QACN,SAAS;QACX;QACAd,eAAe;YAACe,cAAcN,UAAUK,EAAE;QAAA,GACvCE,IAAI,CAAC,CAACC;YACLb,eAAea,SAASC,UAAU;QACpC,GACCC,KAAK,CAAC,CAACC;YACNR,gBAAgBQ,iBAAiBhC,WAAWgC,MAAMC,OAAO,GAAGpB;QAC9D;IACJ,GAAG;QAACQ;QAAWT;QAAgBG;QAAgBF;QAAsBG;KAAe;IAEpF,IAAIO,cAAc;QAChB,qBACE,MAACrB;YAAagC,WAAU;;8BACtB,KAAC9B;oBAAQ+B,MAAK;oBAAQC,MAAK;8BACzB,cAAA,KAAC9B;wBAAK+B,MAAK;kCAAMd;;;8BAEnB,KAACpB;oBAAWmC,OAAO;oBAACC,SAAQ;oBAAQL,WAAU;8BAC5C,cAAA,KAAC3B;wBAAKiC,IAAG;wBAAiCC,QAAQ;4BAACC,eAAerB,UAAUsB,IAAI;wBAAA;kCAAG;;;;;IAM3F;IAEA,qBAAO,KAACtC;QAAeuC,cAAY9B;;AACrC"}
@@ -1,5 +1,5 @@
1
1
  import type { Repository } from '#core/models.js';
2
- export declare function RepositoryPicker({ repositories, selectedRepositoryId, onSelect, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, emptyMessage, searchValue, onSearchChange, searchDisabled, }: {
2
+ export declare function RepositoryPicker({ repositories, selectedRepositoryId, onSelect, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, emptyMessage, }: {
3
3
  repositories: Repository[];
4
4
  selectedRepositoryId: string | undefined;
5
5
  onSelect: (repositoryId: string) => void;
@@ -8,8 +8,5 @@ export declare function RepositoryPicker({ repositories, selectedRepositoryId, o
8
8
  hasNextPage?: boolean;
9
9
  onLoadMore?: () => void;
10
10
  emptyMessage?: string;
11
- searchValue?: string;
12
- onSearchChange?: (value: string) => void;
13
- searchDisabled?: boolean;
14
11
  }): import("react").JSX.Element;
15
12
  //# sourceMappingURL=repository-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repository-picker.d.ts","sourceRoot":"","sources":["../../src/components/repository-picker.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAKhD,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,YAAuC,EACvC,WAAW,EACX,cAAc,EACd,cAAc,GACf,EAAE;IACD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,+BAuDA"}
1
+ {"version":3,"file":"repository-picker.d.ts","sourceRoot":"","sources":["../../src/components/repository-picker.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAIhD,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,YAAuC,GACxC,EAAE;IACD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,+BA6CA"}