Merge pull request #1765 from github/koesie10/selected-copy
Use selected repositories for copying repo lists
This commit is contained in:
@@ -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);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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}`);
|
||||||
|
|||||||
@@ -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 />;
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user