diff --git a/src/commands/pipelineCommands.ts b/src/commands/pipelineCommands.ts index 8d458e9..d7e5a70 100644 --- a/src/commands/pipelineCommands.ts +++ b/src/commands/pipelineCommands.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import type { AdoClient } from '../api/adoClient'; import type { ConfigManager } from '../config/configManager'; import type { PipelineRunNode } from '../providers/pipelinesProvider'; -import { PipelineRunDetailsPanel } from '../views/pipelineRunDetailsPanel'; +import { loadPipelineRunDetailsPanel } from '../views/lazyPanels'; import { showErrorMessage, showInformationMessage } from '../utils/notifications'; import { pipelineRunUrl } from '../utils/pipelineUrls'; @@ -17,6 +17,7 @@ export async function viewPipelineRunDetails( return; } + const { PipelineRunDetailsPanel } = await loadPipelineRunDetailsPanel(); await PipelineRunDetailsPanel.show(context, client, config, node.build.id, { organization: node.organization, project: node.project diff --git a/src/commands/pullRequestCommands.ts b/src/commands/pullRequestCommands.ts index 50dae0f..8f6dea1 100644 --- a/src/commands/pullRequestCommands.ts +++ b/src/commands/pullRequestCommands.ts @@ -7,9 +7,9 @@ import type { import type { AdoClient, GitPullRequest, PullRequestReviewVote } from '../api/adoClient'; import { PullRequestReviewVotes } from '../api/adoClient'; import type { ConfigManager } from '../config/configManager'; -import { PrDetailsPanel } from '../views/prDetailsPanel'; import type { PrCommentController } from '../views/prCommentController'; import type { PrDiffCache } from '../views/prContentProvider'; +import { loadPrDetailsPanel } from '../views/lazyPanels'; import { parseAdoRemoteUrl } from '../utils/repoContext'; import { showErrorMessage, showInformationMessage, showWarningMessage } from '../utils/notifications'; @@ -102,6 +102,7 @@ export async function viewPullRequestDetails( client: AdoClient, config: ConfigManager ): Promise { + const { PrDetailsPanel } = await loadPrDetailsPanel(); await PrDetailsPanel.show(context, client, config, node.pr, { organization: node.organization, project: node.project diff --git a/src/extension.ts b/src/extension.ts index 6f9128a..a71e4df 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,10 +13,8 @@ import { import { PipelinesProvider, type PipelineRunNode, type PipelineStepLogNode } from './providers/pipelinesProvider'; import { BacklogProvider, SprintProvider, BoardProvider } from './providers/planningProviders'; import { WorkItemIconResolver } from './providers/workItemIconResolver'; -import { PlanningPanel } from './views/planningPanel'; import { PrCommentController, type CommentReply } from './views/prCommentController'; import { PrDiffCache, PrDiffContentProvider, PR_DIFF_SCHEME } from './views/prContentProvider'; -import { PrDetailsPanel } from './views/prDetailsPanel'; import { PipelineLogContentProvider, PIPELINE_LOG_SCHEME } from './views/pipelineLogContentProvider'; import { NotificationService } from './notifications/notificationService'; import { PrCommentHandler } from './notifications/handlers/prCommentHandler'; @@ -68,12 +66,17 @@ import { } from './commands/pipelineCommands'; import { McpServerManager } from './mcp/mcpServerManager'; import { TodoCodeActionProvider } from './views/todoCodeActionProvider'; -import { PipelineRunDetailsPanel } from './views/pipelineRunDetailsPanel'; import { AdoCompletionProvider } from './providers/completionProvider'; import { installNotificationMirroring, showErrorMessage, showInformationMessage, showOutputChannel, showWarningMessage } from './utils/notifications'; import { WorkItemHoverProvider, PullRequestHoverProvider } from './providers/hoverProvider'; import { adoErrorFingerprint, classifyAdoAuthError } from './utils/adoErrors'; import type { AuthRecoveryResult } from './utils/authRecovery'; +import { + loadPlanningPanel, + loadedPlanningPanel, + loadedPrDetailsPanel, + loadPipelineRunDetailsPanel +} from './views/lazyPanels'; export async function activate(context: vscode.ExtensionContext): Promise { installNotificationMirroring(); @@ -465,21 +468,21 @@ export async function activate(context: vscode.ExtensionContext): Promise context.subscriptions.push( vscode.commands.registerCommand('adoext.openBacklogView', async () => { if (!(await ensureSignedIn())) { return; } - await PlanningPanel.show(context, 'backlog', client, config, refreshAllViews); + await (await loadPlanningPanel()).PlanningPanel.show(context, 'backlog', client, config, refreshAllViews); }) ); context.subscriptions.push( vscode.commands.registerCommand('adoext.openBoardView', async () => { if (!(await ensureSignedIn())) { return; } - await PlanningPanel.show(context, 'board', client, config, refreshAllViews); + await (await loadPlanningPanel()).PlanningPanel.show(context, 'board', client, config, refreshAllViews); }) ); context.subscriptions.push( vscode.commands.registerCommand('adoext.openSprintView', async () => { if (!(await ensureSignedIn())) { return; } - await PlanningPanel.show(context, 'sprint', client, config, refreshAllViews); + await (await loadPlanningPanel()).PlanningPanel.show(context, 'sprint', client, config, refreshAllViews); }) ); @@ -826,7 +829,8 @@ export async function activate(context: vscode.ExtensionContext): Promise async () => { await toggleResolvedPullRequestThreads(config); pullRequestProvider.refresh(); - await PrDetailsPanel.refreshAllOpenPanels(); + const prMod = loadedPrDetailsPanel(); + if (prMod) { await (await prMod).PrDetailsPanel.refreshAllOpenPanels(); } } ) ); @@ -897,7 +901,7 @@ export async function activate(context: vscode.ExtensionContext): Promise if (!(await ensureSignedIn())) { return; } const newId = await rerunPipelineRun(node, client, config); if (typeof newId === 'number' && newId > 0) { - await PipelineRunDetailsPanel.show(context, client, config, newId, { + await (await loadPipelineRunDetailsPanel()).PipelineRunDetailsPanel.show(context, client, config, newId, { organization: node?.organization, project: node?.project }); @@ -1163,7 +1167,8 @@ export async function activate(context: vscode.ExtensionContext): Promise } refreshAllViews(); if (e.affectsConfiguration('adoext.planningAssignedFilter')) { - void PlanningPanel.refreshOpenPanels(); + const planningMod = loadedPlanningPanel(); + if (planningMod) { void planningMod.then(m => m.PlanningPanel.refreshOpenPanels()); } } if ( e.affectsConfiguration('adoext.notifyOnNewPullRequestComments') || diff --git a/src/views/lazyPanels.ts b/src/views/lazyPanels.ts new file mode 100644 index 0000000..75b80b4 --- /dev/null +++ b/src/views/lazyPanels.ts @@ -0,0 +1,21 @@ +// Shared lazy loaders for heavy webview panel modules. +// Caching the import promise here ensures all callers (extension.ts and +// command modules) observe the same loaded-or-not state, which matters for +// static refresh methods that must no-op when the module was never opened. +// +// `loadX()` triggers (or reuses) the import. +// `loadedX()` returns the cached import promise iff loadX() was ever called, +// otherwise undefined - used to skip work on modules that were never opened. + +let _planning: Promise | undefined; +export const loadPlanningPanel = () => (_planning ??= import('./planningPanel')); +export const loadedPlanningPanel = () => _planning; + +let _prDetails: Promise | undefined; +export const loadPrDetailsPanel = () => (_prDetails ??= import('./prDetailsPanel')); +export const loadedPrDetailsPanel = () => _prDetails; + +let _pipelineRun: Promise | undefined; +export const loadPipelineRunDetailsPanel = () => + (_pipelineRun ??= import('./pipelineRunDetailsPanel')); +export const loadedPipelineRunDetailsPanel = () => _pipelineRun;