Skip to content

Commit d370194

Browse files
committed
Add outcome panels
This creates the component for showing the outcome panels. It does not implement the content of each individual panel; it only implements the tabs, panel views, and the general warnings.
1 parent 43bcd69 commit d370194

7 files changed

Lines changed: 526 additions & 1 deletion

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: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import {
88
} from '../../remote-queries/shared/variant-analysis';
99
import { VariantAnalysisContainer } from './VariantAnalysisContainer';
1010
import { VariantAnalysisHeader } from './VariantAnalysisHeader';
11+
import { VariantAnalysisOutcomePanels } from './VariantAnalysisOutcomePanels';
1112

1213
const variantAnalysis: VariantAnalysisDomainModel = {
1314
id: 1,
1415
controllerRepoId: 1,
16+
actionsWorkflowRunId: 789263,
1517
query: {
1618
name: 'Example query',
1719
filePath: 'example.ql',
@@ -100,7 +102,59 @@ const variantAnalysis: VariantAnalysisDomainModel = {
100102
},
101103
analysisStatus: VariantAnalysisRepoStatus.Pending,
102104
},
103-
]
105+
],
106+
skippedRepos: {
107+
notFoundRepos: {
108+
repositoryCount: 2,
109+
repositories: [
110+
{
111+
fullName: 'octodemo/hello-globe'
112+
},
113+
{
114+
fullName: 'octodemo/hello-planet'
115+
}
116+
]
117+
},
118+
noCodeqlDbRepos: {
119+
repositoryCount: 4,
120+
repositories: [
121+
{
122+
id: 100,
123+
fullName: 'octodemo/no-db-1'
124+
},
125+
{
126+
id: 101,
127+
fullName: 'octodemo/no-db-2'
128+
},
129+
{
130+
id: 102,
131+
fullName: 'octodemo/no-db-3'
132+
},
133+
{
134+
id: 103,
135+
fullName: 'octodemo/no-db-4'
136+
}
137+
]
138+
},
139+
overLimitRepos: {
140+
repositoryCount: 1,
141+
repositories: [
142+
{
143+
id: 201,
144+
fullName: 'octodemo/over-limit-1'
145+
}
146+
]
147+
},
148+
accessMismatchRepos: {
149+
repositoryCount: 1,
150+
repositories: [
151+
{
152+
id: 205,
153+
fullName: 'octodemo/private'
154+
}
155+
]
156+
}
157+
},
104158
};
105159

106160
export function VariantAnalysis(): JSX.Element {
@@ -115,6 +169,7 @@ export function VariantAnalysis(): JSX.Element {
115169
onExportResultsClick={() => console.log('Export results')}
116170
onViewLogsClick={() => console.log('View logs')}
117171
/>
172+
<VariantAnalysisOutcomePanels variantAnalysis={variantAnalysis} />
118173
</VariantAnalysisContainer>
119174
);
120175
}
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)