Skip to content

Commit 110d930

Browse files
authored
Merge pull request #1543 from github/koesie10/outcome-panel
Add outcome panels
2 parents 0b638b6 + f408418 commit 110d930

7 files changed

Lines changed: 537 additions & 11 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import React from 'react';
2+
3+
import { ComponentMeta, ComponentStory } from '@storybook/react';
4+
5+
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
6+
import { VariantAnalysisOutcomePanels } from '../../view/variant-analysis/VariantAnalysisOutcomePanels';
7+
import {
8+
VariantAnalysis,
9+
VariantAnalysisQueryLanguage,
10+
VariantAnalysisRepoStatus,
11+
VariantAnalysisScannedRepository,
12+
VariantAnalysisStatus
13+
} from '../../remote-queries/shared/variant-analysis';
14+
15+
export default {
16+
title: 'Variant Analysis/Variant Analysis Outcome Panels',
17+
component: VariantAnalysisOutcomePanels,
18+
decorators: [
19+
(Story) => (
20+
<VariantAnalysisContainer>
21+
<Story />
22+
</VariantAnalysisContainer>
23+
)
24+
],
25+
} as ComponentMeta<typeof VariantAnalysisOutcomePanels>;
26+
27+
const Template: ComponentStory<typeof VariantAnalysisOutcomePanels> = (args) => (
28+
<VariantAnalysisOutcomePanels {...args} />
29+
);
30+
31+
const buildVariantAnalysis = (data: Partial<VariantAnalysis>) => ({
32+
id: 1,
33+
controllerRepoId: 1,
34+
query: {
35+
name: 'Query name',
36+
filePath: 'example.ql',
37+
language: VariantAnalysisQueryLanguage.Javascript,
38+
},
39+
databases: {},
40+
status: VariantAnalysisStatus.InProgress,
41+
...data,
42+
});
43+
44+
const buildScannedRepo = (id: number, data?: Partial<VariantAnalysisScannedRepository>): VariantAnalysisScannedRepository => ({
45+
repository: {
46+
id: id,
47+
fullName: `octodemo/hello-world-${id}`,
48+
private: false,
49+
},
50+
analysisStatus: VariantAnalysisRepoStatus.Pending,
51+
...data,
52+
});
53+
54+
export const WithoutSkippedRepos = Template.bind({});
55+
WithoutSkippedRepos.args = {
56+
variantAnalysis: buildVariantAnalysis({
57+
scannedRepos: [
58+
buildScannedRepo(1, {
59+
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
60+
resultCount: 99_999,
61+
}),
62+
buildScannedRepo(2, {
63+
analysisStatus: VariantAnalysisRepoStatus.Failed,
64+
}),
65+
buildScannedRepo(3, {
66+
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
67+
resultCount: 0,
68+
}),
69+
buildScannedRepo(4),
70+
buildScannedRepo(5),
71+
buildScannedRepo(6),
72+
buildScannedRepo(7),
73+
buildScannedRepo(8),
74+
buildScannedRepo(9),
75+
buildScannedRepo(10),
76+
]
77+
}),
78+
};
79+
80+
export const WithSkippedRepos = Template.bind({});
81+
WithSkippedRepos.args = {
82+
...WithoutSkippedRepos.args,
83+
variantAnalysis: buildVariantAnalysis({
84+
...WithoutSkippedRepos.args.variantAnalysis,
85+
skippedRepos: {
86+
notFoundRepos: {
87+
repositoryCount: 2,
88+
repositories: [
89+
{
90+
fullName: 'octodemo/hello-globe'
91+
},
92+
{
93+
fullName: 'octodemo/hello-planet'
94+
}
95+
]
96+
},
97+
noCodeqlDbRepos: {
98+
repositoryCount: 4,
99+
repositories: [
100+
{
101+
id: 100,
102+
fullName: 'octodemo/no-db-1'
103+
},
104+
{
105+
id: 101,
106+
fullName: 'octodemo/no-db-2'
107+
},
108+
{
109+
id: 102,
110+
fullName: 'octodemo/no-db-3'
111+
},
112+
{
113+
id: 103,
114+
fullName: 'octodemo/no-db-4'
115+
}
116+
]
117+
},
118+
overLimitRepos: {
119+
repositoryCount: 1,
120+
repositories: [
121+
{
122+
id: 201,
123+
fullName: 'octodemo/over-limit-1'
124+
}
125+
]
126+
},
127+
accessMismatchRepos: {
128+
repositoryCount: 1,
129+
repositories: [
130+
{
131+
id: 205,
132+
fullName: 'octodemo/private'
133+
}
134+
]
135+
}
136+
},
137+
}),
138+
};
139+
140+
export const WithOnlyWarningsSkippedRepos = Template.bind({});
141+
WithOnlyWarningsSkippedRepos.args = {
142+
...WithoutSkippedRepos.args,
143+
variantAnalysis: buildVariantAnalysis({
144+
...WithSkippedRepos.args.variantAnalysis,
145+
skippedRepos: {
146+
...WithSkippedRepos.args.variantAnalysis?.skippedRepos,
147+
notFoundRepos: undefined,
148+
noCodeqlDbRepos: undefined,
149+
}
150+
}),
151+
};

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

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@ import {
88
} from '../../remote-queries/shared/variant-analysis';
99
import { VariantAnalysisContainer } from './VariantAnalysisContainer';
1010
import { VariantAnalysisHeader } from './VariantAnalysisHeader';
11+
import { VariantAnalysisOutcomePanels } from './VariantAnalysisOutcomePanels';
1112
import { VariantAnalysisLoading } from './VariantAnalysisLoading';
1213

1314
const variantAnalysis: VariantAnalysisDomainModel = {
1415
id: 1,
1516
controllerRepoId: 1,
17+
actionsWorkflowRunId: 789263,
1618
query: {
1719
name: 'Example query',
1820
filePath: 'example.ql',
1921
language: VariantAnalysisQueryLanguage.Javascript,
2022
},
2123
databases: {},
2224
status: VariantAnalysisStatus.InProgress,
23-
actionsWorkflowRunId: 123,
2425
scannedRepos: [
2526
{
2627
repository: {
@@ -102,7 +103,59 @@ const variantAnalysis: VariantAnalysisDomainModel = {
102103
},
103104
analysisStatus: VariantAnalysisRepoStatus.Pending,
104105
},
105-
]
106+
],
107+
skippedRepos: {
108+
notFoundRepos: {
109+
repositoryCount: 2,
110+
repositories: [
111+
{
112+
fullName: 'octodemo/hello-globe'
113+
},
114+
{
115+
fullName: 'octodemo/hello-planet'
116+
}
117+
]
118+
},
119+
noCodeqlDbRepos: {
120+
repositoryCount: 4,
121+
repositories: [
122+
{
123+
id: 100,
124+
fullName: 'octodemo/no-db-1'
125+
},
126+
{
127+
id: 101,
128+
fullName: 'octodemo/no-db-2'
129+
},
130+
{
131+
id: 102,
132+
fullName: 'octodemo/no-db-3'
133+
},
134+
{
135+
id: 103,
136+
fullName: 'octodemo/no-db-4'
137+
}
138+
]
139+
},
140+
overLimitRepos: {
141+
repositoryCount: 1,
142+
repositories: [
143+
{
144+
id: 201,
145+
fullName: 'octodemo/over-limit-1'
146+
}
147+
]
148+
},
149+
accessMismatchRepos: {
150+
repositoryCount: 1,
151+
repositories: [
152+
{
153+
id: 205,
154+
fullName: 'octodemo/private'
155+
}
156+
]
157+
}
158+
},
106159
};
107160

108161
function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
@@ -111,15 +164,18 @@ function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
111164
}
112165

113166
return (
114-
<VariantAnalysisHeader
115-
variantAnalysis={variantAnalysis}
116-
onOpenQueryFileClick={() => console.log('Open query')}
117-
onViewQueryTextClick={() => console.log('View query')}
118-
onStopQueryClick={() => console.log('Stop query')}
119-
onCopyRepositoryListClick={() => console.log('Copy repository list')}
120-
onExportResultsClick={() => console.log('Export results')}
121-
onViewLogsClick={() => console.log('View logs')}
122-
/>
167+
<>
168+
<VariantAnalysisHeader
169+
variantAnalysis={variantAnalysis}
170+
onOpenQueryFileClick={() => console.log('Open query')}
171+
onViewQueryTextClick={() => console.log('View query')}
172+
onStopQueryClick={() => console.log('Stop query')}
173+
onCopyRepositoryListClick={() => console.log('Copy repository list')}
174+
onExportResultsClick={() => console.log('Export results')}
175+
onViewLogsClick={() => console.log('View logs')}
176+
/>
177+
<VariantAnalysisOutcomePanels variantAnalysis={variantAnalysis} />
178+
</>
123179
);
124180
}
125181

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from 'react';
2+
3+
export const VariantAnalysisAnalyzedRepos = () => {
4+
return <div>This is the analyzed view</div>;
5+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from 'react';
2+
3+
export const VariantAnalysisNoCodeqlDbRepos = () => {
4+
return <div>This is the no database found view</div>;
5+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from 'react';
2+
3+
export const VariantAnalysisNotFoundRepos = () => {
4+
return <div>This is the no access view</div>;
5+
};
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import * as React from 'react';
2+
import styled from 'styled-components';
3+
import { VSCodeBadge, VSCodePanels, VSCodePanelTab, VSCodePanelView } from '@vscode/webview-ui-toolkit/react';
4+
import { formatDecimal } from '../../pure/number';
5+
import { VariantAnalysis } from '../../remote-queries/shared/variant-analysis';
6+
import { VariantAnalysisAnalyzedRepos } from './VariantAnalysisAnalyzedRepos';
7+
import { VariantAnalysisNotFoundRepos } from './VariantAnalysisNotFoundRepos';
8+
import { VariantAnalysisNoCodeqlDbRepos } from './VariantAnalysisNoCodeqlDbRepos';
9+
import { Alert } from '../common';
10+
11+
export type VariantAnalysisOutcomePanelProps = {
12+
variantAnalysis: VariantAnalysis;
13+
};
14+
15+
const Tab = styled(VSCodePanelTab)`
16+
text-transform: uppercase;
17+
`;
18+
19+
const WarningsContainer = styled.div`
20+
display: flex;
21+
flex-direction: column;
22+
gap: 1em;
23+
24+
margin-top: 1em;
25+
26+
> * {
27+
// Add a margin to the last alert, independent of the number of alerts. This will not add a margin when
28+
// there is no warning to ensure we do not have a margin-top AND a margin-bottom.
29+
&:last-child {
30+
margin-bottom: 1em;
31+
}
32+
}
33+
`;
34+
35+
export const VariantAnalysisOutcomePanels = ({
36+
variantAnalysis
37+
}: VariantAnalysisOutcomePanelProps) => {
38+
const noCodeqlDbRepositoryCount = variantAnalysis.skippedRepos?.noCodeqlDbRepos?.repositoryCount ?? 0;
39+
const notFoundRepositoryCount = variantAnalysis.skippedRepos?.notFoundRepos?.repositoryCount ?? 0;
40+
const overLimitRepositoryCount = variantAnalysis.skippedRepos?.overLimitRepos?.repositoryCount ?? 0;
41+
const accessMismatchRepositoryCount = variantAnalysis.skippedRepos?.accessMismatchRepos?.repositoryCount ?? 0;
42+
43+
const warnings = (
44+
<WarningsContainer>
45+
{overLimitRepositoryCount > 0 && (
46+
<Alert
47+
type="warning"
48+
title="Repository limit exceeded"
49+
message={`The number of requested repositories exceeds the maximum number of repositories supported by multi-repository variant analysis. ${overLimitRepositoryCount} ${overLimitRepositoryCount === 1 ? 'repository was' : 'repositories were'} skipped.`}
50+
/>
51+
)}
52+
{accessMismatchRepositoryCount > 0 && (
53+
<Alert
54+
type="warning"
55+
title="Access mismatch"
56+
message={`${accessMismatchRepositoryCount} ${accessMismatchRepositoryCount === 1 ? 'repository is' : 'repositories are'} private, while the controller repository is public. ${accessMismatchRepositoryCount === 1 ? 'This repository was' : 'These repositories were'} skipped.`}
57+
/>
58+
)}
59+
</WarningsContainer>
60+
);
61+
62+
if (noCodeqlDbRepositoryCount === 0 && notFoundRepositoryCount === 0) {
63+
return (
64+
<>
65+
{warnings}
66+
<VariantAnalysisAnalyzedRepos />
67+
</>
68+
);
69+
}
70+
71+
return (
72+
<>
73+
{warnings}
74+
<VSCodePanels>
75+
<Tab>
76+
Analyzed
77+
<VSCodeBadge appearance="secondary">{formatDecimal(variantAnalysis.scannedRepos?.length ?? 0)}</VSCodeBadge>
78+
</Tab>
79+
{notFoundRepositoryCount > 0 && (
80+
<Tab>
81+
No access
82+
<VSCodeBadge appearance="secondary">{formatDecimal(notFoundRepositoryCount)}</VSCodeBadge>
83+
</Tab>
84+
)}
85+
{noCodeqlDbRepositoryCount > 0 && (
86+
<Tab>
87+
No database
88+
<VSCodeBadge appearance="secondary">{formatDecimal(noCodeqlDbRepositoryCount)}</VSCodeBadge>
89+
</Tab>
90+
)}
91+
<VSCodePanelView><VariantAnalysisAnalyzedRepos /></VSCodePanelView>
92+
{notFoundRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNotFoundRepos /></VSCodePanelView>}
93+
{noCodeqlDbRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNoCodeqlDbRepos /></VSCodePanelView>}
94+
</VSCodePanels>
95+
</>
96+
);
97+
};

0 commit comments

Comments
 (0)