@shipfox/client-integrations 0.2.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 (243) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/.storybook/preview.css +4 -0
  3. package/.storybook/preview.tsx +56 -0
  4. package/.turbo/turbo-build.log +2 -0
  5. package/.turbo/turbo-type$colon$emit.log +1 -0
  6. package/.turbo/turbo-type.log +1 -0
  7. package/CHANGELOG.md +207 -0
  8. package/LICENSE +21 -0
  9. package/dist/components/connection-picker.d.ts +7 -0
  10. package/dist/components/connection-picker.d.ts.map +1 -0
  11. package/dist/components/connection-picker.js +98 -0
  12. package/dist/components/connection-picker.js.map +1 -0
  13. package/dist/components/installed-integrations-section.d.ts +14 -0
  14. package/dist/components/installed-integrations-section.d.ts.map +1 -0
  15. package/dist/components/installed-integrations-section.js +203 -0
  16. package/dist/components/installed-integrations-section.js.map +1 -0
  17. package/dist/components/integration-delete-confirm-modal.d.ts +10 -0
  18. package/dist/components/integration-delete-confirm-modal.d.ts.map +1 -0
  19. package/dist/components/integration-delete-confirm-modal.js +61 -0
  20. package/dist/components/integration-delete-confirm-modal.js.map +1 -0
  21. package/dist/components/integration-gallery-for-workspace.d.ts +9 -0
  22. package/dist/components/integration-gallery-for-workspace.d.ts.map +1 -0
  23. package/dist/components/integration-gallery-for-workspace.js +169 -0
  24. package/dist/components/integration-gallery-for-workspace.js.map +1 -0
  25. package/dist/components/integration-gallery.d.ts +8 -0
  26. package/dist/components/integration-gallery.d.ts.map +1 -0
  27. package/dist/components/integration-gallery.js +26 -0
  28. package/dist/components/integration-gallery.js.map +1 -0
  29. package/dist/components/integration-gallery.stories.d.ts +26 -0
  30. package/dist/components/integration-gallery.stories.d.ts.map +1 -0
  31. package/dist/components/integration-gallery.stories.js +335 -0
  32. package/dist/components/integration-gallery.stories.js.map +1 -0
  33. package/dist/components/integration-usage-events.d.ts +4 -0
  34. package/dist/components/integration-usage-events.d.ts.map +1 -0
  35. package/dist/components/integration-usage-events.js +127 -0
  36. package/dist/components/integration-usage-events.js.map +1 -0
  37. package/dist/components/integration-usage-modal.d.ts +16 -0
  38. package/dist/components/integration-usage-modal.d.ts.map +1 -0
  39. package/dist/components/integration-usage-modal.js +184 -0
  40. package/dist/components/integration-usage-modal.js.map +1 -0
  41. package/dist/components/provider-grid.d.ts +14 -0
  42. package/dist/components/provider-grid.d.ts.map +1 -0
  43. package/dist/components/provider-grid.js +152 -0
  44. package/dist/components/provider-grid.js.map +1 -0
  45. package/dist/components/redirect-install-page.d.ts +19 -0
  46. package/dist/components/redirect-install-page.d.ts.map +1 -0
  47. package/dist/components/redirect-install-page.js +68 -0
  48. package/dist/components/redirect-install-page.js.map +1 -0
  49. package/dist/components/repository-picker.d.ts +15 -0
  50. package/dist/components/repository-picker.d.ts.map +1 -0
  51. package/dist/components/repository-picker.js +78 -0
  52. package/dist/components/repository-picker.js.map +1 -0
  53. package/dist/components/webhook/copyable-value.d.ts +10 -0
  54. package/dist/components/webhook/copyable-value.d.ts.map +1 -0
  55. package/dist/components/webhook/copyable-value.js +65 -0
  56. package/dist/components/webhook/copyable-value.js.map +1 -0
  57. package/dist/components/webhook/webhook-create-modal.d.ts +10 -0
  58. package/dist/components/webhook/webhook-create-modal.d.ts.map +1 -0
  59. package/dist/components/webhook/webhook-create-modal.js +233 -0
  60. package/dist/components/webhook/webhook-create-modal.js.map +1 -0
  61. package/dist/components/webhook/webhook-form-errors.d.ts +11 -0
  62. package/dist/components/webhook/webhook-form-errors.d.ts.map +1 -0
  63. package/dist/components/webhook/webhook-form-errors.js +27 -0
  64. package/dist/components/webhook/webhook-form-errors.js.map +1 -0
  65. package/dist/components/webhook/webhook-modals.stories.d.ts +25 -0
  66. package/dist/components/webhook/webhook-modals.stories.d.ts.map +1 -0
  67. package/dist/components/webhook/webhook-modals.stories.js +222 -0
  68. package/dist/components/webhook/webhook-modals.stories.js.map +1 -0
  69. package/dist/components/webhook/webhook-public-endpoint-alert.d.ts +2 -0
  70. package/dist/components/webhook/webhook-public-endpoint-alert.d.ts.map +1 -0
  71. package/dist/components/webhook/webhook-public-endpoint-alert.js +20 -0
  72. package/dist/components/webhook/webhook-public-endpoint-alert.js.map +1 -0
  73. package/dist/components/webhook/webhook-usage-details.d.ts +7 -0
  74. package/dist/components/webhook/webhook-usage-details.d.ts.map +1 -0
  75. package/dist/components/webhook/webhook-usage-details.js +49 -0
  76. package/dist/components/webhook/webhook-usage-details.js.map +1 -0
  77. package/dist/connection-status-badge.d.ts +12 -0
  78. package/dist/connection-status-badge.d.ts.map +1 -0
  79. package/dist/connection-status-badge.js +34 -0
  80. package/dist/connection-status-badge.js.map +1 -0
  81. package/dist/feature.d.ts +37 -0
  82. package/dist/feature.d.ts.map +1 -0
  83. package/dist/feature.js +48 -0
  84. package/dist/feature.js.map +1 -0
  85. package/dist/hooks/api/integrations.d.ts +265 -0
  86. package/dist/hooks/api/integrations.d.ts.map +1 -0
  87. package/dist/hooks/api/integrations.js +229 -0
  88. package/dist/hooks/api/integrations.js.map +1 -0
  89. package/dist/hooks/api/webhook-connections.d.ts +91 -0
  90. package/dist/hooks/api/webhook-connections.d.ts.map +1 -0
  91. package/dist/hooks/api/webhook-connections.js +97 -0
  92. package/dist/hooks/api/webhook-connections.js.map +1 -0
  93. package/dist/index.d.ts +17 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +18 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/integration-icon.d.ts +17 -0
  98. package/dist/integration-icon.d.ts.map +1 -0
  99. package/dist/integration-icon.js +22 -0
  100. package/dist/integration-icon.js.map +1 -0
  101. package/dist/linear-callback.d.ts +17 -0
  102. package/dist/linear-callback.d.ts.map +1 -0
  103. package/dist/linear-callback.js +113 -0
  104. package/dist/linear-callback.js.map +1 -0
  105. package/dist/pages/gitea-form-errors.d.ts +11 -0
  106. package/dist/pages/gitea-form-errors.d.ts.map +1 -0
  107. package/dist/pages/gitea-form-errors.js +35 -0
  108. package/dist/pages/gitea-form-errors.js.map +1 -0
  109. package/dist/pages/gitea-install-page.d.ts +2 -0
  110. package/dist/pages/gitea-install-page.d.ts.map +1 -0
  111. package/dist/pages/gitea-install-page.js +139 -0
  112. package/dist/pages/gitea-install-page.js.map +1 -0
  113. package/dist/pages/github-install-page.d.ts +2 -0
  114. package/dist/pages/github-install-page.d.ts.map +1 -0
  115. package/dist/pages/github-install-page.js +11 -0
  116. package/dist/pages/github-install-page.js.map +1 -0
  117. package/dist/pages/linear-callback-page.d.ts +2 -0
  118. package/dist/pages/linear-callback-page.d.ts.map +1 -0
  119. package/dist/pages/linear-callback-page.js +192 -0
  120. package/dist/pages/linear-callback-page.js.map +1 -0
  121. package/dist/pages/linear-install-page.d.ts +2 -0
  122. package/dist/pages/linear-install-page.d.ts.map +1 -0
  123. package/dist/pages/linear-install-page.js +24 -0
  124. package/dist/pages/linear-install-page.js.map +1 -0
  125. package/dist/pages/sentry-callback-page.d.ts +2 -0
  126. package/dist/pages/sentry-callback-page.d.ts.map +1 -0
  127. package/dist/pages/sentry-callback-page.js +256 -0
  128. package/dist/pages/sentry-callback-page.js.map +1 -0
  129. package/dist/pages/sentry-install-page.d.ts +2 -0
  130. package/dist/pages/sentry-install-page.d.ts.map +1 -0
  131. package/dist/pages/sentry-install-page.js +17 -0
  132. package/dist/pages/sentry-install-page.js.map +1 -0
  133. package/dist/pages/source-control-onboarding-page.d.ts +2 -0
  134. package/dist/pages/source-control-onboarding-page.d.ts.map +1 -0
  135. package/dist/pages/source-control-onboarding-page.js +37 -0
  136. package/dist/pages/source-control-onboarding-page.js.map +1 -0
  137. package/dist/provider-catalog.d.ts +15 -0
  138. package/dist/provider-catalog.d.ts.map +1 -0
  139. package/dist/provider-catalog.js +28 -0
  140. package/dist/provider-catalog.js.map +1 -0
  141. package/dist/routes/gitea.d.ts +6 -0
  142. package/dist/routes/gitea.d.ts.map +1 -0
  143. package/dist/routes/gitea.js +7 -0
  144. package/dist/routes/gitea.js.map +1 -0
  145. package/dist/routes/github-callback.d.ts +6 -0
  146. package/dist/routes/github-callback.d.ts.map +1 -0
  147. package/dist/routes/github-callback.js +129 -0
  148. package/dist/routes/github-callback.js.map +1 -0
  149. package/dist/routes/github.d.ts +6 -0
  150. package/dist/routes/github.d.ts.map +1 -0
  151. package/dist/routes/github.js +7 -0
  152. package/dist/routes/github.js.map +1 -0
  153. package/dist/routes/integrations.d.ts +6 -0
  154. package/dist/routes/integrations.d.ts.map +1 -0
  155. package/dist/routes/integrations.js +7 -0
  156. package/dist/routes/integrations.js.map +1 -0
  157. package/dist/routes/linear-callback.d.ts +6 -0
  158. package/dist/routes/linear-callback.d.ts.map +1 -0
  159. package/dist/routes/linear-callback.js +7 -0
  160. package/dist/routes/linear-callback.js.map +1 -0
  161. package/dist/routes/linear.d.ts +6 -0
  162. package/dist/routes/linear.d.ts.map +1 -0
  163. package/dist/routes/linear.js +7 -0
  164. package/dist/routes/linear.js.map +1 -0
  165. package/dist/routes/sentry-callback.d.ts +6 -0
  166. package/dist/routes/sentry-callback.d.ts.map +1 -0
  167. package/dist/routes/sentry-callback.js +7 -0
  168. package/dist/routes/sentry-callback.js.map +1 -0
  169. package/dist/routes/sentry.d.ts +6 -0
  170. package/dist/routes/sentry.d.ts.map +1 -0
  171. package/dist/routes/sentry.js +7 -0
  172. package/dist/routes/sentry.js.map +1 -0
  173. package/dist/sentry-callback.d.ts +35 -0
  174. package/dist/sentry-callback.d.ts.map +1 -0
  175. package/dist/sentry-callback.js +132 -0
  176. package/dist/sentry-callback.js.map +1 -0
  177. package/dist/tsconfig.test.tsbuildinfo +1 -0
  178. package/package.json +120 -0
  179. package/src/components/connection-picker.tsx +89 -0
  180. package/src/components/installed-integrations-section.tsx +198 -0
  181. package/src/components/integration-delete-confirm-modal.tsx +62 -0
  182. package/src/components/integration-gallery-for-workspace.tsx +193 -0
  183. package/src/components/integration-gallery.stories.tsx +302 -0
  184. package/src/components/integration-gallery.test.tsx +692 -0
  185. package/src/components/integration-gallery.tsx +49 -0
  186. package/src/components/integration-usage-events.test.ts +80 -0
  187. package/src/components/integration-usage-events.ts +116 -0
  188. package/src/components/integration-usage-modal.tsx +178 -0
  189. package/src/components/provider-grid.tsx +163 -0
  190. package/src/components/redirect-install-page.test.tsx +98 -0
  191. package/src/components/redirect-install-page.tsx +68 -0
  192. package/src/components/repository-picker.tsx +102 -0
  193. package/src/components/webhook/copyable-value.test.tsx +41 -0
  194. package/src/components/webhook/copyable-value.tsx +72 -0
  195. package/src/components/webhook/webhook-create-modal.tsx +247 -0
  196. package/src/components/webhook/webhook-form-errors.test.ts +45 -0
  197. package/src/components/webhook/webhook-form-errors.ts +32 -0
  198. package/src/components/webhook/webhook-modals.stories.tsx +225 -0
  199. package/src/components/webhook/webhook-public-endpoint-alert.tsx +15 -0
  200. package/src/components/webhook/webhook-usage-details.tsx +44 -0
  201. package/src/connection-status-badge.tsx +38 -0
  202. package/src/feature.ts +47 -0
  203. package/src/hooks/api/integrations.test.ts +105 -0
  204. package/src/hooks/api/integrations.ts +287 -0
  205. package/src/hooks/api/webhook-connections.ts +115 -0
  206. package/src/index.ts +16 -0
  207. package/src/integration-icon.react.test.tsx +40 -0
  208. package/src/integration-icon.test.ts +19 -0
  209. package/src/integration-icon.tsx +26 -0
  210. package/src/linear-callback.test.ts +227 -0
  211. package/src/linear-callback.ts +136 -0
  212. package/src/pages/gitea-form-errors.test.ts +55 -0
  213. package/src/pages/gitea-form-errors.ts +36 -0
  214. package/src/pages/gitea-install-page.tsx +108 -0
  215. package/src/pages/github-install-page.tsx +11 -0
  216. package/src/pages/linear-callback-page.test.tsx +157 -0
  217. package/src/pages/linear-callback-page.tsx +175 -0
  218. package/src/pages/linear-install-page.tsx +26 -0
  219. package/src/pages/sentry-callback-page.test.tsx +205 -0
  220. package/src/pages/sentry-callback-page.tsx +238 -0
  221. package/src/pages/sentry-install-page.tsx +17 -0
  222. package/src/pages/source-control-onboarding-page.test.tsx +46 -0
  223. package/src/pages/source-control-onboarding-page.tsx +26 -0
  224. package/src/provider-catalog.test.ts +42 -0
  225. package/src/provider-catalog.ts +49 -0
  226. package/src/routes/gitea.tsx +4 -0
  227. package/src/routes/github-callback.tsx +114 -0
  228. package/src/routes/github.tsx +4 -0
  229. package/src/routes/integrations.tsx +4 -0
  230. package/src/routes/linear-callback.tsx +4 -0
  231. package/src/routes/linear.tsx +4 -0
  232. package/src/routes/sentry-callback.tsx +4 -0
  233. package/src/routes/sentry.tsx +4 -0
  234. package/src/sentry-callback.test.ts +239 -0
  235. package/src/sentry-callback.ts +142 -0
  236. package/test/render.tsx +111 -0
  237. package/test/setup.ts +3 -0
  238. package/tsconfig.build.json +9 -0
  239. package/tsconfig.build.tsbuildinfo +1 -0
  240. package/tsconfig.json +3 -0
  241. package/tsconfig.test.json +8 -0
  242. package/vercel.json +8 -0
  243. package/vitest.config.ts +75 -0
@@ -0,0 +1 @@
1
+ export {default} from '../../.storybook/main.ts';
@@ -0,0 +1,4 @@
1
+ @import "@shipfox/react-ui/index.css";
2
+
3
+ @source "../src";
4
+ @source "../../../shared/react/ui/src";
@@ -0,0 +1,56 @@
1
+ import './preview.css';
2
+ import {ThemeProvider} from '@shipfox/react-ui/theme';
3
+ import type {Decorator, Preview} from '@storybook/react';
4
+
5
+ if (typeof document !== 'undefined' && document.fonts) {
6
+ void Promise.all([
7
+ document.fonts.load("16px 'Inter'"),
8
+ document.fonts.load("italic 16px 'Inter'"),
9
+ document.fonts.load("16px 'Commit Mono'"),
10
+ document.fonts.load("bold 16px 'Commit Mono'"),
11
+ ]);
12
+ }
13
+
14
+ const withTheme: Decorator = (Story, context) => {
15
+ const theme = context.globals.theme;
16
+ return (
17
+ <ThemeProvider key={theme} defaultTheme={theme} storageKey={`shipfox-theme-${theme}`}>
18
+ <Story />
19
+ </ThemeProvider>
20
+ );
21
+ };
22
+
23
+ const preview: Preview = {
24
+ decorators: [withTheme],
25
+ parameters: {
26
+ argos: {
27
+ // Dual-theme coverage lives in @shipfox/react-ui (the theming source of truth);
28
+ // feature packages capture only the primary dark theme to limit Argos spend.
29
+ modes: {
30
+ dark: {theme: 'dark'},
31
+ },
32
+ fitToContent: false,
33
+ },
34
+ options: {
35
+ storySort: {method: 'alphabetical'},
36
+ },
37
+ },
38
+ globalTypes: {
39
+ theme: {
40
+ name: 'Theme',
41
+ description: 'Global theme for components',
42
+ defaultValue: 'dark',
43
+ toolbar: {
44
+ icon: 'sun',
45
+ items: [
46
+ {value: 'light', icon: 'sun', title: 'Light'},
47
+ {value: 'dark', icon: 'moon', title: 'Dark'},
48
+ {value: 'system', icon: 'info', title: 'System'},
49
+ ],
50
+ showName: true,
51
+ },
52
+ },
53
+ },
54
+ };
55
+
56
+ export default preview;
@@ -0,0 +1,2 @@
1
+ $ shipfox-swc
2
+ Successfully compiled: 42 files with swc (57.5ms)
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-emit
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-check
package/CHANGELOG.md ADDED
@@ -0,0 +1,207 @@
1
+ # @shipfox/client-integrations
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3d064b8: Publishes the client runtime closure with shell, feature, route, Vite, and testing contracts.
8
+ - 6bc2e45: Adds the composable upstream client shell, feature catalog, and route manifests for every client feature.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [3d064b8]
13
+ - Updated dependencies [6bc2e45]
14
+ - @shipfox/client-api@0.2.0
15
+ - @shipfox/client-auth@0.2.0
16
+ - @shipfox/client-shell@0.2.0
17
+ - @shipfox/client-ui@0.2.0
18
+
19
+ ## 0.1.2
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [6b23868]
24
+ - Updated dependencies [c18d624]
25
+ - Updated dependencies [60e7bf5]
26
+ - @shipfox/api-integration-core-dto@3.0.0
27
+ - @shipfox/api-integration-github-dto@3.0.0
28
+ - @shipfox/api-integration-sentry-dto@3.0.0
29
+ - @shipfox/api-integration-webhook-dto@3.0.0
30
+ - @shipfox/react-ui@0.3.1
31
+ - @shipfox/api-integration-gitea-dto@3.0.0
32
+ - @shipfox/api-integration-linear-dto@3.0.0
33
+ - @shipfox/client-auth@0.0.5
34
+ - @shipfox/client-ui@0.1.2
35
+
36
+ ## 0.1.1
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [1b0d344]
41
+ - @shipfox/api-integration-core-dto@2.0.0
42
+ - @shipfox/api-integration-gitea-dto@2.0.0
43
+ - @shipfox/api-integration-github-dto@2.0.0
44
+ - @shipfox/api-integration-linear-dto@2.0.0
45
+ - @shipfox/api-integration-sentry-dto@2.0.0
46
+ - @shipfox/api-integration-webhook-dto@2.0.0
47
+ - @shipfox/client-ui@0.1.1
48
+ - @shipfox/client-auth@0.0.4
49
+ - @shipfox/client-api@0.0.1
50
+ - @shipfox/react-ui@0.3.0
51
+
52
+ ## 0.1.0
53
+
54
+ ### Minor Changes
55
+
56
+ - 43d7996: Adds the Linear OAuth connect experience to workspace integration settings.
57
+ - e4c6abf: Add reusable, source-keyed icon building blocks so any surface can render an integration or trigger icon without re-implementing the catalog lookup and fallback.
58
+
59
+ `@shipfox/client-integrations` exposes `getIntegrationIcon(source)` and `<IntegrationIcon source />`, resolving an integration source (a connection `provider`, a run `trigger_source`, or a trigger event `source`) against the central `PROVIDER_CATALOG` with a neutral `componentLine` fallback. The catalog stays the single place each integration declares its icon; the integration gallery now renders `<IntegrationIcon>` instead of an inline lookup (no behavior change).
60
+
61
+ New `@shipfox/client-triggers` package adds `getTriggerSourceIcon(source)` and `<TriggerSourceIcon source />`, built on the integration resolver. It recognizes the system trigger sources `manual` (a person fired the run) and `cron` (a schedule), and delegates every other source to the integration catalog. This is the building block for showing an icon on run rows and trigger events; adopting it on those surfaces lands separately.
62
+
63
+ - b8e49ff: Add the client-side Sentry install/connect flow and a workspace settings
64
+ integrations hub.
65
+ - `@shipfox/client-integrations`: shared `IntegrationGallerySection` (capability
66
+ filter, lifecycle pills, "Added" date, external link, connected-first
67
+ ordering, degraded status mode), shared `RedirectInstallPage` powering the
68
+ GitHub and new Sentry install pages, `SentryCallbackPage` with an explicit
69
+ workspace confirm (sessionStorage only pre-selects), two-tier retry, and the
70
+ Sentry hooks (`useCreateSentryInstallMutation`, `connectSentry`,
71
+ `useIntegrationConnectionsQuery`).
72
+ - `@shipfox/client-workspace-settings`: new `/workspaces/$wid/settings/integrations`
73
+ page and an Integrations entry in the settings nav.
74
+ - `@shipfox/client-router`: routes for the Sentry install page, the root-level
75
+ Sentry callback, and the settings integrations page.
76
+ - `@shipfox/react-ui`: `sentry` icon (monochrome, theme-aware).
77
+ - `@shipfox/api-integration-core-dto`: optional `external_url` on the connection
78
+ DTO and an optional `connectionExternalUrl` method on `IntegrationProvider`.
79
+ - `@shipfox/api-integration-core`: `GET /integration-connections` now returns
80
+ connections of every lifecycle status (the active-only filter prevented
81
+ clients from surfacing disabled/error state) and resolves `external_url`
82
+ per connection best-effort.
83
+ - `@shipfox/api-integration-sentry` / `@shipfox/api-integration-github`:
84
+ implement `connectionExternalUrl` (Sentry org URL via a new
85
+ by-connection-id installation lookup; GitHub installation settings URL).
86
+
87
+ ### Patch Changes
88
+
89
+ - d245be8: [api/integrations] Make the signed Sentry installation webhook authoritative.
90
+ - `@shipfox/api-integration-sentry-dto`: reshape `sentryInstallationWebhookSchema`
91
+ to read `data.installation.{uuid, organization.slug, status, code}` plus an
92
+ optional top-level `actor`. Only consumed fields are validated and the raw
93
+ `code` is never logged.
94
+ - `@shipfox/api-integration-sentry`: the signed `installation.created` webhook now
95
+ exchanges the single-use code and persists a verified-but-unclaimed installation
96
+ (`connection_id IS NULL`, `code_hash = sha256(code)`). The browser flow narrows
97
+ to a claim that binds a verified install to a workspace under unified claim auth
98
+ (exchange-success, same-code hash match, or a retryable
99
+ `verification-in-progress` while a concurrent webhook is mid-exchange), with a
100
+ proof-mismatch 403 closing the bare-uuid IDOR. The exchange/verify run outside
101
+ the DB transaction; a short transaction wraps persist + delivery record. Adds
102
+ `connection_id` nullable + `code_hash` to the installations table and a daily TTL
103
+ cron that tombstones never-claimed installs.
104
+ - `@shipfox/api-integration-core`: inject the Sentry client into the webhook
105
+ context, resolve a null `connection_id` to "no connection" for pre-claim issue
106
+ deliveries, and register the unclaimed-installation cleanup cron when Sentry is
107
+ enabled.
108
+ - `@shipfox/client-integrations`: treat the retryable `verification-in-progress`
109
+ response as a backoff-eligible failure on the connect callback.
110
+
111
+ - 0f06c02: Redesign the integration gallery into separate Installed and Available sections, rendering one card per connection so multiple connections from the same provider are no longer collapsed and silently hidden.
112
+ - 42443b4: Redesign the projects hub cards around source health and align them with the
113
+ integration gallery cards. Each card now shows the integration provider logo
114
+ before the name, drops the raw external repository id, and surfaces a status
115
+ pill only when the project's source is not active (Disabled or Error), in the
116
+ same inline location as the gallery. The cards adopt the gallery layout
117
+ (two-column grid, 16px padding, 24px icon) and carry no call to action.
118
+
119
+ Extract the connection lifecycle pill into a shared `ConnectionStatusBadge` in
120
+ `@shipfox/client-integrations` so the gallery and the projects hub render the
121
+ same taxonomy from one source of truth.
122
+
123
+ - 63bcac8: Moves workspace setup gating into route hooks so VCS onboarding and first project creation resolve before protected workspace content renders.
124
+ - a7da648: Fixes invisible keyboard focus rings on the user menu, integration tiles, and project cards by using the existing neutral button focus token.
125
+ - Updated dependencies [43d7996]
126
+ - Updated dependencies [0948b67]
127
+ - Updated dependencies [14e0bea]
128
+ - Updated dependencies [861091c]
129
+ - Updated dependencies [9018f0b]
130
+ - Updated dependencies [7fdfd72]
131
+ - Updated dependencies [115655e]
132
+ - Updated dependencies [2a3193f]
133
+ - Updated dependencies [ce062a9]
134
+ - Updated dependencies [f104ff2]
135
+ - Updated dependencies [7341569]
136
+ - Updated dependencies [f3614ae]
137
+ - Updated dependencies [d245be8]
138
+ - Updated dependencies [f8f339a]
139
+ - Updated dependencies [e4c6abf]
140
+ - Updated dependencies [58f51bd]
141
+ - Updated dependencies [570ac69]
142
+ - Updated dependencies [857fd73]
143
+ - Updated dependencies [5d0676a]
144
+ - Updated dependencies [a35c2dc]
145
+ - Updated dependencies [58f7aef]
146
+ - Updated dependencies [5264a22]
147
+ - Updated dependencies [9674879]
148
+ - Updated dependencies [225c9a5]
149
+ - Updated dependencies [24f131b]
150
+ - Updated dependencies [7790355]
151
+ - Updated dependencies [bb2a7bc]
152
+ - Updated dependencies [63bcac8]
153
+ - Updated dependencies [5eb06d0]
154
+ - Updated dependencies [4e13e5f]
155
+ - Updated dependencies [e92150d]
156
+ - Updated dependencies [8037501]
157
+ - Updated dependencies [0fb6018]
158
+ - Updated dependencies [c27a1ed]
159
+ - Updated dependencies [b8e49ff]
160
+ - Updated dependencies [5b8ed32]
161
+ - Updated dependencies [d6d4862]
162
+ - Updated dependencies [8037501]
163
+ - Updated dependencies [6c0da64]
164
+ - Updated dependencies [07f8ff8]
165
+ - Updated dependencies [e457582]
166
+ - Updated dependencies [8b5c905]
167
+ - Updated dependencies [01be723]
168
+ - Updated dependencies [f849131]
169
+ - Updated dependencies [94bdcc5]
170
+ - Updated dependencies [a34c8ea]
171
+ - Updated dependencies [27770eb]
172
+ - Updated dependencies [2933c33]
173
+ - Updated dependencies [8ac4bf4]
174
+ - Updated dependencies [3a0be6b]
175
+ - Updated dependencies [d42baf4]
176
+ - Updated dependencies [8037501]
177
+ - Updated dependencies [54bb8a3]
178
+ - Updated dependencies [f711e18]
179
+ - @shipfox/react-ui@0.3.0
180
+ - @shipfox/api-integration-linear-dto@0.0.1
181
+ - @shipfox/api-integration-webhook-dto@0.0.1
182
+ - @shipfox/api-integration-core-dto@0.1.0
183
+ - @shipfox/api-integration-sentry-dto@0.1.0
184
+ - @shipfox/api-integration-gitea-dto@0.0.1
185
+ - @shipfox/client-api@0.0.1
186
+ - @shipfox/client-ui@0.1.0
187
+ - @shipfox/client-auth@0.0.3
188
+ - @shipfox/api-integration-github-dto@0.0.1
189
+
190
+ ## 0.0.2
191
+
192
+ ### Patch Changes
193
+
194
+ - Updated dependencies [5c1e777]
195
+ - @shipfox/react-ui@0.2.0
196
+ - @shipfox/client-auth@0.0.2
197
+
198
+ ## 0.0.1
199
+
200
+ ### Patch Changes
201
+
202
+ - Updated dependencies [2311e15]
203
+ - @shipfox/react-ui@0.1.1
204
+ - @shipfox/client-auth@0.0.1
205
+ - @shipfox/api-integration-core-dto@0.0.0
206
+ - @shipfox/api-integration-github-dto@0.0.0
207
+ - @shipfox/client-api@0.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shipfox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ import type { IntegrationConnectionDto } from '@shipfox/api-integration-core-dto';
2
+ export declare function ConnectionPicker({ connections, selectedConnectionId, onSelect, }: {
3
+ connections: IntegrationConnectionDto[];
4
+ selectedConnectionId: string | undefined;
5
+ onSelect: (connectionId: string) => void;
6
+ }): import("react").JSX.Element;
7
+ //# sourceMappingURL=connection-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-picker.d.ts","sourceRoot":"","sources":["../../src/components/connection-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,mCAAmC,CAAC;AAShF,wBAAgB,gBAAgB,CAAC,EAC/B,WAAW,EACX,oBAAoB,EACpB,QAAQ,GACT,EAAE;IACD,WAAW,EAAE,wBAAwB,EAAE,CAAC;IACxC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C,+BAsBA"}
@@ -0,0 +1,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useIsTextTruncated } from '@shipfox/react-ui/hooks';
3
+ import { Label } from '@shipfox/react-ui/label';
4
+ import { RadioGroup, RadioGroupItem } from '@shipfox/react-ui/radio-group';
5
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
6
+ import { Text } from '@shipfox/react-ui/typography';
7
+ import { useId } from 'react';
8
+ import { IntegrationIcon } from '#integration-icon.js';
9
+ export function ConnectionPicker({ connections, selectedConnectionId, onSelect }) {
10
+ const labelId = useId();
11
+ return /*#__PURE__*/ _jsxs("div", {
12
+ className: "flex flex-col gap-10",
13
+ children: [
14
+ /*#__PURE__*/ _jsx(Label, {
15
+ id: labelId,
16
+ className: "sr-only",
17
+ children: "Source integration"
18
+ }),
19
+ /*#__PURE__*/ _jsx(RadioGroup, {
20
+ "aria-labelledby": labelId,
21
+ value: selectedConnectionId ?? '',
22
+ onValueChange: onSelect,
23
+ className: "grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1",
24
+ children: connections.map((connection)=>/*#__PURE__*/ _jsx(RadioGroupItem, {
25
+ value: connection.id,
26
+ className: "p-12",
27
+ children: /*#__PURE__*/ _jsx(ConnectionOption, {
28
+ connection: connection
29
+ })
30
+ }, connection.id))
31
+ })
32
+ ]
33
+ });
34
+ }
35
+ function ConnectionOption({ connection }) {
36
+ const { ref: nameRef, isTruncated } = useIsTextTruncated(connection.display_name);
37
+ return /*#__PURE__*/ _jsxs("span", {
38
+ className: "flex min-w-0 items-center gap-10",
39
+ children: [
40
+ /*#__PURE__*/ _jsxs(Tooltip, {
41
+ children: [
42
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
43
+ asChild: true,
44
+ children: /*#__PURE__*/ _jsx("span", {
45
+ className: "shrink-0",
46
+ children: /*#__PURE__*/ _jsx(IntegrationIcon, {
47
+ source: connection.provider,
48
+ "aria-hidden": true,
49
+ className: "size-20 text-foreground-neutral-base"
50
+ })
51
+ })
52
+ }),
53
+ /*#__PURE__*/ _jsx(TooltipContent, {
54
+ children: integrationName(connection.provider)
55
+ })
56
+ ]
57
+ }),
58
+ /*#__PURE__*/ _jsxs(Tooltip, {
59
+ children: [
60
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
61
+ asChild: true,
62
+ children: /*#__PURE__*/ _jsx("span", {
63
+ ref: nameRef,
64
+ className: "min-w-0 truncate",
65
+ children: /*#__PURE__*/ _jsx(Text, {
66
+ as: "span",
67
+ size: "sm",
68
+ bold: true,
69
+ children: connection.display_name
70
+ })
71
+ })
72
+ }),
73
+ isTruncated ? /*#__PURE__*/ _jsx(TooltipContent, {
74
+ children: connection.display_name
75
+ }) : null
76
+ ]
77
+ })
78
+ ]
79
+ });
80
+ }
81
+ function integrationName(provider) {
82
+ switch(provider){
83
+ case 'github':
84
+ return 'GitHub';
85
+ case 'gitea':
86
+ return 'Gitea';
87
+ case 'sentry':
88
+ return 'Sentry';
89
+ case 'webhook':
90
+ return 'Webhook';
91
+ case 'debug':
92
+ return 'Debug';
93
+ default:
94
+ return provider;
95
+ }
96
+ }
97
+
98
+ //# sourceMappingURL=connection-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/connection-picker.tsx"],"sourcesContent":["import type {IntegrationConnectionDto} from '@shipfox/api-integration-core-dto';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport {IntegrationIcon} from '#integration-icon.js';\n\nexport function ConnectionPicker({\n connections,\n selectedConnectionId,\n onSelect,\n}: {\n connections: IntegrationConnectionDto[];\n selectedConnectionId: string | undefined;\n onSelect: (connectionId: string) => void;\n}) {\n const labelId = useId();\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Source integration\n </Label>\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedConnectionId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1\"\n >\n {connections.map((connection) => (\n <RadioGroupItem key={connection.id} value={connection.id} className=\"p-12\">\n <ConnectionOption connection={connection} />\n </RadioGroupItem>\n ))}\n </RadioGroup>\n </div>\n );\n}\n\nfunction ConnectionOption({connection}: {connection: IntegrationConnectionDto}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(connection.display_name);\n\n return (\n <span className=\"flex min-w-0 items-center gap-10\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className=\"size-20 text-foreground-neutral-base\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{integrationName(connection.provider)}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={nameRef} className=\"min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {connection.display_name}\n </Text>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{connection.display_name}</TooltipContent> : null}\n </Tooltip>\n </span>\n );\n}\n\nfunction integrationName(provider: string): string {\n switch (provider) {\n case 'github':\n return 'GitHub';\n case 'gitea':\n return 'Gitea';\n case 'sentry':\n return 'Sentry';\n case 'webhook':\n return 'Webhook';\n case 'debug':\n return 'Debug';\n default:\n return provider;\n }\n}\n"],"names":["useIsTextTruncated","Label","RadioGroup","RadioGroupItem","Tooltip","TooltipContent","TooltipTrigger","Text","useId","IntegrationIcon","ConnectionPicker","connections","selectedConnectionId","onSelect","labelId","div","className","id","aria-labelledby","value","onValueChange","map","connection","ConnectionOption","ref","nameRef","isTruncated","display_name","span","asChild","source","provider","aria-hidden","integrationName","as","size","bold"],"mappings":";AACA,SAAQA,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAC5B,SAAQC,eAAe,QAAO,uBAAuB;AAErD,OAAO,SAASC,iBAAiB,EAC/BC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EAKT;IACC,MAAMC,UAAUN;IAEhB,qBACE,MAACO;QAAIC,WAAU;;0BACb,KAACf;gBAAMgB,IAAIH;gBAASE,WAAU;0BAAU;;0BAGxC,KAACd;gBACCgB,mBAAiBJ;gBACjBK,OAAOP,wBAAwB;gBAC/BQ,eAAeP;gBACfG,WAAU;0BAETL,YAAYU,GAAG,CAAC,CAACC,2BAChB,KAACnB;wBAAmCgB,OAAOG,WAAWL,EAAE;wBAAED,WAAU;kCAClE,cAAA,KAACO;4BAAiBD,YAAYA;;uBADXA,WAAWL,EAAE;;;;AAO5C;AAEA,SAASM,iBAAiB,EAACD,UAAU,EAAyC;IAC5E,MAAM,EAACE,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAG1B,mBAAoCsB,WAAWK,YAAY;IAE/F,qBACE,MAACC;QAAKZ,WAAU;;0BACd,MAACZ;;kCACC,KAACE;wBAAeuB,OAAO;kCACrB,cAAA,KAACD;4BAAKZ,WAAU;sCACd,cAAA,KAACP;gCACCqB,QAAQR,WAAWS,QAAQ;gCAC3BC,aAAW;gCACXhB,WAAU;;;;kCAIhB,KAACX;kCAAgB4B,gBAAgBX,WAAWS,QAAQ;;;;0BAGtD,MAAC3B;;kCACC,KAACE;wBAAeuB,OAAO;kCACrB,cAAA,KAACD;4BAAKJ,KAAKC;4BAAST,WAAU;sCAC5B,cAAA,KAACT;gCAAK2B,IAAG;gCAAOC,MAAK;gCAAKC,IAAI;0CAC3Bd,WAAWK,YAAY;;;;oBAI7BD,4BAAc,KAACrB;kCAAgBiB,WAAWK,YAAY;yBAAqB;;;;;AAIpF;AAEA,SAASM,gBAAgBF,QAAgB;IACvC,OAAQA;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,OAAOA;IACX;AACF"}
@@ -0,0 +1,14 @@
1
+ import type { IntegrationConnectionDto, ListIntegrationConnectionsResponseDto } from '@shipfox/api-integration-core-dto';
2
+ import type { UseQueryResult } from '@tanstack/react-query';
3
+ interface InstalledIntegrationsSectionProps {
4
+ connectionsQuery: UseQueryResult<ListIntegrationConnectionsResponseDto, Error>;
5
+ connections: IntegrationConnectionDto[];
6
+ isMutating: boolean;
7
+ onUse: (connectionId: string) => void;
8
+ onSetActive: (connection: IntegrationConnectionDto, active: boolean) => void;
9
+ onDelete: (connectionId: string) => void;
10
+ providerDisplayName: (provider: string) => string | undefined;
11
+ }
12
+ export declare function InstalledIntegrationsSection({ connectionsQuery, connections, isMutating, onUse, onSetActive, onDelete, providerDisplayName, }: InstalledIntegrationsSectionProps): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=installed-integrations-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed-integrations-section.d.ts","sourceRoot":"","sources":["../../src/components/installed-integrations-section.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,qCAAqC,EACtC,MAAM,mCAAmC,CAAC;AAc3C,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAM1D,UAAU,iCAAiC;IACzC,gBAAgB,EAAE,cAAc,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;IAC/E,WAAW,EAAE,wBAAwB,EAAE,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,WAAW,EAAE,CAAC,UAAU,EAAE,wBAAwB,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7E,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC/D;AAKD,wBAAgB,4BAA4B,CAAC,EAC3C,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,KAAK,EACL,WAAW,EACX,QAAQ,EACR,mBAAmB,GACpB,EAAE,iCAAiC,+BA6CnC"}
@@ -0,0 +1,203 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { QueryLoadError } from '@shipfox/client-ui';
3
+ import { IconButton } from '@shipfox/react-ui/button';
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@shipfox/react-ui/dropdown-menu';
5
+ import { EmptyState } from '@shipfox/react-ui/empty-state';
6
+ import { Skeleton } from '@shipfox/react-ui/skeleton';
7
+ import { Header, Text } from '@shipfox/react-ui/typography';
8
+ import { cn, formatDate } from '@shipfox/react-ui/utils';
9
+ import { Link } from '@tanstack/react-router';
10
+ import { ConnectionStatusBadge } from '#connection-status-badge.js';
11
+ import { IntegrationIcon } from '#integration-icon.js';
12
+ import { usageEventsForConnection } from './integration-usage-events.js';
13
+ const INSTALLED_SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
14
+ export function InstalledIntegrationsSection({ connectionsQuery, connections, isMutating, onUse, onSetActive, onDelete, providerDisplayName }) {
15
+ return /*#__PURE__*/ _jsxs("section", {
16
+ className: "flex flex-col gap-16",
17
+ "aria-label": "Installed integrations",
18
+ children: [
19
+ /*#__PURE__*/ _jsxs("div", {
20
+ className: "flex flex-col gap-4",
21
+ children: [
22
+ /*#__PURE__*/ _jsx(Header, {
23
+ variant: "h3",
24
+ children: "Installed integrations"
25
+ }),
26
+ /*#__PURE__*/ _jsx(Text, {
27
+ size: "sm",
28
+ className: "text-foreground-neutral-muted",
29
+ children: "Provider accounts installed in this workspace."
30
+ })
31
+ ]
32
+ }),
33
+ connectionsQuery.isPending ? /*#__PURE__*/ _jsx(InstalledSkeleton, {
34
+ label: "Loading integrations"
35
+ }) : null,
36
+ connectionsQuery.isError && connectionsQuery.data === undefined ? /*#__PURE__*/ _jsx("div", {
37
+ className: cn(INSTALLED_SURFACE_CLASS, 'px-16'),
38
+ children: /*#__PURE__*/ _jsx(QueryLoadError, {
39
+ query: connectionsQuery,
40
+ subject: "integrations"
41
+ })
42
+ }) : null,
43
+ connectionsQuery.data !== undefined && connections.length === 0 ? /*#__PURE__*/ _jsx("div", {
44
+ className: cn(INSTALLED_SURFACE_CLASS, 'px-16'),
45
+ children: /*#__PURE__*/ _jsx(EmptyState, {
46
+ icon: "componentLine",
47
+ title: "No integrations installed yet",
48
+ description: "Install a provider below to get started."
49
+ })
50
+ }) : null,
51
+ connections.length > 0 ? /*#__PURE__*/ _jsx("ul", {
52
+ className: cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS),
53
+ children: connections.map((connection)=>/*#__PURE__*/ _jsx(InstalledRow, {
54
+ connection: connection,
55
+ isMutating: isMutating,
56
+ onUse: onUse,
57
+ onSetActive: (nextActive)=>onSetActive(connection, nextActive),
58
+ onDelete: onDelete,
59
+ providerDisplayName: providerDisplayName
60
+ }, connection.id))
61
+ }) : null
62
+ ]
63
+ });
64
+ }
65
+ function InstalledRow({ connection, isMutating, onUse, onSetActive, onDelete, providerDisplayName }) {
66
+ const muted = connection.lifecycle_status === 'disabled';
67
+ const active = connection.lifecycle_status === 'active';
68
+ const recentEventsEvent = usageEventsForConnection(connection)[0]?.value ?? 'received';
69
+ const providerName = providerDisplayName(connection.provider);
70
+ return /*#__PURE__*/ _jsxs("li", {
71
+ className: "flex items-center gap-12 px-16 py-12 transition-colors hover:bg-background-components-hover",
72
+ children: [
73
+ /*#__PURE__*/ _jsx(IntegrationIcon, {
74
+ source: connection.provider,
75
+ "aria-hidden": true,
76
+ className: cn('size-24 shrink-0', muted ? 'text-foreground-neutral-disabled' : 'text-foreground-neutral-base')
77
+ }),
78
+ /*#__PURE__*/ _jsxs("div", {
79
+ className: "flex min-w-0 flex-1 flex-col gap-2",
80
+ children: [
81
+ /*#__PURE__*/ _jsxs("div", {
82
+ className: "flex min-w-0 items-center gap-8",
83
+ children: [
84
+ /*#__PURE__*/ _jsx(Text, {
85
+ size: "md",
86
+ bold: true,
87
+ className: cn('truncate', muted ? 'text-foreground-neutral-disabled' : undefined),
88
+ children: connection.display_name
89
+ }),
90
+ /*#__PURE__*/ _jsx(ConnectionStatusBadge, {
91
+ status: connection.lifecycle_status,
92
+ className: "shrink-0"
93
+ })
94
+ ]
95
+ }),
96
+ /*#__PURE__*/ _jsxs(Text, {
97
+ size: "sm",
98
+ className: "truncate text-foreground-neutral-muted",
99
+ children: [
100
+ "Added ",
101
+ formatDate(connection.created_at)
102
+ ]
103
+ })
104
+ ]
105
+ }),
106
+ /*#__PURE__*/ _jsxs(DropdownMenu, {
107
+ children: [
108
+ /*#__PURE__*/ _jsx(DropdownMenuTrigger, {
109
+ asChild: true,
110
+ children: /*#__PURE__*/ _jsx(IconButton, {
111
+ size: "sm",
112
+ variant: "transparent",
113
+ icon: "more2Line",
114
+ "aria-label": `Open ${connection.display_name} integration actions`
115
+ })
116
+ }),
117
+ /*#__PURE__*/ _jsxs(DropdownMenuContent, {
118
+ align: "end",
119
+ children: [
120
+ connection.external_url ? /*#__PURE__*/ _jsx(DropdownMenuItem, {
121
+ asChild: true,
122
+ children: /*#__PURE__*/ _jsx("a", {
123
+ href: connection.external_url,
124
+ target: "_blank",
125
+ rel: "noreferrer noopener",
126
+ children: providerName ? `Open in ${providerName}` : 'Open provider settings'
127
+ })
128
+ }) : null,
129
+ /*#__PURE__*/ _jsx(DropdownMenuItem, {
130
+ onSelect: ()=>onUse(connection.id),
131
+ children: "Use this integration"
132
+ }),
133
+ /*#__PURE__*/ _jsx(DropdownMenuItem, {
134
+ asChild: true,
135
+ children: /*#__PURE__*/ _jsx(Link, {
136
+ to: "/workspaces/$wid/settings/events",
137
+ params: {
138
+ wid: connection.workspace_id
139
+ },
140
+ search: {
141
+ source: [
142
+ connection.slug
143
+ ],
144
+ event: [
145
+ recentEventsEvent
146
+ ]
147
+ },
148
+ children: "View recent events"
149
+ })
150
+ }),
151
+ /*#__PURE__*/ _jsx(DropdownMenuSeparator, {}),
152
+ /*#__PURE__*/ _jsx(DropdownMenuItem, {
153
+ disabled: isMutating,
154
+ onSelect: ()=>onSetActive(!active),
155
+ children: active ? 'Disable integration' : 'Enable integration'
156
+ }),
157
+ /*#__PURE__*/ _jsx(DropdownMenuItem, {
158
+ disabled: isMutating,
159
+ onSelect: ()=>onDelete(connection.id),
160
+ children: "Delete integration"
161
+ })
162
+ ]
163
+ })
164
+ ]
165
+ })
166
+ ]
167
+ });
168
+ }
169
+ function InstalledSkeleton({ label }) {
170
+ return /*#__PURE__*/ _jsx("ul", {
171
+ role: "status",
172
+ "aria-label": label,
173
+ className: cn('divide-y divide-border-neutral-base', INSTALLED_SURFACE_CLASS),
174
+ children: [
175
+ 0,
176
+ 1,
177
+ 2
178
+ ].map((row)=>/*#__PURE__*/ _jsxs("li", {
179
+ className: "flex items-center gap-12 px-16 py-12",
180
+ children: [
181
+ /*#__PURE__*/ _jsx(Skeleton, {
182
+ className: "size-24 shrink-0"
183
+ }),
184
+ /*#__PURE__*/ _jsxs("div", {
185
+ className: "flex min-w-0 flex-1 flex-col gap-2",
186
+ children: [
187
+ /*#__PURE__*/ _jsx(Skeleton, {
188
+ className: "h-16 w-120"
189
+ }),
190
+ /*#__PURE__*/ _jsx(Skeleton, {
191
+ className: "h-12 w-80"
192
+ })
193
+ ]
194
+ }),
195
+ /*#__PURE__*/ _jsx(Skeleton, {
196
+ className: "h-20 w-72 shrink-0"
197
+ })
198
+ ]
199
+ }, row))
200
+ });
201
+ }
202
+
203
+ //# sourceMappingURL=installed-integrations-section.js.map