Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add message
  • Loading branch information
DonJayamanne committed Apr 18, 2020
commit 7b18c1fb8fe931c8bf8dc179a590114b1860761c
4 changes: 3 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
"Common.ok": "Ok",
"Common.install": "Install",
"Common.learnMore": "Learn more",
"Common.reportThisIssue": "Report this issue",
"OutputChannelNames.languageServer": "Python Language Server",
"OutputChannelNames.python": "Python",
"OutputChannelNames.pythonTest": "Python Test Log",
Expand Down Expand Up @@ -471,5 +472,6 @@
"DataScience.loadClassFailedWithNoInternet": "Error loading {0}:{1}. Internet connection required for loading 3rd party widgets.",
"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 'python.dataScience.widgetScriptSources'.",
"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})."
"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}).",
"DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork": "Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected."
}
5 changes: 5 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export namespace Common {
export const moreInfo = localize('Common.moreInfo', 'More Info');
export const learnMore = localize('Common.learnMore', 'Learn more');
export const and = localize('Common.and', 'and');
export const reportThisIssue = localize('Common.reportThisIssue', 'Report this issue');
}

export namespace AttachProcess {
Expand Down Expand Up @@ -865,6 +866,10 @@ export namespace DataScience {
'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})."
);
export const widgetScriptNotFoundOnCDNWidgetMightNotWork = localize(
'DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork',
"Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected."
);
}

export namespace DebugConfigStrings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { sha256 } from 'hash.js';
import { ConfigurationChangeEvent, ConfigurationTarget } from 'vscode';
import { IApplicationShell, IWorkspaceService } from '../../common/application/types';
import '../../common/extensions';
import { traceError } from '../../common/logger';
import { IFileSystem } from '../../common/platform/types';
import {
Expand All @@ -17,6 +18,7 @@ import {
} from '../../common/types';
import { createDeferred, Deferred } from '../../common/utils/async';
import { Common, DataScience } from '../../common/utils/localize';
import { noop } from '../../common/utils/misc';
import { IInterpreterService } from '../../interpreter/contracts';
import { sendTelemetryEvent } from '../../telemetry';
import { Telemetry } from '../constants';
Expand All @@ -27,6 +29,7 @@ import { RemoteWidgetScriptSourceProvider } from './remoteWidgetScriptSourceProv
import { IWidgetScriptSourceProvider, WidgetScriptSource } from './types';

const GlobalStateKeyToTrackIfUserConfiguredCDNAtLeastOnce = 'IPYWidgetCDNConfigured';
const GlobalStateKeyToNeverWarnAboutScriptsNotFoundOnCDN = 'IPYWidgetNotFoundOnCDN';

/**
* This class decides where to get widget scripts from.
Expand All @@ -35,13 +38,15 @@ const GlobalStateKeyToTrackIfUserConfiguredCDNAtLeastOnce = 'IPYWidgetCDNConfigu
* If user has not configured antying, user will be presented with a prompt.
*/
export class IPyWidgetScriptSourceProvider implements IWidgetScriptSourceProvider {
private readonly notifiedUserAboutWidgetScriptNotFound = new Set<string>();
private scriptProviders?: IWidgetScriptSourceProvider[];
private configurationPromise?: Deferred<void>;
private get configuredScriptSources(): readonly WidgetCDNs[] {
const settings = this.configurationSettings.getSettings(undefined);
return settings.datascience.widgetScriptSources;
}
private readonly userConfiguredCDNAtLeastOnce: IPersistentState<boolean>;
private readonly neverWarnAboutScriptsNotFoundOnCDN: IPersistentState<boolean>;
constructor(
private readonly notebook: INotebook,
private readonly localResourceUriConverter: ILocalResourceUriConverter,
Expand All @@ -57,6 +62,10 @@ export class IPyWidgetScriptSourceProvider implements IWidgetScriptSourceProvide
GlobalStateKeyToTrackIfUserConfiguredCDNAtLeastOnce,
false
);
this.neverWarnAboutScriptsNotFoundOnCDN = this.stateFactory.createGlobalPersistentState<boolean>(
GlobalStateKeyToNeverWarnAboutScriptsNotFoundOnCDN,
false
);
}
public initialize() {
this.workspaceService.onDidChangeConfiguration(this.onSettingsChagned.bind(this));
Expand Down Expand Up @@ -94,14 +103,44 @@ export class IPyWidgetScriptSourceProvider implements IWidgetScriptSourceProvide

sendTelemetryEvent(Telemetry.HashedIPyWidgetNameUsed, undefined, {
hashedName: sha256().update(found.moduleName).digest('hex'),
source: found.source
source: found.source,
cdnSearched: this.configuredScriptSources.length > 0
});

if (!found.scriptUri) {
traceError(`Script source for Widget ${moduleName}@${moduleVersion} not found`);
}
this.handleWidgetSourceNotFoundOnCDN(found).ignoreErrors();
return found;
}
private async handleWidgetSourceNotFoundOnCDN(widgetSource: WidgetScriptSource) {
// if widget exists nothing to do.
if (widgetSource.source === 'cdn' || this.neverWarnAboutScriptsNotFoundOnCDN.value === true) {
return;
}
if (
this.notifiedUserAboutWidgetScriptNotFound.has(widgetSource.moduleName) ||
this.configuredScriptSources.length === 0
) {
return;
}
this.notifiedUserAboutWidgetScriptNotFound.add(widgetSource.moduleName);
const selection = await this.appShell.showWarningMessage(
DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork().format(widgetSource.moduleName),
Common.ok(),
Common.doNotShowAgain(),
Common.reportThisIssue()
);
switch (selection) {
case Common.doNotShowAgain():
return this.neverWarnAboutScriptsNotFoundOnCDN.updateValue(true);
case Common.reportThisIssue():
return this.appShell.openUrl('https://aka.ms/CreatePVSCDataScienceIssue');
default:
noop();
}
}

private onSettingsChagned(e: ConfigurationChangeEvent) {
if (e.affectsConfiguration('dataScience.widgetScriptSources')) {
this.rebuildProviders();
Expand Down
4 changes: 4 additions & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,10 @@ export interface IEventNamePropertyMapping {
* Where did we find the hashed name (CDN or user environment or remote jupyter).
*/
source?: 'cdn' | 'local' | 'remote';
/**
* Whether we searched CDN or not.
*/
cdnSearched: boolean;
};
/**
* Telemetry event sent with name of a Widget found.
Expand Down