Skip to content

Commit

Permalink
Make sure the webview is loaded before sending requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Or-Geva committed Dec 14, 2023
1 parent c5f8bf3 commit 7052119
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 20 deletions.
34 changes: 32 additions & 2 deletions src/main/webview/event/eventManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,42 @@ import * as vscode from 'vscode';
import { LogManager } from '../../log/logManager';
import { LoginTask } from './tasks/login';
import { JumpToCodeTask } from './tasks/jumpToCode';
import { RunUtils } from '../../utils/runUtils';

/**
* Manages events and communication between the extension and the webview.
*/
export class EventManager {
protected send: EventSender;
private webviewLoaded: boolean = false;
private static TIMEOUT_THREE_MINUTES_IN_MS: number = 3 * 60 * 1000;
private static RETRY_DELAY_TEN_MS: number = 3 * 60 * 1000;

constructor(webview: vscode.Webview, private connectionManager: ConnectionManager, private logManager: LogManager) {
this.send = new EventSender(webview, logManager);
private constructor(webview: vscode.Webview, private connectionManager: ConnectionManager, private logManager: LogManager) {
this.setEventReceiver(webview);
this.send = new EventSender(webview, logManager);
}

public static async createEventManager(
webview: vscode.Webview,
connectionManager: ConnectionManager,
logManager: LogManager
): Promise<EventManager> {
const eventManager: EventManager = new EventManager(webview, connectionManager, logManager);
await EventManager.waitUntilWebviewLoaded(eventManager);
return eventManager;
}

private static async waitUntilWebviewLoaded(eventManager: EventManager) {
const startedTime: number = Date.now();
for (let i: number = 1; !EventManager.timedOut(startedTime) && !eventManager.webviewLoaded; i++) {
eventManager.send.setEventEmitter();
await RunUtils.delay(EventManager.RETRY_DELAY_TEN_MS * i);
}
}

private static timedOut(startedTime: number) {
return Date.now() - startedTime > EventManager.TIMEOUT_THREE_MINUTES_IN_MS;
}

/**
Expand All @@ -38,6 +64,10 @@ export class EventManager {
break;
case WebviewEventType.Login:
await new LoginTask(this.send, message.data, this.connectionManager, this.logManager).run();
break;
case WebviewEventType.WebviewLoaded:
this.webviewLoaded = true;
break;
}
},
undefined,
Expand Down
14 changes: 7 additions & 7 deletions src/main/webview/webviewSidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ export class WebviewSidebar extends WebView implements vscode.WebviewViewProvide

public async resolveWebviewView(webviewView: vscode.WebviewView) {
if (this.webview === undefined) {
this.webview = await this.createWebview(webviewView);
this.eventManager = this.createEventManager(this.webview);
this.webview = this.createWebview(webviewView);
this.eventManager = await this.createEventManager(this.webview);
}
if (this.currentPage != undefined) {
this.eventManager?.loadPage(this.currentPage);
}
}

private async createWebview(currentWebview: vscode.WebviewView) {
private createWebview(currentWebview: vscode.WebviewView) {
currentWebview.webview.html = this.getHtml(this.context, currentWebview.webview);
currentWebview.onDidDispose(
() => {
Expand All @@ -41,13 +41,13 @@ export class WebviewSidebar extends WebView implements vscode.WebviewViewProvide
return currentWebview;
}

private createEventManager(webview: vscode.WebviewView) {
const eventManager: EventManager = new EventManager(webview.webview, this.connectionManager, this._logManager);
webview.onDidChangeVisibility(() => {
private async createEventManager(webview: vscode.WebviewView) {
const eventManager: EventManager = await EventManager.createEventManager(webview.webview, this.connectionManager, this._logManager);
webview.onDidChangeVisibility(async () => {
if (!webview.visible) {
return;
}
this.eventManager = new EventManager(webview.webview, this.connectionManager, this._logManager);
this.eventManager = await EventManager.createEventManager(webview.webview, this.connectionManager, this._logManager);
if (this.currentPage) {
eventManager.loadPage(this.currentPage);
}
Expand Down
12 changes: 3 additions & 9 deletions src/main/webview/webviewTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import { LogManager } from '../log/logManager';
import { EventManager } from './event/eventManager';
import { WebView } from './webview';
import { ConnectionManager } from '../connect/connectionManager';
import { RunUtils } from '../utils/runUtils';

/**
* Show a webview panel with details about objects in the project
*/
export class WebviewTab extends WebView {
private static readonly WEBVIEW_DELAY_MILLISECS: number = 2000;
private panel: vscode.WebviewPanel | undefined;

constructor(logManager: LogManager, private connectionManager: ConnectionManager, private context: vscode.ExtensionContext) {
Expand All @@ -25,11 +23,7 @@ export class WebviewTab extends WebView {
public async resolveWebviewView() {
if (!this.panel) {
this.panel = this.createWebview();
this.eventManager = this.createEventManager(this.panel);
// Workaround: Delay the initial page load to ensure proper message delivery in the Webview.
// This is necessary because in the Webview, messages are only delivered when the webview is alive.
// This workaround applies specifically to VS-Code remote development environments.
await RunUtils.delay(WebviewTab.WEBVIEW_DELAY_MILLISECS);
this.eventManager = await this.createEventManager(this.panel);
} else {
this.panel.reveal();
}
Expand Down Expand Up @@ -67,8 +61,8 @@ export class WebviewTab extends WebView {
return panel;
}

private createEventManager(panel: vscode.WebviewPanel) {
const eventManager: EventManager = new EventManager(panel.webview, this.connectionManager, this._logManager);
private async createEventManager(panel: vscode.WebviewPanel) {
const eventManager: EventManager = await EventManager.createEventManager(panel.webview, this.connectionManager, this._logManager);
panel.onDidChangeViewState(() => {
if (this.currentPage) {
eventManager.loadPage(this.currentPage);
Expand Down
4 changes: 2 additions & 2 deletions src/test/tests/webview/event/eventManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ describe('EventManager', () => {
let webview: MockWebview;
let eventManager: EventManager;
let loadPageStub: any;
beforeEach(() => {
beforeEach(async () => {
webview = new MockWebview();
eventManager = new EventManager(webview, {} as ConnectionManager, {} as LogManager);
eventManager = await EventManager.createEventManager(webview, {} as ConnectionManager, {} as LogManager);
loadPageStub = sinon.stub(eventManager, 'loadPage').resolves();
});

Expand Down

0 comments on commit 7052119

Please sign in to comment.