Skip to content

Commit 141f1d5

Browse files
committed
iterate
1 parent 26e18b2 commit 141f1d5

File tree

12 files changed

+602
-384
lines changed

12 files changed

+602
-384
lines changed

static/app/components/repositories/scmIntegrationTree/providerConfigLink.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {IconOpen} from 'sentry/icons';
66
import {t} from 'sentry/locale';
77
import type {OrganizationIntegration} from 'sentry/types/integrations';
88

9-
function getProviderConfigUrl(integration: OrganizationIntegration): string | null {
9+
export function getProviderConfigUrl(
10+
integration: OrganizationIntegration
11+
): string | null {
1012
const {externalId, provider, domainName, accountType} = integration;
1113
if (!externalId) {
1214
return null;

static/app/utils/api/apiFetch.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import {useEffect} from 'react';
12
import type {QueryFunctionContext} from '@tanstack/react-query';
23

34
import {parseQueryKey} from 'sentry/utils/api/apiQueryKey';
45
import type {ApiQueryKey, InfiniteApiQueryKey} from 'sentry/utils/api/apiQueryKey';
56
import type {ParsedHeader} from 'sentry/utils/parseLinkHeader';
6-
import {QUERY_API_CLIENT} from 'sentry/utils/queryClient';
7+
import {QUERY_API_CLIENT, type UseInfiniteQueryResult} from 'sentry/utils/queryClient';
78

89
export type ApiResponse<TResponseData = unknown> = {
910
headers: {
@@ -68,3 +69,16 @@ export async function apiFetchInfinite<TQueryFnData = unknown>(
6869
json: json as TQueryFnData,
6970
};
7071
}
72+
73+
export function useFetchAllPages<TQueryFnData = unknown>({
74+
result,
75+
}: {
76+
result: UseInfiniteQueryResult<TQueryFnData, Error>;
77+
}) {
78+
const {fetchNextPage, hasNextPage, isError, isFetchingNextPage} = result;
79+
useEffect(() => {
80+
if (!isError && !isFetchingNextPage && hasNextPage) {
81+
fetchNextPage();
82+
}
83+
}, [hasNextPage, fetchNextPage, isError, isFetchingNextPage]);
84+
}

static/app/views/settings/seer/overview/seerOverview.stories.tsx

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,98 @@
1+
import {Grid} from '@sentry/scraps/layout';
2+
13
import * as Storybook from 'sentry/stories';
2-
import {SeerOverview} from 'sentry/views/settings/seer/overview/seerOverview';
4+
import type {OrganizationIntegration} from 'sentry/types/integrations';
5+
import {
6+
AutofixOverviewSection,
7+
CodeReviewOverviewSection,
8+
SCMOverviewSection,
9+
} from 'sentry/views/settings/seer/overview/seerOverview';
10+
import type {useSeerOverviewData} from 'sentry/views/settings/seer/overview/useSeerOverviewData';
11+
12+
function OrganizationIntegrationsFixture(
13+
params: Partial<OrganizationIntegration> = {}
14+
): OrganizationIntegration {
15+
return {
16+
accountType: '',
17+
gracePeriodEnd: '',
18+
organizationIntegrationStatus: 'active',
19+
domainName: 'github.com',
20+
icon: 'https://secure.gravatar.com/avatar/8b4cb68e40b74c90427d8262256bd1c8',
21+
id: '5',
22+
name: 'NisanthanNanthakumar',
23+
provider: {
24+
aspects: {},
25+
canAdd: true,
26+
canDisable: false,
27+
features: ['commits', 'issue-basic'],
28+
key: 'github',
29+
name: 'Github',
30+
slug: 'github',
31+
},
32+
status: 'active',
33+
configData: null,
34+
configOrganization: [],
35+
externalId: 'ext-integration-1',
36+
organizationId: '1',
37+
...params,
38+
};
39+
}
40+
41+
const seerIntegrationsFixture = [
42+
OrganizationIntegrationsFixture({id: '1', name: 'Integration A'}),
43+
OrganizationIntegrationsFixture({id: '2', name: 'Integration B'}),
44+
];
345

4-
const baseStats = {
46+
const baseStats: ReturnType<typeof useSeerOverviewData>['stats'] = {
547
integrationCount: 2,
48+
scmIntegrationCount: 2,
49+
seerIntegrations: seerIntegrationsFixture,
650
seerIntegrationCount: 2,
751
totalRepoCount: 10,
8-
seerRepoCount: 8,
9-
reposWithSettingsCount: 5,
10-
projectsWithReposCount: 4,
11-
projectsWithAutomationCount: 3,
12-
projectsWithCreatePrCount: 2,
52+
seerRepoCount: 10, // equal to totalRepoCount: no "Add all repos" button
53+
reposWithSettingsCount: 10,
54+
projectsWithReposCount: 6, // equal to totalProjects: no "Handoff all to" CompactSelect
55+
projectsWithAutomationCount: 6,
56+
projectsWithCreatePrCount: 6,
1357
totalProjects: 6,
14-
reposWithCodeReviewCount: 3,
58+
reposWithCodeReviewCount: 10, // equal to seerRepoCount
1559
};
1660

61+
function SeerOverview({
62+
stats,
63+
isLoading,
64+
}: {
65+
isLoading: boolean;
66+
stats: ReturnType<typeof useSeerOverviewData>['stats'];
67+
}) {
68+
return (
69+
<Grid columns="minmax(max-content, 140px) max-content 1fr" gap="xl">
70+
<SCMOverviewSection stats={stats} isLoading={isLoading} />
71+
<AutofixOverviewSection stats={stats} isLoading={isLoading} />
72+
<CodeReviewOverviewSection stats={stats} isLoading={isLoading} />
73+
</Grid>
74+
);
75+
}
76+
1777
export default Storybook.story('SeerOverview', story => {
1878
story('No alerts (healthy state)', () => (
1979
<SeerOverview stats={baseStats} isLoading={false} />
2080
));
2181

22-
story('Loading state (no alerts rendered)', () => (
23-
<SeerOverview stats={baseStats} isLoading />
24-
));
82+
story('Loading state', () => <SeerOverview stats={baseStats} isLoading />);
83+
84+
// SCM stories
2585

2686
story('SCM: No SCM integrations installed', () => (
2787
<SeerOverview
2888
stats={{
2989
...baseStats,
30-
seerIntegrationCount: 0,
3190
integrationCount: 0,
32-
seerRepoCount: 0,
91+
scmIntegrationCount: 0,
92+
seerIntegrations: [],
93+
seerIntegrationCount: 0,
3394
totalRepoCount: 0,
95+
seerRepoCount: 0,
3496
reposWithSettingsCount: 0,
3597
projectsWithReposCount: 0,
3698
projectsWithAutomationCount: 0,
@@ -45,8 +107,8 @@ export default Storybook.story('SeerOverview', story => {
45107
<SeerOverview
46108
stats={{
47109
...baseStats,
48-
seerRepoCount: 0,
49110
totalRepoCount: 0,
111+
seerRepoCount: 0,
50112
reposWithSettingsCount: 0,
51113
projectsWithReposCount: 0,
52114
projectsWithAutomationCount: 0,
@@ -57,12 +119,55 @@ export default Storybook.story('SeerOverview', story => {
57119
/>
58120
));
59121

60-
story('Autofix: projects with Autofix Handoff enabled but no repos', () => (
122+
story('SCM: Some repos not yet added to Seer', () => (
123+
<SeerOverview
124+
stats={{
125+
...baseStats,
126+
totalRepoCount: 10,
127+
seerRepoCount: 6, // seerRepoCount !== totalRepoCount → shows "Add all repos"
128+
reposWithSettingsCount: 6,
129+
projectsWithReposCount: 3,
130+
projectsWithAutomationCount: 2,
131+
projectsWithCreatePrCount: 1,
132+
reposWithCodeReviewCount: 2,
133+
}}
134+
isLoading={false}
135+
/>
136+
));
137+
138+
// Autofix stories
139+
140+
story('Autofix: No projects have repos linked', () => (
141+
<SeerOverview
142+
stats={{
143+
...baseStats,
144+
projectsWithReposCount: 0, // hides header link, CompactSelect, and ButtonBar
145+
projectsWithAutomationCount: 0,
146+
projectsWithCreatePrCount: 0,
147+
}}
148+
isLoading={false}
149+
/>
150+
));
151+
152+
story('Autofix: Some projects with repos (partial)', () => (
153+
<SeerOverview
154+
stats={{
155+
...baseStats,
156+
projectsWithReposCount: 3, // < totalProjects (6) → shows "Handoff all to" CompactSelect
157+
projectsWithAutomationCount: 2,
158+
projectsWithCreatePrCount: 1,
159+
}}
160+
isLoading={false}
161+
/>
162+
));
163+
164+
// Code Review stories
165+
166+
story('Code Review: No repos have code review enabled', () => (
61167
<SeerOverview
62168
stats={{
63169
...baseStats,
64-
projectsWithReposCount: 2,
65-
projectsWithAutomationCount: 5,
170+
reposWithCodeReviewCount: 0, // seerRepoCount > 0 → ButtonBar visible, shows 0/10
66171
}}
67172
isLoading={false}
68173
/>

0 commit comments

Comments
 (0)