Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions news/1 Enhancements/16461.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support starting a TensorBoard session with a remote URL hosting log files.
4 changes: 3 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,5 +252,7 @@
"TensorBoard.installProfilerPluginPrompt": "We recommend installing the PyTorch Profiler TensorBoard plugin. Would you like to install the package?",
"TensorBoard.upgradePrompt": "Integrated TensorBoard support is only available for TensorBoard >= 2.4.1. Would you like to upgrade your copy of TensorBoard?",
"TensorBoard.launchNativeTensorBoardSessionCodeAction": "Launch TensorBoard session",
"TensorBoard.launchNativeTensorBoardSessionCodeLens": "▶ Launch TensorBoard Session"
"TensorBoard.launchNativeTensorBoardSessionCodeLens": "▶ Launch TensorBoard Session",
"TensorBoard.enterRemoteUrl": "Enter remote URL",
"TensorBoard.enterRemoteUrlDetail": "Enter a URL pointing to a remote directory containing your TensorBoard log files"
}
5 changes: 5 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ export namespace Jupyter {
}

export namespace TensorBoard {
export const enterRemoteUrl = localize('TensorBoard.enterRemoteUrl', 'Enter remote URL');
export const enterRemoteUrlDetail = localize(
'TensorBoard.enterRemoteUrlDetail',
'Enter a URL pointing to a remote directory containing your TensorBoard log files',
);
export const useCurrentWorkingDirectoryDetail = localize(
'TensorBoard.useCurrentWorkingDirectoryDetail',
'TensorBoard will search for tfevent files in all subdirectories of the current working directory',
Expand Down
28 changes: 21 additions & 7 deletions src/client/tensorBoard/tensorBoardSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ export class TensorBoardSession {
return tensorboardInstallStatus === ProductInstallStatus.Installed;
}

// eslint-disable-next-line class-methods-use-this
private async showFilePicker(): Promise<string | undefined> {
const selection = await this.applicationShell.showOpenDialog({
canSelectFiles: false,
Expand All @@ -285,6 +284,8 @@ export class TensorBoardSession {

// eslint-disable-next-line class-methods-use-this
private getQuickPickItems(logDir: string | undefined) {
const items = [];

if (logDir) {
const useCwd = {
label: TensorBoard.useCurrentWorkingDirectory(),
Expand All @@ -294,13 +295,21 @@ export class TensorBoardSession {
label: TensorBoard.selectAnotherFolder(),
detail: TensorBoard.selectAnotherFolderDetail(),
};
return [useCwd, selectAnotherFolder];
items.push(useCwd, selectAnotherFolder);
} else {
const selectAFolder = {
label: TensorBoard.selectAFolder(),
detail: TensorBoard.selectAFolderDetail(),
};
items.push(selectAFolder);
}
const selectAFolder = {
label: TensorBoard.selectAFolder(),
detail: TensorBoard.selectAFolderDetail(),
};
return [selectAFolder];

items.push({
label: TensorBoard.enterRemoteUrl(),
detail: TensorBoard.enterRemoteUrlDetail(),
});

return items;
}

// Display a quickpick asking the user to acknowledge our autopopulated log directory or
Expand All @@ -319,6 +328,7 @@ export class TensorBoardSession {
const useCurrentWorkingDirectory = TensorBoard.useCurrentWorkingDirectory();
const selectAFolder = TensorBoard.selectAFolder();
const selectAnotherFolder = TensorBoard.selectAnotherFolder();
const enterRemoteUrl = TensorBoard.enterRemoteUrl();
const items: QuickPickItem[] = this.getQuickPickItems(logDir);
const item = await this.applicationShell.showQuickPick(items, {
canPickMany: false,
Expand All @@ -331,6 +341,10 @@ export class TensorBoardSession {
case selectAFolder:
case selectAnotherFolder:
return this.showFilePicker();
case enterRemoteUrl:
return this.applicationShell.showInputBox({
prompt: TensorBoard.enterRemoteUrlDetail(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be any validation on the url? I believe we do that for jupyter URIs. Not sure if there's a standard form for tensorboard remote URIs

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was debating this. This can be any web URL AFAIK. I didn't really want to roll my own validation here. One thought I had was since VS Code has a URI implementation that can parse URLs, we could either hand off the URL to their Uri.parse function and check if the key properties are empty string, or duplicate the regex and logic they use for validation. But it would probably also work to just reuse our existing validation logic.

});
default:
return undefined;
}
Expand Down
17 changes: 16 additions & 1 deletion src/test/tensorBoard/tensorBoardSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ suite('TensorBoard session creation', async () => {
assert.ok(daemon?.killed, 'TensorBoard session process not killed after webview closed');
});
test('When user selects file picker, display file picker', async () => {
errorMessageStub = sandbox.stub(applicationShell, 'showErrorMessage');
// Stub user selections
sandbox.stub(applicationShell, 'showQuickPick').resolves({ label: TensorBoard.selectAnotherFolder() });
const filePickerStub = sandbox.stub(applicationShell, 'showOpenDialog');
Expand All @@ -150,6 +149,22 @@ suite('TensorBoard session creation', async () => {

assert.ok(filePickerStub.called, 'User requests to select another folder and file picker was not shown');
});
test('When user selects remote URL, display input box', async () => {
sandbox.stub(applicationShell, 'showQuickPick').resolves({ label: TensorBoard.enterRemoteUrl() });
const inputBoxStub = sandbox.stub(applicationShell, 'showInputBox');

// Create session
await commandManager.executeCommand(
'python.launchTensorBoard',
TensorBoardEntrypoint.palette,
TensorBoardEntrypointTrigger.palette,
);

assert.ok(
inputBoxStub.called,
'User requested to enter remote URL and input box to enter URL was not shown',
);
});
});
suite('Installation prompt message', async () => {
async function createSessionAndVerifyMessage(message: string) {
Expand Down