diff --git a/CHANGELOG.md b/CHANGELOG.md index 4793f0e3141b..3481f32347a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,71 @@ # Changelog +## 2020.8.4 (2 September 2020) + +### Enhancements + +1. Make Jupyter Server name clickable to select Jupyter server. + ([#13656](https://github.com/Microsoft/vscode-python/issues/13656)) + +### Fixes + +1. Fixed connection to a Compute Instance from the quickpicks history options. + ([#13387](https://github.com/Microsoft/vscode-python/issues/13387)) + +### Thanks + +Thanks to the following projects which we fully rely on to provide some of +our features: + +- [debugpy](https://pypi.org/project/debugpy/) +- [isort](https://pypi.org/project/isort/) +- [jedi](https://pypi.org/project/jedi/) + and [parso](https://pypi.org/project/parso/) +- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server) +- [Pylance](https://github.com/microsoft/pylance-release) +- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed) +- [rope](https://pypi.org/project/rope/) (user-installed) + +Also thanks to the various projects we provide integrations with which help +make this extension useful: + +- Debugging support: + [Django](https://pypi.org/project/Django/), + [Flask](https://pypi.org/project/Flask/), + [gevent](https://pypi.org/project/gevent/), + [Jinja](https://pypi.org/project/Jinja/), + [Pyramid](https://pypi.org/project/pyramid/), + [PySpark](https://pypi.org/project/pyspark/), + [Scrapy](https://pypi.org/project/Scrapy/), + [Watson](https://pypi.org/project/Watson/) +- Formatting: + [autopep8](https://pypi.org/project/autopep8/), + [black](https://pypi.org/project/black/), + [yapf](https://pypi.org/project/yapf/) +- Interpreter support: + [conda](https://conda.io/), + [direnv](https://direnv.net/), + [pipenv](https://pypi.org/project/pipenv/), + [pyenv](https://github.com/pyenv/pyenv), + [venv](https://docs.python.org/3/library/venv.html#module-venv), + [virtualenv](https://pypi.org/project/virtualenv/) +- Linting: + [bandit](https://pypi.org/project/bandit/), + [flake8](https://pypi.org/project/flake8/), + [mypy](https://pypi.org/project/mypy/), + [prospector](https://pypi.org/project/prospector/), + [pylint](https://pypi.org/project/pylint/), + [pydocstyle](https://pypi.org/project/pydocstyle/), + [pylama](https://pypi.org/project/pylama/) +- Testing: + [nose](https://pypi.org/project/nose/), + [pytest](https://pypi.org/project/pytest/), + [unittest](https://docs.python.org/3/library/unittest.html#module-unittest) + +And finally thanks to the [Python](https://www.python.org/) development team and +community for creating a fantastic programming language and community to be a +part of! + ## 2020.8.3 (31 August 2020) ### Enhancements diff --git a/src/client/datascience/common.ts b/src/client/datascience/common.ts index 87ade2bdb53a..534db4db0e08 100644 --- a/src/client/datascience/common.ts +++ b/src/client/datascience/common.ts @@ -45,21 +45,23 @@ const AllowedKeys = { ['execute_result']: new Set(Object.keys(dummyExecuteResultObj)) }; -export function getSavedUriList(globalState: Memento): { uri: string; time: number }[] { - const uriList = globalState.get<{ uri: string; time: number }[]>(Settings.JupyterServerUriList); +export function getSavedUriList(globalState: Memento): { uri: string; time: number; displayName?: string }[] { + const uriList = globalState.get<{ uri: string; time: number; displayName?: string }[]>( + Settings.JupyterServerUriList + ); return uriList ? uriList.sort((a, b) => { return b.time - a.time; }) : []; } -export function addToUriList(globalState: Memento, uri: string, time: number) { +export function addToUriList(globalState: Memento, uri: string, time: number, displayName: string) { const uriList = getSavedUriList(globalState); const editList = uriList.filter((f, i) => { return f.uri !== uri && i < Settings.JupyterServerUriListMax - 1; }); - editList.splice(0, 0, { uri, time }); + editList.splice(0, 0, { uri, time, displayName }); globalState.update(Settings.JupyterServerUriList, editList).then(noop, noop); } diff --git a/src/client/datascience/interactive-common/interactiveBase.ts b/src/client/datascience/interactive-common/interactiveBase.ts index 39cdc9a8c6ac..2c0588208dbd 100644 --- a/src/client/datascience/interactive-common/interactiveBase.ts +++ b/src/client/datascience/interactive-common/interactiveBase.ts @@ -37,6 +37,7 @@ import { EXTENSION_ROOT_DIR, isTestExecution, PYTHON_LANGUAGE } from '../../comm import { RemoveKernelToolbarInInteractiveWindow, RunByLine } from '../../common/experiments/groups'; import { traceError, traceInfo, traceWarning } from '../../common/logger'; +import { isNil } from 'lodash'; import { IConfigurationService, IDisposableRegistry, @@ -1162,10 +1163,13 @@ export abstract class InteractiveBase extends WebViewHost getJupyterServerUri(uri)?.authorizationHeader : undefined + getAuthHeader: serverUri ? () => getJupyterServerUri(uri)?.authorizationHeader : undefined, + url: uri }; } diff --git a/src/client/datascience/jupyter/serverSelector.ts b/src/client/datascience/jupyter/serverSelector.ts index 6bcca160975d..201c0c6eee6f 100644 --- a/src/client/datascience/jupyter/serverSelector.ts +++ b/src/client/datascience/jupyter/serverSelector.ts @@ -4,6 +4,7 @@ 'use strict'; import { inject, injectable, named } from 'inversify'; +import { isNil } from 'lodash'; import { ConfigurationTarget, Memento, QuickPickItem, Uri } from 'vscode'; import { IClipboard, ICommandManager } from '../../common/application/types'; import { GLOBAL_MEMENTO, IConfigurationService, IMemento } from '../../common/types'; @@ -26,6 +27,7 @@ const defaultUri = 'https://hostname:8080/?token=849d61a414abafab97bc4aab1f35477 interface ISelectUriQuickPickItem extends QuickPickItem { newChoice: boolean; provider?: IJupyterUriProvider; + url?: string; } @injectable() @@ -66,7 +68,7 @@ export class JupyterServerSelector { if (item.label === this.localLabel) { await this.setJupyterURIToLocal(); } else if (!item.newChoice && !item.provider) { - await this.setJupyterURIToRemote(item.label); + await this.setJupyterURIToRemote(!isNil(item.url) ? item.url : item.label); } else if (!item.provider) { return this.selectRemoteURI.bind(this); } else { @@ -208,9 +210,10 @@ export class JupyterServerSelector { if (uriItem.uri) { const uriDate = new Date(uriItem.time); items.push({ - label: uriItem.uri, + label: !isNil(uriItem.displayName) ? uriItem.displayName : uriItem.uri, detail: DataScience.jupyterSelectURIMRUDetail().format(uriDate.toLocaleString()), - newChoice: false + newChoice: false, + url: uriItem.uri }); } }); diff --git a/src/client/datascience/types.ts b/src/client/datascience/types.ts index ffd7bcc1abca..123f8b560130 100644 --- a/src/client/datascience/types.ts +++ b/src/client/datascience/types.ts @@ -74,6 +74,7 @@ export interface IJupyterConnection extends Disposable { readonly token: string; readonly hostName: string; localProcExitCode: number | undefined; + readonly url?: string; // tslint:disable-next-line: no-any getAuthHeader?(): any; // Snould be a json object } diff --git a/src/datascience-ui/interactive-common/jupyterInfo.tsx b/src/datascience-ui/interactive-common/jupyterInfo.tsx index 03b5b3550384..ec94902757f3 100644 --- a/src/datascience-ui/interactive-common/jupyterInfo.tsx +++ b/src/datascience-ui/interactive-common/jupyterInfo.tsx @@ -33,6 +33,7 @@ export class JupyterInfo extends React.Component { constructor(prop: IJupyterInfoProps) { super(prop); this.selectKernel = this.selectKernel.bind(this); + this.selectServer = this.selectServer.bind(this); } public render() { @@ -59,11 +60,18 @@ export class JupyterInfo extends React.Component { maxWidth: getMaxWidth(displayNameTextSize) }; + const ariaDisabled = this.props.isNotebookTrusted === undefined ? false : this.props.isNotebookTrusted; return (
{this.renderTrustMessage()} -
-
+
+
{getLocString('DataScience.jupyterServer', 'Jupyter Server')}: {jupyterServerDisplayName}
{ return res[1]; } + + private selectServer(): void { + this.props.selectServer(); + } } diff --git a/src/test/datascience/jupyter/serverSelector.unit.test.ts b/src/test/datascience/jupyter/serverSelector.unit.test.ts index 44a17ad33dbe..5fd6bdd72f0b 100644 --- a/src/test/datascience/jupyter/serverSelector.unit.test.ts +++ b/src/test/datascience/jupyter/serverSelector.unit.test.ts @@ -103,7 +103,7 @@ suite('DataScience - Jupyter Server URI Selector', () => { // Add in a new server const serverA1 = { uri: 'ServerA', time: 1, date: new Date(1) }; - addToUriList(mockStorage, serverA1.uri, serverA1.time); + addToUriList(mockStorage, serverA1.uri, serverA1.time, serverA1.uri); await ds.selectJupyterURI(true); assert.equal(quickPick?.items.length, 3, 'Wrong number of items in the quick pick'); @@ -111,7 +111,7 @@ suite('DataScience - Jupyter Server URI Selector', () => { // Add in a second server, the newer server should be higher in the list due to newer time const serverB1 = { uri: 'ServerB', time: 2, date: new Date(2) }; - addToUriList(mockStorage, serverB1.uri, serverB1.time); + addToUriList(mockStorage, serverB1.uri, serverB1.time, serverB1.uri); await ds.selectJupyterURI(true); assert.equal(quickPick?.items.length, 4, 'Wrong number of items in the quick pick'); quickPickCheck(quickPick?.items[2], serverB1); @@ -119,7 +119,7 @@ suite('DataScience - Jupyter Server URI Selector', () => { // Reconnect to server A with a new time, it should now be higher in the list const serverA3 = { uri: 'ServerA', time: 3, date: new Date(3) }; - addToUriList(mockStorage, serverA3.uri, serverA3.time); + addToUriList(mockStorage, serverA3.uri, serverA3.time, serverA3.uri); await ds.selectJupyterURI(true); assert.equal(quickPick?.items.length, 4, 'Wrong number of items in the quick pick'); quickPickCheck(quickPick?.items[3], serverB1); @@ -127,7 +127,7 @@ suite('DataScience - Jupyter Server URI Selector', () => { // Verify that we stick to our settings limit for (let i = 0; i < Settings.JupyterServerUriListMax + 10; i = i + 1) { - addToUriList(mockStorage, i.toString(), i); + addToUriList(mockStorage, i.toString(), i, i.toString()); } await ds.selectJupyterURI(true);