Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";
import * as vscode from "vscode";
import { trackWebviewPanel } from "../../../../utils/webviewTracker";
import { getWorkSpaceFolder, getWorkSpaceUri } from "../../../../utils";
import { IndexingStatusBarHandler } from "../statusBarHandler";

Expand Down Expand Up @@ -1013,6 +1014,7 @@ export async function createIndexWithContext(context: vscode.ExtensionContext) {
vscode.ViewColumn.One,
{}
);
trackWebviewPanel(panel, "fileInfo", "contentIndexes.getFileInfo");

// Generate HTML content
panel.webview.html = `
Expand Down
12 changes: 12 additions & 0 deletions src/bookNameSettings/bookNameSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ import * as vscode from "vscode";
import * as xml2js from "xml2js";
import { addMetadataEdit } from "@/utils/editMapUtils";
import { getCorrespondingSourceUri } from "@/utils/codexNotebookUtils";
import { trackWebviewPanel } from "../utils/webviewTracker";

let currentPanel: vscode.WebviewPanel | undefined;

export async function openBookNameEditor() {
if (currentPanel) {
currentPanel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
"bookNameEditor",
"Edit Book Names",
Expand All @@ -14,6 +21,11 @@ export async function openBookNameEditor() {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(panel, "bookNameEditor", "openBookNameEditor");
currentPanel = panel;
panel.onDidDispose(() => {
currentPanel = undefined;
});

// Dynamic import for fs and path
const fs = await import("fs");
Expand Down
14 changes: 14 additions & 0 deletions src/cellLabelImporter/cellLabelImporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { copyToTempStorage, getColumnHeaders } from "./utils";
import { updateCellLabels } from "./updater";
import { getNonce } from "../providers/dictionaryTable/utilities/getNonce";
import { safePostMessageToPanel } from "../utils/webviewUtils";
import { trackWebviewPanel } from "../utils/webviewTracker";

const DEBUG_CELL_LABEL_IMPORTER = false;
function debug(message: string, ...args: any[]): void {
Expand All @@ -21,6 +22,8 @@ function debug(message: string, ...args: any[]): void {
}
}

let currentPanel: vscode.WebviewPanel | undefined;

// Interface for the cell label data
interface CellLabelData {
cellId: string;
Expand Down Expand Up @@ -142,6 +145,10 @@ async function getHtmlForCellLabelImporterView(
}

export async function openCellLabelImporter(context: vscode.ExtensionContext) {
if (currentPanel) {
currentPanel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
"cellLabelImporter",
"Import Cell Labels (React)",
Expand All @@ -155,9 +162,16 @@ export async function openCellLabelImporter(context: vscode.ExtensionContext) {
],
}
);
trackWebviewPanel(panel, "cellLabelImporter", "openCellLabelImporter");

context.subscriptions.push(panel);
let disposables: vscode.Disposable[] = [];
currentPanel = panel;
panel.onDidDispose(() => {
currentPanel = undefined;
disposables.forEach((d) => d.dispose());
disposables = [];
});

// --- Variables to manage temporary files and import sources for the current session ---
let currentSessionTempFileUris: vscode.Uri[] = [];
Expand Down
12 changes: 12 additions & 0 deletions src/copilotSettings/copilotSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from "vscode";
import { callLLM } from "../utils/llmUtils";
import { CompletionConfig } from "@/utils/llmUtils";
import { MetadataManager } from "../utils/metadataManager";
import { trackWebviewPanel } from "../utils/webviewTracker";

interface ProjectLanguage {
tag: string;
Expand All @@ -16,6 +17,8 @@ function debug(message: string, ...args: any[]): void {
}
}

let currentPanel: vscode.WebviewPanel | undefined;

export async function debugValidationSetting() {
const config = vscode.workspace.getConfiguration("codex-editor-extension");
const useOnlyValidatedExamples = config.get("useOnlyValidatedExamples");
Expand All @@ -34,6 +37,10 @@ export async function debugValidationSetting() {
}

export async function openSystemMessageEditor() {
if (currentPanel) {
currentPanel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
"systemMessageEditor",
"Copilot Settings",
Expand All @@ -43,6 +50,11 @@ export async function openSystemMessageEditor() {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(panel, "systemMessageEditor", "openSystemMessageEditor");
currentPanel = panel;
panel.onDidDispose(() => {
currentPanel = undefined;
});

const scriptUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(
Expand Down
7 changes: 7 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { checkIfMetadataAndGitIsInitialized } from "./projectManager/utils/proje
import { CommentsMigrator } from "./utils/commentsMigrationUtils";
import { registerTestingCommands } from "./evaluation/testingCommands";
import { initializeABTesting } from "./utils/abTestingSetup";
import { dumpActiveWebviews } from "./utils/webviewTracker";
import {
migration_addValidationsForUserEdits,
migration_moveTimestampsToMetadataData,
Expand Down Expand Up @@ -561,6 +562,12 @@ export async function activate(context: vscode.ExtensionContext) {
(async () => registerTestingCommands(context))(),
]);

context.subscriptions.push(
vscode.commands.registerCommand("codex-editor.debugWebviews", () => {
dumpActiveWebviews();
})
);

// Initialize A/B testing registry (always-on)
initializeABTesting();

Expand Down
24 changes: 23 additions & 1 deletion src/globalProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { CustomWebviewProvider } from "./providers/parallelPassagesWebview/custo
import { GlobalContentType, GlobalMessage } from "../types";
import { getNonce } from "./providers/dictionaryTable/utilities/getNonce";
import { safePostMessageToView } from "./utils/webviewUtils";
import { trackWebviewView } from "./utils/webviewTracker";



// Base class for all webview providers to extend
export abstract class BaseWebviewProvider implements vscode.WebviewViewProvider {
protected _view?: vscode.WebviewView;
protected _context: vscode.ExtensionContext;
private viewDisposables: vscode.Disposable[] = [];

constructor(context: vscode.ExtensionContext) {
this._context = context;
Expand All @@ -28,6 +30,12 @@ export abstract class BaseWebviewProvider implements vscode.WebviewViewProvider

// Common webview resolution
public resolveWebviewView(webviewView: vscode.WebviewView) {
trackWebviewView(webviewView, this.getWebviewId(), "BaseWebviewProvider.resolveWebviewView");
// Clean up any previous view-specific disposables before replacing the view
if (this.viewDisposables.length > 0) {
this.viewDisposables.forEach((d) => d.dispose());
this.viewDisposables = [];
}
this._view = webviewView;

webviewView.webview.options = {
Expand All @@ -38,7 +46,7 @@ export abstract class BaseWebviewProvider implements vscode.WebviewViewProvider
webviewView.webview.html = this.getHtmlForWebview(webviewView);

// Set up message handling with common handlers
webviewView.webview.onDidReceiveMessage(async (message: any) => {
const messageDisposable = webviewView.webview.onDidReceiveMessage(async (message: any) => {
// Handle global messages first
if ("destination" in message) {
GlobalProvider.getInstance().handleMessage(message);
Expand All @@ -54,6 +62,15 @@ export abstract class BaseWebviewProvider implements vscode.WebviewViewProvider
// Pass to child class for specific handling
await this.handleMessage(message);
});
this.viewDisposables.push(messageDisposable);

const disposeDisposable = webviewView.onDidDispose(() => {
this._view = undefined;
this.viewDisposables.forEach((d) => d.dispose());
this.viewDisposables = [];
this.onWebviewDisposed();
});
this.viewDisposables.push(disposeDisposable);

// Call child class initialization if needed
this.onWebviewResolved(webviewView);
Expand All @@ -64,6 +81,11 @@ export abstract class BaseWebviewProvider implements vscode.WebviewViewProvider
// Child classes can override this for additional initialization
}

// Optional hook for cleanup when the webview is disposed
protected onWebviewDisposed(): void {
// Child classes can override this for cleanup
}

// Common message handlers
protected async handleCommonMessage(message: any): Promise<boolean> {
switch (message.command) {
Expand Down
12 changes: 12 additions & 0 deletions src/licenseSettings/licenseSettings.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import { trackWebviewPanel } from "../utils/webviewTracker";

let currentPanel: vscode.WebviewPanel | undefined;

export async function openLicenseEditor() {
if (currentPanel) {
currentPanel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
"licenseEditor",
"Project License",
Expand All @@ -12,6 +19,11 @@ export async function openLicenseEditor() {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(panel, "licenseEditor", "openLicenseEditor");
currentPanel = panel;
panel.onDidDispose(() => {
currentPanel = undefined;
});

// Get workspace folder
const workspaceFolders = vscode.workspace.workspaceFolders;
Expand Down
12 changes: 12 additions & 0 deletions src/projectManager/projectExportView.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { CodexExportFormat } from "../exportHandler/exportHandler";
import * as vscode from "vscode";
import { safePostMessageToPanel } from "../utils/webviewUtils";
import { trackWebviewPanel } from "../utils/webviewTracker";

let currentPanel: vscode.WebviewPanel | undefined;

export async function openProjectExportView(context: vscode.ExtensionContext) {
if (currentPanel) {
currentPanel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
"projectExportView",
"Export Project",
Expand All @@ -12,6 +19,11 @@ export async function openProjectExportView(context: vscode.ExtensionContext) {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(panel, "projectExportView", "openProjectExportView");
currentPanel = panel;
panel.onDidDispose(() => {
currentPanel = undefined;
});

// Get project configuration
const projectConfig = vscode.workspace.getConfiguration("codex-project-manager");
Expand Down
2 changes: 2 additions & 0 deletions src/providers/EditAnalysisView/EditAnalysisViewProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import { analyzeEditHistory } from "../../activationHelpers/contextAware/contentIndexes/indexes/editHistory";
import { readLocalProjectSettings, writeLocalProjectSettings } from "../../utils/localProjectSettings";
import { trackWebviewPanel } from "../../utils/webviewTracker";

export class EditAnalysisProvider implements vscode.Disposable {
public static readonly viewType = "codex-editor.editAnalysis";
Expand Down Expand Up @@ -28,6 +29,7 @@ export class EditAnalysisProvider implements vscode.Disposable {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(this._panel, EditAnalysisProvider.viewType, "EditAnalysisProvider.show");

this._panel.onDidDispose(() => {
this._panel = undefined;
Expand Down
2 changes: 2 additions & 0 deletions src/providers/NewSourceUploader/NewSourceUploaderProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { getNotebookMetadataManager } from "../../utils/notebookMetadataManager"
import { migrateLocalizedBooksToMetadata as migrateLocalizedBooks } from "./localizedBooksMigration/localizedBooksMigration";
import { removeLocalizedBooksJsonIfPresent as removeLocalizedBooksJson } from "./localizedBooksMigration/removeLocalizedBooksJson";
import { getAttachmentDocumentSegmentFromUri } from "../../utils/attachmentFolderUtils";
import { trackWebviewPanel } from "../../utils/webviewTracker";
// import { parseRtfWithPandoc as parseRtfNode } from "../../../webviews/codex-webviews/src/NewSourceUploader/importers/rtf/pandocNodeBridge";

const execAsync = promisify(exec);
Expand Down Expand Up @@ -102,6 +103,7 @@ export class NewSourceUploaderProvider implements vscode.CustomTextEditorProvide
webviewPanel: vscode.WebviewPanel,
token: vscode.CancellationToken
): Promise<void> {
trackWebviewPanel(webviewPanel, NewSourceUploaderProvider.viewType, "NewSourceUploaderProvider.resolveCustomTextEditor");
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
webviewPanel.webview.options = {
enableScripts: true,
Expand Down
2 changes: 2 additions & 0 deletions src/providers/SplashScreen/SplashScreenProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from "vscode";
import { ActivationTiming } from "../../extension";
import { getWebviewHtml } from "../../utils/webviewTemplate";
import { safePostMessageToPanel } from "../../utils/webviewUtils";
import { trackWebviewPanel } from "../../utils/webviewTracker";

const DEBUG_SPLASH_SCREEN_PROVIDER = false;
function debug(message: string, ...args: any[]): void {
Expand Down Expand Up @@ -61,6 +62,7 @@ export class SplashScreenProvider {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(this._panel, SplashScreenProvider.viewType, "SplashScreenProvider.show");
debug("[SplashScreen] Panel created successfully");

// Set webview options
Expand Down
2 changes: 2 additions & 0 deletions src/providers/StartupFlow/StartupFlowProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import JSZip from "jszip";
import { getWebviewHtml } from "../../utils/webviewTemplate";

import { safePostMessageToPanel, safeIsVisible, safeSetHtml, safeSetOptions } from "../../utils/webviewUtils";
import { trackWebviewPanel } from "../../utils/webviewTracker";
import * as path from "path";
import * as fs from "fs";
import git from "isomorphic-git";
Expand Down Expand Up @@ -197,6 +198,7 @@ export class StartupFlowProvider implements vscode.CustomTextEditorProvider {
_token: vscode.CancellationToken
): void | Thenable<void> {
this.webviewPanel = webviewPanel;
trackWebviewPanel(webviewPanel, StartupFlowProvider.viewType, "StartupFlowProvider.resolveCustomTextEditor");
this.disposables.push(webviewPanel);

// Set options before content
Expand Down
2 changes: 2 additions & 0 deletions src/providers/VideoEditor/VideoEditorProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as vscode from "vscode";
import { trackWebviewPanel } from "../../utils/webviewTracker";

export class VideoEditorProvider implements vscode.CustomTextEditorProvider {
public static readonly viewType = "codex.videoEditor";
Expand All @@ -10,6 +11,7 @@ export class VideoEditorProvider implements vscode.CustomTextEditorProvider {
webviewPanel: vscode.WebviewPanel,
_token: vscode.CancellationToken
): Promise<void> {
trackWebviewPanel(webviewPanel, VideoEditorProvider.viewType, "VideoEditorProvider.resolveCustomTextEditor");
// Set the HTML content for the webview
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);

Expand Down
2 changes: 2 additions & 0 deletions src/providers/VideoPlayer/VideoPlayerProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as vscode from "vscode";
import { getWebviewHtml } from "../../utils/webviewTemplate";
import { trackWebviewPanel } from "../../utils/webviewTracker";
export class VideoPlayerProvider
implements vscode.TextDocumentContentProvider, vscode.CustomTextEditorProvider
{
Expand Down Expand Up @@ -30,6 +31,7 @@ export class VideoPlayerProvider
webviewPanel: vscode.WebviewPanel,
_token: vscode.CancellationToken
): Promise<void> {
trackWebviewPanel(webviewPanel, VideoPlayerProvider.viewType, "VideoPlayerProvider.resolveCustomTextEditor");
webviewPanel.webview.options = {
enableScripts: true,
localResourceRoots: [this.context.extensionUri],
Expand Down
2 changes: 2 additions & 0 deletions src/providers/WelcomeView/welcomeViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as path from "path";

import { getAuthApi } from "../../extension";
import { safePostMessageToPanel } from "../../utils/webviewUtils";
import { trackWebviewPanel } from "../../utils/webviewTracker";
import { StartupFlowGlobalState } from "../StartupFlow/StartupFlowProvider";

const DEBUG_MODE = false;
Expand Down Expand Up @@ -278,6 +279,7 @@ export class WelcomeViewProvider {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(this._panel, WelcomeViewProvider.viewType, "WelcomeViewProvider.show");

// Set the webview's html content
this._panel.webview.html = this._getHtmlForWebview();
Expand Down
2 changes: 2 additions & 0 deletions src/providers/WordsView/WordsViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "../../activationHelpers/contextAware/contentIndexes/indexes/wordsIndex";
import { readSourceAndTargetFiles } from "../../activationHelpers/contextAware/contentIndexes/indexes/fileReaders";
import { safePostMessageToPanel } from "../../utils/webviewUtils";
import { trackWebviewPanel } from "../../utils/webviewTracker";

export class WordsViewProvider implements vscode.Disposable {
public static readonly viewType = "frontier.wordsView";
Expand Down Expand Up @@ -43,6 +44,7 @@ export class WordsViewProvider implements vscode.Disposable {
retainContextWhenHidden: true,
}
);
trackWebviewPanel(this._panel, WordsViewProvider.viewType, "WordsViewProvider.show");

this._panel.onDidDispose(() => {
this._panel = undefined;
Expand Down
Loading