Skip to content

Commit 0a6db47

Browse files
Merge pull request #1549 from github/robertbrignull/skipped-repos
Implement skipped repositories tabs
2 parents 2065c7d + 72253a1 commit 0a6db47

11 files changed

+439
-30
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,13 @@ export interface VariantAnalysisSkippedRepositories {
7373

7474
export interface VariantAnalysisSkippedRepositoryGroup {
7575
repositoryCount: number,
76-
repositories: Array<{
77-
id?: number,
78-
fullName: string
79-
}>
76+
repositories: VariantAnalysisSkippedRepository[],
77+
}
78+
79+
export interface VariantAnalysisSkippedRepository {
80+
id?: number,
81+
fullName: string,
82+
private?: boolean,
8083
}
8184

8285
export interface VariantAnalysisScannedRepositoryResult {
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import React from 'react';
2+
3+
import { ComponentMeta, ComponentStory } from '@storybook/react';
4+
5+
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
6+
import { VariantAnalysisSkippedRepositoriesTab } from '../../view/variant-analysis/VariantAnalysisSkippedRepositoriesTab';
7+
8+
export default {
9+
title: 'Variant Analysis/Variant Analysis Skipped Repositories Tab',
10+
component: VariantAnalysisSkippedRepositoriesTab,
11+
decorators: [
12+
(Story) => (
13+
<VariantAnalysisContainer>
14+
<Story />
15+
</VariantAnalysisContainer>
16+
)
17+
],
18+
} as ComponentMeta<typeof VariantAnalysisSkippedRepositoriesTab>;
19+
20+
const Template: ComponentStory<typeof VariantAnalysisSkippedRepositoriesTab> = (args) => (
21+
<VariantAnalysisSkippedRepositoriesTab {...args} />
22+
);
23+
24+
export const NoAccessNoOmissions = Template.bind({});
25+
NoAccessNoOmissions.args = {
26+
alertTitle: 'No access',
27+
alertMessage: 'The following repositories could not be scanned because you do not have read access.',
28+
skippedRepositoryGroup: {
29+
repositoryCount: 2,
30+
repositories: [
31+
{
32+
fullName: 'octodemo/hello-globe',
33+
},
34+
{
35+
fullName: 'octodemo/hello-planet',
36+
},
37+
],
38+
},
39+
};
40+
41+
export const NoAccessWithOmissions = Template.bind({});
42+
NoAccessWithOmissions.args = {
43+
...NoAccessNoOmissions.args,
44+
skippedRepositoryGroup: {
45+
repositoryCount: 12345,
46+
repositories: [
47+
{
48+
fullName: 'octodemo/hello-globe',
49+
},
50+
{
51+
fullName: 'octodemo/hello-planet',
52+
},
53+
{
54+
fullName: 'octodemo/hello-universe',
55+
},
56+
],
57+
},
58+
};
59+
60+
export const NoDatabaseNoOmissions = Template.bind({});
61+
NoDatabaseNoOmissions.args = {
62+
alertTitle: 'No database',
63+
alertMessage: 'The following repositories could not be scanned because they do not have an available CodeQL database.',
64+
skippedRepositoryGroup: {
65+
repositoryCount: 2,
66+
repositories: [
67+
{
68+
id: 1,
69+
fullName: 'octodemo/hello-globe',
70+
private: false,
71+
},
72+
{
73+
id: 2,
74+
fullName: 'octodemo/hello-planet',
75+
private: true,
76+
},
77+
],
78+
},
79+
};
80+
81+
export const NoDatabaseWithOmissions = Template.bind({});
82+
NoDatabaseWithOmissions.args = {
83+
...NoDatabaseNoOmissions.args,
84+
skippedRepositoryGroup: {
85+
repositoryCount: 12345,
86+
repositories: [
87+
{
88+
id: 1,
89+
fullName: 'octodemo/hello-globe',
90+
private: false,
91+
},
92+
{
93+
id: 2,
94+
fullName: 'octodemo/hello-planet',
95+
private: true,
96+
},
97+
{
98+
id: 3,
99+
fullName: 'octodemo/hello-universe',
100+
private: false,
101+
},
102+
],
103+
},
104+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
3+
import { ComponentMeta, ComponentStory } from '@storybook/react';
4+
5+
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
6+
import { VariantAnalysisSkippedRepositoryRow } from '../../view/variant-analysis/VariantAnalysisSkippedRepositoryRow';
7+
8+
export default {
9+
title: 'Variant Analysis/Variant Analysis Skipped Repository',
10+
component: VariantAnalysisSkippedRepositoryRow,
11+
decorators: [
12+
(Story) => (
13+
<VariantAnalysisContainer>
14+
<Story />
15+
</VariantAnalysisContainer>
16+
)
17+
],
18+
} as ComponentMeta<typeof VariantAnalysisSkippedRepositoryRow>;
19+
20+
const Template: ComponentStory<typeof VariantAnalysisSkippedRepositoryRow> = (args) => (
21+
<VariantAnalysisSkippedRepositoryRow {...args} />
22+
);
23+
24+
export const OnlyFullName = Template.bind({});
25+
OnlyFullName.args = {
26+
repository: {
27+
fullName: 'octodemo/hello-globe',
28+
}
29+
};
30+
31+
export const Public = Template.bind({});
32+
Public.args = {
33+
repository: {
34+
fullName: 'octodemo/hello-globe',
35+
private: false,
36+
}
37+
};
38+
39+
export const Private = Template.bind({});
40+
Private.args = {
41+
repository: {
42+
fullName: 'octodemo/hello-globe',
43+
private: true,
44+
}
45+
};

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
106106
],
107107
skippedRepos: {
108108
notFoundRepos: {
109-
repositoryCount: 2,
109+
repositoryCount: 9999,
110110
repositories: [
111111
{
112112
fullName: 'octodemo/hello-globe'
@@ -121,19 +121,23 @@ const variantAnalysis: VariantAnalysisDomainModel = {
121121
repositories: [
122122
{
123123
id: 100,
124-
fullName: 'octodemo/no-db-1'
124+
fullName: 'octodemo/no-db-1',
125+
private: false,
125126
},
126127
{
127128
id: 101,
128-
fullName: 'octodemo/no-db-2'
129+
fullName: 'octodemo/no-db-2',
130+
private: true,
129131
},
130132
{
131133
id: 102,
132-
fullName: 'octodemo/no-db-3'
134+
fullName: 'octodemo/no-db-3',
135+
private: true,
133136
},
134137
{
135138
id: 103,
136-
fullName: 'octodemo/no-db-4'
139+
fullName: 'octodemo/no-db-4',
140+
private: false,
137141
}
138142
]
139143
},

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

Lines changed: 0 additions & 5 deletions
This file was deleted.

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

Lines changed: 0 additions & 5 deletions
This file was deleted.

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { VSCodeBadge, VSCodePanels, VSCodePanelTab, VSCodePanelView } from '@vsc
44
import { formatDecimal } from '../../pure/number';
55
import { VariantAnalysis, VariantAnalysisScannedRepositoryResult } from '../../remote-queries/shared/variant-analysis';
66
import { VariantAnalysisAnalyzedRepos } from './VariantAnalysisAnalyzedRepos';
7-
import { VariantAnalysisNotFoundRepos } from './VariantAnalysisNotFoundRepos';
8-
import { VariantAnalysisNoCodeqlDbRepos } from './VariantAnalysisNoCodeqlDbRepos';
97
import { Alert } from '../common';
8+
import { VariantAnalysisSkippedRepositoriesTab } from './VariantAnalysisSkippedRepositoriesTab';
109

1110
export type VariantAnalysisOutcomePanelProps = {
1211
variantAnalysis: VariantAnalysis;
@@ -37,8 +36,8 @@ export const VariantAnalysisOutcomePanels = ({
3736
variantAnalysis,
3837
repositoryResults,
3938
}: VariantAnalysisOutcomePanelProps) => {
40-
const noCodeqlDbRepositoryCount = variantAnalysis.skippedRepos?.noCodeqlDbRepos?.repositoryCount ?? 0;
41-
const notFoundRepositoryCount = variantAnalysis.skippedRepos?.notFoundRepos?.repositoryCount ?? 0;
39+
const noCodeqlDbRepos = variantAnalysis.skippedRepos?.noCodeqlDbRepos;
40+
const notFoundRepos = variantAnalysis.skippedRepos?.notFoundRepos;
4241
const overLimitRepositoryCount = variantAnalysis.skippedRepos?.overLimitRepos?.repositoryCount ?? 0;
4342
const accessMismatchRepositoryCount = variantAnalysis.skippedRepos?.accessMismatchRepos?.repositoryCount ?? 0;
4443

@@ -61,7 +60,7 @@ export const VariantAnalysisOutcomePanels = ({
6160
</WarningsContainer>
6261
);
6362

64-
if (noCodeqlDbRepositoryCount === 0 && notFoundRepositoryCount === 0) {
63+
if (!noCodeqlDbRepos?.repositoryCount && !notFoundRepos?.repositoryCount) {
6564
return (
6665
<>
6766
{warnings}
@@ -78,21 +77,33 @@ export const VariantAnalysisOutcomePanels = ({
7877
Analyzed
7978
<VSCodeBadge appearance="secondary">{formatDecimal(variantAnalysis.scannedRepos?.length ?? 0)}</VSCodeBadge>
8079
</Tab>
81-
{notFoundRepositoryCount > 0 && (
80+
{notFoundRepos?.repositoryCount && (
8281
<Tab>
8382
No access
84-
<VSCodeBadge appearance="secondary">{formatDecimal(notFoundRepositoryCount)}</VSCodeBadge>
83+
<VSCodeBadge appearance="secondary">{formatDecimal(notFoundRepos.repositoryCount)}</VSCodeBadge>
8584
</Tab>
8685
)}
87-
{noCodeqlDbRepositoryCount > 0 && (
86+
{noCodeqlDbRepos?.repositoryCount && (
8887
<Tab>
8988
No database
90-
<VSCodeBadge appearance="secondary">{formatDecimal(noCodeqlDbRepositoryCount)}</VSCodeBadge>
89+
<VSCodeBadge appearance="secondary">{formatDecimal(noCodeqlDbRepos.repositoryCount)}</VSCodeBadge>
9190
</Tab>
9291
)}
9392
<VSCodePanelView><VariantAnalysisAnalyzedRepos variantAnalysis={variantAnalysis} repositoryResults={repositoryResults} /></VSCodePanelView>
94-
{notFoundRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNotFoundRepos /></VSCodePanelView>}
95-
{noCodeqlDbRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNoCodeqlDbRepos /></VSCodePanelView>}
93+
{notFoundRepos?.repositoryCount &&
94+
<VSCodePanelView>
95+
<VariantAnalysisSkippedRepositoriesTab
96+
alertTitle='No access'
97+
alertMessage='The following repositories could not be scanned because you do not have read access.'
98+
skippedRepositoryGroup={notFoundRepos} />
99+
</VSCodePanelView>}
100+
{noCodeqlDbRepos?.repositoryCount &&
101+
<VSCodePanelView>
102+
<VariantAnalysisSkippedRepositoriesTab
103+
alertTitle='No database'
104+
alertMessage='The following repositories could not be scanned because they do not have an available CodeQL database.'
105+
skippedRepositoryGroup={noCodeqlDbRepos} />
106+
</VSCodePanelView>}
96107
</VSCodePanels>
97108
</>
98109
);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as React from 'react';
2+
import styled from 'styled-components';
3+
import { VariantAnalysisSkippedRepositoryGroup } from '../../remote-queries/shared/variant-analysis';
4+
import { Alert } from '../common';
5+
import { VariantAnalysisSkippedRepositoryRow } from './VariantAnalysisSkippedRepositoryRow';
6+
7+
export type VariantAnalysisSkippedRepositoriesTabProps = {
8+
alertTitle: string,
9+
alertMessage: string,
10+
skippedRepositoryGroup: VariantAnalysisSkippedRepositoryGroup,
11+
};
12+
13+
function getSkipReasonAlert(
14+
title: string,
15+
message: string,
16+
repos: VariantAnalysisSkippedRepositoryGroup
17+
) {
18+
const repositoriesOmittedText = repos.repositoryCount > repos.repositories.length
19+
? ` (Only the first ${repos.repositories.length > 1 ? `${repos.repositories.length} repositories are` : 'repository is'} shown.)`
20+
: '';
21+
return (
22+
<Alert
23+
key='alert'
24+
type='warning'
25+
title={title}
26+
message={message + repositoriesOmittedText}
27+
/>
28+
);
29+
}
30+
31+
const Container = styled.div`
32+
display: flex;
33+
flex-direction: column;
34+
gap: 0.5em;
35+
width: 100%;
36+
`;
37+
38+
export const VariantAnalysisSkippedRepositoriesTab = ({
39+
alertTitle,
40+
alertMessage,
41+
skippedRepositoryGroup,
42+
}: VariantAnalysisSkippedRepositoriesTabProps) => {
43+
return (
44+
<Container>
45+
{getSkipReasonAlert(alertTitle, alertMessage, skippedRepositoryGroup)}
46+
{skippedRepositoryGroup.repositories.map((repo) =>
47+
<VariantAnalysisSkippedRepositoryRow key={`repo/${repo.fullName}`} repository={repo} />
48+
)}
49+
</Container>
50+
);
51+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { VSCodeBadge, VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
2+
import * as React from 'react';
3+
import styled from 'styled-components';
4+
import { Codicon, WarningIcon } from '../common';
5+
import { VariantAnalysisSkippedRepository as SkippedRepo } from '../../remote-queries/shared/variant-analysis';
6+
7+
export type VariantAnalysisSkippedRepositoryRowProps = {
8+
repository: SkippedRepo,
9+
};
10+
11+
const Row = styled.div`
12+
display: flex;
13+
flex-direction: row;
14+
gap: 0.5em;
15+
align-items: center;
16+
`;
17+
18+
const ChevronIcon = styled(Codicon)`
19+
color: var(--vscode-disabledForeground);
20+
`;
21+
22+
const PrivacyText = styled.span`
23+
font-size: small;
24+
color: var(--vscode-descriptionForeground);
25+
`;
26+
27+
function getPrivacyElement(isPrivate: boolean | undefined) {
28+
if (isPrivate === undefined) {
29+
return undefined;
30+
}
31+
const text = isPrivate ? 'private' : 'public';
32+
return <PrivacyText>{text}</PrivacyText>;
33+
}
34+
35+
export const VariantAnalysisSkippedRepositoryRow = ({
36+
repository,
37+
}: VariantAnalysisSkippedRepositoryRowProps) => {
38+
return (
39+
<Row>
40+
<VSCodeCheckbox />
41+
<ChevronIcon name='chevron-right' label='Expand' />
42+
<VSCodeBadge>-</VSCodeBadge>
43+
<span>{repository.fullName}</span>
44+
{getPrivacyElement(repository.private)}
45+
<WarningIcon />
46+
</Row>
47+
);
48+
};

0 commit comments

Comments
 (0)