Merge pull request #1544 from github/koesie10/scanned-repos-tab
Add analyzed repositories component
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { Repository } from './repository';
|
import { Repository } from './repository';
|
||||||
|
import { AnalysisAlert, AnalysisRawResults } from './analysis-result';
|
||||||
|
|
||||||
export interface VariantAnalysis {
|
export interface VariantAnalysis {
|
||||||
id: number,
|
id: number,
|
||||||
@@ -78,6 +79,12 @@ export interface VariantAnalysisSkippedRepositoryGroup {
|
|||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VariantAnalysisScannedRepositoryResult {
|
||||||
|
repositoryId: number;
|
||||||
|
interpretedResults?: AnalysisAlert[];
|
||||||
|
rawResults?: AnalysisRawResults;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures information needed to submit a variant
|
* Captures information needed to submit a variant
|
||||||
* analysis for processing.
|
* analysis for processing.
|
||||||
@@ -102,16 +109,24 @@ export interface VariantAnalysisSubmission {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param repo
|
* @param status
|
||||||
* @returns whether the repo scan is in a completed state, i.e. it cannot normally change state anymore
|
* @returns whether the status is in a completed state, i.e. it cannot normally change state anymore
|
||||||
*/
|
*/
|
||||||
export function hasRepoScanCompleted(repo: VariantAnalysisScannedRepository): boolean {
|
export function isCompletedAnalysisRepoStatus(status: VariantAnalysisRepoStatus): boolean {
|
||||||
return [
|
return [
|
||||||
// All states that indicates the repository has been scanned and cannot
|
// All states that indicates the repository has been scanned and cannot
|
||||||
// change status anymore.
|
// change status anymore.
|
||||||
VariantAnalysisRepoStatus.Succeeded, VariantAnalysisRepoStatus.Failed,
|
VariantAnalysisRepoStatus.Succeeded, VariantAnalysisRepoStatus.Failed,
|
||||||
VariantAnalysisRepoStatus.Canceled, VariantAnalysisRepoStatus.TimedOut,
|
VariantAnalysisRepoStatus.Canceled, VariantAnalysisRepoStatus.TimedOut,
|
||||||
].includes(repo.analysisStatus);
|
].includes(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param repo
|
||||||
|
* @returns whether the repo scan is in a completed state, i.e. it cannot normally change state anymore
|
||||||
|
*/
|
||||||
|
export function hasRepoScanCompleted(repo: VariantAnalysisScannedRepository): boolean {
|
||||||
|
return isCompletedAnalysisRepoStatus(repo.analysisStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
26
extensions/ql-vscode/src/stories/remote-queries/data/rawResults.json
generated
Normal file
26
extensions/ql-vscode/src/stories/remote-queries/data/rawResults.json
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"name": "#select",
|
||||||
|
"rows": 1,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"kind": "i"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resultSet": {
|
||||||
|
"schema": {
|
||||||
|
"name": "#select",
|
||||||
|
"rows": 1,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"kind": "i"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rows": [[60688]]
|
||||||
|
},
|
||||||
|
"fileLinkPrefix": "https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7",
|
||||||
|
"sourceLocationPrefix": "/home/runner/work/bulk-builder/bulk-builder",
|
||||||
|
"capped": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||||
|
|
||||||
|
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
|
||||||
|
import { VariantAnalysisAnalyzedRepoItem } from '../../view/variant-analysis/VariantAnalysisAnalyzedRepoItem';
|
||||||
|
import { VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis';
|
||||||
|
import { AnalysisAlert, AnalysisRawResults } from '../../remote-queries/shared/analysis-result';
|
||||||
|
|
||||||
|
import analysesResults from '../remote-queries/data/analysesResultsMessage.json';
|
||||||
|
import rawResults from '../remote-queries/data/rawResults.json';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Variant Analysis/Analyzed Repo Item',
|
||||||
|
component: VariantAnalysisAnalyzedRepoItem,
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<VariantAnalysisContainer>
|
||||||
|
<Story />
|
||||||
|
</VariantAnalysisContainer>
|
||||||
|
)
|
||||||
|
],
|
||||||
|
} as ComponentMeta<typeof VariantAnalysisAnalyzedRepoItem>;
|
||||||
|
|
||||||
|
const Template: ComponentStory<typeof VariantAnalysisAnalyzedRepoItem> = (args) => (
|
||||||
|
<VariantAnalysisAnalyzedRepoItem {...args} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Pending = Template.bind({});
|
||||||
|
Pending.args = {
|
||||||
|
repository: {
|
||||||
|
id: 63537249,
|
||||||
|
fullName: 'facebook/create-react-app',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
status: VariantAnalysisRepoStatus.Pending,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InProgress = Template.bind({});
|
||||||
|
InProgress.args = {
|
||||||
|
...Pending.args,
|
||||||
|
status: VariantAnalysisRepoStatus.InProgress,
|
||||||
|
interpretedResults: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Failed = Template.bind({});
|
||||||
|
Failed.args = {
|
||||||
|
...Pending.args,
|
||||||
|
status: VariantAnalysisRepoStatus.Failed,
|
||||||
|
interpretedResults: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TimedOut = Template.bind({});
|
||||||
|
TimedOut.args = {
|
||||||
|
...Pending.args,
|
||||||
|
status: VariantAnalysisRepoStatus.TimedOut,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Canceled = Template.bind({});
|
||||||
|
Canceled.args = {
|
||||||
|
...Pending.args,
|
||||||
|
status: VariantAnalysisRepoStatus.Canceled,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InterpretedResults = Template.bind({});
|
||||||
|
InterpretedResults.args = {
|
||||||
|
...Pending.args,
|
||||||
|
status: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 198,
|
||||||
|
interpretedResults: analysesResults.analysesResults.find(v => v.nwo === 'facebook/create-react-app')?.interpretedResults as unknown as AnalysisAlert[],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RawResults = Template.bind({});
|
||||||
|
RawResults.args = {
|
||||||
|
...InterpretedResults.args,
|
||||||
|
interpretedResults: undefined,
|
||||||
|
resultCount: 1,
|
||||||
|
rawResults: rawResults as unknown as AnalysisRawResults,
|
||||||
|
};
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||||
|
|
||||||
|
import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer';
|
||||||
|
import { VariantAnalysisAnalyzedRepos } from '../../view/variant-analysis/VariantAnalysisAnalyzedRepos';
|
||||||
|
import {
|
||||||
|
VariantAnalysisQueryLanguage,
|
||||||
|
VariantAnalysisRepoStatus,
|
||||||
|
VariantAnalysisStatus
|
||||||
|
} from '../../remote-queries/shared/variant-analysis';
|
||||||
|
import { AnalysisAlert } from '../../remote-queries/shared/analysis-result';
|
||||||
|
|
||||||
|
import analysesResults from '../remote-queries/data/analysesResultsMessage.json';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Variant Analysis/Analyzed Repos',
|
||||||
|
component: VariantAnalysisAnalyzedRepos,
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<VariantAnalysisContainer>
|
||||||
|
<Story />
|
||||||
|
</VariantAnalysisContainer>
|
||||||
|
)
|
||||||
|
],
|
||||||
|
} as ComponentMeta<typeof VariantAnalysisAnalyzedRepos>;
|
||||||
|
|
||||||
|
const Template: ComponentStory<typeof VariantAnalysisAnalyzedRepos> = (args) => (
|
||||||
|
<VariantAnalysisAnalyzedRepos {...args} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const interpretedResultsForRepo = (nwo: string): AnalysisAlert[] | undefined => {
|
||||||
|
return analysesResults.analysesResults.find(v => v.nwo === nwo)?.interpretedResults as unknown as AnalysisAlert[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Example = Template.bind({});
|
||||||
|
Example.args = {
|
||||||
|
variantAnalysis: {
|
||||||
|
id: 1,
|
||||||
|
controllerRepoId: 1,
|
||||||
|
query: {
|
||||||
|
name: 'Query name',
|
||||||
|
filePath: 'example.ql',
|
||||||
|
language: VariantAnalysisQueryLanguage.Javascript,
|
||||||
|
},
|
||||||
|
databases: {},
|
||||||
|
status: VariantAnalysisStatus.InProgress,
|
||||||
|
scannedRepos: [
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 63537249,
|
||||||
|
fullName: 'facebook/create-react-app',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded, resultCount: 198,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 167174,
|
||||||
|
fullName: 'jquery/jquery',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 67,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 237159,
|
||||||
|
fullName: 'expressjs/express',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 26,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 15062869,
|
||||||
|
fullName: 'facebook/jest',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Failed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 24195339,
|
||||||
|
fullName: 'angular/angular',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.InProgress,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 24560307,
|
||||||
|
fullName: 'babel/babel',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
repositoryResults: [
|
||||||
|
{
|
||||||
|
repositoryId: 63537249,
|
||||||
|
interpretedResults: interpretedResultsForRepo('facebook/create-react-app'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repositoryId: 167174,
|
||||||
|
interpretedResults: interpretedResultsForRepo('jquery/jquery'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repositoryId: 237159,
|
||||||
|
interpretedResults: interpretedResultsForRepo('expressjs/express'),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
;
|
||||||
13
extensions/ql-vscode/src/view/common/icon/LoadingIcon.tsx
Normal file
13
extensions/ql-vscode/src/view/common/icon/LoadingIcon.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { Codicon } from './Codicon';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoadingIcon = ({
|
||||||
|
label = 'Loading...',
|
||||||
|
className,
|
||||||
|
}: Props) => <Codicon name="loading" label={label} className={classNames(className, 'codicon-modifier-spin')} />;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './Codicon';
|
export * from './Codicon';
|
||||||
export * from './ErrorIcon';
|
export * from './ErrorIcon';
|
||||||
|
export * from './LoadingIcon';
|
||||||
export * from './SuccessIcon';
|
export * from './SuccessIcon';
|
||||||
export * from './WarningIcon';
|
export * from './WarningIcon';
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { AnalysisAlert, AnalysisRawResults } from '../../remote-queries/shared/analysis-result';
|
||||||
|
import AnalysisAlertResult from '../remote-queries/AnalysisAlertResult';
|
||||||
|
import RawResultsTable from '../remote-queries/RawResultsTable';
|
||||||
|
import { VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis';
|
||||||
|
import { Alert } from '../common';
|
||||||
|
|
||||||
|
const ContentContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AlertContainer = styled.div`
|
||||||
|
margin-top: 1em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InterpretedResultsContainer = styled.ul`
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 1em 0 0;
|
||||||
|
padding: 0.5em 0 0 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InterpretedResultItem = styled.li`
|
||||||
|
margin-bottom: 1em;
|
||||||
|
background-color: var(--vscode-notifications-background);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RawResultsContainer = styled.div`
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type AnalyzedRepoItemContentProps = {
|
||||||
|
status: VariantAnalysisRepoStatus;
|
||||||
|
|
||||||
|
interpretedResults?: AnalysisAlert[];
|
||||||
|
rawResults?: AnalysisRawResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnalyzedRepoItemContent = ({
|
||||||
|
status,
|
||||||
|
interpretedResults,
|
||||||
|
rawResults,
|
||||||
|
}: AnalyzedRepoItemContentProps) => {
|
||||||
|
return (
|
||||||
|
<ContentContainer>
|
||||||
|
{status === VariantAnalysisRepoStatus.Failed && <AlertContainer>
|
||||||
|
<Alert
|
||||||
|
type="error"
|
||||||
|
title="Failed"
|
||||||
|
message="The query failed to run on this repository."
|
||||||
|
/>
|
||||||
|
</AlertContainer>}
|
||||||
|
{status === VariantAnalysisRepoStatus.TimedOut && <AlertContainer>
|
||||||
|
<Alert
|
||||||
|
type="error"
|
||||||
|
title="Timed out"
|
||||||
|
message="The analysis ran out of time and we couldn't scan the repository."
|
||||||
|
/>
|
||||||
|
</AlertContainer>}
|
||||||
|
{status === VariantAnalysisRepoStatus.Canceled && <AlertContainer>
|
||||||
|
<Alert
|
||||||
|
type="error"
|
||||||
|
title="Canceled"
|
||||||
|
message="The variant analysis or this repository was canceled."
|
||||||
|
/>
|
||||||
|
</AlertContainer>}
|
||||||
|
{interpretedResults && (
|
||||||
|
<InterpretedResultsContainer>
|
||||||
|
{interpretedResults.map((r, i) =>
|
||||||
|
<InterpretedResultItem key={i}>
|
||||||
|
<AnalysisAlertResult alert={r} />
|
||||||
|
</InterpretedResultItem>)}
|
||||||
|
</InterpretedResultsContainer>
|
||||||
|
)}
|
||||||
|
{rawResults && (
|
||||||
|
<RawResultsContainer>
|
||||||
|
<RawResultsTable
|
||||||
|
schema={rawResults.schema}
|
||||||
|
results={rawResults.resultSet}
|
||||||
|
fileLinkPrefix={rawResults.fileLinkPrefix}
|
||||||
|
sourceLocationPrefix={rawResults.sourceLocationPrefix} />
|
||||||
|
</RawResultsContainer>
|
||||||
|
)}
|
||||||
|
</ContentContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|||||||
import {
|
import {
|
||||||
VariantAnalysis as VariantAnalysisDomainModel,
|
VariantAnalysis as VariantAnalysisDomainModel,
|
||||||
VariantAnalysisQueryLanguage,
|
VariantAnalysisQueryLanguage,
|
||||||
VariantAnalysisRepoStatus,
|
VariantAnalysisRepoStatus, VariantAnalysisScannedRepositoryResult,
|
||||||
VariantAnalysisStatus
|
VariantAnalysisStatus
|
||||||
} from '../../remote-queries/shared/variant-analysis';
|
} from '../../remote-queries/shared/variant-analysis';
|
||||||
import { VariantAnalysisContainer } from './VariantAnalysisContainer';
|
import { VariantAnalysisContainer } from './VariantAnalysisContainer';
|
||||||
@@ -29,7 +29,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-1',
|
fullName: 'octodemo/hello-world-1',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -37,7 +37,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-2',
|
fullName: 'octodemo/hello-world-2',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.Canceled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -45,7 +45,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-3',
|
fullName: 'octodemo/hello-world-3',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.TimedOut,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -53,7 +53,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-4',
|
fullName: 'octodemo/hello-world-4',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.Failed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -61,7 +61,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-5',
|
fullName: 'octodemo/hello-world-5',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.InProgress,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -69,7 +69,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
fullName: 'octodemo/hello-world-6',
|
fullName: 'octodemo/hello-world-6',
|
||||||
private: false,
|
private: false,
|
||||||
},
|
},
|
||||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
analysisStatus: VariantAnalysisRepoStatus.InProgress,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repository: {
|
repository: {
|
||||||
@@ -158,6 +158,42 @@ const variantAnalysis: VariantAnalysisDomainModel = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const repositoryResults: VariantAnalysisScannedRepositoryResult[] = [
|
||||||
|
{
|
||||||
|
repositoryId: 1,
|
||||||
|
rawResults: {
|
||||||
|
schema: {
|
||||||
|
name: '#select',
|
||||||
|
rows: 1,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
kind: 'i'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resultSet: {
|
||||||
|
schema: {
|
||||||
|
name: '#select',
|
||||||
|
rows: 1,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
kind: 'i'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rows: [
|
||||||
|
[
|
||||||
|
60688
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
fileLinkPrefix: 'https://github.com/octodemo/hello-world-1/blob/59a2a6c7d9dde7a6ecb77c2f7e8197d6925c143b',
|
||||||
|
sourceLocationPrefix: '/home/runner/work/bulk-builder/bulk-builder',
|
||||||
|
capped: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
|
function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
|
||||||
if (variantAnalysis.actionsWorkflowRunId === undefined) {
|
if (variantAnalysis.actionsWorkflowRunId === undefined) {
|
||||||
return <VariantAnalysisLoading />;
|
return <VariantAnalysisLoading />;
|
||||||
@@ -174,7 +210,10 @@ function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
|
|||||||
onExportResultsClick={() => console.log('Export results')}
|
onExportResultsClick={() => console.log('Export results')}
|
||||||
onViewLogsClick={() => console.log('View logs')}
|
onViewLogsClick={() => console.log('View logs')}
|
||||||
/>
|
/>
|
||||||
<VariantAnalysisOutcomePanels variantAnalysis={variantAnalysis} />
|
<VariantAnalysisOutcomePanels
|
||||||
|
variantAnalysis={variantAnalysis}
|
||||||
|
repositoryResults={repositoryResults}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { VSCodeBadge } from '@vscode/webview-ui-toolkit/react';
|
||||||
|
import { isCompletedAnalysisRepoStatus, VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis';
|
||||||
|
import { formatDecimal } from '../../pure/number';
|
||||||
|
import { Codicon, ErrorIcon, LoadingIcon, SuccessIcon } from '../common';
|
||||||
|
import { Repository } from '../../remote-queries/shared/repository';
|
||||||
|
import { AnalysisAlert, AnalysisRawResults } from '../../remote-queries/shared/analysis-result';
|
||||||
|
import { AnalyzedRepoItemContent } from './AnalyzedRepoItemContent';
|
||||||
|
|
||||||
|
// This will ensure that these icons have a className which we can use in the TitleContainer
|
||||||
|
const ExpandCollapseCodicon = styled(Codicon)``;
|
||||||
|
|
||||||
|
const TitleContainer = styled.button`
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
color: var(--vscode-editor-foreground);
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
${ExpandCollapseCodicon} {
|
||||||
|
color: var(--vscode-disabledForeground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Visibility = styled.span`
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: var(--vscode-descriptionForeground);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type VariantAnalysisAnalyzedRepoItemProps = {
|
||||||
|
repository: Repository;
|
||||||
|
status: VariantAnalysisRepoStatus;
|
||||||
|
resultCount?: number;
|
||||||
|
|
||||||
|
interpretedResults?: AnalysisAlert[];
|
||||||
|
rawResults?: AnalysisRawResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getErrorLabel = (status: VariantAnalysisRepoStatus.Failed | VariantAnalysisRepoStatus.TimedOut | VariantAnalysisRepoStatus.Canceled): string => {
|
||||||
|
switch (status) {
|
||||||
|
case VariantAnalysisRepoStatus.Failed:
|
||||||
|
return 'Failed';
|
||||||
|
case VariantAnalysisRepoStatus.TimedOut:
|
||||||
|
return 'Timed out';
|
||||||
|
case VariantAnalysisRepoStatus.Canceled:
|
||||||
|
return 'Canceled';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VariantAnalysisAnalyzedRepoItem = ({
|
||||||
|
repository,
|
||||||
|
status,
|
||||||
|
resultCount,
|
||||||
|
interpretedResults,
|
||||||
|
rawResults,
|
||||||
|
}: VariantAnalysisAnalyzedRepoItemProps) => {
|
||||||
|
const [isExpanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
|
const toggleExpanded = useCallback(() => {
|
||||||
|
setExpanded(oldIsExpanded => !oldIsExpanded);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const disabled = !isCompletedAnalysisRepoStatus(status);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TitleContainer onClick={toggleExpanded} disabled={disabled} aria-expanded={isExpanded}>
|
||||||
|
{isExpanded ? <ExpandCollapseCodicon name="chevron-down" label="Collapse" /> : <ExpandCollapseCodicon name="chevron-right" label="Expand" />}
|
||||||
|
<VSCodeBadge>{resultCount === undefined ? '-' : formatDecimal(resultCount)}</VSCodeBadge>
|
||||||
|
<span>{repository.fullName}</span>
|
||||||
|
<Visibility>{repository.private ? 'private' : 'public'}</Visibility>
|
||||||
|
<span>
|
||||||
|
{status === VariantAnalysisRepoStatus.Succeeded && <SuccessIcon />}
|
||||||
|
{(status === VariantAnalysisRepoStatus.Failed || status === VariantAnalysisRepoStatus.TimedOut || status === VariantAnalysisRepoStatus.Canceled) && <ErrorIcon label={getErrorLabel(status)} />}
|
||||||
|
{status === VariantAnalysisRepoStatus.InProgress && <LoadingIcon label="In progress" />}
|
||||||
|
</span>
|
||||||
|
</TitleContainer>
|
||||||
|
{isExpanded && <AnalyzedRepoItemContent status={status} interpretedResults={interpretedResults} rawResults={rawResults} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,5 +1,48 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { VariantAnalysis, VariantAnalysisScannedRepositoryResult } from '../../remote-queries/shared/variant-analysis';
|
||||||
|
import { VariantAnalysisAnalyzedRepoItem } from './VariantAnalysisAnalyzedRepoItem';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const VariantAnalysisAnalyzedRepos = () => {
|
const Container = styled.div`
|
||||||
return <div>This is the analyzed view</div>;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type VariantAnalysisAnalyzedReposProps = {
|
||||||
|
variantAnalysis: VariantAnalysis;
|
||||||
|
repositoryResults?: VariantAnalysisScannedRepositoryResult[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VariantAnalysisAnalyzedRepos = ({
|
||||||
|
variantAnalysis,
|
||||||
|
repositoryResults,
|
||||||
|
}: VariantAnalysisAnalyzedReposProps) => {
|
||||||
|
const repositoryResultsById = useMemo(() => {
|
||||||
|
const map = new Map<number, VariantAnalysisScannedRepositoryResult>();
|
||||||
|
repositoryResults?.forEach((repository) => {
|
||||||
|
map.set(repository.repositoryId, repository);
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}, [repositoryResults]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
{variantAnalysis.scannedRepos?.map(repository => {
|
||||||
|
const results = repositoryResultsById.get(repository.repository.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VariantAnalysisAnalyzedRepoItem
|
||||||
|
key={repository.repository.id}
|
||||||
|
repository={repository.repository}
|
||||||
|
status={repository.analysisStatus}
|
||||||
|
resultCount={repository.resultCount}
|
||||||
|
interpretedResults={results?.interpretedResults}
|
||||||
|
rawResults={results?.rawResults}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { VSCodeBadge, VSCodePanels, VSCodePanelTab, VSCodePanelView } from '@vscode/webview-ui-toolkit/react';
|
import { VSCodeBadge, VSCodePanels, VSCodePanelTab, VSCodePanelView } from '@vscode/webview-ui-toolkit/react';
|
||||||
import { formatDecimal } from '../../pure/number';
|
import { formatDecimal } from '../../pure/number';
|
||||||
import { VariantAnalysis } from '../../remote-queries/shared/variant-analysis';
|
import { VariantAnalysis, VariantAnalysisScannedRepositoryResult } from '../../remote-queries/shared/variant-analysis';
|
||||||
import { VariantAnalysisAnalyzedRepos } from './VariantAnalysisAnalyzedRepos';
|
import { VariantAnalysisAnalyzedRepos } from './VariantAnalysisAnalyzedRepos';
|
||||||
import { VariantAnalysisNotFoundRepos } from './VariantAnalysisNotFoundRepos';
|
import { VariantAnalysisNotFoundRepos } from './VariantAnalysisNotFoundRepos';
|
||||||
import { VariantAnalysisNoCodeqlDbRepos } from './VariantAnalysisNoCodeqlDbRepos';
|
import { VariantAnalysisNoCodeqlDbRepos } from './VariantAnalysisNoCodeqlDbRepos';
|
||||||
@@ -10,6 +10,7 @@ import { Alert } from '../common';
|
|||||||
|
|
||||||
export type VariantAnalysisOutcomePanelProps = {
|
export type VariantAnalysisOutcomePanelProps = {
|
||||||
variantAnalysis: VariantAnalysis;
|
variantAnalysis: VariantAnalysis;
|
||||||
|
repositoryResults?: VariantAnalysisScannedRepositoryResult[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const Tab = styled(VSCodePanelTab)`
|
const Tab = styled(VSCodePanelTab)`
|
||||||
@@ -33,7 +34,8 @@ const WarningsContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const VariantAnalysisOutcomePanels = ({
|
export const VariantAnalysisOutcomePanels = ({
|
||||||
variantAnalysis
|
variantAnalysis,
|
||||||
|
repositoryResults,
|
||||||
}: VariantAnalysisOutcomePanelProps) => {
|
}: VariantAnalysisOutcomePanelProps) => {
|
||||||
const noCodeqlDbRepositoryCount = variantAnalysis.skippedRepos?.noCodeqlDbRepos?.repositoryCount ?? 0;
|
const noCodeqlDbRepositoryCount = variantAnalysis.skippedRepos?.noCodeqlDbRepos?.repositoryCount ?? 0;
|
||||||
const notFoundRepositoryCount = variantAnalysis.skippedRepos?.notFoundRepos?.repositoryCount ?? 0;
|
const notFoundRepositoryCount = variantAnalysis.skippedRepos?.notFoundRepos?.repositoryCount ?? 0;
|
||||||
@@ -63,7 +65,7 @@ export const VariantAnalysisOutcomePanels = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{warnings}
|
{warnings}
|
||||||
<VariantAnalysisAnalyzedRepos />
|
<VariantAnalysisAnalyzedRepos variantAnalysis={variantAnalysis} repositoryResults={repositoryResults} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -88,7 +90,7 @@ export const VariantAnalysisOutcomePanels = ({
|
|||||||
<VSCodeBadge appearance="secondary">{formatDecimal(noCodeqlDbRepositoryCount)}</VSCodeBadge>
|
<VSCodeBadge appearance="secondary">{formatDecimal(noCodeqlDbRepositoryCount)}</VSCodeBadge>
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
<VSCodePanelView><VariantAnalysisAnalyzedRepos /></VSCodePanelView>
|
<VSCodePanelView><VariantAnalysisAnalyzedRepos variantAnalysis={variantAnalysis} repositoryResults={repositoryResults} /></VSCodePanelView>
|
||||||
{notFoundRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNotFoundRepos /></VSCodePanelView>}
|
{notFoundRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNotFoundRepos /></VSCodePanelView>}
|
||||||
{noCodeqlDbRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNoCodeqlDbRepos /></VSCodePanelView>}
|
{noCodeqlDbRepositoryCount > 0 && <VSCodePanelView><VariantAnalysisNoCodeqlDbRepos /></VSCodePanelView>}
|
||||||
</VSCodePanels>
|
</VSCodePanels>
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render as reactRender, screen } from '@testing-library/react';
|
||||||
|
import { VariantAnalysisRepoStatus } from '../../../remote-queries/shared/variant-analysis';
|
||||||
|
import { AnalyzedRepoItemContent, AnalyzedRepoItemContentProps } from '../AnalyzedRepoItemContent';
|
||||||
|
|
||||||
|
describe(AnalyzedRepoItemContent.name, () => {
|
||||||
|
const render = (props: Partial<AnalyzedRepoItemContentProps> = {}) => {
|
||||||
|
return reactRender(
|
||||||
|
<AnalyzedRepoItemContent
|
||||||
|
status={VariantAnalysisRepoStatus.Succeeded}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders the succeeded state with interpreted results', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
interpretedResults: [
|
||||||
|
{
|
||||||
|
message: {
|
||||||
|
tokens: [
|
||||||
|
{
|
||||||
|
t: 'text',
|
||||||
|
text: 'This is an empty block.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
shortDescription: 'This is an empty block.',
|
||||||
|
fileLink: {
|
||||||
|
fileLinkPrefix: 'https://github.com/facebook/create-react-app/blob/f34d88e30c7d8be7181f728d1abc4fd8d5cd07d3',
|
||||||
|
filePath: 'packages/create-react-app/createReactApp.js'
|
||||||
|
},
|
||||||
|
severity: 'Warning',
|
||||||
|
codeSnippet: {
|
||||||
|
startLine: 655,
|
||||||
|
endLine: 662,
|
||||||
|
text: ' try {\n callback();\n } catch (ignored) {\n // Callback might throw and fail, since it\'s a temp directory the\n // OS will clean it up eventually...\n }\n },\n });\n'
|
||||||
|
},
|
||||||
|
highlightedRegion: {
|
||||||
|
startLine: 657,
|
||||||
|
startColumn: 31,
|
||||||
|
endLine: 660,
|
||||||
|
endColumn: 14
|
||||||
|
},
|
||||||
|
codeFlows: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('This is an empty block.')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the succeeded state with raw results', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
rawResults: {
|
||||||
|
schema: {
|
||||||
|
name: '#select',
|
||||||
|
rows: 1,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
kind: 'i'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resultSet: {
|
||||||
|
schema: {
|
||||||
|
name: '#select',
|
||||||
|
rows: 1,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
kind: 'i'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rows: [
|
||||||
|
[
|
||||||
|
60688
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
fileLinkPrefix: 'https://github.com/octodemo/hello-world-1/blob/59a2a6c7d9dde7a6ecb77c2f7e8197d6925c143b',
|
||||||
|
sourceLocationPrefix: '/home/runner/work/bulk-builder/bulk-builder',
|
||||||
|
capped: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('60688')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the failed state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Failed,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Error: Failed')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the timed out state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.TimedOut,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Error: Timed out')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the canceled state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Canceled,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Error: Canceled')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render as reactRender, screen } from '@testing-library/react';
|
||||||
|
import { VariantAnalysisRepoStatus } from '../../../remote-queries/shared/variant-analysis';
|
||||||
|
import {
|
||||||
|
VariantAnalysisAnalyzedRepoItem,
|
||||||
|
VariantAnalysisAnalyzedRepoItemProps
|
||||||
|
} from '../VariantAnalysisAnalyzedRepoItem';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
describe(VariantAnalysisAnalyzedRepoItem.name, () => {
|
||||||
|
const render = (props: Partial<VariantAnalysisAnalyzedRepoItemProps> = {}) => {
|
||||||
|
return reactRender(
|
||||||
|
<VariantAnalysisAnalyzedRepoItem
|
||||||
|
repository={{
|
||||||
|
id: 1,
|
||||||
|
fullName: 'octodemo/hello-world-1',
|
||||||
|
private: false,
|
||||||
|
}}
|
||||||
|
status={VariantAnalysisRepoStatus.Pending}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders the pending state', () => {
|
||||||
|
render();
|
||||||
|
|
||||||
|
expect(screen.getByText('octodemo/hello-world-1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('-')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.queryByRole('img', {
|
||||||
|
// There should not be any icons, except the expand icon
|
||||||
|
name: (name) => name.toLowerCase() !== 'expand',
|
||||||
|
})).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the in progress state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.InProgress,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('img', {
|
||||||
|
name: 'In progress',
|
||||||
|
})).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the succeeded state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 178,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('img', {
|
||||||
|
name: 'Success',
|
||||||
|
})).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('178')).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the failed state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Failed,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('img', {
|
||||||
|
name: 'Failed',
|
||||||
|
})).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the timed out state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.TimedOut,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('img', {
|
||||||
|
name: 'Timed out',
|
||||||
|
})).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the canceled state', () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.Canceled,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('img', {
|
||||||
|
name: 'Canceled',
|
||||||
|
})).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole<HTMLButtonElement>('button', {
|
||||||
|
expanded: false
|
||||||
|
})).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the repo as public', () => {
|
||||||
|
render({
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: 'octodemo/hello-world-1',
|
||||||
|
private: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('public')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the repo as private', () => {
|
||||||
|
render({
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: 'octodemo/hello-world-1',
|
||||||
|
private: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('private')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can expand the repo item', async () => {
|
||||||
|
render({
|
||||||
|
status: VariantAnalysisRepoStatus.TimedOut,
|
||||||
|
});
|
||||||
|
|
||||||
|
await userEvent.click(screen.getByRole('button', {
|
||||||
|
expanded: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
screen.getByRole('button', {
|
||||||
|
expanded: true,
|
||||||
|
});
|
||||||
|
screen.getByText('Error: Timed out');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render as reactRender, screen } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import {
|
||||||
|
VariantAnalysisQueryLanguage,
|
||||||
|
VariantAnalysisRepoStatus,
|
||||||
|
VariantAnalysisStatus
|
||||||
|
} from '../../../remote-queries/shared/variant-analysis';
|
||||||
|
import { VariantAnalysisAnalyzedRepos, VariantAnalysisAnalyzedReposProps } from '../VariantAnalysisAnalyzedRepos';
|
||||||
|
|
||||||
|
describe(VariantAnalysisAnalyzedRepos.name, () => {
|
||||||
|
const defaultVariantAnalysis = {
|
||||||
|
id: 1,
|
||||||
|
controllerRepoId: 1,
|
||||||
|
actionsWorkflowRunId: 789263,
|
||||||
|
query: {
|
||||||
|
name: 'Example query',
|
||||||
|
filePath: 'example.ql',
|
||||||
|
language: VariantAnalysisQueryLanguage.Javascript,
|
||||||
|
},
|
||||||
|
databases: {},
|
||||||
|
status: VariantAnalysisStatus.InProgress,
|
||||||
|
scannedRepos: [
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: 'octodemo/hello-world-1',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 2,
|
||||||
|
fullName: 'octodemo/hello-world-2',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 3,
|
||||||
|
fullName: 'octodemo/hello-world-3',
|
||||||
|
private: true,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Failed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 4,
|
||||||
|
fullName: 'octodemo/hello-world-4',
|
||||||
|
private: false,
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.InProgress,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const render = (props: Partial<VariantAnalysisAnalyzedReposProps> = {}) => {
|
||||||
|
return reactRender(
|
||||||
|
<VariantAnalysisAnalyzedRepos
|
||||||
|
variantAnalysis={defaultVariantAnalysis}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders the repository names', () => {
|
||||||
|
render();
|
||||||
|
|
||||||
|
expect(screen.getByText('octodemo/hello-world-1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('octodemo/hello-world-2')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('octodemo/hello-world-3')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('octodemo/hello-world-4')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the interpreted result for a succeeded repo', async () => {
|
||||||
|
render({
|
||||||
|
repositoryResults: [
|
||||||
|
{
|
||||||
|
repositoryId: 2,
|
||||||
|
interpretedResults: [
|
||||||
|
{
|
||||||
|
message: {
|
||||||
|
tokens: [
|
||||||
|
{
|
||||||
|
t: 'text',
|
||||||
|
text: 'This is an empty block.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
shortDescription: 'This is an empty block.',
|
||||||
|
fileLink: {
|
||||||
|
fileLinkPrefix: 'https://github.com/facebook/create-react-app/blob/f34d88e30c7d8be7181f728d1abc4fd8d5cd07d3',
|
||||||
|
filePath: 'packages/create-react-app/createReactApp.js'
|
||||||
|
},
|
||||||
|
severity: 'Warning',
|
||||||
|
codeFlows: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.queryByText('This is an empty block.')).not.toBeInTheDocument();
|
||||||
|
await userEvent.click(screen.getByRole('button', {
|
||||||
|
name: /octodemo\/hello-world-2/,
|
||||||
|
}));
|
||||||
|
expect(screen.getByText('This is an empty block.')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user