Use selected repositories for copying repo lists
This will use the selected repositories to limit which repositories are included in the copied repo list. If there are both selected repositories and a search filter (on the full name), the search filter will be ignored and the selected repositories will be used in full.
This commit is contained in:
@@ -116,7 +116,7 @@ import { createVariantAnalysisContentProvider } from './remote-queries/variant-a
|
||||
import { VSCodeMockGitHubApiServer } from './mocks/vscode-mock-gh-api-server';
|
||||
import { VariantAnalysisResultsManager } from './remote-queries/variant-analysis-results-manager';
|
||||
import { initializeDbModule } from './databases/db-module';
|
||||
import { RepositoriesFilterSortState } from './pure/variant-analysis-filter-sort';
|
||||
import { RepositoriesFilterSortStateWithIds } from './pure/variant-analysis-filter-sort';
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -946,7 +946,7 @@ async function activateWithInstalledDistribution(
|
||||
);
|
||||
|
||||
ctx.subscriptions.push(
|
||||
commandRunner('codeQL.copyVariantAnalysisRepoList', async (variantAnalysisId: number, filterSort?: RepositoriesFilterSortState) => {
|
||||
commandRunner('codeQL.copyVariantAnalysisRepoList', async (variantAnalysisId: number, filterSort?: RepositoriesFilterSortStateWithIds) => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysisId, filterSort);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
VariantAnalysisScannedRepositoryResult,
|
||||
VariantAnalysisScannedRepositoryState,
|
||||
} 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
|
||||
@@ -475,7 +475,7 @@ export interface OpenQueryTextMessage {
|
||||
|
||||
export interface CopyRepositoryListMessage {
|
||||
t: 'copyRepositoryList';
|
||||
filterSort?: RepositoriesFilterSortState;
|
||||
filterSort?: RepositoriesFilterSortStateWithIds;
|
||||
}
|
||||
|
||||
export interface OpenLogsMessage {
|
||||
|
||||
@@ -13,6 +13,10 @@ export type RepositoriesFilterSortState = {
|
||||
sortKey: SortKey;
|
||||
}
|
||||
|
||||
export type RepositoriesFilterSortStateWithIds = RepositoriesFilterSortState & {
|
||||
repositoryIds?: number[];
|
||||
}
|
||||
|
||||
export const defaultFilterSortState: RepositoriesFilterSortState = {
|
||||
searchValue: '',
|
||||
sortKey: SortKey.Name,
|
||||
@@ -52,7 +56,7 @@ export function compareRepository(filterSortState: RepositoriesFilterSortState |
|
||||
}
|
||||
|
||||
type SortableResult = {
|
||||
repository: SortableRepository;
|
||||
repository: SortableRepository & Pick<Repository, 'id'>;
|
||||
resultCount?: number;
|
||||
}
|
||||
|
||||
@@ -72,16 +76,30 @@ export function compareWithResults(filterSortState: RepositoriesFilterSortState
|
||||
};
|
||||
}
|
||||
|
||||
// These define the behavior for undefined input values
|
||||
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;
|
||||
function hasRepositoryIds(filterSortState: RepositoriesFilterSortState | RepositoriesFilterSortStateWithIds | undefined): filterSortState is RepositoriesFilterSortStateWithIds {
|
||||
if (!filterSortState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | undefined): T[] | undefined {
|
||||
return 'repositoryIds' in filterSortState;
|
||||
}
|
||||
|
||||
function isFilterOnRepositoryIds(filterSortState: RepositoriesFilterSortState | RepositoriesFilterSortStateWithIds | undefined): filterSortState is RepositoriesFilterSortStateWithIds & Required<Pick<RepositoriesFilterSortStateWithIds, 'repositoryIds'>> {
|
||||
return hasRepositoryIds(filterSortState) && filterSortState.repositoryIds !== undefined && filterSortState.repositoryIds.length > 0;
|
||||
}
|
||||
|
||||
// These define the behavior for undefined input values
|
||||
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[], filterSortState: RepositoriesFilterSortState | RepositoriesFilterSortStateWithIds | undefined): T[];
|
||||
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | RepositoriesFilterSortStateWithIds | undefined): T[] | undefined;
|
||||
|
||||
export function filterAndSortRepositoriesWithResults<T extends SortableResult>(repositories: T[] | undefined, filterSortState: RepositoriesFilterSortState | RepositoriesFilterSortStateWithIds | undefined): T[] | undefined {
|
||||
if (!repositories) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return repositories
|
||||
.filter(repo => matchesFilter(repo.repository, filterSortState))
|
||||
.sort(compareWithResults(filterSortState));
|
||||
const filteredRepositories = isFilterOnRepositoryIds(filterSortState) ?
|
||||
repositories.filter(repo => filterSortState.repositoryIds.includes(repo.repository.id)) :
|
||||
repositories.filter(repo => matchesFilter(repo.repository, filterSortState));
|
||||
|
||||
return filteredRepositories.sort(compareWithResults(filterSortState));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import { CodeQLCliServer } from '../cli';
|
||||
import {
|
||||
defaultFilterSortState,
|
||||
filterAndSortRepositoriesWithResults,
|
||||
RepositoriesFilterSortState,
|
||||
RepositoriesFilterSortStateWithIds,
|
||||
} from '../pure/variant-analysis-filter-sort';
|
||||
|
||||
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
|
||||
@@ -373,7 +373,7 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
|
||||
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);
|
||||
if (!variantAnalysis) {
|
||||
throw new Error(`No variant analysis with id: ${variantAnalysisId}`);
|
||||
|
||||
@@ -91,9 +91,12 @@ export function VariantAnalysis({
|
||||
const copyRepositoryList = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: 'copyRepositoryList',
|
||||
filterSort: filterSortState,
|
||||
filterSort: {
|
||||
...filterSortState,
|
||||
repositoryIds: selectedRepositoryIds,
|
||||
},
|
||||
});
|
||||
}, [filterSortState]);
|
||||
}, [filterSortState, selectedRepositoryIds]);
|
||||
|
||||
if (variantAnalysis?.actionsWorkflowRunId === undefined) {
|
||||
return <VariantAnalysisLoading />;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { compareRepository, compareWithResults, defaultFilterSortState, matchesFilter, SortKey } from '../../../pure/variant-analysis-filter-sort';
|
||||
import {
|
||||
compareRepository,
|
||||
compareWithResults,
|
||||
defaultFilterSortState,
|
||||
filterAndSortRepositoriesWithResults,
|
||||
matchesFilter,
|
||||
SortKey,
|
||||
} from '../../../pure/variant-analysis-filter-sort';
|
||||
|
||||
// TODO: Move this file to the "pure" tests once it has been switched to Jest
|
||||
describe(matchesFilter.name, () => {
|
||||
@@ -170,11 +177,13 @@ describe(compareWithResults.name, () => {
|
||||
|
||||
const left = {
|
||||
repository: {
|
||||
id: 10,
|
||||
fullName: 'github/galaxy',
|
||||
},
|
||||
};
|
||||
const right = {
|
||||
repository: {
|
||||
id: 12,
|
||||
fullName: 'github/world',
|
||||
},
|
||||
};
|
||||
@@ -192,12 +201,14 @@ describe(compareWithResults.name, () => {
|
||||
|
||||
const left = {
|
||||
repository: {
|
||||
id: 11,
|
||||
fullName: 'github/galaxy',
|
||||
stargazersCount: 1,
|
||||
},
|
||||
};
|
||||
const right = {
|
||||
repository: {
|
||||
id: 12,
|
||||
fullName: 'github/world',
|
||||
stargazersCount: 10,
|
||||
},
|
||||
@@ -216,12 +227,14 @@ describe(compareWithResults.name, () => {
|
||||
|
||||
const left = {
|
||||
repository: {
|
||||
id: 11,
|
||||
fullName: 'github/galaxy',
|
||||
updatedAt: '2020-01-01T00:00:00Z',
|
||||
},
|
||||
};
|
||||
const right = {
|
||||
repository: {
|
||||
id: 12,
|
||||
fullName: 'github/world',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
@@ -240,12 +253,14 @@ describe(compareWithResults.name, () => {
|
||||
|
||||
const left = {
|
||||
repository: {
|
||||
id: 11,
|
||||
fullName: 'github/galaxy',
|
||||
},
|
||||
resultCount: 10,
|
||||
};
|
||||
const right = {
|
||||
repository: {
|
||||
id: 12,
|
||||
fullName: 'github/world',
|
||||
},
|
||||
resultCount: 100,
|
||||
@@ -278,3 +293,84 @@ describe(compareWithResults.name, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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