@shipfox/client-integrations 5.0.0 → 6.0.2
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 +84 -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 +7 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +10 -9
- 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 +45 -240
- package/dist/hooks/api/integrations.d.ts.map +1 -1
- package/dist/hooks/api/integrations.js +78 -31
- 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 +17 -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/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 +18 -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 +17 -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 +12 -10
- package/src/hooks/api/integration-mapper.ts +64 -0
- package/src/hooks/api/integrations.test.ts +44 -22
- package/src/hooks/api/integrations.ts +229 -84
- package/src/hooks/api/webhook-connections.ts +58 -17
- package/src/index.ts +2 -1
- package/src/linear-callback.ts +24 -16
- package/src/pages/gitea-install-page.tsx +1 -10
- package/src/pages/linear-callback-page.tsx +18 -30
- package/src/pages/linear-install-page.tsx +2 -1
- package/src/pages/sentry-callback-page.test.tsx +5 -1
- 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 -26
- 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/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 +30 -20
- package/src/slack-callback.ts +24 -16
- 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,48 +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 {
|
|
38
|
+
import {
|
|
39
|
+
createSlackInstallResponseSchema,
|
|
40
|
+
slackCallbackResponseSchema,
|
|
41
|
+
} from '@shipfox/api-integration-slack-dto';
|
|
42
|
+
import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';
|
|
36
43
|
import {
|
|
37
44
|
type FetchQueryOptions,
|
|
45
|
+
type InfiniteData,
|
|
46
|
+
infiniteQueryOptions,
|
|
38
47
|
queryOptions,
|
|
48
|
+
type UseInfiniteQueryOptions,
|
|
39
49
|
useInfiniteQuery,
|
|
40
50
|
useMutation,
|
|
41
51
|
useQuery,
|
|
42
52
|
useQueryClient,
|
|
43
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';
|
|
44
61
|
import {serializeLinearCallbackQuery} from '#linear-callback.js';
|
|
45
62
|
import {serializeSlackCallbackQuery} from '#slack-callback.js';
|
|
63
|
+
import {
|
|
64
|
+
toInstallRedirect,
|
|
65
|
+
toIntegrationConnection,
|
|
66
|
+
toIntegrationProvider,
|
|
67
|
+
toRepository,
|
|
68
|
+
} from './integration-mapper.js';
|
|
46
69
|
|
|
47
70
|
export const integrationsQueryKeys = {
|
|
48
71
|
all: ['integrations'] as const,
|
|
@@ -66,24 +89,57 @@ type SourceConnectionsQueryKey =
|
|
|
66
89
|
| readonly ['integrations', 'source-connections'];
|
|
67
90
|
|
|
68
91
|
type SourceConnectionsQueryOptions = FetchQueryOptions<
|
|
69
|
-
|
|
92
|
+
IntegrationConnection[],
|
|
70
93
|
Error,
|
|
71
|
-
|
|
94
|
+
IntegrationConnection[],
|
|
72
95
|
SourceConnectionsQueryKey
|
|
73
96
|
>;
|
|
74
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
|
+
|
|
75
130
|
export async function listIntegrationProviders({
|
|
76
131
|
capability,
|
|
77
132
|
signal,
|
|
78
133
|
}: {
|
|
79
134
|
capability?: IntegrationCapabilityDto;
|
|
80
135
|
signal?: AbortSignal;
|
|
81
|
-
}) {
|
|
136
|
+
}): Promise<IntegrationProvider[]> {
|
|
82
137
|
const search = new URLSearchParams();
|
|
83
138
|
if (capability) search.set('capability', capability);
|
|
84
139
|
const query = search.toString();
|
|
85
140
|
const path = query ? `/integration-providers?${query}` : '/integration-providers';
|
|
86
|
-
|
|
141
|
+
const response = await checkedApiRequest(listIntegrationProvidersResponseSchema, path, {signal});
|
|
142
|
+
return response.providers.map(toIntegrationProvider);
|
|
87
143
|
}
|
|
88
144
|
|
|
89
145
|
export async function listIntegrationConnections({
|
|
@@ -94,13 +150,15 @@ export async function listIntegrationConnections({
|
|
|
94
150
|
workspaceId: string;
|
|
95
151
|
capability?: IntegrationCapabilityDto | undefined;
|
|
96
152
|
signal?: AbortSignal | undefined;
|
|
97
|
-
}) {
|
|
153
|
+
}): Promise<IntegrationConnection[]> {
|
|
98
154
|
const search = new URLSearchParams({workspace_id: workspaceId});
|
|
99
155
|
if (capability) search.set('capability', capability);
|
|
100
|
-
|
|
156
|
+
const response = await checkedApiRequest(
|
|
157
|
+
listIntegrationConnectionsResponseSchema,
|
|
101
158
|
`/integration-connections?${search.toString()}`,
|
|
102
159
|
{signal},
|
|
103
160
|
);
|
|
161
|
+
return response.connections.map(toIntegrationConnection);
|
|
104
162
|
}
|
|
105
163
|
|
|
106
164
|
export async function listSourceConnections({
|
|
@@ -109,8 +167,8 @@ export async function listSourceConnections({
|
|
|
109
167
|
}: {
|
|
110
168
|
workspaceId: string;
|
|
111
169
|
signal?: AbortSignal;
|
|
112
|
-
}) {
|
|
113
|
-
const
|
|
170
|
+
}): Promise<IntegrationConnection[]> {
|
|
171
|
+
const connections = await listIntegrationConnections({
|
|
114
172
|
workspaceId,
|
|
115
173
|
capability: 'source_control',
|
|
116
174
|
signal,
|
|
@@ -118,12 +176,7 @@ export async function listSourceConnections({
|
|
|
118
176
|
// The endpoint returns every lifecycle status (the settings hub needs that),
|
|
119
177
|
// but source-control consumers (onboarding redirect, project creation) only
|
|
120
178
|
// act on usable connections — a disabled/error one must read as "not there".
|
|
121
|
-
return
|
|
122
|
-
...result,
|
|
123
|
-
connections: result.connections.filter(
|
|
124
|
-
(connection) => connection.lifecycle_status === 'active',
|
|
125
|
-
),
|
|
126
|
-
};
|
|
179
|
+
return connections.filter(isUsableConnection);
|
|
127
180
|
}
|
|
128
181
|
|
|
129
182
|
export function sourceConnectionsQueryOptions(
|
|
@@ -138,39 +191,85 @@ export function sourceConnectionsQueryOptions(
|
|
|
138
191
|
});
|
|
139
192
|
}
|
|
140
193
|
|
|
141
|
-
export async function createGiteaConnection(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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);
|
|
146
206
|
}
|
|
147
207
|
|
|
148
|
-
export async function createGithubInstall(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
+
);
|
|
153
217
|
}
|
|
154
218
|
|
|
155
|
-
export async function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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);
|
|
160
240
|
}
|
|
161
241
|
|
|
162
|
-
export async function
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
+
);
|
|
167
251
|
}
|
|
168
252
|
|
|
169
|
-
export async function
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
+
);
|
|
174
273
|
}
|
|
175
274
|
|
|
176
275
|
export async function completeLinearCallback({
|
|
@@ -179,11 +278,13 @@ export async function completeLinearCallback({
|
|
|
179
278
|
}: {
|
|
180
279
|
query: LinearCallbackQueryDto;
|
|
181
280
|
token: string;
|
|
182
|
-
}) {
|
|
183
|
-
|
|
281
|
+
}): Promise<IntegrationConnection> {
|
|
282
|
+
const response = await checkedApiRequest(
|
|
283
|
+
linearCallbackResponseSchema,
|
|
184
284
|
`/integrations/linear/callback/api?${serializeLinearCallbackQuery(query)}`,
|
|
185
285
|
{headers: {authorization: `Bearer ${token}`}},
|
|
186
286
|
);
|
|
287
|
+
return toIntegrationConnection(response);
|
|
187
288
|
}
|
|
188
289
|
|
|
189
290
|
export async function completeSlackCallback({
|
|
@@ -192,21 +293,28 @@ export async function completeSlackCallback({
|
|
|
192
293
|
}: {
|
|
193
294
|
query: SlackCallbackQueryDto;
|
|
194
295
|
token: string;
|
|
195
|
-
}) {
|
|
196
|
-
|
|
296
|
+
}): Promise<IntegrationConnection> {
|
|
297
|
+
const response = await checkedApiRequest(
|
|
298
|
+
slackCallbackResponseSchema,
|
|
197
299
|
`/integrations/slack/callback/api?${serializeSlackCallbackQuery(query)}`,
|
|
198
300
|
{headers: {authorization: `Bearer ${token}`}},
|
|
199
301
|
);
|
|
302
|
+
return toIntegrationConnection(response);
|
|
200
303
|
}
|
|
201
304
|
|
|
202
305
|
// Called from the callback route with an explicit bearer (same as the GitHub
|
|
203
306
|
// callback): the route refreshes auth itself before forwarding the grant code.
|
|
204
307
|
export async function connectSentry({body, token}: {body: SentryConnectBodyDto; token: string}) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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);
|
|
210
318
|
}
|
|
211
319
|
|
|
212
320
|
export async function listRepositories({
|
|
@@ -219,7 +327,7 @@ export async function listRepositories({
|
|
|
219
327
|
cursor?: string;
|
|
220
328
|
search?: string;
|
|
221
329
|
signal?: AbortSignal;
|
|
222
|
-
}) {
|
|
330
|
+
}): Promise<RepositoryPage> {
|
|
223
331
|
const params = new URLSearchParams();
|
|
224
332
|
if (cursor) params.set('cursor', cursor);
|
|
225
333
|
if (search) params.set('search', search);
|
|
@@ -227,7 +335,11 @@ export async function listRepositories({
|
|
|
227
335
|
const path = query
|
|
228
336
|
? `/integration-connections/${connectionId}/repositories?${query}`
|
|
229
337
|
: `/integration-connections/${connectionId}/repositories`;
|
|
230
|
-
|
|
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
|
+
};
|
|
231
343
|
}
|
|
232
344
|
|
|
233
345
|
export async function updateIntegrationConnection({
|
|
@@ -236,22 +348,33 @@ export async function updateIntegrationConnection({
|
|
|
236
348
|
}: {
|
|
237
349
|
connectionId: string;
|
|
238
350
|
body: UpdateIntegrationConnectionBodyDto;
|
|
239
|
-
}) {
|
|
240
|
-
|
|
351
|
+
}): Promise<IntegrationConnection> {
|
|
352
|
+
const response = await checkedApiRequest(
|
|
353
|
+
integrationConnectionDtoSchema,
|
|
241
354
|
`/integration-connections/${encodeURIComponent(connectionId)}`,
|
|
242
355
|
{method: 'PATCH', body},
|
|
243
356
|
);
|
|
357
|
+
return toIntegrationConnection(response);
|
|
244
358
|
}
|
|
245
359
|
|
|
246
360
|
export async function deleteIntegrationConnection({connectionId}: {connectionId: string}) {
|
|
247
|
-
await
|
|
248
|
-
|
|
249
|
-
|
|
361
|
+
await checkedApiRequest(
|
|
362
|
+
emptyResponseSchema,
|
|
363
|
+
`/integration-connections/${encodeURIComponent(connectionId)}`,
|
|
364
|
+
{
|
|
365
|
+
method: 'DELETE',
|
|
366
|
+
},
|
|
367
|
+
);
|
|
250
368
|
}
|
|
251
369
|
|
|
252
370
|
export function useIntegrationProvidersQuery(params?: {capability?: IntegrationCapabilityDto}) {
|
|
253
|
-
|
|
254
|
-
|
|
371
|
+
return useQuery(integrationProvidersQueryOptions(params?.capability));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function integrationProvidersQueryOptions(
|
|
375
|
+
capability?: IntegrationCapabilityDto,
|
|
376
|
+
): ProvidersQueryOptions {
|
|
377
|
+
return queryOptions({
|
|
255
378
|
queryKey: integrationsQueryKeys.providers(capability ?? 'all'),
|
|
256
379
|
queryFn: ({signal}) => listIntegrationProviders(capability ? {capability, signal} : {signal}),
|
|
257
380
|
});
|
|
@@ -262,24 +385,30 @@ export function useSourceConnectionsQuery(workspaceId: string | undefined) {
|
|
|
262
385
|
}
|
|
263
386
|
|
|
264
387
|
export function useIntegrationConnectionsQuery(workspaceId: string | undefined) {
|
|
265
|
-
return useQuery(
|
|
388
|
+
return useQuery(integrationConnectionsQueryOptions(workspaceId));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function integrationConnectionsQueryOptions(
|
|
392
|
+
workspaceId: string | undefined,
|
|
393
|
+
): ConnectionsQueryOptions {
|
|
394
|
+
return queryOptions({
|
|
266
395
|
queryKey: workspaceId
|
|
267
396
|
? integrationsQueryKeys.connections(workspaceId, 'all')
|
|
268
|
-
: [...integrationsQueryKeys.all, 'connections'],
|
|
397
|
+
: ([...integrationsQueryKeys.all, 'connections'] as const),
|
|
269
398
|
enabled: Boolean(workspaceId),
|
|
270
399
|
queryFn: ({signal}) => listIntegrationConnections({workspaceId: workspaceId ?? '', signal}),
|
|
271
400
|
});
|
|
272
401
|
}
|
|
273
402
|
|
|
274
|
-
export function
|
|
403
|
+
export function repositoriesInfiniteQueryOptions(
|
|
275
404
|
connectionId: string | undefined,
|
|
276
405
|
options?: {search?: string},
|
|
277
|
-
) {
|
|
406
|
+
): RepositoriesInfiniteQueryOptions {
|
|
278
407
|
const trimmedSearch = options?.search?.trim() ?? '';
|
|
279
|
-
return
|
|
408
|
+
return infiniteQueryOptions({
|
|
280
409
|
queryKey: connectionId
|
|
281
410
|
? integrationsQueryKeys.repositories(connectionId, trimmedSearch)
|
|
282
|
-
: [...integrationsQueryKeys.all, 'repositories'],
|
|
411
|
+
: ([...integrationsQueryKeys.all, 'repositories'] as const),
|
|
283
412
|
enabled: Boolean(connectionId),
|
|
284
413
|
initialPageParam: undefined as string | undefined,
|
|
285
414
|
queryFn: ({pageParam, signal}) => {
|
|
@@ -291,12 +420,28 @@ export function useRepositoriesInfiniteQuery(
|
|
|
291
420
|
if (trimmedSearch) args.search = trimmedSearch;
|
|
292
421
|
return listRepositories(args);
|
|
293
422
|
},
|
|
294
|
-
getNextPageParam: (lastPage) => lastPage.
|
|
423
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
295
424
|
});
|
|
296
425
|
}
|
|
297
426
|
|
|
427
|
+
export function useRepositoriesInfiniteQuery(
|
|
428
|
+
connectionId: string | undefined,
|
|
429
|
+
options?: {search?: string},
|
|
430
|
+
) {
|
|
431
|
+
return useInfiniteQuery(repositoriesInfiniteQueryOptions(connectionId, options));
|
|
432
|
+
}
|
|
433
|
+
|
|
298
434
|
export function useCreateGiteaConnectionMutation() {
|
|
299
|
-
|
|
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
|
+
});
|
|
300
445
|
}
|
|
301
446
|
|
|
302
447
|
export function useCreateLinearInstallMutation() {
|
|
@@ -321,7 +466,7 @@ export function useUpdateIntegrationConnectionMutation() {
|
|
|
321
466
|
mutationFn: updateIntegrationConnection,
|
|
322
467
|
onSuccess: async (connection) => {
|
|
323
468
|
await queryClient.invalidateQueries({
|
|
324
|
-
queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.
|
|
469
|
+
queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspaceId),
|
|
325
470
|
});
|
|
326
471
|
},
|
|
327
472
|
});
|