Skip to content

Commit c9f65be

Browse files
committed
Use domain model for VariantAnalysisHeader
This will change the VariantAnalysisHeader to take the VariantAnalysis domain model instead of a large amount of props. It also adds the `canceled` status to the `VariantAnalysisStatus` to represent a stopped variant analysis.
1 parent 9c07615 commit c9f65be

7 files changed

Lines changed: 148 additions & 59 deletions

File tree

extensions/ql-vscode/src/remote-queries/shared/variant-analysis.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export enum VariantAnalysisStatus {
3434
InProgress = 'inProgress',
3535
Succeeded = 'succeeded',
3636
Failed = 'failed',
37+
Canceled = 'canceled',
3738
}
3839

3940
export enum VariantAnalysisFailureReason {

extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisHeader.stories.tsx

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import React from 'react';
22

3-
import { ComponentStory, ComponentMeta } from '@storybook/react';
3+
import { ComponentMeta, ComponentStory } from '@storybook/react';
44

55
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
66
import { VariantAnalysisHeader } from '../../view/variant-analysis/VariantAnalysisHeader';
7-
import { VariantAnalysisStatus } from '../../remote-queries/shared/variant-analysis';
7+
import {
8+
VariantAnalysis,
9+
VariantAnalysisQueryLanguage,
10+
VariantAnalysisRepoStatus,
11+
VariantAnalysisScannedRepository,
12+
VariantAnalysisStatus
13+
} from '../../remote-queries/shared/variant-analysis';
814

915
export default {
1016
title: 'Variant Analysis/Variant Analysis Header',
@@ -60,30 +66,75 @@ const Template: ComponentStory<typeof VariantAnalysisHeader> = (args) => (
6066
<VariantAnalysisHeader {...args} />
6167
);
6268

69+
const buildVariantAnalysis = (data: Partial<VariantAnalysis>) => ({
70+
id: 1,
71+
controllerRepoId: 1,
72+
query: {
73+
name: 'Query name',
74+
filePath: 'example.ql',
75+
language: VariantAnalysisQueryLanguage.Javascript,
76+
},
77+
databases: {},
78+
status: VariantAnalysisStatus.InProgress,
79+
...data,
80+
});
81+
82+
const buildScannedRepo = (id: number, data?: Partial<VariantAnalysisScannedRepository>): VariantAnalysisScannedRepository => ({
83+
repository: {
84+
id: id,
85+
fullName: `octodemo/hello-world-${id}`,
86+
private: false,
87+
},
88+
analysisStatus: VariantAnalysisRepoStatus.Pending,
89+
...data,
90+
});
91+
6392
export const InProgress = Template.bind({});
6493
InProgress.args = {
65-
queryName: 'Query name',
66-
queryFileName: 'example.ql',
67-
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
68-
totalRepositoryCount: 10,
69-
completedRepositoryCount: 2,
70-
resultCount: 99_999,
94+
variantAnalysis: buildVariantAnalysis({
95+
scannedRepos: [
96+
buildScannedRepo(1, {
97+
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
98+
resultCount: 99_999,
99+
}),
100+
buildScannedRepo(2, {
101+
analysisStatus: VariantAnalysisRepoStatus.Failed,
102+
}),
103+
buildScannedRepo(3, {
104+
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
105+
resultCount: 0,
106+
}),
107+
buildScannedRepo(4),
108+
buildScannedRepo(5),
109+
buildScannedRepo(6),
110+
buildScannedRepo(7),
111+
buildScannedRepo(8),
112+
buildScannedRepo(9),
113+
buildScannedRepo(10),
114+
]
115+
}),
71116
};
72117

73118
export const Succeeded = Template.bind({});
74119
Succeeded.args = {
75120
...InProgress.args,
76-
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
77-
totalRepositoryCount: 1000,
78-
completedRepositoryCount: 1000,
121+
variantAnalysis: buildVariantAnalysis({
122+
status: VariantAnalysisStatus.Succeeded,
123+
scannedRepos: Array.from({ length: 1000 }, (_, i) => buildScannedRepo(i + 1, {
124+
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
125+
resultCount: 100,
126+
}))
127+
}),
79128
duration: 720_000,
80129
completedAt: new Date(1661263446000),
81130
};
82131

83132
export const Failed = Template.bind({});
84133
Failed.args = {
85134
...InProgress.args,
86-
variantAnalysisStatus: VariantAnalysisStatus.Failed,
135+
variantAnalysis: buildVariantAnalysis({
136+
status: VariantAnalysisStatus.Failed,
137+
}),
87138
duration: 10_000,
88139
completedAt: new Date(1661263446000),
89140
};

extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisStats.stories.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Started.args = {
4646
export const StartedWithWarnings = Template.bind({});
4747
StartedWithWarnings.args = {
4848
...Starting.args,
49-
queryResult: 'warning',
49+
hasWarnings: true,
5050
};
5151

5252
export const Succeeded = Template.bind({});
@@ -64,7 +64,7 @@ SucceededWithWarnings.args = {
6464
...Succeeded.args,
6565
totalRepositoryCount: 10,
6666
completedRepositoryCount: 2,
67-
queryResult: 'warning',
67+
hasWarnings: true,
6868
};
6969

7070
export const Failed = Template.bind({});
@@ -78,5 +78,5 @@ Failed.args = {
7878
export const Stopped = Template.bind({});
7979
Stopped.args = {
8080
...SucceededWithWarnings.args,
81-
queryResult: 'stopped',
81+
variantAnalysisStatus: VariantAnalysisStatus.Canceled,
8282
};

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import * as React from 'react';
2+
import { useMemo } from 'react';
23
import styled from 'styled-components';
3-
import { VariantAnalysisStatus } from '../../remote-queries/shared/variant-analysis';
4+
import { VariantAnalysis, VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis';
45
import { QueryDetails } from './QueryDetails';
56
import { VariantAnalysisActions } from './VariantAnalysisActions';
67
import { VariantAnalysisStats } from './VariantAnalysisStats';
78

89
export type VariantAnalysisHeaderProps = {
9-
queryName: string;
10-
queryFileName: string;
11-
variantAnalysisStatus: VariantAnalysisStatus;
10+
variantAnalysis: VariantAnalysis;
1211

13-
totalRepositoryCount: number;
14-
completedRepositoryCount?: number | undefined;
15-
16-
queryResult?: 'warning' | 'stopped';
17-
18-
resultCount?: number | undefined;
1912
duration?: number | undefined;
2013
completedAt?: Date | undefined;
2114

@@ -42,44 +35,65 @@ const Row = styled.div`
4235
`;
4336

4437
export const VariantAnalysisHeader = ({
45-
queryName,
46-
queryFileName,
47-
totalRepositoryCount,
48-
completedRepositoryCount,
49-
queryResult,
50-
resultCount,
38+
variantAnalysis,
5139
duration,
5240
completedAt,
53-
variantAnalysisStatus,
5441
onOpenQueryFileClick,
5542
onViewQueryTextClick,
5643
onStopQueryClick,
5744
onCopyRepositoryListClick,
5845
onExportResultsClick,
5946
onViewLogsClick,
6047
}: VariantAnalysisHeaderProps) => {
48+
const totalRepositoryCount = useMemo(() => {
49+
return variantAnalysis.scannedRepos?.length ?? 0;
50+
}, [variantAnalysis.scannedRepos]);
51+
const completedRepositoryCount = useMemo(() => {
52+
return variantAnalysis.scannedRepos?.filter(repo => [
53+
// All states that indicates the repository has been scanned and cannot
54+
// change status anymore.
55+
VariantAnalysisRepoStatus.Succeeded, VariantAnalysisRepoStatus.Failed,
56+
VariantAnalysisRepoStatus.Canceled, VariantAnalysisRepoStatus.TimedOut,
57+
].includes(repo.analysisStatus))?.length ?? 0;
58+
}, [variantAnalysis.scannedRepos]);
59+
const resultCount = useMemo(() => {
60+
const reposWithResultCounts = variantAnalysis.scannedRepos?.filter(repo => repo.resultCount !== undefined);
61+
if (reposWithResultCounts === undefined || reposWithResultCounts.length === 0) {
62+
return undefined;
63+
}
64+
65+
return reposWithResultCounts.map(repo => repo.resultCount ?? 0).reduce((a, b) => a + b, 0);
66+
}, [variantAnalysis.scannedRepos]);
67+
const hasSkippedRepos = useMemo(() => {
68+
if (!variantAnalysis.skippedRepos) {
69+
return false;
70+
}
71+
72+
return Object.values(variantAnalysis.skippedRepos).some(skippedRepos => skippedRepos.length > 0);
73+
}, [variantAnalysis.skippedRepos]);
74+
6175
return (
6276
<Container>
6377
<Row>
6478
<QueryDetails
65-
queryName={queryName}
66-
queryFileName={queryFileName}
79+
queryName={variantAnalysis.query.name}
80+
queryFileName={variantAnalysis.query.filePath}
6781
onOpenQueryFileClick={onOpenQueryFileClick}
6882
onViewQueryTextClick={onViewQueryTextClick}
6983
/>
7084
<VariantAnalysisActions
71-
variantAnalysisStatus={variantAnalysisStatus}
85+
variantAnalysisStatus={variantAnalysis.status}
7286
onStopQueryClick={onStopQueryClick}
7387
onCopyRepositoryListClick={onCopyRepositoryListClick}
7488
onExportResultsClick={onExportResultsClick}
7589
/>
7690
</Row>
7791
<VariantAnalysisStats
78-
variantAnalysisStatus={variantAnalysisStatus}
92+
variantAnalysisStatus={variantAnalysis.status}
7993
totalRepositoryCount={totalRepositoryCount}
8094
completedRepositoryCount={completedRepositoryCount}
81-
queryResult={queryResult}
8295
resultCount={resultCount}
96+
hasWarnings={hasSkippedRepos}
8397
duration={duration}
8498
completedAt={completedAt}
8599
onViewLogsClick={onViewLogsClick}

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisRepositoriesStats.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ type Props = {
99
totalRepositoryCount: number;
1010
completedRepositoryCount?: number | undefined;
1111

12-
queryResult?: 'warning' | 'stopped';
12+
showWarning?: boolean;
1313
};
1414

1515
export const VariantAnalysisRepositoriesStats = ({
1616
variantAnalysisStatus,
1717
totalRepositoryCount,
1818
completedRepositoryCount = 0,
19-
queryResult,
19+
showWarning,
2020
}: Props) => {
2121
if (variantAnalysisStatus === VariantAnalysisStatus.Failed) {
2222
return (
@@ -29,8 +29,8 @@ export const VariantAnalysisRepositoriesStats = ({
2929
return (
3030
<>
3131
{formatDecimal(completedRepositoryCount)}/{formatDecimal(totalRepositoryCount)}
32-
{queryResult && <><HorizontalSpace size={2} /><WarningIcon /></>}
33-
{!queryResult && variantAnalysisStatus === VariantAnalysisStatus.Succeeded &&
32+
{showWarning && <><HorizontalSpace size={2} /><WarningIcon /></>}
33+
{!showWarning && variantAnalysisStatus === VariantAnalysisStatus.Succeeded &&
3434
<><HorizontalSpace size={2} /><SuccessIcon label="Completed" /></>}
3535
</>
3636
);

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisStats.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type VariantAnalysisStatsProps = {
1414
totalRepositoryCount: number;
1515
completedRepositoryCount?: number | undefined;
1616

17-
queryResult?: 'warning' | 'stopped';
17+
hasWarnings?: boolean;
1818

1919
resultCount?: number | undefined;
2020
duration?: number | undefined;
@@ -33,7 +33,7 @@ export const VariantAnalysisStats = ({
3333
variantAnalysisStatus,
3434
totalRepositoryCount,
3535
completedRepositoryCount = 0,
36-
queryResult,
36+
hasWarnings,
3737
resultCount,
3838
duration,
3939
completedAt,
@@ -48,16 +48,16 @@ export const VariantAnalysisStats = ({
4848
return 'Failed';
4949
}
5050

51-
if (queryResult === 'warning') {
52-
return 'Succeeded warnings';
51+
if (variantAnalysisStatus === VariantAnalysisStatus.Canceled) {
52+
return 'Stopped';
5353
}
5454

55-
if (queryResult === 'stopped') {
56-
return 'Stopped';
55+
if (variantAnalysisStatus === VariantAnalysisStatus.Succeeded && hasWarnings) {
56+
return 'Succeeded warnings';
5757
}
5858

5959
return 'Succeeded';
60-
}, [variantAnalysisStatus, queryResult]);
60+
}, [variantAnalysisStatus]);
6161

6262
return (
6363
<Row>
@@ -69,7 +69,7 @@ export const VariantAnalysisStats = ({
6969
variantAnalysisStatus={variantAnalysisStatus}
7070
totalRepositoryCount={totalRepositoryCount}
7171
completedRepositoryCount={completedRepositoryCount}
72-
queryResult={queryResult}
72+
showWarning={hasWarnings}
7373
/>
7474
</StatItem>
7575
<StatItem title="Duration">

extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisStats.spec.tsx

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,8 @@ describe(VariantAnalysisStats.name, () => {
3939
expect(screen.getByText('654,321/123,456')).toBeInTheDocument();
4040
});
4141

42-
it('renders a warning icon when the query result is a warning', () => {
43-
render({ queryResult: 'warning' });
44-
45-
expect(screen.getByRole('img', {
46-
name: 'Warning',
47-
})).toBeInTheDocument();
48-
});
49-
50-
it('renders a warning icon when the query result is stopped', () => {
51-
render({ queryResult: 'stopped' });
42+
it('renders a warning icon when has warnings is set', () => {
43+
render({ hasWarnings: true });
5244

5345
expect(screen.getByRole('img', {
5446
name: 'Warning',
@@ -77,4 +69,35 @@ describe(VariantAnalysisStats.name, () => {
7769
userEvent.click(screen.getByText('View logs'));
7870
expect(onViewLogsClick).toHaveBeenCalledTimes(1);
7971
});
72+
73+
it('renders a running text when the variant analysis status is in progress', () => {
74+
render({ variantAnalysisStatus: VariantAnalysisStatus.InProgress });
75+
76+
expect(screen.getByText('Running')).toBeInTheDocument();
77+
});
78+
79+
it('renders a failed text when the variant analysis status is failed', () => {
80+
render({ variantAnalysisStatus: VariantAnalysisStatus.Failed });
81+
82+
expect(screen.getByText('Failed')).toBeInTheDocument();
83+
});
84+
85+
it('renders a stopped text when the variant analysis status is canceled', () => {
86+
render({ variantAnalysisStatus: VariantAnalysisStatus.Canceled });
87+
88+
expect(screen.getByText('Stopped')).toBeInTheDocument();
89+
});
90+
91+
it('renders a succeeded warnings text when the variant analysis status is succeeded and has warnings', () => {
92+
render({ variantAnalysisStatus: VariantAnalysisStatus.Succeeded, hasWarnings: true });
93+
94+
expect(screen.getByText('Succeeded warnings')).toBeInTheDocument();
95+
});
96+
97+
it('renders a succeeded text when the variant analysis status is succeeded', () => {
98+
render({ variantAnalysisStatus: VariantAnalysisStatus.Succeeded });
99+
100+
expect(screen.getByText('Succeeded')).toBeInTheDocument();
101+
expect(screen.queryByText('Succeeded warnings')).not.toBeInTheDocument();
102+
});
80103
});

0 commit comments

Comments
 (0)