Skip to content

Commit 7d0ed6c

Browse files
authored
Port fixes into April point release (#11392)
Cherry pick the following PRs: #11248 #11276 #11249 #11280 #11364
1 parent 9d09af1 commit 7d0ed6c

File tree

16 files changed

+223
-12
lines changed

16 files changed

+223
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
([#11334](https://github.com/Microsoft/vscode-python/issues/11334))
1111
1. Show unhandled widget messages in the jupyter output window.
1212
([#11239](https://github.com/Microsoft/vscode-python/issues/11239))
13+
1. Warn when using a version of the widget `qgrid` greater than `1.1.1` with the recommendation to downgrade to `1.1.1`.
14+
([#11245](https://github.com/Microsoft/vscode-python/issues/11245))
1315

1416
### Thanks
1517

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,5 +470,6 @@
470470
"DataScience.loadThirdPartyWidgetScriptsPostEnabled": "Please restart the Kernel when changing the setting 'python.dataScience.widgetScriptSources'.",
471471
"DataScience.enableCDNForWidgetsSetting": "Widgets require us to download supporting files from a 3rd party website. Click <a href='https://command:python.datascience.enableLoadingWidgetScriptsFromThirdPartySource'>here</a> to enable this or click <a href='https://aka.ms/PVSCIPyWidgets'>here</a> for more information. (Error loading {0}:{1}).",
472472
"DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork": "Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected.",
473-
"DataScience.unhandledMessage": "Unhandled kernel message from a widget: {0} : {1}"
473+
"DataScience.unhandledMessage": "Unhandled kernel message from a widget: {0} : {1}",
474+
"DataScience.qgridWidgetScriptVersionCompatibilityWarning": "Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1."
474475
}

src/client/common/utils/localize.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,10 @@ export namespace DataScience {
860860
'DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork',
861861
"Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected."
862862
);
863+
export const qgridWidgetScriptVersionCompatibilityWarning = localize(
864+
'DataScience.qgridWidgetScriptVersionCompatibilityWarning',
865+
"Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1."
866+
);
863867
}
864868

865869
export namespace DebugConfigStrings {

src/client/datascience/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ export enum Telemetry {
292292
ZMQNotSupported = 'DATASCIENCE.ZMQ_NATIVE_BINARIES_NOT_LOADING',
293293
IPyWidgetLoadSuccess = 'DS_INTERNAL.IPYWIDGET_LOAD_SUCCESS',
294294
IPyWidgetLoadFailure = 'DS_INTERNAL.IPYWIDGET_LOAD_FAILURE',
295+
IPyWidgetWidgetVersionNotSupportedLoadFailure = 'DS_INTERNAL.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED_LOAD_FAILURE',
295296
IPyWidgetLoadDisabled = 'DS_INTERNAL.IPYWIDGET_LOAD_DISABLED',
296297
HashedIPyWidgetNameUsed = 'DS_INTERNAL.IPYWIDGET_USED_BY_USER',
297298
HashedIPyWidgetNameDiscovered = 'DS_INTERNAL.IPYWIDGET_DISCOVERED',

src/client/datascience/interactive-common/interactiveWindowTypes.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
CommonActionType,
1111
IAddCellAction,
1212
ILoadIPyWidgetClassFailureAction,
13-
LoadIPyWidgetClassLoadAction
13+
LoadIPyWidgetClassLoadAction,
14+
NotifyIPyWidgeWidgetVersionNotSupportedAction
1415
} from '../../../datascience-ui/interactive-common/redux/reducers/types';
1516
import { PythonInterpreter } from '../../interpreter/contracts';
1617
import { WidgetScriptSource } from '../ipywidgets/types';
@@ -115,7 +116,8 @@ export enum InteractiveWindowMessages {
115116
IPyWidgetLoadSuccess = 'ipywidget_load_success',
116117
IPyWidgetLoadFailure = 'ipywidget_load_failure',
117118
IPyWidgetRenderFailure = 'ipywidget_render_failure',
118-
IPyWidgetUnhandledKernelMessage = 'ipywidget_unhandled_kernel_message'
119+
IPyWidgetUnhandledKernelMessage = 'ipywidget_unhandled_kernel_message',
120+
IPyWidgetWidgetVersionNotSupported = 'ipywidget_widget_version_not_supported'
119121
}
120122

121123
export enum IPyWidgetMessages {
@@ -607,6 +609,7 @@ export class IInteractiveWindowMapping {
607609
public [InteractiveWindowMessages.UpdateDisplayData]: KernelMessage.IUpdateDisplayDataMsg;
608610
public [InteractiveWindowMessages.IPyWidgetLoadSuccess]: LoadIPyWidgetClassLoadAction;
609611
public [InteractiveWindowMessages.IPyWidgetLoadFailure]: ILoadIPyWidgetClassFailureAction;
612+
public [InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported]: NotifyIPyWidgeWidgetVersionNotSupportedAction;
610613
public [InteractiveWindowMessages.ConvertUriForUseInWebViewRequest]: Uri;
611614
public [InteractiveWindowMessages.ConvertUriForUseInWebViewResponse]: { request: Uri; response: Uri };
612615
public [InteractiveWindowMessages.IPyWidgetRenderFailure]: Error;

src/client/datascience/interactive-common/synchronization.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ const messageWithMessageTypes: MessageMapping<IInteractiveWindowMapping> & Messa
8787
[CommonActionType.FOCUS_INPUT]: MessageType.other,
8888
[CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: MessageType.other,
8989
[CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: MessageType.other,
90+
[CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: MessageType.other,
9091
[CommonActionType.IPYWIDGET_RENDER_FAILURE]: MessageType.other,
9192

9293
// Types from InteractiveWindowMessages
@@ -117,6 +118,7 @@ const messageWithMessageTypes: MessageMapping<IInteractiveWindowMapping> & Messa
117118
[InteractiveWindowMessages.IPyWidgetLoadFailure]: MessageType.other,
118119
[InteractiveWindowMessages.IPyWidgetRenderFailure]: MessageType.other,
119120
[InteractiveWindowMessages.IPyWidgetUnhandledKernelMessage]: MessageType.other,
121+
[InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported]: MessageType.other,
120122
[InteractiveWindowMessages.LoadAllCells]: MessageType.other,
121123
[InteractiveWindowMessages.LoadAllCellsComplete]: MessageType.other,
122124
[InteractiveWindowMessages.LoadOnigasmAssemblyRequest]: MessageType.other,

src/client/datascience/ipywidgets/ipywidgetHandler.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import stripAnsi from 'strip-ansi';
99
import { Event, EventEmitter, Uri } from 'vscode';
1010
import {
1111
ILoadIPyWidgetClassFailureAction,
12-
LoadIPyWidgetClassLoadAction
12+
LoadIPyWidgetClassLoadAction,
13+
NotifyIPyWidgeWidgetVersionNotSupportedAction
1314
} from '../../../datascience-ui/interactive-common/redux/reducers/types';
1415
import { EnableIPyWidgets } from '../../common/experimentGroups';
1516
import { traceError, traceInfo } from '../../common/logger';
@@ -75,6 +76,8 @@ export class IPyWidgetHandler implements IInteractiveWindowListener {
7576
this.sendLoadSucceededTelemetry(payload);
7677
} else if (message === InteractiveWindowMessages.IPyWidgetLoadFailure) {
7778
this.sendLoadFailureTelemetry(payload);
79+
} else if (message === InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported) {
80+
this.sendUnsupportedWidgetVersionFailureTelemetry(payload);
7881
} else if (message === InteractiveWindowMessages.IPyWidgetRenderFailure) {
7982
this.sendRenderFailureTelemetry(payload);
8083
} else if (message === InteractiveWindowMessages.IPyWidgetUnhandledKernelMessage) {
@@ -111,6 +114,16 @@ export class IPyWidgetHandler implements IInteractiveWindowListener {
111114
// do nothing on failure
112115
}
113116
}
117+
private sendUnsupportedWidgetVersionFailureTelemetry(payload: NotifyIPyWidgeWidgetVersionNotSupportedAction) {
118+
try {
119+
sendTelemetryEvent(Telemetry.IPyWidgetWidgetVersionNotSupportedLoadFailure, 0, {
120+
moduleHash: this.hash(payload.moduleName),
121+
moduleVersion: payload.moduleVersion
122+
});
123+
} catch {
124+
// do nothing on failure
125+
}
126+
}
114127
private sendRenderFailureTelemetry(payload: Error) {
115128
try {
116129
traceError('Error rendering a widget: ', payload);

src/client/telemetry/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,10 @@ export interface IEventNamePropertyMapping {
19921992
// Whether we timedout getting the source of the script (fetching script source in extension code).
19931993
timedout: boolean;
19941994
};
1995+
/**
1996+
* Telemetry event sent when an ipywidget version that is not supported is used & we have trapped this and warned the user abou it.
1997+
*/
1998+
[Telemetry.IPyWidgetWidgetVersionNotSupportedLoadFailure]: { moduleHash: string; moduleVersion: string };
19951999
/**
19962000
* Telemetry event sent when an loading of 3rd party ipywidget JS scripts from 3rd party source has been disabled.
19972001
*/

src/datascience-ui/history-react/redux/reducers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const reducerMap: Partial<IInteractiveActionMapping> = {
4141
[CommonActionType.FOCUS_INPUT]: CommonEffects.focusInput,
4242
[CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: CommonEffects.handleLoadIPyWidgetClassSuccess,
4343
[CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: CommonEffects.handleLoadIPyWidgetClassFailure,
44+
[CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: CommonEffects.notifyAboutUnsupportedWidgetVersions,
4445
[CommonActionType.IPYWIDGET_RENDER_FAILURE]: CommonEffects.handleIPyWidgetRenderFailure,
4546

4647
// Messages from the webview (some are ignored)

src/datascience-ui/interactive-common/cellOutput.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ export class CellOutput extends React.Component<ICellOutputProps> {
199199
if (nextProps.cellVM.cell.data.outputs !== this.props.cellVM.cell.data.outputs) {
200200
return true;
201201
}
202+
if (nextProps.cellVM.uiSideError !== this.props.cellVM.uiSideError) {
203+
return true;
204+
}
202205
if (
203206
!this.isCodeCell() &&
204207
nextProps.cellVM.cell.id !== Identifiers.EditCellId &&
@@ -271,7 +274,7 @@ export class CellOutput extends React.Component<ICellOutputProps> {
271274
// tslint:disable: react-no-dangerous-html
272275
if (this.props.cellVM.uiSideError) {
273276
outputs.push(
274-
<div className="cell-output-uiSideError">
277+
<div key={'uiError'} className="cell-output-uiSideError">
275278
<div dangerouslySetInnerHTML={{ __html: this.props.cellVM.uiSideError }} />
276279
</div>
277280
);

src/datascience-ui/interactive-common/redux/reducers/commonEffects.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
CommonReducerArg,
1919
ILoadIPyWidgetClassFailureAction,
2020
IOpenSettingsAction,
21-
LoadIPyWidgetClassLoadAction
21+
LoadIPyWidgetClassLoadAction,
22+
NotifyIPyWidgeWidgetVersionNotSupportedAction
2223
} from './types';
2324

2425
export namespace CommonEffects {
@@ -242,9 +243,11 @@ export namespace CommonEffects {
242243
"Widgets require us to download supporting files from a 3rd party website. Click <a href='https://command:python.datascience.enableLoadingWidgetScriptsFromThirdPartySource'>here</a> to enable this or click <a href='https://aka.ms/PVSCIPyWidgets'>here</a> for more information. (Error loading {0}:{1})."
243244
).format(arg.payload.data.moduleName, arg.payload.data.moduleVersion);
244245
}
246+
// Preserve existing error messages.
247+
const existingErrorMessage = current.uiSideError ? `${current.uiSideError}\n` : '';
245248
newVMs[index] = Helpers.asCellViewModel({
246249
...current,
247-
uiSideError: errorMessage
250+
uiSideError: `${existingErrorMessage}${errorMessage}`
248251
});
249252

250253
// Make sure to tell the extension so it can log telemetry.
@@ -258,6 +261,42 @@ export namespace CommonEffects {
258261
return arg.prevState;
259262
}
260263
}
264+
export function notifyAboutUnsupportedWidgetVersions(
265+
arg: CommonReducerArg<CommonActionType, NotifyIPyWidgeWidgetVersionNotSupportedAction>
266+
): IMainState {
267+
// Find the first currently executing cell and add an error to its output
268+
let index = arg.prevState.cellVMs.findIndex((c) => c.cell.state === CellState.executing);
269+
270+
// If there isn't one, then find the latest that matches the current execution count.
271+
if (index < 0) {
272+
index = arg.prevState.cellVMs.findIndex(
273+
(c) => c.cell.data.execution_count === arg.prevState.currentExecutionCount
274+
);
275+
}
276+
if (index >= 0 && arg.prevState.cellVMs[index].cell.data.cell_type === 'code') {
277+
const newVMs = [...arg.prevState.cellVMs];
278+
const current = arg.prevState.cellVMs[index];
279+
280+
const errorMessage = getLocString(
281+
'DataScience.qgridWidgetScriptVersionCompatibilityWarning',
282+
"Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1."
283+
);
284+
newVMs[index] = Helpers.asCellViewModel({
285+
...current,
286+
uiSideError: errorMessage
287+
});
288+
289+
// Make sure to tell the extension so it can log telemetry.
290+
postActionToExtension(arg, InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported, arg.payload.data);
291+
292+
return {
293+
...arg.prevState,
294+
cellVMs: newVMs
295+
};
296+
} else {
297+
return arg.prevState;
298+
}
299+
}
261300
export function handleIPyWidgetRenderFailure(arg: CommonReducerArg<CommonActionType, Error>): IMainState {
262301
// Make sure to tell the extension so it can log telemetry.
263302
postActionToExtension(arg, InteractiveWindowMessages.IPyWidgetRenderFailure, arg.payload.data);

src/datascience-ui/interactive-common/redux/reducers/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export enum CommonActionType {
5858
IPYWIDGET_RENDER_FAILURE = 'action.ipywidget_render_failure',
5959
LOAD_IPYWIDGET_CLASS_SUCCESS = 'action.load_ipywidget_class_success',
6060
LOAD_IPYWIDGET_CLASS_FAILURE = 'action.load_ipywidget_class_failure',
61+
IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED = 'action.ipywidget_widget_version_not_supported',
6162
LOADED_ALL_CELLS = 'action.loaded_all_cells',
6263
LINK_CLICK = 'action.link_click',
6364
MOVE_CELL_DOWN = 'action.move_cell_down',
@@ -134,6 +135,7 @@ export type CommonActionTypeMapping = {
134135
[CommonActionType.FOCUS_INPUT]: never | undefined;
135136
[CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: LoadIPyWidgetClassLoadAction;
136137
[CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: ILoadIPyWidgetClassFailureAction;
138+
[CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: NotifyIPyWidgeWidgetVersionNotSupportedAction;
137139
[CommonActionType.IPYWIDGET_RENDER_FAILURE]: Error;
138140
};
139141

@@ -232,5 +234,9 @@ export type LoadIPyWidgetClassLoadAction = {
232234
moduleName: string;
233235
moduleVersion: string;
234236
};
237+
export type NotifyIPyWidgeWidgetVersionNotSupportedAction = {
238+
moduleName: 'qgrid';
239+
moduleVersion: string;
240+
};
235241

236242
export type CommonAction<T = never | undefined> = ActionWithPayload<T, CommonActionType | InteractiveWindowMessages>;

src/datascience-ui/ipywidgets/container.tsx

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ import {
1919
CommonAction,
2020
CommonActionType,
2121
ILoadIPyWidgetClassFailureAction,
22-
LoadIPyWidgetClassLoadAction
22+
LoadIPyWidgetClassLoadAction,
23+
NotifyIPyWidgeWidgetVersionNotSupportedAction
2324
} from '../interactive-common/redux/reducers/types';
2425
import { IStore } from '../interactive-common/redux/store';
2526
import { PostOffice } from '../react-common/postOffice';
27+
import { warnAboutWidgetVersionsThatAreNotSupported } from './incompatibleWidgetHandler';
2628
import { WidgetManager } from './manager';
2729
import { registerScripts } from './requirejsRegistry';
2830

@@ -38,6 +40,7 @@ export class WidgetManagerComponent extends React.Component<Props> {
3840
string,
3941
{ deferred: Deferred<void>; timer: NodeJS.Timeout | number | undefined }
4042
>();
43+
private readonly registeredWidgetSources = new Map<string, WidgetScriptSource>();
4144
private timedoutWaitingForWidgetsToGetLoaded?: boolean;
4245
private widgetsCanLoadFromCDN: boolean = false;
4346
private readonly loaderSettings = {
@@ -78,6 +81,7 @@ export class WidgetManagerComponent extends React.Component<Props> {
7881
// This happens when we have restarted a kernel.
7982
// If user changed the kernel, then some widgets might exist now and some might now.
8083
this.widgetSourceRequests.clear();
84+
this.registeredWidgetSources.clear();
8185
}
8286
return true;
8387
}
@@ -108,6 +112,7 @@ export class WidgetManagerComponent extends React.Component<Props> {
108112

109113
// Now resolve promises (anything that was waiting for modules to get registered can carry on).
110114
sources.forEach((source) => {
115+
this.registeredWidgetSources.set(source.moduleName, source);
111116
// We have fetched the script sources for all of these modules.
112117
// In some cases we might not have the source, meaning we don't have it or couldn't find it.
113118
let request = this.widgetSourceRequests.get(source.moduleName);
@@ -167,6 +172,21 @@ export class WidgetManagerComponent extends React.Component<Props> {
167172
}
168173
};
169174
}
175+
private createWidgetVersionNotSupportedErrorAction(
176+
moduleName: 'qgrid',
177+
moduleVersion: string
178+
): CommonAction<NotifyIPyWidgeWidgetVersionNotSupportedAction> {
179+
return {
180+
type: CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED,
181+
payload: {
182+
messageDirection: 'incoming',
183+
data: {
184+
moduleName,
185+
moduleVersion
186+
}
187+
}
188+
};
189+
}
170190
private async handleLoadError(
171191
className: string,
172192
moduleName: string,
@@ -233,10 +253,25 @@ export class WidgetManagerComponent extends React.Component<Props> {
233253
{ moduleName, moduleVersion }
234254
);
235255

236-
return request.deferred.promise.catch((ex) =>
237-
// tslint:disable-next-line: no-console
238-
console.error(`Failed to load Widget Script from Extension for for ${moduleName}, ${moduleVersion}`, ex)
239-
);
256+
return request.deferred.promise
257+
.then(() => {
258+
const widgetSource = this.registeredWidgetSources.get(moduleName);
259+
if (widgetSource) {
260+
warnAboutWidgetVersionsThatAreNotSupported(
261+
widgetSource,
262+
moduleVersion,
263+
this.widgetsCanLoadFromCDN,
264+
(info) =>
265+
this.props.store.dispatch(
266+
this.createWidgetVersionNotSupportedErrorAction(info.moduleName, info.moduleVersion)
267+
)
268+
);
269+
}
270+
})
271+
.catch((ex) =>
272+
// tslint:disable-next-line: no-console
273+
console.error(`Failed to load Widget Script from Extension for for ${moduleName}, ${moduleVersion}`, ex)
274+
);
240275
}
241276

242277
private handleLoadSuccess(className: string, moduleName: string, moduleVersion: string) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import * as semver from 'semver';
7+
import { WidgetScriptSource } from '../../client/datascience/ipywidgets/types';
8+
const supportedVersionOfQgrid = '1.1.1';
9+
const qgridModuleName = 'qgrid';
10+
11+
/**
12+
* For now only warns about qgrid.
13+
* Warn user about qgrid versions > 1.1.1 (we know CDN isn't available for newer versions and local widget source will not work).
14+
* Recommend to downgrade to 1.1.1.
15+
* Returns `true` if a warning has been displayed.
16+
*/
17+
export function warnAboutWidgetVersionsThatAreNotSupported(
18+
widgetSource: WidgetScriptSource,
19+
moduleVersion: string,
20+
cdnSupported: boolean,
21+
errorDispatcher: (info: { moduleName: typeof qgridModuleName; moduleVersion: string }) => void
22+
) {
23+
// if widget exists on CDN or CDN is disabled, get out.
24+
if (widgetSource.source === 'cdn' || !cdnSupported) {
25+
return false;
26+
}
27+
// Warn about qrid.
28+
if (widgetSource.moduleName !== qgridModuleName) {
29+
return false;
30+
}
31+
// We're only interested in versions > 1.1.1.
32+
try {
33+
// If we have an exact version, & if that is <= 1.1.1, then no warning needs to be displayed.
34+
if (!moduleVersion.startsWith('^') && semver.compare(moduleVersion, supportedVersionOfQgrid) <= 0) {
35+
return false;
36+
}
37+
// If we have a version range, then check the range.
38+
// Basically if our minimum version 1.1.1 is met, then nothing to do.
39+
// Eg. requesting script source for version `^1.3.0`.
40+
if (moduleVersion.startsWith('^') && semver.satisfies(supportedVersionOfQgrid, moduleVersion)) {
41+
return false;
42+
}
43+
} catch {
44+
return false;
45+
}
46+
errorDispatcher({ moduleName: widgetSource.moduleName, moduleVersion });
47+
}

0 commit comments

Comments
 (0)