Restore variant analysis view on restart of VSCode
This implements persistence for the variant analysis webview, allowing the webview panel to be restored when VSCode is restarted. It's probably easier to add this now than to try to add it later. The basic idea is that there are no real differences when opening the webview for the first time. However, when VSCode is restarted it will use the `VariantAnalysisViewSerializer` to restore the webview panel. In our case this means recreating the `VariantAnalysisView`. To fully test this, I've also added a mock variant analysis ID as the state of the webview. This value is now randomly generated when calling the `codeQL.mockVariantAnalysisView` command. This allows us to test opening multiple webviews and that the webviews are restored with the correct state. See: https://code.visualstudio.com/api/extension-guides/webview#persistence
This commit is contained in:
@@ -33,5 +33,6 @@ export const parameters = {
|
||||
};
|
||||
|
||||
(window as any).acquireVsCodeApi = () => ({
|
||||
postMessage: action('post-vscode-message')
|
||||
postMessage: action('post-vscode-message'),
|
||||
setState: action('set-vscode-state'),
|
||||
});
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"onCommand:codeQL.quickQuery",
|
||||
"onCommand:codeQL.restartQueryServer",
|
||||
"onWebviewPanel:resultsView",
|
||||
"onWebviewPanel:codeQL.variantAnalysis",
|
||||
"onFileSystem:codeql-zip-archive"
|
||||
],
|
||||
"main": "./out/extension",
|
||||
|
||||
@@ -33,6 +33,11 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
|
||||
super();
|
||||
}
|
||||
|
||||
public async restoreView(panel: WebviewPanel): Promise<void> {
|
||||
this.panel = panel;
|
||||
this.setupPanel(panel);
|
||||
}
|
||||
|
||||
protected get isShowingPanel() {
|
||||
return !!this.panel;
|
||||
}
|
||||
@@ -59,37 +64,43 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
|
||||
],
|
||||
}
|
||||
);
|
||||
this.push(
|
||||
this.panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
this.panelLoaded = false;
|
||||
this.onPanelDispose();
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
)
|
||||
);
|
||||
|
||||
this.panel.webview.html = getHtmlForWebview(
|
||||
ctx,
|
||||
this.panel.webview,
|
||||
config.view,
|
||||
{
|
||||
allowInlineStyles: true,
|
||||
}
|
||||
);
|
||||
this.push(
|
||||
this.panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.onMessage(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
)
|
||||
);
|
||||
this.setupPanel(this.panel);
|
||||
}
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
protected setupPanel(panel: WebviewPanel): void {
|
||||
const config = this.getPanelConfig();
|
||||
|
||||
this.push(
|
||||
panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
this.panelLoaded = false;
|
||||
this.onPanelDispose();
|
||||
},
|
||||
null,
|
||||
this.ctx.subscriptions
|
||||
)
|
||||
);
|
||||
|
||||
panel.webview.html = getHtmlForWebview(
|
||||
this.ctx,
|
||||
panel.webview,
|
||||
config.view,
|
||||
{
|
||||
allowInlineStyles: true,
|
||||
}
|
||||
);
|
||||
this.push(
|
||||
panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.onMessage(e),
|
||||
undefined,
|
||||
this.ctx.subscriptions
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract getPanelConfig(): WebviewPanelConfig;
|
||||
|
||||
protected abstract onPanelDispose(): void;
|
||||
|
||||
@@ -105,6 +105,7 @@ import { createInitialQueryInfo } from './run-queries-shared';
|
||||
import { LegacyQueryRunner } from './legacy-query-server/legacyRunner';
|
||||
import { QueryRunner } from './queryRunner';
|
||||
import { VariantAnalysisView } from './remote-queries/variant-analysis-view';
|
||||
import { VariantAnalysisViewSerializer } from './remote-queries/variant-analysis-view-serializer';
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -381,7 +382,10 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
|
||||
allowAutoUpdating: true
|
||||
})));
|
||||
|
||||
return await installOrUpdateThenTryActivate({
|
||||
const variantAnalysisViewSerializer = new VariantAnalysisViewSerializer(ctx);
|
||||
Window.registerWebviewPanelSerializer(VariantAnalysisView.viewType, variantAnalysisViewSerializer);
|
||||
|
||||
const codeQlExtension = await installOrUpdateThenTryActivate({
|
||||
isUserInitiated: !!ctx.globalState.get(shouldUpdateOnNextActivationKey),
|
||||
shouldDisplayMessageWhenNoUpdates: false,
|
||||
|
||||
@@ -389,6 +393,10 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
|
||||
// otherwise, ask user to accept the update
|
||||
allowAutoUpdating: !!ctx.globalState.get(shouldUpdateOnNextActivationKey)
|
||||
});
|
||||
|
||||
variantAnalysisViewSerializer.onExtensionLoaded();
|
||||
|
||||
return codeQlExtension;
|
||||
}
|
||||
|
||||
async function activateWithInstalledDistribution(
|
||||
@@ -909,8 +917,11 @@ async function activateWithInstalledDistribution(
|
||||
|
||||
ctx.subscriptions.push(
|
||||
commandRunner('codeQL.mockVariantAnalysisView', async () => {
|
||||
const variantAnalysisView = new VariantAnalysisView(ctx);
|
||||
variantAnalysisView.openView();
|
||||
// Generate a random variant analysis ID for testing
|
||||
const variantAnalysisId: number = Math.floor(Math.random() * 1000000);
|
||||
|
||||
const variantAnalysisView = new VariantAnalysisView(ctx, variantAnalysisId);
|
||||
void variantAnalysisView.openView();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as sarif from 'sarif';
|
||||
import { AnalysisResults } from '../remote-queries/shared/analysis-result';
|
||||
import { AnalysisSummary, RemoteQueryResult } from '../remote-queries/shared/remote-query-result';
|
||||
import { RawResultSet, ResultRow, ResultSetSchema, Column, ResolvableLocationValue } from './bqrs-cli-types';
|
||||
import { VariantAnalysis } from '../remote-queries/shared/variant-analysis';
|
||||
|
||||
/**
|
||||
* This module contains types and code that are shared between
|
||||
@@ -429,3 +430,24 @@ export interface CopyRepoListMessage {
|
||||
t: 'copyRepoList';
|
||||
queryId: string;
|
||||
}
|
||||
|
||||
export interface SetVariantAnalysisMessage {
|
||||
t: 'setVariantAnalysis';
|
||||
variantAnalysis: VariantAnalysis;
|
||||
}
|
||||
|
||||
export type ToVariantAnalysisMessage =
|
||||
| SetVariantAnalysisMessage;
|
||||
|
||||
export type StopVariantAnalysisMessage = {
|
||||
t: 'stopVariantAnalysis';
|
||||
variantAnalysisId: number;
|
||||
}
|
||||
|
||||
export type FromVariantAnalysisMessage =
|
||||
| ViewLoadedMsg
|
||||
| StopVariantAnalysisMessage;
|
||||
|
||||
export type VariantAnalysisState = {
|
||||
variantAnalysisId: number;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { ExtensionContext, WebviewPanel, WebviewPanelSerializer } from 'vscode';
|
||||
import { VariantAnalysisView } from './variant-analysis-view';
|
||||
import { VariantAnalysisState } from '../pure/interface-types';
|
||||
|
||||
export class VariantAnalysisViewSerializer implements WebviewPanelSerializer {
|
||||
private extensionLoaded = false;
|
||||
private readonly resolvePromises: (() => void)[] = [];
|
||||
|
||||
public constructor(
|
||||
private readonly ctx: ExtensionContext
|
||||
) { }
|
||||
|
||||
onExtensionLoaded(): void {
|
||||
this.extensionLoaded = true;
|
||||
this.resolvePromises.forEach((resolve) => resolve());
|
||||
}
|
||||
|
||||
async deserializeWebviewPanel(webviewPanel: WebviewPanel, state: unknown): Promise<void> {
|
||||
if (!state || typeof state !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('variantAnalysisId' in state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const variantAnalysisState: VariantAnalysisState = state as VariantAnalysisState;
|
||||
|
||||
await this.waitForExtensionFullyLoaded();
|
||||
|
||||
const view = new VariantAnalysisView(this.ctx, variantAnalysisState.variantAnalysisId);
|
||||
await view.restoreView(webviewPanel);
|
||||
}
|
||||
|
||||
private waitForExtensionFullyLoaded(): Promise<void> {
|
||||
if (this.extensionLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.resolvePromises.push(resolve);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,38 @@
|
||||
import { ViewColumn } from 'vscode';
|
||||
import { ExtensionContext, ViewColumn } from 'vscode';
|
||||
import { AbstractWebview, WebviewPanelConfig } from '../abstract-webview';
|
||||
import { WebviewMessage } from '../interface-utils';
|
||||
import { logger } from '../logging';
|
||||
import { FromVariantAnalysisMessage, ToVariantAnalysisMessage } from '../pure/interface-types';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import {
|
||||
VariantAnalysis,
|
||||
VariantAnalysisQueryLanguage,
|
||||
VariantAnalysisRepoStatus,
|
||||
VariantAnalysisStatus
|
||||
} from './shared/variant-analysis';
|
||||
|
||||
export class VariantAnalysisView extends AbstractWebview<WebviewMessage, WebviewMessage> {
|
||||
public openView() {
|
||||
export class VariantAnalysisView extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage> {
|
||||
public static readonly viewType = 'codeQL.variantAnalysis';
|
||||
|
||||
public constructor(
|
||||
ctx: ExtensionContext,
|
||||
private readonly variantAnalysisId: number
|
||||
) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public async openView() {
|
||||
this.getPanel().reveal(undefined, true);
|
||||
|
||||
await this.waitForPanelLoaded();
|
||||
}
|
||||
|
||||
protected getPanelConfig(): WebviewPanelConfig {
|
||||
return {
|
||||
viewId: 'variantAnalysisView',
|
||||
title: 'CodeQL Query Results',
|
||||
viewId: VariantAnalysisView.viewType,
|
||||
title: `CodeQL query results for query ${this.variantAnalysisId}`,
|
||||
viewColumn: ViewColumn.Active,
|
||||
preserveFocus: true,
|
||||
view: 'variant-analysis'
|
||||
view: 'variant-analysis',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,7 +40,173 @@ export class VariantAnalysisView extends AbstractWebview<WebviewMessage, Webview
|
||||
// Nothing to dispose currently.
|
||||
}
|
||||
|
||||
protected async onMessage(msg: WebviewMessage): Promise<void> {
|
||||
void logger.log('Received message on variant analysis view: ' + msg.t);
|
||||
protected async onMessage(msg: FromVariantAnalysisMessage): Promise<void> {
|
||||
switch (msg.t) {
|
||||
case 'viewLoaded':
|
||||
this.onWebViewLoaded();
|
||||
|
||||
void logger.log('Variant analysis view loaded');
|
||||
|
||||
await this.postMessage({
|
||||
t: 'setVariantAnalysis',
|
||||
variantAnalysis: this.getVariantAnalysis(),
|
||||
});
|
||||
|
||||
break;
|
||||
case 'stopVariantAnalysis':
|
||||
void logger.log(`Stop variant analysis: ${msg.variantAnalysisId}`);
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private getVariantAnalysis(): VariantAnalysis {
|
||||
return {
|
||||
id: this.variantAnalysisId,
|
||||
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.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 3,
|
||||
fullName: 'octodemo/hello-world-3',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 4,
|
||||
fullName: 'octodemo/hello-world-4',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 5,
|
||||
fullName: 'octodemo/hello-world-5',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 6,
|
||||
fullName: 'octodemo/hello-world-6',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 7,
|
||||
fullName: 'octodemo/hello-world-7',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 8,
|
||||
fullName: 'octodemo/hello-world-8',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 9,
|
||||
fullName: 'octodemo/hello-world-9',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 10,
|
||||
fullName: 'octodemo/hello-world-10',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
],
|
||||
skippedRepos: {
|
||||
notFoundRepos: {
|
||||
repositoryCount: 2,
|
||||
repositories: [
|
||||
{
|
||||
fullName: 'octodemo/hello-globe'
|
||||
},
|
||||
{
|
||||
fullName: 'octodemo/hello-planet'
|
||||
}
|
||||
]
|
||||
},
|
||||
noCodeqlDbRepos: {
|
||||
repositoryCount: 4,
|
||||
repositories: [
|
||||
{
|
||||
id: 100,
|
||||
fullName: 'octodemo/no-db-1'
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
fullName: 'octodemo/no-db-2'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
fullName: 'octodemo/no-db-3'
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
fullName: 'octodemo/no-db-4'
|
||||
}
|
||||
]
|
||||
},
|
||||
overLimitRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 201,
|
||||
fullName: 'octodemo/over-limit-1'
|
||||
}
|
||||
]
|
||||
},
|
||||
accessMismatchRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 205,
|
||||
fullName: 'octodemo/private'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,171 @@ import React from 'react';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import { VariantAnalysis as VariantAnalysisComponent } from '../../view/variant-analysis/VariantAnalysis';
|
||||
import {
|
||||
VariantAnalysis as VariantAnalysisDomainModel,
|
||||
VariantAnalysisQueryLanguage, VariantAnalysisRepoStatus, VariantAnalysisStatus
|
||||
} from '../../remote-queries/shared/variant-analysis';
|
||||
|
||||
export default {
|
||||
title: 'Variant Analysis/Variant Analysis',
|
||||
component: VariantAnalysisComponent,
|
||||
} as ComponentMeta<typeof VariantAnalysisComponent>;
|
||||
|
||||
const Template: ComponentStory<typeof VariantAnalysisComponent> = () => (
|
||||
<VariantAnalysisComponent />
|
||||
const Template: ComponentStory<typeof VariantAnalysisComponent> = (args) => (
|
||||
<VariantAnalysisComponent {...args} />
|
||||
);
|
||||
|
||||
export const VariantAnalysis = Template.bind({});
|
||||
const variantAnalysis: VariantAnalysisDomainModel = {
|
||||
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.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 3,
|
||||
fullName: 'octodemo/hello-world-3',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 4,
|
||||
fullName: 'octodemo/hello-world-4',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 5,
|
||||
fullName: 'octodemo/hello-world-5',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 6,
|
||||
fullName: 'octodemo/hello-world-6',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 7,
|
||||
fullName: 'octodemo/hello-world-7',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 8,
|
||||
fullName: 'octodemo/hello-world-8',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 9,
|
||||
fullName: 'octodemo/hello-world-9',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 10,
|
||||
fullName: 'octodemo/hello-world-10',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
],
|
||||
skippedRepos: {
|
||||
notFoundRepos: {
|
||||
repositoryCount: 2,
|
||||
repositories: [
|
||||
{
|
||||
fullName: 'octodemo/hello-globe'
|
||||
},
|
||||
{
|
||||
fullName: 'octodemo/hello-planet'
|
||||
}
|
||||
]
|
||||
},
|
||||
noCodeqlDbRepos: {
|
||||
repositoryCount: 4,
|
||||
repositories: [
|
||||
{
|
||||
id: 100,
|
||||
fullName: 'octodemo/no-db-1'
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
fullName: 'octodemo/no-db-2'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
fullName: 'octodemo/no-db-3'
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
fullName: 'octodemo/no-db-4'
|
||||
}
|
||||
]
|
||||
},
|
||||
overLimitRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 201,
|
||||
fullName: 'octodemo/over-limit-1'
|
||||
}
|
||||
]
|
||||
},
|
||||
accessMismatchRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 205,
|
||||
fullName: 'octodemo/private'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const Loading = Template.bind({});
|
||||
Loading.args = {};
|
||||
|
||||
export const FullExample = Template.bind({});
|
||||
FullExample.args = {
|
||||
variantAnalysis: variantAnalysis,
|
||||
};
|
||||
|
||||
@@ -1,162 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
VariantAnalysis as VariantAnalysisDomainModel,
|
||||
VariantAnalysisQueryLanguage,
|
||||
VariantAnalysisRepoStatus,
|
||||
VariantAnalysisStatus
|
||||
} from '../../remote-queries/shared/variant-analysis';
|
||||
import { VariantAnalysis as VariantAnalysisDomainModel } from '../../remote-queries/shared/variant-analysis';
|
||||
import { VariantAnalysisContainer } from './VariantAnalysisContainer';
|
||||
import { VariantAnalysisHeader } from './VariantAnalysisHeader';
|
||||
import { VariantAnalysisOutcomePanels } from './VariantAnalysisOutcomePanels';
|
||||
import { VariantAnalysisLoading } from './VariantAnalysisLoading';
|
||||
|
||||
const variantAnalysis: VariantAnalysisDomainModel = {
|
||||
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.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 3,
|
||||
fullName: 'octodemo/hello-world-3',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 4,
|
||||
fullName: 'octodemo/hello-world-4',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 5,
|
||||
fullName: 'octodemo/hello-world-5',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 6,
|
||||
fullName: 'octodemo/hello-world-6',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 7,
|
||||
fullName: 'octodemo/hello-world-7',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 8,
|
||||
fullName: 'octodemo/hello-world-8',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 9,
|
||||
fullName: 'octodemo/hello-world-9',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
{
|
||||
repository: {
|
||||
id: 10,
|
||||
fullName: 'octodemo/hello-world-10',
|
||||
private: false,
|
||||
},
|
||||
analysisStatus: VariantAnalysisRepoStatus.Pending,
|
||||
},
|
||||
],
|
||||
skippedRepos: {
|
||||
notFoundRepos: {
|
||||
repositoryCount: 2,
|
||||
repositories: [
|
||||
{
|
||||
fullName: 'octodemo/hello-globe'
|
||||
},
|
||||
{
|
||||
fullName: 'octodemo/hello-planet'
|
||||
}
|
||||
]
|
||||
},
|
||||
noCodeqlDbRepos: {
|
||||
repositoryCount: 4,
|
||||
repositories: [
|
||||
{
|
||||
id: 100,
|
||||
fullName: 'octodemo/no-db-1'
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
fullName: 'octodemo/no-db-2'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
fullName: 'octodemo/no-db-3'
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
fullName: 'octodemo/no-db-4'
|
||||
}
|
||||
]
|
||||
},
|
||||
overLimitRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 201,
|
||||
fullName: 'octodemo/over-limit-1'
|
||||
}
|
||||
]
|
||||
},
|
||||
accessMismatchRepos: {
|
||||
repositoryCount: 1,
|
||||
repositories: [
|
||||
{
|
||||
id: 205,
|
||||
fullName: 'octodemo/private'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
};
|
||||
import { ToVariantAnalysisMessage } from '../../pure/interface-types';
|
||||
import { vscode } from '../vscode-api';
|
||||
|
||||
function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
|
||||
if (variantAnalysis.actionsWorkflowRunId === undefined) {
|
||||
@@ -179,7 +30,37 @@ function getContainerContents(variantAnalysis: VariantAnalysisDomainModel) {
|
||||
);
|
||||
}
|
||||
|
||||
export function VariantAnalysis(): JSX.Element {
|
||||
type Props = {
|
||||
variantAnalysis?: VariantAnalysisDomainModel;
|
||||
}
|
||||
|
||||
export function VariantAnalysis({
|
||||
variantAnalysis: initialVariantAnalysis,
|
||||
}: Props): JSX.Element {
|
||||
const [variantAnalysis, setVariantAnalysis] = useState<VariantAnalysisDomainModel | undefined>(initialVariantAnalysis);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('message', (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToVariantAnalysisMessage = evt.data;
|
||||
if (msg.t === 'setVariantAnalysis') {
|
||||
setVariantAnalysis(msg.variantAnalysis);
|
||||
vscode.setState({
|
||||
variantAnalysisId: msg.variantAnalysis.id,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, '');
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!variantAnalysis) {
|
||||
return <VariantAnalysisLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<VariantAnalysisContainer>
|
||||
{getContainerContents(variantAnalysis)}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { FromCompareViewMessage, FromRemoteQueriesMessage, FromResultsViewMsg } from '../pure/interface-types';
|
||||
import {
|
||||
FromCompareViewMessage,
|
||||
FromRemoteQueriesMessage,
|
||||
FromResultsViewMsg,
|
||||
FromVariantAnalysisMessage, VariantAnalysisState
|
||||
} from '../pure/interface-types';
|
||||
|
||||
export interface VsCodeApi {
|
||||
/**
|
||||
* Post message back to vscode extension.
|
||||
*/
|
||||
postMessage(msg: FromResultsViewMsg | FromCompareViewMessage | FromRemoteQueriesMessage): void;
|
||||
postMessage(msg: FromResultsViewMsg | FromCompareViewMessage | FromRemoteQueriesMessage | FromVariantAnalysisMessage): void;
|
||||
|
||||
/**
|
||||
* Set state of the webview.
|
||||
*/
|
||||
setState(state: VariantAnalysisState): void;
|
||||
}
|
||||
|
||||
declare const acquireVsCodeApi: () => VsCodeApi;
|
||||
|
||||
Reference in New Issue
Block a user