@shipfox/client-integrations 4.0.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +86 -0
- package/dist/application/complete-integration-callback.d.ts +13 -0
- package/dist/application/complete-integration-callback.d.ts.map +1 -0
- package/dist/application/complete-integration-callback.js +26 -0
- package/dist/application/complete-integration-callback.js.map +1 -0
- package/dist/components/connection-picker.d.ts +2 -2
- package/dist/components/connection-picker.d.ts.map +1 -1
- package/dist/components/connection-picker.js +4 -4
- package/dist/components/connection-picker.js.map +1 -1
- package/dist/components/installed-integrations-section.d.ts +8 -6
- package/dist/components/installed-integrations-section.d.ts.map +1 -1
- package/dist/components/installed-integrations-section.js +22 -15
- package/dist/components/installed-integrations-section.js.map +1 -1
- package/dist/components/integration-gallery-for-workspace.d.ts +2 -2
- package/dist/components/integration-gallery-for-workspace.d.ts.map +1 -1
- package/dist/components/integration-gallery-for-workspace.js +14 -7
- package/dist/components/integration-gallery-for-workspace.js.map +1 -1
- package/dist/components/integration-gallery.d.ts +2 -2
- package/dist/components/integration-gallery.d.ts.map +1 -1
- package/dist/components/integration-gallery.js.map +1 -1
- package/dist/components/integration-usage-events.d.ts +1 -3
- package/dist/components/integration-usage-events.d.ts.map +1 -1
- package/dist/components/integration-usage-events.js +1 -125
- package/dist/components/integration-usage-events.js.map +1 -1
- package/dist/components/integration-usage-modal.d.ts +2 -2
- package/dist/components/integration-usage-modal.d.ts.map +1 -1
- package/dist/components/integration-usage-modal.js +2 -2
- package/dist/components/integration-usage-modal.js.map +1 -1
- package/dist/components/provider-grid.d.ts +7 -4
- package/dist/components/provider-grid.d.ts.map +1 -1
- package/dist/components/provider-grid.js +15 -10
- package/dist/components/provider-grid.js.map +1 -1
- package/dist/components/redirect-install-page.d.ts +2 -3
- package/dist/components/redirect-install-page.d.ts.map +1 -1
- package/dist/components/redirect-install-page.js +1 -1
- package/dist/components/redirect-install-page.js.map +1 -1
- package/dist/components/repository-picker.d.ts +2 -2
- package/dist/components/repository-picker.d.ts.map +1 -1
- package/dist/components/repository-picker.js +4 -4
- package/dist/components/repository-picker.js.map +1 -1
- package/dist/components/webhook/webhook-create-modal.d.ts +2 -2
- package/dist/components/webhook/webhook-create-modal.d.ts.map +1 -1
- package/dist/components/webhook/webhook-create-modal.js +8 -8
- package/dist/components/webhook/webhook-create-modal.js.map +1 -1
- package/dist/components/webhook/webhook-modals.stories.d.ts.map +1 -1
- package/dist/components/webhook/webhook-modals.stories.js +7 -7
- package/dist/components/webhook/webhook-modals.stories.js.map +1 -1
- package/dist/components/webhook/webhook-usage-details.d.ts.map +1 -1
- package/dist/components/webhook/webhook-usage-details.js +2 -2
- package/dist/components/webhook/webhook-usage-details.js.map +1 -1
- package/dist/connection-status-badge.d.ts +2 -2
- package/dist/connection-status-badge.d.ts.map +1 -1
- package/dist/connection-status-badge.js +11 -15
- package/dist/connection-status-badge.js.map +1 -1
- package/dist/core/models.d.ts +66 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +156 -0
- package/dist/core/models.js.map +1 -0
- package/dist/feature.d.ts +18 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +16 -1
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/integration-mapper.d.ts +11 -0
- package/dist/hooks/api/integration-mapper.d.ts.map +1 -0
- package/dist/hooks/api/integration-mapper.js +54 -0
- package/dist/hooks/api/integration-mapper.js.map +1 -0
- package/dist/hooks/api/integrations.d.ts +47 -237
- package/dist/hooks/api/integrations.d.ts.map +1 -1
- package/dist/hooks/api/integrations.js +92 -42
- package/dist/hooks/api/integrations.js.map +1 -1
- package/dist/hooks/api/webhook-connections.d.ts +12 -64
- package/dist/hooks/api/webhook-connections.d.ts.map +1 -1
- package/dist/hooks/api/webhook-connections.js +17 -9
- package/dist/hooks/api/webhook-connections.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/linear-callback.d.ts +2 -1
- package/dist/linear-callback.d.ts.map +1 -1
- package/dist/linear-callback.js +14 -15
- package/dist/linear-callback.js.map +1 -1
- package/dist/pages/gitea-install-page.d.ts.map +1 -1
- package/dist/pages/gitea-install-page.js +1 -10
- package/dist/pages/gitea-install-page.js.map +1 -1
- package/dist/pages/linear-callback-page.d.ts.map +1 -1
- package/dist/pages/linear-callback-page.js +19 -32
- package/dist/pages/linear-callback-page.js.map +1 -1
- package/dist/pages/linear-install-page.d.ts.map +1 -1
- package/dist/pages/linear-install-page.js +2 -1
- package/dist/pages/linear-install-page.js.map +1 -1
- package/dist/pages/sentry-callback-page.d.ts.map +1 -1
- package/dist/pages/sentry-callback-page.js +22 -25
- package/dist/pages/sentry-callback-page.js.map +1 -1
- package/dist/pages/sentry-install-page.d.ts.map +1 -1
- package/dist/pages/sentry-install-page.js +2 -1
- package/dist/pages/sentry-install-page.js.map +1 -1
- package/dist/pages/slack-callback-page.d.ts.map +1 -1
- package/dist/pages/slack-callback-page.js +21 -28
- package/dist/pages/slack-callback-page.js.map +1 -1
- package/dist/pages/slack-install-page.d.ts.map +1 -1
- package/dist/pages/slack-install-page.js +2 -1
- package/dist/pages/slack-install-page.js.map +1 -1
- package/dist/pages/source-control-onboarding-page.d.ts.map +1 -1
- package/dist/pages/source-control-onboarding-page.js +5 -1
- package/dist/pages/source-control-onboarding-page.js.map +1 -1
- package/dist/provider-catalog.d.ts.map +1 -1
- package/dist/provider-catalog.js +7 -6
- package/dist/provider-catalog.js.map +1 -1
- package/dist/routes/github-callback.d.ts +16 -0
- package/dist/routes/github-callback.d.ts.map +1 -1
- package/dist/routes/github-callback.js +43 -21
- package/dist/routes/github-callback.js.map +1 -1
- package/dist/routes/integrations-settings.d.ts +6 -0
- package/dist/routes/integrations-settings.d.ts.map +1 -0
- package/dist/routes/integrations-settings.js +7 -0
- package/dist/routes/integrations-settings.js.map +1 -0
- package/dist/routes/linear-callback.d.ts +2 -0
- package/dist/routes/linear-callback.d.ts.map +1 -1
- package/dist/routes/linear-callback.js +2 -0
- package/dist/routes/linear-callback.js.map +1 -1
- package/dist/routes/sentry-callback.d.ts +2 -0
- package/dist/routes/sentry-callback.d.ts.map +1 -1
- package/dist/routes/sentry-callback.js +2 -0
- package/dist/routes/sentry-callback.js.map +1 -1
- package/dist/routes/slack-callback.d.ts +2 -0
- package/dist/routes/slack-callback.d.ts.map +1 -1
- package/dist/routes/slack-callback.js +2 -0
- package/dist/routes/slack-callback.js.map +1 -1
- package/dist/sentry-callback.d.ts +2 -1
- package/dist/sentry-callback.d.ts.map +1 -1
- package/dist/sentry-callback.js +16 -19
- package/dist/sentry-callback.js.map +1 -1
- package/dist/slack-callback.d.ts +2 -1
- package/dist/slack-callback.d.ts.map +1 -1
- package/dist/slack-callback.js +14 -15
- package/dist/slack-callback.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/application/complete-integration-callback.test.ts +41 -0
- package/src/application/complete-integration-callback.ts +39 -0
- package/src/components/connection-picker.tsx +7 -7
- package/src/components/installed-integrations-section.tsx +29 -24
- package/src/components/integration-gallery-for-workspace.tsx +23 -16
- package/src/components/integration-gallery.tsx +3 -3
- package/src/components/integration-usage-events.ts +1 -116
- package/src/components/integration-usage-modal.tsx +4 -4
- package/src/components/provider-grid.tsx +30 -18
- package/src/components/redirect-install-page.test.tsx +2 -6
- package/src/components/redirect-install-page.tsx +3 -2
- package/src/components/repository-picker.tsx +6 -6
- package/src/components/webhook/webhook-create-modal.tsx +12 -11
- package/src/components/webhook/webhook-modals.stories.tsx +10 -10
- package/src/components/webhook/webhook-usage-details.tsx +2 -4
- package/src/connection-status-badge.tsx +8 -14
- package/src/core/models.ts +200 -0
- package/src/feature.ts +17 -1
- package/src/hooks/api/integration-mapper.ts +64 -0
- package/src/hooks/api/integrations.test.ts +44 -22
- package/src/hooks/api/integrations.ts +258 -89
- package/src/hooks/api/webhook-connections.ts +58 -17
- package/src/index.ts +2 -1
- package/src/linear-callback.ts +21 -16
- package/src/pages/gitea-install-page.tsx +1 -10
- package/src/pages/linear-callback-page.test.tsx +1 -1
- package/src/pages/linear-callback-page.tsx +18 -29
- package/src/pages/linear-install-page.tsx +2 -1
- package/src/pages/sentry-callback-page.test.tsx +6 -2
- package/src/pages/sentry-callback-page.tsx +28 -25
- package/src/pages/sentry-install-page.tsx +2 -1
- package/src/pages/slack-callback-page.tsx +20 -25
- package/src/pages/slack-install-page.tsx +2 -1
- package/src/pages/source-control-onboarding-page.tsx +5 -1
- package/src/provider-catalog.ts +7 -6
- package/src/routes/github-callback.test.ts +35 -1
- package/src/routes/github-callback.tsx +47 -21
- package/src/routes/integrations-settings.tsx +4 -0
- package/src/routes/linear-callback.tsx +5 -1
- package/src/routes/sentry-callback.tsx +5 -1
- package/src/routes/slack-callback.tsx +6 -1
- package/src/sentry-callback.test.ts +2 -1
- package/src/sentry-callback.ts +28 -20
- package/src/slack-callback.ts +21 -16
- package/test/render.tsx +1 -5
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vercel.json +5 -0
- package/dist/integration-icon.d.ts +0 -17
- package/dist/integration-icon.d.ts.map +0 -1
- package/dist/integration-icon.js +0 -22
- package/dist/integration-icon.js.map +0 -1
- package/src/integration-icon.react.test.tsx +0 -40
- package/src/integration-icon.test.ts +0 -19
- package/src/integration-icon.tsx +0 -26
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
function connection(overrides: Partial<IntegrationConnectionDto> = {}): IntegrationConnectionDto {
|
|
12
12
|
return {
|
|
13
|
-
id: '
|
|
14
|
-
workspace_id: '
|
|
13
|
+
id: '11111111-1111-4111-8111-111111111111',
|
|
14
|
+
workspace_id: '22222222-2222-4222-8222-222222222222',
|
|
15
15
|
provider: 'github',
|
|
16
16
|
external_account_id: 'acct',
|
|
17
17
|
slug: 'github_acct',
|
|
@@ -40,19 +40,23 @@ describe('listSourceConnections', () => {
|
|
|
40
40
|
return Promise.resolve(
|
|
41
41
|
jsonResponse({
|
|
42
42
|
connections: [
|
|
43
|
-
connection({id: '
|
|
44
|
-
connection({id: '
|
|
45
|
-
connection({id: '
|
|
43
|
+
connection({id: '33333333-3333-4333-8333-333333333333', lifecycle_status: 'active'}),
|
|
44
|
+
connection({id: '44444444-4444-4444-8444-444444444444', lifecycle_status: 'disabled'}),
|
|
45
|
+
connection({id: '55555555-5555-4555-8555-555555555555', lifecycle_status: 'error'}),
|
|
46
46
|
],
|
|
47
47
|
}),
|
|
48
48
|
);
|
|
49
49
|
});
|
|
50
50
|
configureApiClient({baseUrl: 'https://api.example.test', fetchImpl});
|
|
51
51
|
|
|
52
|
-
const result = await listSourceConnections({
|
|
52
|
+
const result = await listSourceConnections({
|
|
53
|
+
workspaceId: '22222222-2222-4222-8222-222222222222',
|
|
54
|
+
});
|
|
53
55
|
|
|
54
56
|
expect(requestedUrl).toContain('capability=source_control');
|
|
55
|
-
expect(result.
|
|
57
|
+
expect(result.map((connection) => connection.id)).toEqual([
|
|
58
|
+
'33333333-3333-4333-8333-333333333333',
|
|
59
|
+
]);
|
|
56
60
|
});
|
|
57
61
|
});
|
|
58
62
|
|
|
@@ -63,11 +67,20 @@ describe('Slack transport', () => {
|
|
|
63
67
|
baseUrl: 'https://api.example.test',
|
|
64
68
|
fetchImpl: vi.fn((input, init) => {
|
|
65
69
|
requests.push(new Request(input, init));
|
|
66
|
-
|
|
70
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
71
|
+
return Promise.resolve(
|
|
72
|
+
jsonResponse(
|
|
73
|
+
url.endsWith('/install')
|
|
74
|
+
? {install_url: 'https://slack.example.test/install'}
|
|
75
|
+
: connection({provider: 'slack'}),
|
|
76
|
+
),
|
|
77
|
+
);
|
|
67
78
|
}),
|
|
68
79
|
});
|
|
69
80
|
|
|
70
|
-
await createSlackInstall({
|
|
81
|
+
const install = await createSlackInstall({
|
|
82
|
+
workspace_id: '11111111-1111-4111-8111-111111111111',
|
|
83
|
+
});
|
|
71
84
|
await completeSlackCallback({
|
|
72
85
|
query: {code: 'grant code', state: 'signed state'},
|
|
73
86
|
token: 'session-token',
|
|
@@ -77,6 +90,7 @@ describe('Slack transport', () => {
|
|
|
77
90
|
expect(await requests[0]?.json()).toEqual({
|
|
78
91
|
workspace_id: '11111111-1111-4111-8111-111111111111',
|
|
79
92
|
});
|
|
93
|
+
expect(install).toEqual({installUrl: 'https://slack.example.test/install'});
|
|
80
94
|
expect(requests[1]?.url).toBe(
|
|
81
95
|
'https://api.example.test/integrations/slack/callback/api?code=grant+code&state=signed+state',
|
|
82
96
|
);
|
|
@@ -89,24 +103,31 @@ describe('Linear transport', () => {
|
|
|
89
103
|
const requests: Request[] = [];
|
|
90
104
|
const fetchImpl = vi.fn((input: RequestInfo | URL, init?: RequestInit) => {
|
|
91
105
|
requests.push(new Request(input, init));
|
|
106
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
92
107
|
return Promise.resolve(
|
|
93
|
-
jsonResponse(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
jsonResponse(
|
|
109
|
+
url.endsWith('/install')
|
|
110
|
+
? {install_url: 'https://linear.example.test/install'}
|
|
111
|
+
: {
|
|
112
|
+
id: '33333333-3333-4333-8333-333333333333',
|
|
113
|
+
workspace_id: '11111111-1111-4111-8111-111111111111',
|
|
114
|
+
provider: 'linear',
|
|
115
|
+
external_account_id: 'linear-org',
|
|
116
|
+
slug: 'linear_org',
|
|
117
|
+
display_name: 'Linear org',
|
|
118
|
+
lifecycle_status: 'active',
|
|
119
|
+
capabilities: [],
|
|
120
|
+
created_at: '2026-01-01T00:00:00.000Z',
|
|
121
|
+
updated_at: '2026-01-01T00:00:00.000Z',
|
|
122
|
+
},
|
|
123
|
+
),
|
|
105
124
|
);
|
|
106
125
|
});
|
|
107
126
|
configureApiClient({baseUrl: 'https://api.example.test', fetchImpl});
|
|
108
127
|
|
|
109
|
-
await createLinearInstall({
|
|
128
|
+
const install = await createLinearInstall({
|
|
129
|
+
workspace_id: '11111111-1111-4111-8111-111111111111',
|
|
130
|
+
});
|
|
110
131
|
await completeLinearCallback({
|
|
111
132
|
query: {code: 'grant code', state: 'signed state'},
|
|
112
133
|
token: 'session-token',
|
|
@@ -124,6 +145,7 @@ describe('Linear transport', () => {
|
|
|
124
145
|
expect(await requests[0]?.json()).toEqual({
|
|
125
146
|
workspace_id: '11111111-1111-4111-8111-111111111111',
|
|
126
147
|
});
|
|
148
|
+
expect(install).toEqual({installUrl: 'https://linear.example.test/install'});
|
|
127
149
|
expect(requests[1]?.url).toBe(
|
|
128
150
|
'https://api.example.test/integrations/linear/callback/api?code=grant+code&state=signed+state',
|
|
129
151
|
);
|
|
@@ -1,41 +1,71 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
IntegrationCapabilityDto,
|
|
3
|
-
IntegrationConnectionDto,
|
|
4
|
-
ListIntegrationConnectionsResponseDto,
|
|
5
|
-
ListIntegrationProvidersResponseDto,
|
|
6
|
-
ListRepositoriesResponseDto,
|
|
7
3
|
UpdateIntegrationConnectionBodyDto,
|
|
8
4
|
} from '@shipfox/api-integration-core-dto';
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
import {
|
|
6
|
+
integrationConnectionDtoSchema,
|
|
7
|
+
listIntegrationConnectionsResponseSchema,
|
|
8
|
+
listIntegrationProvidersResponseSchema,
|
|
9
|
+
listRepositoriesResponseSchema,
|
|
10
|
+
} from '@shipfox/api-integration-core-dto';
|
|
11
|
+
import type {CreateGiteaConnectionBodyDto} from '@shipfox/api-integration-gitea-dto';
|
|
12
|
+
import {createGiteaConnectionResponseSchema} from '@shipfox/api-integration-gitea-dto';
|
|
13
|
+
import type {CreateGithubInstallBodyDto} from '@shipfox/api-integration-github-dto';
|
|
14
|
+
import {
|
|
15
|
+
createGithubInstallResponseSchema,
|
|
16
|
+
githubCallbackResponseSchema,
|
|
16
17
|
} from '@shipfox/api-integration-github-dto';
|
|
17
18
|
import type {
|
|
18
19
|
CreateLinearInstallBodyDto,
|
|
19
|
-
CreateLinearInstallResponseDto,
|
|
20
20
|
LinearCallbackQueryDto,
|
|
21
|
-
|
|
21
|
+
} from '@shipfox/api-integration-linear-dto';
|
|
22
|
+
import {
|
|
23
|
+
createLinearInstallResponseSchema,
|
|
24
|
+
linearCallbackResponseSchema,
|
|
22
25
|
} from '@shipfox/api-integration-linear-dto';
|
|
23
26
|
import type {
|
|
24
27
|
CreateSentryInstallBodyDto,
|
|
25
|
-
CreateSentryInstallResponseDto,
|
|
26
28
|
SentryConnectBodyDto,
|
|
27
|
-
|
|
29
|
+
} from '@shipfox/api-integration-sentry-dto';
|
|
30
|
+
import {
|
|
31
|
+
createSentryInstallResponseSchema,
|
|
32
|
+
sentryConnectResponseSchema,
|
|
28
33
|
} from '@shipfox/api-integration-sentry-dto';
|
|
29
34
|
import type {
|
|
30
35
|
CreateSlackInstallBodyDto,
|
|
31
|
-
CreateSlackInstallResponseDto,
|
|
32
36
|
SlackCallbackQueryDto,
|
|
33
|
-
SlackCallbackResponseDto,
|
|
34
37
|
} from '@shipfox/api-integration-slack-dto';
|
|
35
|
-
import {
|
|
36
|
-
|
|
38
|
+
import {
|
|
39
|
+
createSlackInstallResponseSchema,
|
|
40
|
+
slackCallbackResponseSchema,
|
|
41
|
+
} from '@shipfox/api-integration-slack-dto';
|
|
42
|
+
import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';
|
|
43
|
+
import {
|
|
44
|
+
type FetchQueryOptions,
|
|
45
|
+
type InfiniteData,
|
|
46
|
+
infiniteQueryOptions,
|
|
47
|
+
queryOptions,
|
|
48
|
+
type UseInfiniteQueryOptions,
|
|
49
|
+
useInfiniteQuery,
|
|
50
|
+
useMutation,
|
|
51
|
+
useQuery,
|
|
52
|
+
useQueryClient,
|
|
53
|
+
} from '@tanstack/react-query';
|
|
54
|
+
import {
|
|
55
|
+
type InstallRedirect,
|
|
56
|
+
type IntegrationConnection,
|
|
57
|
+
type IntegrationProvider,
|
|
58
|
+
isUsableConnection,
|
|
59
|
+
type RepositoryPage,
|
|
60
|
+
} from '#core/models.js';
|
|
37
61
|
import {serializeLinearCallbackQuery} from '#linear-callback.js';
|
|
38
62
|
import {serializeSlackCallbackQuery} from '#slack-callback.js';
|
|
63
|
+
import {
|
|
64
|
+
toInstallRedirect,
|
|
65
|
+
toIntegrationConnection,
|
|
66
|
+
toIntegrationProvider,
|
|
67
|
+
toRepository,
|
|
68
|
+
} from './integration-mapper.js';
|
|
39
69
|
|
|
40
70
|
export const integrationsQueryKeys = {
|
|
41
71
|
all: ['integrations'] as const,
|
|
@@ -54,18 +84,62 @@ export const integrationsQueryKeys = {
|
|
|
54
84
|
[...integrationsQueryKeys.all, 'repositories', connectionId, search] as const,
|
|
55
85
|
};
|
|
56
86
|
|
|
87
|
+
type SourceConnectionsQueryKey =
|
|
88
|
+
| ReturnType<typeof integrationsQueryKeys.sourceConnections>
|
|
89
|
+
| readonly ['integrations', 'source-connections'];
|
|
90
|
+
|
|
91
|
+
type SourceConnectionsQueryOptions = FetchQueryOptions<
|
|
92
|
+
IntegrationConnection[],
|
|
93
|
+
Error,
|
|
94
|
+
IntegrationConnection[],
|
|
95
|
+
SourceConnectionsQueryKey
|
|
96
|
+
>;
|
|
97
|
+
|
|
98
|
+
type ProvidersQueryKey = ReturnType<typeof integrationsQueryKeys.providers>;
|
|
99
|
+
|
|
100
|
+
type ProvidersQueryOptions = FetchQueryOptions<
|
|
101
|
+
IntegrationProvider[],
|
|
102
|
+
Error,
|
|
103
|
+
IntegrationProvider[],
|
|
104
|
+
ProvidersQueryKey
|
|
105
|
+
>;
|
|
106
|
+
|
|
107
|
+
type ConnectionsQueryKey =
|
|
108
|
+
| ReturnType<typeof integrationsQueryKeys.connections>
|
|
109
|
+
| readonly ['integrations', 'connections'];
|
|
110
|
+
|
|
111
|
+
type ConnectionsQueryOptions = FetchQueryOptions<
|
|
112
|
+
IntegrationConnection[],
|
|
113
|
+
Error,
|
|
114
|
+
IntegrationConnection[],
|
|
115
|
+
ConnectionsQueryKey
|
|
116
|
+
>;
|
|
117
|
+
|
|
118
|
+
type RepositoriesQueryKey =
|
|
119
|
+
| ReturnType<typeof integrationsQueryKeys.repositories>
|
|
120
|
+
| readonly ['integrations', 'repositories'];
|
|
121
|
+
|
|
122
|
+
type RepositoriesInfiniteQueryOptions = UseInfiniteQueryOptions<
|
|
123
|
+
RepositoryPage,
|
|
124
|
+
Error,
|
|
125
|
+
InfiniteData<RepositoryPage, string | undefined>,
|
|
126
|
+
RepositoriesQueryKey,
|
|
127
|
+
string | undefined
|
|
128
|
+
>;
|
|
129
|
+
|
|
57
130
|
export async function listIntegrationProviders({
|
|
58
131
|
capability,
|
|
59
132
|
signal,
|
|
60
133
|
}: {
|
|
61
134
|
capability?: IntegrationCapabilityDto;
|
|
62
135
|
signal?: AbortSignal;
|
|
63
|
-
}) {
|
|
136
|
+
}): Promise<IntegrationProvider[]> {
|
|
64
137
|
const search = new URLSearchParams();
|
|
65
138
|
if (capability) search.set('capability', capability);
|
|
66
139
|
const query = search.toString();
|
|
67
140
|
const path = query ? `/integration-providers?${query}` : '/integration-providers';
|
|
68
|
-
|
|
141
|
+
const response = await checkedApiRequest(listIntegrationProvidersResponseSchema, path, {signal});
|
|
142
|
+
return response.providers.map(toIntegrationProvider);
|
|
69
143
|
}
|
|
70
144
|
|
|
71
145
|
export async function listIntegrationConnections({
|
|
@@ -76,13 +150,15 @@ export async function listIntegrationConnections({
|
|
|
76
150
|
workspaceId: string;
|
|
77
151
|
capability?: IntegrationCapabilityDto | undefined;
|
|
78
152
|
signal?: AbortSignal | undefined;
|
|
79
|
-
}) {
|
|
153
|
+
}): Promise<IntegrationConnection[]> {
|
|
80
154
|
const search = new URLSearchParams({workspace_id: workspaceId});
|
|
81
155
|
if (capability) search.set('capability', capability);
|
|
82
|
-
|
|
156
|
+
const response = await checkedApiRequest(
|
|
157
|
+
listIntegrationConnectionsResponseSchema,
|
|
83
158
|
`/integration-connections?${search.toString()}`,
|
|
84
159
|
{signal},
|
|
85
160
|
);
|
|
161
|
+
return response.connections.map(toIntegrationConnection);
|
|
86
162
|
}
|
|
87
163
|
|
|
88
164
|
export async function listSourceConnections({
|
|
@@ -91,8 +167,8 @@ export async function listSourceConnections({
|
|
|
91
167
|
}: {
|
|
92
168
|
workspaceId: string;
|
|
93
169
|
signal?: AbortSignal;
|
|
94
|
-
}) {
|
|
95
|
-
const
|
|
170
|
+
}): Promise<IntegrationConnection[]> {
|
|
171
|
+
const connections = await listIntegrationConnections({
|
|
96
172
|
workspaceId,
|
|
97
173
|
capability: 'source_control',
|
|
98
174
|
signal,
|
|
@@ -100,47 +176,100 @@ export async function listSourceConnections({
|
|
|
100
176
|
// The endpoint returns every lifecycle status (the settings hub needs that),
|
|
101
177
|
// but source-control consumers (onboarding redirect, project creation) only
|
|
102
178
|
// act on usable connections — a disabled/error one must read as "not there".
|
|
103
|
-
return
|
|
104
|
-
...result,
|
|
105
|
-
connections: result.connections.filter(
|
|
106
|
-
(connection) => connection.lifecycle_status === 'active',
|
|
107
|
-
),
|
|
108
|
-
};
|
|
179
|
+
return connections.filter(isUsableConnection);
|
|
109
180
|
}
|
|
110
181
|
|
|
111
|
-
export
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
182
|
+
export function sourceConnectionsQueryOptions(
|
|
183
|
+
workspaceId: string | undefined,
|
|
184
|
+
): SourceConnectionsQueryOptions {
|
|
185
|
+
return queryOptions({
|
|
186
|
+
queryKey: workspaceId
|
|
187
|
+
? integrationsQueryKeys.sourceConnections(workspaceId)
|
|
188
|
+
: ([...integrationsQueryKeys.all, 'source-connections'] as const),
|
|
189
|
+
enabled: Boolean(workspaceId),
|
|
190
|
+
queryFn: ({signal}) => listSourceConnections({workspaceId: workspaceId ?? '', signal}),
|
|
115
191
|
});
|
|
116
192
|
}
|
|
117
193
|
|
|
118
|
-
export async function
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
194
|
+
export async function createGiteaConnection(
|
|
195
|
+
body: CreateGiteaConnectionBodyDto,
|
|
196
|
+
): Promise<IntegrationConnection> {
|
|
197
|
+
const response = await checkedApiRequest(
|
|
198
|
+
createGiteaConnectionResponseSchema,
|
|
199
|
+
'/integrations/gitea/connections',
|
|
200
|
+
{
|
|
201
|
+
method: 'POST',
|
|
202
|
+
body,
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
return toIntegrationConnection(response);
|
|
123
206
|
}
|
|
124
207
|
|
|
125
|
-
export async function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
208
|
+
export async function createGithubInstall(
|
|
209
|
+
body: CreateGithubInstallBodyDto,
|
|
210
|
+
): Promise<InstallRedirect> {
|
|
211
|
+
return toInstallRedirect(
|
|
212
|
+
await checkedApiRequest(createGithubInstallResponseSchema, '/integrations/github/install', {
|
|
213
|
+
method: 'POST',
|
|
214
|
+
body,
|
|
215
|
+
}),
|
|
216
|
+
);
|
|
130
217
|
}
|
|
131
218
|
|
|
132
|
-
export async function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
219
|
+
export async function completeGithubCallback({
|
|
220
|
+
code,
|
|
221
|
+
installationId,
|
|
222
|
+
state,
|
|
223
|
+
setupAction,
|
|
224
|
+
token,
|
|
225
|
+
}: {
|
|
226
|
+
code: string;
|
|
227
|
+
installationId: number;
|
|
228
|
+
state: string;
|
|
229
|
+
setupAction?: string;
|
|
230
|
+
token: string;
|
|
231
|
+
}): Promise<IntegrationConnection> {
|
|
232
|
+
const query = new URLSearchParams({code, installation_id: String(installationId), state});
|
|
233
|
+
if (setupAction) query.set('setup_action', setupAction);
|
|
234
|
+
const response = await checkedApiRequest(
|
|
235
|
+
githubCallbackResponseSchema,
|
|
236
|
+
`/integrations/github/callback/api?${query.toString()}`,
|
|
237
|
+
{headers: {authorization: `Bearer ${token}`}},
|
|
238
|
+
);
|
|
239
|
+
return toIntegrationConnection(response);
|
|
137
240
|
}
|
|
138
241
|
|
|
139
|
-
export async function
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
242
|
+
export async function createSentryInstall(
|
|
243
|
+
body: CreateSentryInstallBodyDto,
|
|
244
|
+
): Promise<InstallRedirect> {
|
|
245
|
+
return toInstallRedirect(
|
|
246
|
+
await checkedApiRequest(createSentryInstallResponseSchema, '/integrations/sentry/install', {
|
|
247
|
+
method: 'POST',
|
|
248
|
+
body,
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export async function createLinearInstall(
|
|
254
|
+
body: CreateLinearInstallBodyDto,
|
|
255
|
+
): Promise<InstallRedirect> {
|
|
256
|
+
return toInstallRedirect(
|
|
257
|
+
await checkedApiRequest(createLinearInstallResponseSchema, '/integrations/linear/install', {
|
|
258
|
+
method: 'POST',
|
|
259
|
+
body,
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export async function createSlackInstall(
|
|
265
|
+
body: CreateSlackInstallBodyDto,
|
|
266
|
+
): Promise<InstallRedirect> {
|
|
267
|
+
return toInstallRedirect(
|
|
268
|
+
await checkedApiRequest(createSlackInstallResponseSchema, '/integrations/slack/install', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
body,
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
144
273
|
}
|
|
145
274
|
|
|
146
275
|
export async function completeLinearCallback({
|
|
@@ -149,11 +278,13 @@ export async function completeLinearCallback({
|
|
|
149
278
|
}: {
|
|
150
279
|
query: LinearCallbackQueryDto;
|
|
151
280
|
token: string;
|
|
152
|
-
}) {
|
|
153
|
-
|
|
281
|
+
}): Promise<IntegrationConnection> {
|
|
282
|
+
const response = await checkedApiRequest(
|
|
283
|
+
linearCallbackResponseSchema,
|
|
154
284
|
`/integrations/linear/callback/api?${serializeLinearCallbackQuery(query)}`,
|
|
155
285
|
{headers: {authorization: `Bearer ${token}`}},
|
|
156
286
|
);
|
|
287
|
+
return toIntegrationConnection(response);
|
|
157
288
|
}
|
|
158
289
|
|
|
159
290
|
export async function completeSlackCallback({
|
|
@@ -162,21 +293,28 @@ export async function completeSlackCallback({
|
|
|
162
293
|
}: {
|
|
163
294
|
query: SlackCallbackQueryDto;
|
|
164
295
|
token: string;
|
|
165
|
-
}) {
|
|
166
|
-
|
|
296
|
+
}): Promise<IntegrationConnection> {
|
|
297
|
+
const response = await checkedApiRequest(
|
|
298
|
+
slackCallbackResponseSchema,
|
|
167
299
|
`/integrations/slack/callback/api?${serializeSlackCallbackQuery(query)}`,
|
|
168
300
|
{headers: {authorization: `Bearer ${token}`}},
|
|
169
301
|
);
|
|
302
|
+
return toIntegrationConnection(response);
|
|
170
303
|
}
|
|
171
304
|
|
|
172
305
|
// Called from the callback route with an explicit bearer (same as the GitHub
|
|
173
306
|
// callback): the route refreshes auth itself before forwarding the grant code.
|
|
174
307
|
export async function connectSentry({body, token}: {body: SentryConnectBodyDto; token: string}) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
308
|
+
const response = await checkedApiRequest(
|
|
309
|
+
sentryConnectResponseSchema,
|
|
310
|
+
'/integrations/sentry/connect',
|
|
311
|
+
{
|
|
312
|
+
method: 'POST',
|
|
313
|
+
body,
|
|
314
|
+
headers: {authorization: `Bearer ${token}`},
|
|
315
|
+
},
|
|
316
|
+
);
|
|
317
|
+
return toIntegrationConnection(response);
|
|
180
318
|
}
|
|
181
319
|
|
|
182
320
|
export async function listRepositories({
|
|
@@ -189,7 +327,7 @@ export async function listRepositories({
|
|
|
189
327
|
cursor?: string;
|
|
190
328
|
search?: string;
|
|
191
329
|
signal?: AbortSignal;
|
|
192
|
-
}) {
|
|
330
|
+
}): Promise<RepositoryPage> {
|
|
193
331
|
const params = new URLSearchParams();
|
|
194
332
|
if (cursor) params.set('cursor', cursor);
|
|
195
333
|
if (search) params.set('search', search);
|
|
@@ -197,7 +335,11 @@ export async function listRepositories({
|
|
|
197
335
|
const path = query
|
|
198
336
|
? `/integration-connections/${connectionId}/repositories?${query}`
|
|
199
337
|
: `/integration-connections/${connectionId}/repositories`;
|
|
200
|
-
|
|
338
|
+
const response = await checkedApiRequest(listRepositoriesResponseSchema, path, {signal});
|
|
339
|
+
return {
|
|
340
|
+
repositories: response.repositories.map(toRepository),
|
|
341
|
+
...(response.next_cursor == null ? {} : {nextCursor: response.next_cursor}),
|
|
342
|
+
};
|
|
201
343
|
}
|
|
202
344
|
|
|
203
345
|
export async function updateIntegrationConnection({
|
|
@@ -206,56 +348,67 @@ export async function updateIntegrationConnection({
|
|
|
206
348
|
}: {
|
|
207
349
|
connectionId: string;
|
|
208
350
|
body: UpdateIntegrationConnectionBodyDto;
|
|
209
|
-
}) {
|
|
210
|
-
|
|
351
|
+
}): Promise<IntegrationConnection> {
|
|
352
|
+
const response = await checkedApiRequest(
|
|
353
|
+
integrationConnectionDtoSchema,
|
|
211
354
|
`/integration-connections/${encodeURIComponent(connectionId)}`,
|
|
212
355
|
{method: 'PATCH', body},
|
|
213
356
|
);
|
|
357
|
+
return toIntegrationConnection(response);
|
|
214
358
|
}
|
|
215
359
|
|
|
216
360
|
export async function deleteIntegrationConnection({connectionId}: {connectionId: string}) {
|
|
217
|
-
await
|
|
218
|
-
|
|
219
|
-
|
|
361
|
+
await checkedApiRequest(
|
|
362
|
+
emptyResponseSchema,
|
|
363
|
+
`/integration-connections/${encodeURIComponent(connectionId)}`,
|
|
364
|
+
{
|
|
365
|
+
method: 'DELETE',
|
|
366
|
+
},
|
|
367
|
+
);
|
|
220
368
|
}
|
|
221
369
|
|
|
222
370
|
export function useIntegrationProvidersQuery(params?: {capability?: IntegrationCapabilityDto}) {
|
|
223
|
-
|
|
224
|
-
|
|
371
|
+
return useQuery(integrationProvidersQueryOptions(params?.capability));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function integrationProvidersQueryOptions(
|
|
375
|
+
capability?: IntegrationCapabilityDto,
|
|
376
|
+
): ProvidersQueryOptions {
|
|
377
|
+
return queryOptions({
|
|
225
378
|
queryKey: integrationsQueryKeys.providers(capability ?? 'all'),
|
|
226
379
|
queryFn: ({signal}) => listIntegrationProviders(capability ? {capability, signal} : {signal}),
|
|
227
380
|
});
|
|
228
381
|
}
|
|
229
382
|
|
|
230
383
|
export function useSourceConnectionsQuery(workspaceId: string | undefined) {
|
|
231
|
-
return useQuery(
|
|
232
|
-
queryKey: workspaceId
|
|
233
|
-
? integrationsQueryKeys.sourceConnections(workspaceId)
|
|
234
|
-
: [...integrationsQueryKeys.all, 'source-connections'],
|
|
235
|
-
enabled: Boolean(workspaceId),
|
|
236
|
-
queryFn: ({signal}) => listSourceConnections({workspaceId: workspaceId ?? '', signal}),
|
|
237
|
-
});
|
|
384
|
+
return useQuery(sourceConnectionsQueryOptions(workspaceId));
|
|
238
385
|
}
|
|
239
386
|
|
|
240
387
|
export function useIntegrationConnectionsQuery(workspaceId: string | undefined) {
|
|
241
|
-
return useQuery(
|
|
388
|
+
return useQuery(integrationConnectionsQueryOptions(workspaceId));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function integrationConnectionsQueryOptions(
|
|
392
|
+
workspaceId: string | undefined,
|
|
393
|
+
): ConnectionsQueryOptions {
|
|
394
|
+
return queryOptions({
|
|
242
395
|
queryKey: workspaceId
|
|
243
396
|
? integrationsQueryKeys.connections(workspaceId, 'all')
|
|
244
|
-
: [...integrationsQueryKeys.all, 'connections'],
|
|
397
|
+
: ([...integrationsQueryKeys.all, 'connections'] as const),
|
|
245
398
|
enabled: Boolean(workspaceId),
|
|
246
399
|
queryFn: ({signal}) => listIntegrationConnections({workspaceId: workspaceId ?? '', signal}),
|
|
247
400
|
});
|
|
248
401
|
}
|
|
249
402
|
|
|
250
|
-
export function
|
|
403
|
+
export function repositoriesInfiniteQueryOptions(
|
|
251
404
|
connectionId: string | undefined,
|
|
252
405
|
options?: {search?: string},
|
|
253
|
-
) {
|
|
406
|
+
): RepositoriesInfiniteQueryOptions {
|
|
254
407
|
const trimmedSearch = options?.search?.trim() ?? '';
|
|
255
|
-
return
|
|
408
|
+
return infiniteQueryOptions({
|
|
256
409
|
queryKey: connectionId
|
|
257
410
|
? integrationsQueryKeys.repositories(connectionId, trimmedSearch)
|
|
258
|
-
: [...integrationsQueryKeys.all, 'repositories'],
|
|
411
|
+
: ([...integrationsQueryKeys.all, 'repositories'] as const),
|
|
259
412
|
enabled: Boolean(connectionId),
|
|
260
413
|
initialPageParam: undefined as string | undefined,
|
|
261
414
|
queryFn: ({pageParam, signal}) => {
|
|
@@ -267,12 +420,28 @@ export function useRepositoriesInfiniteQuery(
|
|
|
267
420
|
if (trimmedSearch) args.search = trimmedSearch;
|
|
268
421
|
return listRepositories(args);
|
|
269
422
|
},
|
|
270
|
-
getNextPageParam: (lastPage) => lastPage.
|
|
423
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
271
424
|
});
|
|
272
425
|
}
|
|
273
426
|
|
|
427
|
+
export function useRepositoriesInfiniteQuery(
|
|
428
|
+
connectionId: string | undefined,
|
|
429
|
+
options?: {search?: string},
|
|
430
|
+
) {
|
|
431
|
+
return useInfiniteQuery(repositoriesInfiniteQueryOptions(connectionId, options));
|
|
432
|
+
}
|
|
433
|
+
|
|
274
434
|
export function useCreateGiteaConnectionMutation() {
|
|
275
|
-
|
|
435
|
+
const queryClient = useQueryClient();
|
|
436
|
+
return useMutation({
|
|
437
|
+
mutationFn: createGiteaConnection,
|
|
438
|
+
onSuccess: async (connection) => {
|
|
439
|
+
await queryClient.invalidateQueries({
|
|
440
|
+
queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspaceId),
|
|
441
|
+
refetchType: 'all',
|
|
442
|
+
});
|
|
443
|
+
},
|
|
444
|
+
});
|
|
276
445
|
}
|
|
277
446
|
|
|
278
447
|
export function useCreateLinearInstallMutation() {
|
|
@@ -297,7 +466,7 @@ export function useUpdateIntegrationConnectionMutation() {
|
|
|
297
466
|
mutationFn: updateIntegrationConnection,
|
|
298
467
|
onSuccess: async (connection) => {
|
|
299
468
|
await queryClient.invalidateQueries({
|
|
300
|
-
queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.
|
|
469
|
+
queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspaceId),
|
|
301
470
|
});
|
|
302
471
|
},
|
|
303
472
|
});
|