Dashboard/book widget (#6447)

* initial commit: new modelview widget that shows books

* moved the new command action to notebook contribution and addressed the comments

* localize changes

* removed changes from src/vs file and string changes

* make directory for each contribution

* typo fix
This commit is contained in:
Maddy
2019-07-22 17:00:02 -07:00
committed by GitHub
parent d976dad139
commit 7e98727d4c
6 changed files with 176 additions and 4 deletions

View File

@@ -417,7 +417,7 @@
{
"name": "%title.endpoints%",
"row": 0,
"col": 2,
"col": 4,
"rowspan": 1.5,
"colspan": 2,
"widget": {
@@ -425,6 +425,17 @@
"id": "bdc-endpoints"
}
}
},
{
"name": "%title.books%",
"row": 0,
"col": 2,
"colspan": 1,
"widget": {
"modelview": {
"id": "books-widget"
}
}
}
]
}
@@ -932,4 +943,4 @@
]
}
}
}
}

View File

@@ -31,6 +31,7 @@
"title.clearSearchServerResult": "Search: Clear Search Server Results",
"title.endpoints": "Service Endpoints",
"title.books": "Notebooks",
"mssql.configuration.title": "MSSQL configuration",
"mssql.query.displayBitAsNumber": "Should BIT columns be displayed as numbers (1 or 0)? If false, BIT columns will be displayed as 'true' or 'false'",

View File

@@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as nls from 'vscode-nls';
import * as fs from 'fs-extra';
import * as path from 'path';
import {
BookContributionProvider, BookContribution
} from './bookExtensions';
import * as Utils from '../utils';
const localize = nls.loadMessageBundle();
export function registerBooksWidget(bookContributionProvider: BookContributionProvider): void {
azdata.ui.registerModelViewProvider('books-widget', async (view) => {
const container = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column',
width: '100%',
height: '100%',
alignItems: 'left'
}).component();
const bookslocationContainer = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column',
width: '270px',
height: '100%',
alignItems: 'left',
position: 'absolute'
}).component();
let books = bookContributionProvider.contributions.map(contribution => {
const bookRow = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'row'
}).component();
const tsgbooklink = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: contribution.name,
title: contribution.name
}).component();
tsgbooklink.onDidClick(() => {
promptForFolder(contribution);
});
bookRow.addItem(tsgbooklink, {
CSSStyles: {
'width': '100%',
'color': '#0078d4',
'text-decoration': 'underline',
'padding-top': '10px',
'text-align': 'left'
}
});
return bookRow;
});
container.addItems(books, {
CSSStyles: {
'padding-left': '10px',
'border-top': 'solid 1px #ccc',
'box-sizing': 'border-box',
'user-select': 'text'
}
});
bookslocationContainer.addItem(container, {
CSSStyles: {
'padding-top': '25px',
'padding-left': '5px'
}
});
await view.initializeModel(bookslocationContainer);
});
}
async function promptForFolder(bookContribution: BookContribution): Promise<void> {
try {
const allFilesFilter = localize('allFiles', "All Files");
let filter = {};
filter[allFilesFilter] = '*';
let uris = await vscode.window.showOpenDialog({
filters: filter,
canSelectFiles: false,
canSelectMany: false,
canSelectFolders: true,
openLabel: localize('labelPickFolder', "Pick Folder")
});
if (uris && uris.length > 0) {
let pickedFolder = uris[0];
await saveBooksToFolder(pickedFolder, bookContribution);
await promptToReloadWindow(pickedFolder);
}
return;
} catch (error) {
vscode.window.showErrorMessage(localize('FailedDuringSaveAndPrompt', 'Failed : {0}', Utils.getErrorMessage(error)));
}
}
async function saveBooksToFolder(folderUri: vscode.Uri, bookContribution: BookContribution): Promise<void> {
// Get book contributions
if (bookContribution && folderUri) {
//remove folder if exists
await fs.removeSync(path.join(folderUri.path, bookContribution.name));
//copy them from the books extension:
const destinationFolder = path.join(folderUri.path, bookContribution.name);
fs.mkdirSync(destinationFolder);
await fs.copy(bookContribution.path, destinationFolder);
}
}
function promptToReloadWindow(folderUri: vscode.Uri): void {
const actionReload = localize('prompt.reloadInstance', "Reload");
const actionOpenNew = localize('prompt.openNewInstance', "Open new instance");
vscode.window.showInformationMessage(localize('prompt.reloadDescription', "Reload and view the Jupyter Books in the Files view."), actionReload, actionOpenNew)
.then(selectedAction => {
if (selectedAction === actionReload) {
vscode.commands.executeCommand('workbench.action.setWorkspaceAndOpen', {
forceNewWindow: false,
folderPath: folderUri
});
}
if (selectedAction === actionOpenNew) {
vscode.commands.executeCommand('workbench.action.setWorkspaceAndOpen', {
forceNewWindow: true,
folderPath: folderUri
});
}
});
}

View File

@@ -8,6 +8,7 @@ import * as azdata from 'azdata';
import * as path from 'path';
import * as os from 'os';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
@@ -35,6 +36,7 @@ import { registerSearchServerCommand } from './objectExplorerNodeProvider/comman
import { MssqlIconProvider } from './iconProvider';
import { registerServiceEndpoints } from './dashboard/serviceEndpoints';
import { getBookExtensionContributions } from './dashboard/bookExtensions';
import { registerBooksWidget } from './dashboard/bookWidget';
const baseConfig = require('./config.json');
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
@@ -121,6 +123,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
const bookContributionProvider = getBookExtensionContributions(context);
context.subscriptions.push(bookContributionProvider);
registerBooksWidget(bookContributionProvider);
let api: MssqlExtensionApi = {
getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser {
return {

View File

@@ -69,7 +69,7 @@ export class UploadFilesCommand extends ProgressCommand {
async execute(context: ICommandViewContext | ICommandObjectExplorerContext, ...args: any[]): Promise<void> {
try {
let folderNode = await getNode<FolderNode>(context, this.appContext);
const allFilesFilter = localize('allFiles', 'All Files');
const allFilesFilter = localize('allFiles', "All Files");
let filter = {};
filter[allFilesFilter] = '*';
if (folderNode) {

View File

@@ -6,7 +6,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { SyncActionDescriptor, registerAction } from 'vs/platform/actions/common/actions';
import { NotebookInput } from 'sql/workbench/parts/notebook/node/notebookInput';
import { NotebookEditor } from 'sql/workbench/parts/notebook/electron-browser/notebookEditor';
@@ -21,6 +21,11 @@ import { PlotlyOutputComponent } from 'sql/workbench/parts/notebook/outputs/plot
import { registerComponentType } from 'sql/workbench/parts/notebook/electron-browser/outputs/mimeRegistry';
import { MimeRendererComponent } from 'sql/workbench/parts/notebook/electron-browser/outputs/mimeRenderer.component';
import { MarkdownOutputComponent } from 'sql/workbench/parts/notebook/electron-browser/outputs/markdownOutput.component';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { Uri } from 'vscode';
// Model View editor registration
const viewModelEditorDescriptor = new EditorDescriptor(
@@ -45,6 +50,29 @@ actionRegistry.registerWorkbenchAction(
),
NewNotebookAction.LABEL
);
registerAction({
id: 'workbench.action.setWorkspaceAndOpen',
handler: async (accessor, options: { forceNewWindow: boolean, folderPath: Uri }) => {
const viewletService = accessor.get(IViewletService);
const workspaceEditingService = accessor.get(IWorkspaceEditingService);
const windowService = accessor.get(IWindowService);
let folders = [];
if (!options.folderPath) {
return;
}
folders.push(options.folderPath);
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder })));
await viewletService.openViewlet(viewletService.getDefaultViewletId(), true);
if (options.forceNewWindow) {
return windowService.openWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
}
else {
return windowService.reloadWindow();
}
}
});
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'notebook',