Merge pull request #1765 from github/koesie10/selected-copy

Use selected repositories for copying repo lists
This commit is contained in:
Koen Vlaswinkel
2022-11-16 18:41:46 +01:00
committed by GitHub
7 changed files with 183 additions and 17 deletions

View File

@@ -123,7 +123,7 @@ import { VSCodeMockGitHubApiServer } from './mocks/vscode-mock-gh-api-server';
import { VariantAnalysisResultsManager } from './remote-queries/variant-analysis-results-manager'; import { VariantAnalysisResultsManager } from './remote-queries/variant-analysis-results-manager';
import { initializeDbModule } from './databases/db-module'; import { initializeDbModule } from './databases/db-module';
import { ExtensionApp } from './common/vscode/vscode-app'; import { ExtensionApp } from './common/vscode/vscode-app';
import { RepositoriesFilterSortState } from './pure/variant-analysis-filter-sort'; import { RepositoriesFilterSortStateWithIds } from './pure/variant-analysis-filter-sort';
/** /**
* extension.ts * extension.ts
@@ -963,7 +963,7 @@ async function activateWithInstalledDistribution(
); );
ctx.subscriptions.push( ctx.subscriptions.push(
commandRunner('codeQL.copyVariantAnalysisRepoList', async (variantAnalysisId: number, filterSort?: RepositoriesFilterSortState) => { commandRunner('codeQL.copyVariantAnalysisRepoList', async (variantAnalysisId: number, filterSort?: RepositoriesFilterSortStateWithIds) => {
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysisId, filterSort); await variantAnalysisManager.copyRepoListToClipboard(variantAnalysisId, filterSort);
}) })
); );

View File

@@ -7,7 +7,7 @@ import {
VariantAnalysisScannedRepositoryResult, VariantAnalysisScannedRepositoryResult,
VariantAnalysisScannedRepositoryState, VariantAnalysisScannedRepositoryState,
} from '../remote-queries/shared/variant-analysis'; } from '../remote-queries/shared/variant-analysis';
import { RepositoriesFilterSortState } from './variant-analysis-filter-sort'; import { RepositoriesFilterSortStateWithIds } from './variant-analysis-filter-sort';
/** /**
* This module contains types and code that are shared between * This module contains types and code that are shared between
@@ -475,7 +475,7 @@ export interface OpenQueryTextMessage {
export interface CopyRepositoryListMessage { export interface CopyRepositoryListMessage {
t: 'copyRepositoryList'; t: 'copyRepositoryList';
filterSort?: RepositoriesFilterSortState; filterSort?: RepositoriesFilterSortStateWithIds;
} }
export interface ExportResultsMessage { export interface ExportResultsMessage {

View File

@@ -13,6 +13,10 @@ export type RepositoriesFilterSortState = {
sortKey: SortKey; sortKey: SortKey;
} }
export type RepositoriesFilterSortStateWithIds = RepositoriesFilterSortState & {
repositoryIds?: number[];
}
export const defaultFilterSortState: RepositoriesFilterSortState = { export const defaultFilterSortState: RepositoriesFilterSortState = {
searchValue: '', searchValue: '',
sortKey: SortKey.Name, sortKey: SortKey.Name,
@@ -52,7 +56,7 @@ export function compareRepository(filterSortState: RepositoriesFilterSortState |
} }
type SortableResult = { type SortableResult = {
repository: SortableRepository; repository: SortableRepository & Pick<Repository, 'id'>;
resultCount?: number; resultCount?: number;
} }
@@ -72,11 +76,7 @@ export function compareWithResults(filterSortState: RepositoriesFilterSortState
}; };
} }
// These define the behavior for undefined input values export function filterAndSortRepositoriesWithResultsByName<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | undefined): T[] | undefined {
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[], filterSortState: RepositoriesFilterSortState | undefined): T[];
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | undefined): T[] | undefined;
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | undefined): T[] | undefined {
if (!repositories) { if (!repositories) {
return undefined; return undefined;
} }
@@ -85,3 +85,17 @@ export function filterAndSortRepositoriesWithResults<T extends SortableResult>(r
.filter(repo => matchesFilter(repo.repository, filterSortState)) .filter(repo => matchesFilter(repo.repository, filterSortState))
.sort(compareWithResults(filterSortState)); .sort(compareWithResults(filterSortState));
} }
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortStateWithIds | undefined): T[] | undefined {
if (!repositories) {
return undefined;
}
if (filterSortState?.repositoryIds && filterSortState.repositoryIds.length > 0) {
return repositories
.filter(repo => filterSortState.repositoryIds?.includes(repo.repository.id))
.sort(compareWithResults(filterSortState));
}
return filterAndSortRepositoriesWithResultsByName(repositories, filterSortState);
}

View File

@@ -33,7 +33,7 @@ import { CodeQLCliServer } from '../cli';
import { import {
defaultFilterSortState, defaultFilterSortState,
filterAndSortRepositoriesWithResults, filterAndSortRepositoriesWithResults,
RepositoriesFilterSortState, RepositoriesFilterSortStateWithIds,
} from '../pure/variant-analysis-filter-sort'; } from '../pure/variant-analysis-filter-sort';
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> { export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
@@ -371,7 +371,7 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
await cancelVariantAnalysis(credentials, variantAnalysis); await cancelVariantAnalysis(credentials, variantAnalysis);
} }
public async copyRepoListToClipboard(variantAnalysisId: number, filterSort: RepositoriesFilterSortState = defaultFilterSortState) { public async copyRepoListToClipboard(variantAnalysisId: number, filterSort: RepositoriesFilterSortStateWithIds = defaultFilterSortState) {
const variantAnalysis = this.variantAnalyses.get(variantAnalysisId); const variantAnalysis = this.variantAnalyses.get(variantAnalysisId);
if (!variantAnalysis) { if (!variantAnalysis) {
throw new Error(`No variant analysis with id: ${variantAnalysisId}`); throw new Error(`No variant analysis with id: ${variantAnalysisId}`);

View File

@@ -97,9 +97,12 @@ export function VariantAnalysis({
const copyRepositoryList = useCallback(() => { const copyRepositoryList = useCallback(() => {
vscode.postMessage({ vscode.postMessage({
t: 'copyRepositoryList', t: 'copyRepositoryList',
filterSort: filterSortState, filterSort: {
...filterSortState,
repositoryIds: selectedRepositoryIds,
},
}); });
}, [filterSortState]); }, [filterSortState, selectedRepositoryIds]);
if (variantAnalysis?.actionsWorkflowRunId === undefined) { if (variantAnalysis?.actionsWorkflowRunId === undefined) {
return <VariantAnalysisLoading />; return <VariantAnalysisLoading />;

View File

@@ -8,7 +8,7 @@ import {
VariantAnalysisScannedRepositoryState VariantAnalysisScannedRepositoryState
} from '../../remote-queries/shared/variant-analysis'; } from '../../remote-queries/shared/variant-analysis';
import { import {
filterAndSortRepositoriesWithResults, filterAndSortRepositoriesWithResultsByName,
RepositoriesFilterSortState, RepositoriesFilterSortState,
} from '../../pure/variant-analysis-filter-sort'; } from '../../pure/variant-analysis-filter-sort';
@@ -55,7 +55,7 @@ export const VariantAnalysisAnalyzedRepos = ({
}, [repositoryResults]); }, [repositoryResults]);
const repositories = useMemo(() => { const repositories = useMemo(() => {
return filterAndSortRepositoriesWithResults(variantAnalysis.scannedRepos, filterSortState); return filterAndSortRepositoriesWithResultsByName(variantAnalysis.scannedRepos, filterSortState);
}, [filterSortState, variantAnalysis.scannedRepos]); }, [filterSortState, variantAnalysis.scannedRepos]);
const onSelectedChange = useCallback((repositoryId: number, selected: boolean) => { const onSelectedChange = useCallback((repositoryId: number, selected: boolean) => {

View File

@@ -1,4 +1,12 @@
import { compareRepository, compareWithResults, defaultFilterSortState, matchesFilter, SortKey } from '../../../pure/variant-analysis-filter-sort'; import {
compareRepository,
compareWithResults,
defaultFilterSortState,
filterAndSortRepositoriesWithResults,
filterAndSortRepositoriesWithResultsByName,
matchesFilter,
SortKey,
} from '../../../pure/variant-analysis-filter-sort';
// TODO: Move this file to the "pure" tests once it has been switched to Jest // TODO: Move this file to the "pure" tests once it has been switched to Jest
describe(matchesFilter.name, () => { describe(matchesFilter.name, () => {
@@ -170,11 +178,13 @@ describe(compareWithResults.name, () => {
const left = { const left = {
repository: { repository: {
id: 10,
fullName: 'github/galaxy', fullName: 'github/galaxy',
}, },
}; };
const right = { const right = {
repository: { repository: {
id: 12,
fullName: 'github/world', fullName: 'github/world',
}, },
}; };
@@ -192,12 +202,14 @@ describe(compareWithResults.name, () => {
const left = { const left = {
repository: { repository: {
id: 11,
fullName: 'github/galaxy', fullName: 'github/galaxy',
stargazersCount: 1, stargazersCount: 1,
}, },
}; };
const right = { const right = {
repository: { repository: {
id: 12,
fullName: 'github/world', fullName: 'github/world',
stargazersCount: 10, stargazersCount: 10,
}, },
@@ -216,12 +228,14 @@ describe(compareWithResults.name, () => {
const left = { const left = {
repository: { repository: {
id: 11,
fullName: 'github/galaxy', fullName: 'github/galaxy',
updatedAt: '2020-01-01T00:00:00Z', updatedAt: '2020-01-01T00:00:00Z',
}, },
}; };
const right = { const right = {
repository: { repository: {
id: 12,
fullName: 'github/world', fullName: 'github/world',
updatedAt: '2021-01-01T00:00:00Z', updatedAt: '2021-01-01T00:00:00Z',
}, },
@@ -240,12 +254,14 @@ describe(compareWithResults.name, () => {
const left = { const left = {
repository: { repository: {
id: 11,
fullName: 'github/galaxy', fullName: 'github/galaxy',
}, },
resultCount: 10, resultCount: 10,
}; };
const right = { const right = {
repository: { repository: {
id: 12,
fullName: 'github/world', fullName: 'github/world',
}, },
resultCount: 100, resultCount: 100,
@@ -278,3 +294,136 @@ describe(compareWithResults.name, () => {
}); });
}); });
}); });
describe(filterAndSortRepositoriesWithResultsByName.name, () => {
const repositories = [
{
repository: {
id: 10,
fullName: 'github/galaxy',
},
resultCount: 10,
},
{
repository: {
id: 11,
fullName: 'github/world',
},
resultCount: undefined,
},
{
repository: {
id: 13,
fullName: 'github/planet',
},
resultCount: 500,
},
{
repository: {
id: 783532,
fullName: 'github/stars',
},
resultCount: 8000,
}
];
describe('when sort key is given without filter', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResultsByName(repositories, {
...defaultFilterSortState,
sortKey: SortKey.ResultsCount,
})).toEqual([repositories[3], repositories[2], repositories[0], repositories[1]]);
});
});
describe('when sort key and search filter are given', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResultsByName(repositories, {
...defaultFilterSortState,
sortKey: SortKey.ResultsCount,
searchValue: 'la',
})).toEqual([repositories[2], repositories[0]]);
});
});
});
describe(filterAndSortRepositoriesWithResults.name, () => {
const repositories = [
{
repository: {
id: 10,
fullName: 'github/galaxy',
},
resultCount: 10,
},
{
repository: {
id: 11,
fullName: 'github/world',
},
resultCount: undefined,
},
{
repository: {
id: 13,
fullName: 'github/planet',
},
resultCount: 500,
},
{
repository: {
id: 783532,
fullName: 'github/stars',
},
resultCount: 8000,
}
];
describe('when sort key is given without filter', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResults(repositories, {
...defaultFilterSortState,
sortKey: SortKey.ResultsCount,
})).toEqual([repositories[3], repositories[2], repositories[0], repositories[1]]);
});
});
describe('when sort key and search filter are given', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResults(repositories, {
...defaultFilterSortState,
sortKey: SortKey.ResultsCount,
searchValue: 'la',
})).toEqual([repositories[2], repositories[0]]);
});
});
describe('when sort key, search filter, and repository ids are given', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResults(repositories, {
...defaultFilterSortState,
sortKey: SortKey.ResultsCount,
searchValue: 'la',
repositoryIds: [repositories[1].repository.id, repositories[3].repository.id],
})).toEqual([repositories[3], repositories[1]]);
});
});
describe('when repository ids are given', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResults(repositories, {
...defaultFilterSortState,
repositoryIds: [repositories[0].repository.id, repositories[3].repository.id],
})).toEqual([repositories[0], repositories[3]]);
});
});
describe('when empty repository ids are given', () => {
it('returns the correct results', () => {
expect(filterAndSortRepositoriesWithResults(repositories, {
...defaultFilterSortState,
repositoryIds: [],
})).toEqual([repositories[0], repositories[2], repositories[3], repositories[1]]);
});
});
});