delegate requests from the debug variable view as well (#15681)
* delegate requests from the variable view as well * add new file * fix return types, rename command * update test, get full variable for variable view request * remove test.only
This commit is contained in:
Родитель
ca1db4e9e7
Коммит
df007bf29a
|
@ -2033,7 +2033,7 @@
|
|||
],
|
||||
"jupyterVariableViewers": [
|
||||
{
|
||||
"command": "jupyter.showDataViewer",
|
||||
"command": "jupyter.showJupyterDataViewer",
|
||||
"title": "%jupyter.command.jupyter.showDataViewer.title%",
|
||||
"dataTypes": [
|
||||
"DataFrame",
|
||||
|
|
|
@ -176,6 +176,7 @@ export interface ICommandNameArgumentTypeMapping {
|
|||
[DSCommands.LatestExtension]: [string];
|
||||
[DSCommands.EnableLoadingWidgetsFrom3rdPartySource]: [];
|
||||
[DSCommands.ShowDataViewer]: [IJupyterVariable | IShowDataViewerFromVariablePanel];
|
||||
[DSCommands.ShowJupyterDataViewer]: [IJupyterVariable];
|
||||
[DSCommands.RefreshDataViewer]: [];
|
||||
[DSCommands.ClearSavedJupyterUris]: [];
|
||||
[DSCommands.RunByLine]: [NotebookCell];
|
||||
|
|
|
@ -225,6 +225,7 @@ export namespace Commands {
|
|||
export const LatestExtension = 'jupyter.latestExtension';
|
||||
export const EnableLoadingWidgetsFrom3rdPartySource = 'jupyter.enableLoadingWidgetScriptsFromThirdPartySource';
|
||||
export const ShowDataViewer = 'jupyter.showDataViewer';
|
||||
export const ShowJupyterDataViewer = 'jupyter.showJupyterDataViewer';
|
||||
export const RefreshDataViewer = 'jupyter.refreshDataViewer';
|
||||
export const ClearSavedJupyterUris = 'jupyter.clearSavedJupyterUris';
|
||||
export const OpenVariableView = 'jupyter.openVariableView';
|
||||
|
|
|
@ -112,6 +112,7 @@ suite('DataViewer @webview', function () {
|
|||
evaluateName: 'my_list',
|
||||
name: 'my_list',
|
||||
value: '[1, 2, 3]',
|
||||
type: 'list',
|
||||
variablesReference
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,6 +33,7 @@ import { PythonEnvironment } from '../../../platform/pythonEnvironments/info';
|
|||
import { IKernelProvider } from '../../../kernels/types';
|
||||
import { IInteractiveWindowProvider } from '../../../interactive-window/types';
|
||||
import { IShowDataViewerFromVariablePanel } from '../../../messageTypes';
|
||||
import { DataViewerDelegator } from './dataViewerDelegator';
|
||||
|
||||
export const PromptAboutDeprecation = 'ds_prompt_about_deprecation';
|
||||
|
||||
|
@ -60,7 +61,8 @@ export class DataViewerCommandRegistry implements IExtensionSyncActivationServic
|
|||
@inject(IKernelProvider) private readonly kernelProvider: IKernelProvider,
|
||||
@inject(IInteractiveWindowProvider) private interactiveWindowProvider: IInteractiveWindowProvider,
|
||||
@inject(IExperimentService) private readonly experimentService: IExperimentService,
|
||||
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly globalMemento: Memento
|
||||
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly globalMemento: Memento,
|
||||
@inject(DataViewerDelegator) private readonly dataViewerDelegator: DataViewerDelegator
|
||||
) {
|
||||
this.dataViewerChecker = new DataViewerChecker(configService);
|
||||
if (!workspace.isTrusted) {
|
||||
|
@ -74,7 +76,8 @@ export class DataViewerCommandRegistry implements IExtensionSyncActivationServic
|
|||
if (!workspace.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.registerCommand(Commands.ShowDataViewer, this.onVariablePanelShowDataViewerRequest);
|
||||
this.registerCommand(Commands.ShowDataViewer, this.delegateDataViewer);
|
||||
this.registerCommand(Commands.ShowJupyterDataViewer, this.showJupyterVariableView);
|
||||
}
|
||||
private registerCommand<
|
||||
E extends keyof ICommandNameArgumentTypeMapping,
|
||||
|
@ -84,8 +87,26 @@ export class DataViewerCommandRegistry implements IExtensionSyncActivationServic
|
|||
const disposable = commands.registerCommand(command, callback, this);
|
||||
this.disposables.push(disposable);
|
||||
}
|
||||
private async onVariablePanelShowDataViewerRequest(request: IJupyterVariable | IShowDataViewerFromVariablePanel) {
|
||||
const requestVariable = 'variable' in request ? request.variable : request;
|
||||
|
||||
private async delegateDataViewer(request: IJupyterVariable | IShowDataViewerFromVariablePanel) {
|
||||
const variable = 'variable' in request ? await this.getVariableFromRequest(request) : request;
|
||||
if (!variable) {
|
||||
return;
|
||||
}
|
||||
return this.dataViewerDelegator.showContributedDataViewer(variable);
|
||||
}
|
||||
|
||||
// get the information needed about the request from the debug variable view
|
||||
private async getVariableFromRequest(request: IShowDataViewerFromVariablePanel) {
|
||||
if (this.variableProvider) {
|
||||
const variable = convertDebugProtocolVariableToIJupyterVariable(
|
||||
request.variable as unknown as DebugProtocol.Variable
|
||||
);
|
||||
return this.variableProvider.getFullVariable(variable);
|
||||
}
|
||||
}
|
||||
|
||||
private async showJupyterVariableView(requestVariable: IJupyterVariable) {
|
||||
sendTelemetryEvent(EventName.OPEN_DATAVIEWER_FROM_VARIABLE_WINDOW_REQUEST);
|
||||
|
||||
// DataViewerDeprecation
|
||||
|
@ -128,17 +149,13 @@ export class DataViewerCommandRegistry implements IExtensionSyncActivationServic
|
|||
pythonEnv && (await this.dataViewerDependencyService.checkAndInstallMissingDependencies(pythonEnv));
|
||||
}
|
||||
|
||||
const variable = convertDebugProtocolVariableToIJupyterVariable(
|
||||
requestVariable as unknown as DebugProtocol.Variable
|
||||
);
|
||||
const jupyterVariable = await this.variableProvider.getFullVariable(variable);
|
||||
const jupyterVariableDataProvider = await this.jupyterVariableDataProviderFactory.create(
|
||||
jupyterVariable
|
||||
requestVariable
|
||||
);
|
||||
const dataFrameInfo = await jupyterVariableDataProvider.getDataFrameInfo();
|
||||
const columnSize = dataFrameInfo?.columns?.length;
|
||||
if (columnSize && (await this.dataViewerChecker.isRequestedColumnSizeAllowed(columnSize))) {
|
||||
const title: string = `${DataScience.dataExplorerTitle} - ${jupyterVariable.name}`;
|
||||
const title: string = `${DataScience.dataExplorerTitle} - ${requestVariable.name}`;
|
||||
const dv = await this.dataViewerFactory.create(jupyterVariableDataProvider, title);
|
||||
sendTelemetryEvent(EventName.OPEN_DATAVIEWER_FROM_VARIABLE_WINDOW_SUCCESS);
|
||||
return dv;
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { commands, Extension, QuickPickItem, window, extensions } from 'vscode';
|
||||
import { Experiments, IExperimentService } from '../../../platform/common/types';
|
||||
import { Commands, JVSC_EXTENSION_ID, Telemetry } from '../../../platform/common/constants';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { IJupyterVariable } from '../../../kernels/variables/types';
|
||||
import { IVariableViewer } from '../variablesView/types';
|
||||
import { noop } from '../../../platform/common/utils/misc';
|
||||
import { sendTelemetryEvent } from '../../../platform/telemetry';
|
||||
import { logger } from '../../../platform/logging';
|
||||
import * as localize from '../../../platform/common/utils/localize';
|
||||
|
||||
@injectable()
|
||||
export class DataViewerDelegator {
|
||||
constructor(@inject(IExperimentService) private readonly experiments: IExperimentService) {}
|
||||
|
||||
public async showContributedDataViewer(variable: IJupyterVariable) {
|
||||
try {
|
||||
if (this.experiments.inExperiment(Experiments.DataViewerContribution)) {
|
||||
// jupyterVariableViewers
|
||||
const variableViewers = this.getMatchingVariableViewers(variable);
|
||||
if (variableViewers.length === 0) {
|
||||
// No data frame viewer extensions, show notifications
|
||||
return commands.executeCommand('workbench.extensions.search', '@tag:jupyterVariableViewers');
|
||||
} else if (variableViewers.length === 1) {
|
||||
const command = variableViewers[0].jupyterVariableViewers.command;
|
||||
return commands.executeCommand(command, variable);
|
||||
} else {
|
||||
const thirdPartyViewers = variableViewers.filter((d) => d.extension.id !== JVSC_EXTENSION_ID);
|
||||
if (thirdPartyViewers.length === 1) {
|
||||
const command = thirdPartyViewers[0].jupyterVariableViewers.command;
|
||||
return commands.executeCommand(command, variable);
|
||||
}
|
||||
// show quick pick
|
||||
const quickPick = window.createQuickPick<QuickPickItem & { command: string }>();
|
||||
quickPick.title = 'Select DataFrame Viewer';
|
||||
quickPick.items = variableViewers.map((d) => {
|
||||
return {
|
||||
label: d.jupyterVariableViewers.title,
|
||||
detail: d.extension.packageJSON?.displayName ?? d.extension.id,
|
||||
command: d.jupyterVariableViewers.command
|
||||
};
|
||||
});
|
||||
quickPick.onDidAccept(async () => {
|
||||
const item = quickPick.selectedItems[0];
|
||||
if (item) {
|
||||
quickPick.hide();
|
||||
return commands.executeCommand(item.command, variable);
|
||||
}
|
||||
});
|
||||
quickPick.show();
|
||||
}
|
||||
} else {
|
||||
return commands.executeCommand(Commands.ShowJupyterDataViewer, variable);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
sendTelemetryEvent(Telemetry.FailedShowDataViewer);
|
||||
window.showErrorMessage(localize.DataScience.showDataViewerFail).then(noop, noop);
|
||||
}
|
||||
}
|
||||
|
||||
private getMatchingVariableViewers(
|
||||
variable: IJupyterVariable
|
||||
): { extension: Extension<unknown>; jupyterVariableViewers: IVariableViewer }[] {
|
||||
const variableViewers = this.getVariableViewers();
|
||||
return variableViewers.filter((d) => d.jupyterVariableViewers.dataTypes.includes(variable.type));
|
||||
}
|
||||
|
||||
public getVariableViewers(): { extension: Extension<unknown>; jupyterVariableViewers: IVariableViewer }[] {
|
||||
const variableViewers = extensions.all
|
||||
.filter(
|
||||
(e) =>
|
||||
e.packageJSON?.contributes?.jupyterVariableViewers &&
|
||||
e.packageJSON?.contributes?.jupyterVariableViewers.length
|
||||
)
|
||||
.map((e) => {
|
||||
const contributes = e.packageJSON?.contributes;
|
||||
if (contributes?.jupyterVariableViewers) {
|
||||
return contributes.jupyterVariableViewers.map((jupyterVariableViewers: IVariableViewer) => ({
|
||||
extension: e,
|
||||
jupyterVariableViewers
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
})
|
||||
.flat();
|
||||
|
||||
return variableViewers;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { IExtensionSyncActivationService } from '../../platform/activation/types
|
|||
import { IServiceManager } from '../../platform/ioc/types';
|
||||
import { DataViewer } from './dataviewer/dataViewer';
|
||||
import { DataViewerCommandRegistry } from './dataviewer/dataViewerCommandRegistry';
|
||||
import { DataViewerDelegator } from './dataviewer/dataViewerDelegator';
|
||||
import { DataViewerDependencyService } from './dataviewer/dataViewerDependencyService.node';
|
||||
import { DataViewerFactory } from './dataviewer/dataViewerFactory';
|
||||
import { JupyterVariableDataProvider } from './dataviewer/jupyterVariableDataProvider';
|
||||
|
@ -46,6 +47,7 @@ export function registerTypes(serviceManager: IServiceManager) {
|
|||
IExtensionSyncActivationService,
|
||||
DataViewerCommandRegistry
|
||||
);
|
||||
serviceManager.addSingleton<DataViewerDelegator>(DataViewerDelegator, DataViewerDelegator);
|
||||
|
||||
// Plot Viewer
|
||||
serviceManager.add<IPlotViewer>(IPlotViewer, PlotViewer);
|
||||
|
|
|
@ -28,6 +28,7 @@ import { PlotViewHandler } from './plotView/plotViewHandler';
|
|||
import { RendererCommunication } from './plotView/rendererCommunication';
|
||||
import { IPlotSaveHandler } from './plotView/types';
|
||||
import { IPyWidgetRendererComms } from './ipywidgets/rendererComms';
|
||||
import { DataViewerDelegator } from './dataviewer/dataViewerDelegator';
|
||||
|
||||
export function registerTypes(serviceManager: IServiceManager) {
|
||||
serviceManager.addSingleton<IExtensionSyncActivationService>(
|
||||
|
@ -46,6 +47,7 @@ export function registerTypes(serviceManager: IServiceManager) {
|
|||
IDataViewerDependencyService,
|
||||
DataViewerDependencyService
|
||||
);
|
||||
serviceManager.addSingleton<DataViewerDelegator>(DataViewerDelegator, DataViewerDelegator);
|
||||
|
||||
// Plot Viewer
|
||||
serviceManager.add<IPlotViewer>(IPlotViewer, PlotViewer);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { Extension, QuickPickItem, Uri, commands, WebviewView as vscodeWebviewView, window } from 'vscode';
|
||||
import { Uri, WebviewView as vscodeWebviewView, window } from 'vscode';
|
||||
import { joinPath } from '../../../platform/vscode-path/resources';
|
||||
import { capturePerfTelemetry, sendTelemetryEvent, Telemetry } from '../../../telemetry';
|
||||
import { INotebookWatcher, IVariableViewPanelMapping, IVariableViewer } from './types';
|
||||
import { INotebookWatcher, IVariableViewPanelMapping } from './types';
|
||||
import { VariableViewMessageListener } from './variableViewMessageListener';
|
||||
import { InteractiveWindowMessages, IShowDataViewer } from '../../../messageTypes';
|
||||
import {
|
||||
IJupyterVariable,
|
||||
IJupyterVariables,
|
||||
IJupyterVariablesRequest,
|
||||
IJupyterVariablesResponse
|
||||
|
@ -25,12 +24,10 @@ import {
|
|||
IExperimentService,
|
||||
Experiments
|
||||
} from '../../../platform/common/types';
|
||||
import * as localize from '../../../platform/common/utils/localize';
|
||||
import { WebviewViewHost } from '../../../platform/webviews/webviewViewHost';
|
||||
import { swallowExceptions } from '../../../platform/common/utils/decorators';
|
||||
import { noop } from '../../../platform/common/utils/misc';
|
||||
import { Commands, JVSC_EXTENSION_ID } from '../../../platform/common/constants';
|
||||
import { extensions } from 'vscode';
|
||||
import { DataViewerDelegator } from '../dataviewer/dataViewerDelegator';
|
||||
|
||||
// This is the client side host for the native notebook variable view webview
|
||||
// It handles passing messages to and from the react view as well as the connection
|
||||
|
@ -46,7 +43,8 @@ export class VariableView extends WebviewViewHost<IVariableViewPanelMapping> imp
|
|||
private readonly variables: IJupyterVariables,
|
||||
private readonly disposables: IDisposableRegistry,
|
||||
private readonly notebookWatcher: INotebookWatcher,
|
||||
private readonly experiments: IExperimentService
|
||||
private readonly experiments: IExperimentService,
|
||||
private readonly dataViewerDelegator: DataViewerDelegator
|
||||
) {
|
||||
const variableViewDir = joinPath(context.extensionUri, 'dist', 'webviews', 'webview-side', 'viewers');
|
||||
super(configuration, (c, d) => new VariableViewMessageListener(c, d), provider, variableViewDir, [
|
||||
|
@ -138,90 +136,11 @@ export class VariableView extends WebviewViewHost<IVariableViewPanelMapping> imp
|
|||
@swallowExceptions()
|
||||
public async showDataViewer(request: IShowDataViewer) {
|
||||
request.variable.fileName = request.variable.fileName ?? this.notebookWatcher.activeKernel?.notebook.uri;
|
||||
try {
|
||||
if (this.experiments.inExperiment(Experiments.DataViewerContribution)) {
|
||||
// jupyterVariableViewers
|
||||
const variableViewers = this.getMatchingVariableViewers(request.variable);
|
||||
if (variableViewers.length === 0) {
|
||||
// No data frame viewer extensions, show notifications
|
||||
await commands.executeCommand('workbench.extensions.search', '@tag:jupyterVariableViewers');
|
||||
return;
|
||||
} else if (variableViewers.length === 1) {
|
||||
const command = variableViewers[0].jupyterVariableViewers.command;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return commands.executeCommand(command as any, request.variable);
|
||||
} else {
|
||||
const thirdPartyViewers = variableViewers.filter((d) => d.extension.id !== JVSC_EXTENSION_ID);
|
||||
if (thirdPartyViewers.length === 1) {
|
||||
const command = thirdPartyViewers[0].jupyterVariableViewers.command;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return commands.executeCommand(command as any, request.variable);
|
||||
}
|
||||
// show quick pick
|
||||
const quickPick = window.createQuickPick<QuickPickItem & { command: string }>();
|
||||
quickPick.title = 'Select DataFrame Viewer';
|
||||
quickPick.items = variableViewers.map((d) => {
|
||||
return {
|
||||
label: d.jupyterVariableViewers.title,
|
||||
detail: d.extension.packageJSON?.displayName ?? d.extension.id,
|
||||
command: d.jupyterVariableViewers.command
|
||||
};
|
||||
});
|
||||
quickPick.onDidAccept(() => {
|
||||
const item = quickPick.selectedItems[0];
|
||||
if (item) {
|
||||
quickPick.hide();
|
||||
commands
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
.executeCommand(item.command as any, request.variable)
|
||||
.then(noop, noop);
|
||||
}
|
||||
});
|
||||
quickPick.show();
|
||||
}
|
||||
} else {
|
||||
return commands.executeCommand(Commands.ShowDataViewer, request.variable);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
sendTelemetryEvent(Telemetry.FailedShowDataViewer);
|
||||
window.showErrorMessage(localize.DataScience.showDataViewerFail).then(noop, noop);
|
||||
}
|
||||
}
|
||||
|
||||
private getMatchingVariableViewers(
|
||||
variable: IJupyterVariable
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): { extension: Extension<any>; jupyterVariableViewers: IVariableViewer }[] {
|
||||
const variableViewers = this.getVariableViewers();
|
||||
return variableViewers.filter((d) => d.jupyterVariableViewers.dataTypes.includes(variable.type));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private getVariableViewers(): { extension: Extension<any>; jupyterVariableViewers: IVariableViewer }[] {
|
||||
const variableViewers = extensions.all
|
||||
.filter(
|
||||
(e) =>
|
||||
e.packageJSON?.contributes?.jupyterVariableViewers &&
|
||||
e.packageJSON?.contributes?.jupyterVariableViewers.length
|
||||
)
|
||||
.map((e) => {
|
||||
const contributes = e.packageJSON?.contributes;
|
||||
if (contributes?.jupyterVariableViewers) {
|
||||
return contributes.jupyterVariableViewers.map((jupyterVariableViewers: IVariableViewer) => ({
|
||||
extension: e,
|
||||
jupyterVariableViewers
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
})
|
||||
.flat();
|
||||
|
||||
return variableViewers;
|
||||
return this.dataViewerDelegator.showContributedDataViewer(request.variable);
|
||||
}
|
||||
|
||||
private postProcessSupportsDataExplorer(response: IJupyterVariablesResponse) {
|
||||
const variableViewers = this.getVariableViewers();
|
||||
const variableViewers = this.dataViewerDelegator.getVariableViewers();
|
||||
response.pageResponse.forEach((variable) => {
|
||||
if (this.experiments.inExperiment(Experiments.DataViewerContribution)) {
|
||||
variable.supportsDataExplorer = variableViewers.some((d) =>
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import { createDeferred, Deferred } from '../../../platform/common/utils/async';
|
||||
import { INotebookWatcher, IVariableViewProvider } from './types';
|
||||
import { VariableView } from './variableView';
|
||||
import { DataViewerDelegator } from '../dataviewer/dataViewerDelegator';
|
||||
|
||||
// This class creates our UI for our variable view and links it to the vs code webview view
|
||||
@injectable()
|
||||
|
@ -47,7 +48,8 @@ export class VariableViewProvider implements IVariableViewProvider {
|
|||
@inject(IJupyterVariables) @named(Identifiers.ALL_VARIABLES) private variables: IJupyterVariables,
|
||||
@inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry,
|
||||
@inject(INotebookWatcher) private readonly notebookWatcher: INotebookWatcher,
|
||||
@inject(IExperimentService) private readonly experiments: IExperimentService
|
||||
@inject(IExperimentService) private readonly experiments: IExperimentService,
|
||||
@inject(DataViewerDelegator) private readonly dataViewerDelegator: DataViewerDelegator
|
||||
) {}
|
||||
|
||||
public async resolveWebviewView(
|
||||
|
@ -65,7 +67,8 @@ export class VariableViewProvider implements IVariableViewProvider {
|
|||
this.variables,
|
||||
this.disposables,
|
||||
this.notebookWatcher,
|
||||
this.experiments
|
||||
this.experiments,
|
||||
this.dataViewerDelegator
|
||||
);
|
||||
|
||||
// If someone is waiting for the variable view resolve that here
|
||||
|
|
Загрузка…
Ссылка в новой задаче