Skip to content

Commit 3dbd071

Browse files
authored
Merge pull request #1711 from github/koesie10/sort-repositories
Add sorting to variant analysis repositories
2 parents fe90f38 + 588351b commit 3dbd071

12 files changed

+638
-41
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useState } from 'react';
2+
3+
import { ComponentMeta } from '@storybook/react';
4+
5+
import { RepositoriesSearchSortRow as RepositoriesSearchSortRowComponent } from '../../view/variant-analysis/RepositoriesSearchSortRow';
6+
import { defaultFilterSortState } from '../../view/variant-analysis/filterSort';
7+
8+
export default {
9+
title: 'Variant Analysis/Repositories Search and Sort Row',
10+
component: RepositoriesSearchSortRowComponent,
11+
argTypes: {
12+
value: {
13+
control: {
14+
disable: true,
15+
},
16+
},
17+
}
18+
} as ComponentMeta<typeof RepositoriesSearchSortRowComponent>;
19+
20+
export const RepositoriesSearchSortRow = () => {
21+
const [value, setValue] = useState(defaultFilterSortState);
22+
23+
return (
24+
<RepositoriesSearchSortRowComponent value={value} onChange={setValue} />
25+
);
26+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useState } from 'react';
2+
3+
import { ComponentMeta } from '@storybook/react';
4+
5+
import { RepositoriesSort as RepositoriesSortComponent } from '../../view/variant-analysis/RepositoriesSort';
6+
import { SortKey } from '../../view/variant-analysis/filterSort';
7+
8+
export default {
9+
title: 'Variant Analysis/Repositories Sort',
10+
component: RepositoriesSortComponent,
11+
argTypes: {
12+
value: {
13+
control: {
14+
disable: true,
15+
},
16+
},
17+
}
18+
} as ComponentMeta<typeof RepositoriesSortComponent>;
19+
20+
export const RepositoriesSort = () => {
21+
const [value, setValue] = useState(SortKey.Name);
22+
23+
return (
24+
<RepositoriesSortComponent value={value} onChange={setValue} />
25+
);
26+
};

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ const TextField = styled(VSCodeTextField)`
1111
type Props = {
1212
value: string;
1313
onChange: (value: string) => void;
14+
15+
className?: string;
1416
}
1517

16-
export const RepositoriesSearch = ({ value, onChange }: Props) => {
18+
export const RepositoriesSearch = ({ value, onChange, className }: Props) => {
1719
const handleInput = useCallback((e: InputEvent) => {
1820
const target = e.target as HTMLInputElement;
1921

@@ -25,6 +27,7 @@ export const RepositoriesSearch = ({ value, onChange }: Props) => {
2527
placeholder='Filter by repository owner/name'
2628
value={value}
2729
onInput={handleInput}
30+
className={className}
2831
>
2932
<Codicon name="search" label="Search..." slot="start" />
3033
</TextField>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as React from 'react';
2+
import { Dispatch, SetStateAction, useCallback } from 'react';
3+
import styled from 'styled-components';
4+
import { RepositoriesFilterSortState, SortKey } from './filterSort';
5+
import { RepositoriesSearch } from './RepositoriesSearch';
6+
import { RepositoriesSort } from './RepositoriesSort';
7+
8+
type Props = {
9+
value: RepositoriesFilterSortState;
10+
onChange: Dispatch<SetStateAction<RepositoriesFilterSortState>>;
11+
}
12+
13+
const Container = styled.div`
14+
display: flex;
15+
gap: 1em;
16+
17+
width: 100%;
18+
`;
19+
20+
const RepositoriesSearchColumn = styled(RepositoriesSearch)`
21+
flex: 3;
22+
`;
23+
24+
const RepositoriesSortColumn = styled(RepositoriesSort)`
25+
flex: 1;
26+
`;
27+
28+
export const RepositoriesSearchSortRow = ({ value, onChange }: Props) => {
29+
const handleSearchValueChange = useCallback((searchValue: string) => {
30+
onChange(oldValue => ({
31+
...oldValue,
32+
searchValue,
33+
}));
34+
}, [onChange]);
35+
36+
const handleSortKeyChange = useCallback((sortKey: SortKey) => {
37+
onChange(oldValue => ({
38+
...oldValue,
39+
sortKey,
40+
}));
41+
}, [onChange]);
42+
43+
return (
44+
<Container>
45+
<RepositoriesSearchColumn value={value.searchValue} onChange={handleSearchValueChange} />
46+
<RepositoriesSortColumn value={value.sortKey} onChange={handleSortKeyChange} />
47+
</Container>
48+
);
49+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as React from 'react';
2+
import { useCallback } from 'react';
3+
import styled from 'styled-components';
4+
import { VSCodeDropdown, VSCodeOption } from '@vscode/webview-ui-toolkit/react';
5+
import { SortKey } from './filterSort';
6+
import { Codicon } from '../common';
7+
8+
const Dropdown = styled(VSCodeDropdown)`
9+
width: 100%;
10+
`;
11+
12+
type Props = {
13+
value: SortKey;
14+
onChange: (value: SortKey) => void;
15+
16+
className?: string;
17+
}
18+
19+
export const RepositoriesSort = ({ value, onChange, className }: Props) => {
20+
const handleInput = useCallback((e: InputEvent) => {
21+
const target = e.target as HTMLSelectElement;
22+
23+
onChange(target.value as SortKey);
24+
}, [onChange]);
25+
26+
return (
27+
<Dropdown
28+
value={value}
29+
onInput={handleInput}
30+
className={className}
31+
>
32+
<Codicon name="sort-precedence" label="Sort..." slot="indicator" />
33+
<VSCodeOption value={SortKey.Name}>Name</VSCodeOption>
34+
<VSCodeOption value={SortKey.ResultsCount}>Results</VSCodeOption>
35+
<VSCodeOption value={SortKey.Stars}>Stars</VSCodeOption>
36+
<VSCodeOption value={SortKey.LastUpdated}>Last commit</VSCodeOption>
37+
</Dropdown>
38+
);
39+
};

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
VariantAnalysisScannedRepositoryResult,
88
VariantAnalysisScannedRepositoryState
99
} from '../../remote-queries/shared/variant-analysis';
10-
import { matchesSearchValue } from './filterSort';
10+
import { compareWithResults, matchesFilter, RepositoriesFilterSortState } from './filterSort';
1111

1212
const Container = styled.div`
1313
display: flex;
@@ -21,14 +21,14 @@ export type VariantAnalysisAnalyzedReposProps = {
2121
repositoryStates?: VariantAnalysisScannedRepositoryState[];
2222
repositoryResults?: VariantAnalysisScannedRepositoryResult[];
2323

24-
searchValue?: string;
24+
filterSortState?: RepositoriesFilterSortState;
2525
}
2626

2727
export const VariantAnalysisAnalyzedRepos = ({
2828
variantAnalysis,
2929
repositoryStates,
3030
repositoryResults,
31-
searchValue,
31+
filterSortState,
3232
}: VariantAnalysisAnalyzedReposProps) => {
3333
const repositoryStateById = useMemo(() => {
3434
const map = new Map<number, VariantAnalysisScannedRepositoryState>();
@@ -47,14 +47,10 @@ export const VariantAnalysisAnalyzedRepos = ({
4747
}, [repositoryResults]);
4848

4949
const repositories = useMemo(() => {
50-
if (searchValue) {
51-
return variantAnalysis.scannedRepos?.filter((repoTask) => {
52-
return matchesSearchValue(repoTask.repository, searchValue);
53-
});
54-
}
55-
56-
return variantAnalysis.scannedRepos;
57-
}, [searchValue, variantAnalysis.scannedRepos]);
50+
return variantAnalysis.scannedRepos?.filter((repoTask) => {
51+
return matchesFilter(repoTask.repository, filterSortState);
52+
})?.sort(compareWithResults(filterSortState));
53+
}, [filterSortState, variantAnalysis.scannedRepos]);
5854

5955
return (
6056
<Container>

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
import { VariantAnalysisAnalyzedRepos } from './VariantAnalysisAnalyzedRepos';
1212
import { Alert } from '../common';
1313
import { VariantAnalysisSkippedRepositoriesTab } from './VariantAnalysisSkippedRepositoriesTab';
14-
import { RepositoriesSearch } from './RepositoriesSearch';
14+
import { defaultFilterSortState, RepositoriesFilterSortState } from './filterSort';
15+
import { RepositoriesSearchSortRow } from './RepositoriesSearchSortRow';
1516

1617
export type VariantAnalysisOutcomePanelProps = {
1718
variantAnalysis: VariantAnalysis;
@@ -44,7 +45,7 @@ export const VariantAnalysisOutcomePanels = ({
4445
repositoryStates,
4546
repositoryResults,
4647
}: VariantAnalysisOutcomePanelProps) => {
47-
const [searchValue, setSearchValue] = useState('');
48+
const [filterSortState, setFilterSortState] = useState<RepositoriesFilterSortState>(defaultFilterSortState);
4849

4950
const noCodeqlDbRepos = variantAnalysis.skippedRepos?.noCodeqlDbRepos;
5051
const notFoundRepos = variantAnalysis.skippedRepos?.notFoundRepos;
@@ -74,12 +75,12 @@ export const VariantAnalysisOutcomePanels = ({
7475
return (
7576
<>
7677
{warnings}
77-
<RepositoriesSearch value={searchValue} onChange={setSearchValue} />
78+
<RepositoriesSearchSortRow value={filterSortState} onChange={setFilterSortState} />
7879
<VariantAnalysisAnalyzedRepos
7980
variantAnalysis={variantAnalysis}
8081
repositoryStates={repositoryStates}
8182
repositoryResults={repositoryResults}
82-
searchValue={searchValue}
83+
filterSortState={filterSortState}
8384
/>
8485
</>
8586
);
@@ -88,7 +89,7 @@ export const VariantAnalysisOutcomePanels = ({
8889
return (
8990
<>
9091
{warnings}
91-
<RepositoriesSearch value={searchValue} onChange={setSearchValue} />
92+
<RepositoriesSearchSortRow value={filterSortState} onChange={setFilterSortState} />
9293
<VSCodePanels>
9394
<Tab>
9495
Analyzed
@@ -111,7 +112,7 @@ export const VariantAnalysisOutcomePanels = ({
111112
variantAnalysis={variantAnalysis}
112113
repositoryStates={repositoryStates}
113114
repositoryResults={repositoryResults}
114-
searchValue={searchValue}
115+
filterSortState={filterSortState}
115116
/>
116117
</VSCodePanelView>
117118
{notFoundRepos?.repositoryCount &&
@@ -120,7 +121,7 @@ export const VariantAnalysisOutcomePanels = ({
120121
alertTitle='No access'
121122
alertMessage='The following repositories could not be scanned because you do not have read access.'
122123
skippedRepositoryGroup={notFoundRepos}
123-
searchValue={searchValue}
124+
filterSortState={filterSortState}
124125
/>
125126
</VSCodePanelView>}
126127
{noCodeqlDbRepos?.repositoryCount &&
@@ -129,7 +130,7 @@ export const VariantAnalysisOutcomePanels = ({
129130
alertTitle='No database'
130131
alertMessage='The following repositories could not be scanned because they do not have an available CodeQL database.'
131132
skippedRepositoryGroup={noCodeqlDbRepos}
132-
searchValue={searchValue}
133+
filterSortState={filterSortState}
133134
/>
134135
</VSCodePanelView>}
135136
</VSCodePanels>

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import styled from 'styled-components';
44
import { VariantAnalysisSkippedRepositoryGroup } from '../../remote-queries/shared/variant-analysis';
55
import { Alert } from '../common';
66
import { RepoRow } from './RepoRow';
7-
import { matchesSearchValue } from './filterSort';
7+
import { compareRepository, matchesFilter, RepositoriesFilterSortState } from './filterSort';
88

99
export type VariantAnalysisSkippedRepositoriesTabProps = {
1010
alertTitle: string,
1111
alertMessage: string,
1212
skippedRepositoryGroup: VariantAnalysisSkippedRepositoryGroup,
1313

14-
searchValue?: string,
14+
filterSortState?: RepositoriesFilterSortState,
1515
};
1616

1717
function getSkipReasonAlert(
@@ -43,17 +43,13 @@ export const VariantAnalysisSkippedRepositoriesTab = ({
4343
alertTitle,
4444
alertMessage,
4545
skippedRepositoryGroup,
46-
searchValue,
46+
filterSortState,
4747
}: VariantAnalysisSkippedRepositoriesTabProps) => {
4848
const repositories = useMemo(() => {
49-
if (searchValue) {
50-
return skippedRepositoryGroup.repositories?.filter((repo) => {
51-
return matchesSearchValue(repo, searchValue);
52-
});
53-
}
54-
55-
return skippedRepositoryGroup.repositories;
56-
}, [searchValue, skippedRepositoryGroup.repositories]);
49+
return skippedRepositoryGroup.repositories?.filter((repo) => {
50+
return matchesFilter(repo, filterSortState);
51+
})?.sort(compareRepository(filterSortState));
52+
}, [filterSortState, skippedRepositoryGroup.repositories]);
5753

5854
return (
5955
<Container>

0 commit comments

Comments
 (0)