From b1f70d0fc436c9bade9941406b2590b4034cf2bf Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 2 Apr 2021 12:30:08 -0700 Subject: [PATCH] Change IPyWidgets CDN error message links to buttons (#5395) --- news/2 Fixes/5352.md | 1 + package.nls.json | 3 ++- package.nls.zh-cn.json | 2 +- src/client/common/application/commands.ts | 2 +- src/client/common/utils/localize.ts | 4 +++- .../ipywidgets/commonMessageCoordinator.ts | 23 +++++++++++++++---- 6 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 news/2 Fixes/5352.md diff --git a/news/2 Fixes/5352.md b/news/2 Fixes/5352.md new file mode 100644 index 00000000000..d6ec7984b7c --- /dev/null +++ b/news/2 Fixes/5352.md @@ -0,0 +1 @@ +When 3rd party CDN downloads need to be enabled for ipywidgets support, display More Info and Enable Downloads buttons instead of embedding them as links in the message. \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index 75186ff48e5..63e885d108a 100644 --- a/package.nls.json +++ b/package.nls.json @@ -436,7 +436,8 @@ "DataScience.useCDNForWidgets": "Widgets require us to download supporting files from a 3rd party website. Click [here](https://aka.ms/PVSCIPyWidgets) for more information.", "DataScience.loadThirdPartyWidgetScriptsPostEnabled": "Please restart the Kernel when changing the setting 'jupyter.widgetScriptSources'.", "DataScience.enableCDNForWidgetsSettingHtml": "Widgets require us to download supporting files from a 3rd party website. Click here to enable this or click here for more information. (Error loading {0}:{1}).", - "DataScience.enableCDNForWidgetsSetting": "Widgets require us to download supporting files from a 3rd party website. Click [here](command:jupyter.enableLoadingWidgetScriptsFromThirdPartySource) to enable this or click [here](https://aka.ms/PVSCIPyWidgets) for more information. (Error loading {0}:{1}).", + "DataScience.enableCDNForWidgetsSetting": "Widgets require us to download supporting files from a 3rd party website. (Error loading {0}:{1}).", + "DataScience.enableCDNForWidgetsButton": "Enable Downloads", "DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork": "Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected.", "DataScience.unhandledMessage": "Unhandled kernel message from a widget: {0} : {1}", "DataScience.qgridWidgetScriptVersionCompatibilityWarning": "Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1.", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 7669f3a71c0..7bd16febd7f 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -433,7 +433,7 @@ "DataScience.useCDNForWidgets": "控件需要从第三方网站下载支持文件。点击[这里](https://aka.ms/PVSCIPyWidgets)获取更多信息。", "DataScience.loadThirdPartyWidgetScriptsPostEnabled": "改变 \"jupyter.widgetScriptSources\" 的设置后请重新启动内核。", "DataScience.enableCDNForWidgetsSettingHtml": "控件需要从第三方网站下载支持文件。点击这里启用此功能,或点击这里获取更多信息。(加载错误 {0}:{1})。", - "DataScience.enableCDNForWidgetsSetting": "控件需要从第三方网站下载支持文件。点击[这里](command:jupyter.enableLoadingWidgetScriptsFromThirdPartySource)启用此功能,或点击[这里](https://aka.ms/PVSCIPyWidgets)获取更多信息。(加载错误 {0}:{1})。", + "DataScience.enableCDNForWidgetsSetting": "控件需要从第三方网站下载支持文件。(加载错误 {0}:{1})。", "DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork": "无法加载 '{0}' 控件的兼容版本。预期行为可能会受到影响。", "DataScience.unhandledMessage": "来自控件未处理的内核消息:{0} : {1}", "DataScience.qgridWidgetScriptVersionCompatibilityWarning": "无法加载 'qgrid' 控件的兼容版本,请考虑降级到 1.1.1 版本。", diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index b04fbca79f1..a708ff48ac6 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -137,7 +137,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [DSCommands.SaveAsNotebookNonCustomEditor]: [INotebookModel, Uri]; [DSCommands.OpenNotebookNonCustomEditor]: [Uri]; [DSCommands.LatestExtension]: [string]; - [DSCommands.EnableLoadingWidgetsFrom3rdPartySource]: [undefined | never]; + [DSCommands.EnableLoadingWidgetsFrom3rdPartySource]: []; [DSCommands.TrustNotebook]: [undefined | never | Uri]; [DSCommands.NotebookTrusted]: []; [DSCommands.NotebookEditorExpandAllCells]: []; diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index 9c60f6cde10..6fff010690e 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -868,9 +868,11 @@ export namespace DataScience { export const enableCDNForWidgetsSetting = localize( 'DataScience.enableCDNForWidgetsSetting', - 'Widgets require us to download supporting files from a 3rd party website. Click [here](command:jupyter.enableLoadingWidgetScriptsFromThirdPartySource) to enable this or click [here](https://aka.ms/PVSCIPyWidgets) for more information. (Error loading {0}:{1}).' + 'Widgets require us to download supporting files from a 3rd party website. (Error loading {0}:{1}).' ); + export const enableCDNForWidgetsButton = localize('DataScience.enableCDNForWidgetsButton', 'Enable Downloads'); + export const unhandledMessage = localize( 'DataScience.unhandledMessage', 'Unhandled kernel message from a widget: {0} : {1}' diff --git a/src/client/datascience/ipywidgets/commonMessageCoordinator.ts b/src/client/datascience/ipywidgets/commonMessageCoordinator.ts index 9e41d22ec18..70ea637691d 100644 --- a/src/client/datascience/ipywidgets/commonMessageCoordinator.ts +++ b/src/client/datascience/ipywidgets/commonMessageCoordinator.ts @@ -12,7 +12,7 @@ import { LoadIPyWidgetClassLoadAction, NotifyIPyWidgeWidgetVersionNotSupportedAction } from '../../../datascience-ui/interactive-common/redux/reducers/types'; -import { IApplicationShell, IWorkspaceService } from '../../common/application/types'; +import { IApplicationShell, ICommandManager, IWorkspaceService } from '../../common/application/types'; import { STANDARD_OUTPUT_CHANNEL } from '../../common/constants'; import { traceError, traceInfo } from '../../common/logger'; import { IFileSystem } from '../../common/platform/types'; @@ -30,7 +30,7 @@ import { IInterpreterService } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; import { sendTelemetryEvent } from '../../telemetry'; import { getTelemetrySafeHashedString } from '../../telemetry/helpers'; -import { Telemetry } from '../constants'; +import { Commands, Telemetry } from '../constants'; import { InteractiveWindowMessages } from '../interactive-common/interactiveWindowTypes'; import { INotebookProvider } from '../types'; import { IPyWidgetMessageDispatcherFactory } from './ipyWidgetMessageDispatcherFactory'; @@ -50,6 +50,7 @@ export class CommonMessageCoordinator { private ipyWidgetMessageDispatcher?: IIPyWidgetMessageDispatcher; private ipyWidgetScriptSource?: IPyWidgetScriptSource; private appShell: IApplicationShell; + private commandManager: ICommandManager; // eslint-disable-next-line @typescript-eslint/no-explicit-any private postEmitter: EventEmitter<{ message: string; payload: any }>; private disposables: IDisposableRegistry; @@ -71,6 +72,7 @@ export class CommonMessageCoordinator { this.disposables = this.serviceContainer.get(IDisposableRegistry); this.jupyterOutput = this.serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); this.appShell = this.serviceContainer.get(IApplicationShell, IApplicationShell); + this.commandManager = this.serviceContainer.get(ICommandManager); } public static async create( @@ -136,16 +138,29 @@ export class CommonMessageCoordinator { payload.moduleName, payload.moduleVersion ); + this.appShell.showErrorMessage(errorMessage).then(noop, noop); } else if (!payload.cdnsUsed) { + const moreInfo = localize.Common.moreInfo(); + const enableDownloads = localize.DataScience.enableCDNForWidgetsButton(); errorMessage = localize.DataScience.enableCDNForWidgetsSetting().format( payload.moduleName, payload.moduleVersion ); + this.appShell.showErrorMessage(errorMessage, ...[enableDownloads, moreInfo]).then((selection) => { + switch (selection) { + case moreInfo: + this.appShell.openUrl('https://aka.ms/PVSCIPyWidgets'); + break; + case enableDownloads: + void this.commandManager.executeCommand(Commands.EnableLoadingWidgetsFrom3rdPartySource); + break; + default: + break; + } + }, noop); } traceError(`Widget load failure ${errorMessage}`, payload); - this.appShell.showErrorMessage(errorMessage).then(noop, noop); - sendTelemetryEvent(Telemetry.IPyWidgetLoadFailure, 0, { isOnline: payload.isOnline, moduleHash: getTelemetrySafeHashedString(payload.moduleName),