Keep track of opened variant analysis views

To be able to send messages to the open view for a variant analysis, we
need to have a reference to the view. This is done by keeping track of
all open views in a dictionary indexed by their variant analysis ID.

We currently only allow one view per variant analysis, but do allow
multiple variant analysis views to be open at a time. In the future, we
may want to allow multiple views per variant analysis (such that e.g.
"Split right" works), but this is not supported yet.

The reason for the indirection through the interfaces is to prevent
circular dependencies between the variant analysis view and the manager.
This commit is contained in:
Koen Vlaswinkel
2022-10-03 13:24:50 +02:00
parent ab9cf465cc
commit 401da636a0
4 changed files with 46 additions and 10 deletions

View File

@@ -104,7 +104,6 @@ import { LogScannerService } from './log-insights/log-scanner-service';
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 { VariantAnalysis } from './remote-queries/shared/variant-analysis';
import {
VariantAnalysis as VariantAnalysisApiResponse,
@@ -935,16 +934,14 @@ async function activateWithInstalledDistribution(
ctx.subscriptions.push(
commandRunner('codeQL.mockVariantAnalysisView', async () => {
const variantAnalysisView = new VariantAnalysisView(ctx, 1);
variantAnalysisView.openView();
await variantAnalysisManager.showView(1);
})
);
// The "openVariantAnalysisView" command is internal-only.
ctx.subscriptions.push(
commandRunner('codeQL.openVariantAnalysisView', async (variantAnalysisId: number) => {
const variantAnalysisView = new VariantAnalysisView(ctx, variantAnalysisId);
variantAnalysisView.openView();
await variantAnalysisManager.showView(variantAnalysisId);
})
);

View File

@@ -13,9 +13,12 @@ import {
} from './gh-api/variant-analysis';
import { VariantAnalysis } from './shared/variant-analysis';
import { getErrorMessage } from '../pure/helpers-pure';
import { VariantAnalysisView } from './variant-analysis-view';
import { VariantAnalysisViewManager } from './variant-analysis-view-manager';
export class VariantAnalysisManager extends DisposableObject {
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
private readonly variantAnalysisMonitor: VariantAnalysisMonitor;
private readonly views = new Map<number, VariantAnalysisView>();
constructor(
private readonly ctx: ExtensionContext,
@@ -25,6 +28,29 @@ export class VariantAnalysisManager extends DisposableObject {
this.variantAnalysisMonitor = new VariantAnalysisMonitor(ctx, logger);
}
public async showView(variantAnalysisId: number): Promise<void> {
if (!this.views.has(variantAnalysisId)) {
// The view will register itself with the manager, so we don't need to do anything here.
new VariantAnalysisView(this.ctx, variantAnalysisId, this);
}
const variantAnalysisView = this.views.get(variantAnalysisId)!;
await variantAnalysisView.openView();
return;
}
public registerView(view: VariantAnalysisView): void {
if (this.views.has(view.variantAnalysisId)) {
throw new Error(`View for variant analysis with id: ${view.variantAnalysisId} already exists`);
}
this.views.set(view.variantAnalysisId, view);
}
public unregisterView(view: VariantAnalysisView): void {
this.views.delete(view.variantAnalysisId);
}
public async monitorVariantAnalysis(
variantAnalysis: VariantAnalysis,
cancellationToken: CancellationToken

View File

@@ -0,0 +1,9 @@
export interface VariantAnalysisViewInterface {
variantAnalysisId: number;
openView(): Promise<void>;
}
export interface VariantAnalysisViewManager<T extends VariantAnalysisViewInterface> {
registerView(view: T): void;
unregisterView(view: T): void;
}

View File

@@ -2,16 +2,20 @@ import { ExtensionContext, ViewColumn } from 'vscode';
import { AbstractWebview, WebviewPanelConfig } from '../abstract-webview';
import { WebviewMessage } from '../interface-utils';
import { logger } from '../logging';
import { VariantAnalysisViewInterface, VariantAnalysisViewManager } from './variant-analysis-view-manager';
export class VariantAnalysisView extends AbstractWebview<WebviewMessage, WebviewMessage> {
export class VariantAnalysisView extends AbstractWebview<WebviewMessage, WebviewMessage> implements VariantAnalysisViewInterface {
public constructor(
ctx: ExtensionContext,
private readonly variantAnalysisId: number,
public readonly variantAnalysisId: number,
private readonly manager: VariantAnalysisViewManager<VariantAnalysisView>,
) {
super(ctx);
manager.registerView(this);
}
public openView() {
public async openView() {
this.getPanel().reveal(undefined, true);
}
@@ -26,7 +30,7 @@ export class VariantAnalysisView extends AbstractWebview<WebviewMessage, Webview
}
protected onPanelDispose(): void {
// Nothing to dispose currently.
this.manager.unregisterView(this);
}
protected async onMessage(msg: WebviewMessage): Promise<void> {