Merge pull request #1816 from github/koesie10/export-cancelled-results
Add exporting of in-progress/cancelled results
This commit is contained in:
@@ -2,12 +2,12 @@ import { join } from "path";
|
||||
import { ensureDir, writeFile } from "fs-extra";
|
||||
|
||||
import {
|
||||
window,
|
||||
commands,
|
||||
Uri,
|
||||
ExtensionContext,
|
||||
workspace,
|
||||
Uri,
|
||||
ViewColumn,
|
||||
window,
|
||||
workspace,
|
||||
} from "vscode";
|
||||
import { Credentials } from "../authentication";
|
||||
import { UserCancellationException } from "../commandRunner";
|
||||
@@ -30,6 +30,7 @@ import { assertNever } from "../pure/helpers-pure";
|
||||
import {
|
||||
VariantAnalysis,
|
||||
VariantAnalysisScannedRepository,
|
||||
VariantAnalysisScannedRepositoryDownloadStatus,
|
||||
VariantAnalysisScannedRepositoryResult,
|
||||
} from "./shared/variant-analysis";
|
||||
import {
|
||||
@@ -154,6 +155,10 @@ export async function exportVariantAnalysisResults(
|
||||
);
|
||||
}
|
||||
|
||||
const repoStates = await variantAnalysisManager.getRepoStates(
|
||||
variantAnalysisId,
|
||||
);
|
||||
|
||||
void extLogger.log(
|
||||
`Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`,
|
||||
);
|
||||
@@ -179,6 +184,18 @@ export async function exportVariantAnalysisResults(
|
||||
}
|
||||
|
||||
for (const repo of repositories) {
|
||||
const repoState = repoStates.find(
|
||||
(r) => r.repositoryId === repo.repository.id,
|
||||
);
|
||||
|
||||
// Do not export if it has not yet completed or the download has not yet succeeded.
|
||||
if (
|
||||
repoState?.downloadStatus !==
|
||||
VariantAnalysisScannedRepositoryDownloadStatus.Succeeded
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (repo.resultCount == 0) {
|
||||
yield [
|
||||
repo,
|
||||
|
||||
@@ -43,6 +43,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||
resultCount: 100,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
|
||||
@@ -47,10 +47,24 @@ InProgress.args = {
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
};
|
||||
|
||||
export const InProgressWithResults = Template.bind({});
|
||||
InProgressWithResults.args = {
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
showResultActions: true,
|
||||
};
|
||||
|
||||
export const InProgressWithoutDownloadedRepos = Template.bind({});
|
||||
InProgressWithoutDownloadedRepos.args = {
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
showResultActions: true,
|
||||
exportResultsDisabled: true,
|
||||
};
|
||||
|
||||
export const Succeeded = Template.bind({});
|
||||
Succeeded.args = {
|
||||
...InProgress.args,
|
||||
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
|
||||
showResultActions: true,
|
||||
};
|
||||
|
||||
export const Failed = Template.bind({});
|
||||
|
||||
@@ -144,6 +144,9 @@ export function VariantAnalysis({
|
||||
<>
|
||||
<VariantAnalysisHeader
|
||||
variantAnalysis={variantAnalysis}
|
||||
repositoryStates={repoStates}
|
||||
filterSortState={filterSortState}
|
||||
selectedRepositoryIds={selectedRepositoryIds}
|
||||
onOpenQueryFileClick={openQueryFile}
|
||||
onViewQueryTextClick={openQueryText}
|
||||
onStopQueryClick={stopQuery}
|
||||
|
||||
@@ -3,14 +3,17 @@ import styled from "styled-components";
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react";
|
||||
import { VariantAnalysisStatus } from "../../remote-queries/shared/variant-analysis";
|
||||
|
||||
type Props = {
|
||||
export type VariantAnalysisActionsProps = {
|
||||
variantAnalysisStatus: VariantAnalysisStatus;
|
||||
|
||||
onStopQueryClick: () => void;
|
||||
stopQueryDisabled?: boolean;
|
||||
|
||||
showResultActions?: boolean;
|
||||
onCopyRepositoryListClick: () => void;
|
||||
onExportResultsClick: () => void;
|
||||
copyRepositoryListDisabled?: boolean;
|
||||
exportResultsDisabled?: boolean;
|
||||
};
|
||||
|
||||
const Container = styled.div`
|
||||
@@ -26,12 +29,33 @@ const Button = styled(VSCodeButton)`
|
||||
export const VariantAnalysisActions = ({
|
||||
variantAnalysisStatus,
|
||||
onStopQueryClick,
|
||||
stopQueryDisabled,
|
||||
showResultActions,
|
||||
onCopyRepositoryListClick,
|
||||
onExportResultsClick,
|
||||
stopQueryDisabled,
|
||||
}: Props) => {
|
||||
copyRepositoryListDisabled,
|
||||
exportResultsDisabled,
|
||||
}: VariantAnalysisActionsProps) => {
|
||||
return (
|
||||
<Container>
|
||||
{showResultActions && (
|
||||
<>
|
||||
<Button
|
||||
appearance="secondary"
|
||||
onClick={onCopyRepositoryListClick}
|
||||
disabled={copyRepositoryListDisabled}
|
||||
>
|
||||
Copy repository list
|
||||
</Button>
|
||||
<Button
|
||||
appearance="primary"
|
||||
onClick={onExportResultsClick}
|
||||
disabled={exportResultsDisabled}
|
||||
>
|
||||
Export results
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{variantAnalysisStatus === VariantAnalysisStatus.InProgress && (
|
||||
<Button
|
||||
appearance="secondary"
|
||||
@@ -41,16 +65,6 @@ export const VariantAnalysisActions = ({
|
||||
Stop query
|
||||
</Button>
|
||||
)}
|
||||
{variantAnalysisStatus === VariantAnalysisStatus.Succeeded && (
|
||||
<>
|
||||
<Button appearance="secondary" onClick={onCopyRepositoryListClick}>
|
||||
Copy repository list
|
||||
</Button>
|
||||
<Button appearance="primary" onClick={onExportResultsClick}>
|
||||
Export results
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,15 +6,25 @@ import {
|
||||
getTotalResultCount,
|
||||
hasRepoScanCompleted,
|
||||
VariantAnalysis,
|
||||
VariantAnalysisScannedRepositoryDownloadStatus,
|
||||
VariantAnalysisScannedRepositoryState,
|
||||
} from "../../remote-queries/shared/variant-analysis";
|
||||
import { QueryDetails } from "./QueryDetails";
|
||||
import { VariantAnalysisActions } from "./VariantAnalysisActions";
|
||||
import { VariantAnalysisStats } from "./VariantAnalysisStats";
|
||||
import { parseDate } from "../../pure/date";
|
||||
import { basename } from "../common/path";
|
||||
import {
|
||||
defaultFilterSortState,
|
||||
filterAndSortRepositoriesWithResults,
|
||||
RepositoriesFilterSortState,
|
||||
} from "../../pure/variant-analysis-filter-sort";
|
||||
|
||||
export type VariantAnalysisHeaderProps = {
|
||||
variantAnalysis: VariantAnalysis;
|
||||
repositoryStates?: VariantAnalysisScannedRepositoryState[];
|
||||
filterSortState?: RepositoriesFilterSortState;
|
||||
selectedRepositoryIds?: number[];
|
||||
|
||||
onOpenQueryFileClick: () => void;
|
||||
onViewQueryTextClick: () => void;
|
||||
@@ -40,6 +50,9 @@ const Row = styled.div`
|
||||
|
||||
export const VariantAnalysisHeader = ({
|
||||
variantAnalysis,
|
||||
repositoryStates,
|
||||
filterSortState,
|
||||
selectedRepositoryIds,
|
||||
onOpenQueryFileClick,
|
||||
onViewQueryTextClick,
|
||||
onStopQueryClick,
|
||||
@@ -62,6 +75,36 @@ export const VariantAnalysisHeader = ({
|
||||
const hasSkippedRepos = useMemo(() => {
|
||||
return getSkippedRepoCount(variantAnalysis.skippedRepos) > 0;
|
||||
}, [variantAnalysis.skippedRepos]);
|
||||
const filteredRepositories = useMemo(() => {
|
||||
return filterAndSortRepositoriesWithResults(variantAnalysis.scannedRepos, {
|
||||
...defaultFilterSortState,
|
||||
...filterSortState,
|
||||
repositoryIds: selectedRepositoryIds,
|
||||
});
|
||||
}, [filterSortState, selectedRepositoryIds, variantAnalysis.scannedRepos]);
|
||||
const hasDownloadedRepos = useMemo(() => {
|
||||
const repositoryStatesById = new Map<
|
||||
number,
|
||||
VariantAnalysisScannedRepositoryState
|
||||
>();
|
||||
if (repositoryStates) {
|
||||
for (const repositoryState of repositoryStates) {
|
||||
repositoryStatesById.set(repositoryState.repositoryId, repositoryState);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredRepositories?.some((repo) => {
|
||||
return (
|
||||
repositoryStatesById.get(repo.repository.id)?.downloadStatus ===
|
||||
VariantAnalysisScannedRepositoryDownloadStatus.Succeeded
|
||||
);
|
||||
});
|
||||
}, [repositoryStates, filteredRepositories]);
|
||||
const hasReposWithResults = useMemo(() => {
|
||||
return filteredRepositories?.some(
|
||||
(repo) => repo.resultCount && repo.resultCount > 0,
|
||||
);
|
||||
}, [filteredRepositories]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@@ -74,10 +117,13 @@ export const VariantAnalysisHeader = ({
|
||||
/>
|
||||
<VariantAnalysisActions
|
||||
variantAnalysisStatus={variantAnalysis.status}
|
||||
showResultActions={(resultCount ?? 0) > 0}
|
||||
onStopQueryClick={onStopQueryClick}
|
||||
onCopyRepositoryListClick={onCopyRepositoryListClick}
|
||||
onExportResultsClick={onExportResultsClick}
|
||||
stopQueryDisabled={!variantAnalysis.actionsWorkflowRunId}
|
||||
exportResultsDisabled={!hasDownloadedRepos}
|
||||
copyRepositoryListDisabled={!hasReposWithResults}
|
||||
/>
|
||||
</Row>
|
||||
<VariantAnalysisStats
|
||||
|
||||
@@ -2,7 +2,10 @@ import * as React from "react";
|
||||
import { render as reactRender, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { VariantAnalysisStatus } from "../../../remote-queries/shared/variant-analysis";
|
||||
import { VariantAnalysisActions } from "../VariantAnalysisActions";
|
||||
import {
|
||||
VariantAnalysisActions,
|
||||
VariantAnalysisActionsProps,
|
||||
} from "../VariantAnalysisActions";
|
||||
|
||||
describe(VariantAnalysisActions.name, () => {
|
||||
const onStopQueryClick = jest.fn();
|
||||
@@ -15,51 +18,78 @@ describe(VariantAnalysisActions.name, () => {
|
||||
onExportResultsClick.mockReset();
|
||||
});
|
||||
|
||||
const render = (variantAnalysisStatus: VariantAnalysisStatus) =>
|
||||
const render = (
|
||||
props: Pick<VariantAnalysisActionsProps, "variantAnalysisStatus"> &
|
||||
Partial<VariantAnalysisActionsProps>,
|
||||
) =>
|
||||
reactRender(
|
||||
<VariantAnalysisActions
|
||||
variantAnalysisStatus={variantAnalysisStatus}
|
||||
onStopQueryClick={onStopQueryClick}
|
||||
onCopyRepositoryListClick={onCopyRepositoryListClick}
|
||||
onExportResultsClick={onExportResultsClick}
|
||||
{...props}
|
||||
/>,
|
||||
);
|
||||
|
||||
it("renders 1 button when in progress", async () => {
|
||||
const { container } = render(VariantAnalysisStatus.InProgress);
|
||||
const { container } = render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll("vscode-button").length).toEqual(1);
|
||||
});
|
||||
|
||||
it("renders the stop query button when in progress", async () => {
|
||||
render(VariantAnalysisStatus.InProgress);
|
||||
render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByText("Stop query"));
|
||||
expect(onStopQueryClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("renders 3 buttons when in progress with results", async () => {
|
||||
const { container } = render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
|
||||
showResultActions: true,
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll("vscode-button").length).toEqual(3);
|
||||
});
|
||||
|
||||
it("renders 2 buttons when succeeded", async () => {
|
||||
const { container } = render(VariantAnalysisStatus.Succeeded);
|
||||
const { container } = render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
|
||||
showResultActions: true,
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll("vscode-button").length).toEqual(2);
|
||||
});
|
||||
|
||||
it("renders the copy repository list button when succeeded", async () => {
|
||||
render(VariantAnalysisStatus.Succeeded);
|
||||
render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
|
||||
showResultActions: true,
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByText("Copy repository list"));
|
||||
expect(onCopyRepositoryListClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("renders the export results button when succeeded", async () => {
|
||||
render(VariantAnalysisStatus.Succeeded);
|
||||
render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
|
||||
showResultActions: true,
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByText("Export results"));
|
||||
expect(onExportResultsClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not render any buttons when failed", () => {
|
||||
const { container } = render(VariantAnalysisStatus.Failed);
|
||||
const { container } = render({
|
||||
variantAnalysisStatus: VariantAnalysisStatus.Failed,
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll("vscode-button").length).toEqual(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user