mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
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:
@@ -417,7 +417,7 @@
|
|||||||
{
|
{
|
||||||
"name": "%title.endpoints%",
|
"name": "%title.endpoints%",
|
||||||
"row": 0,
|
"row": 0,
|
||||||
"col": 2,
|
"col": 4,
|
||||||
"rowspan": 1.5,
|
"rowspan": 1.5,
|
||||||
"colspan": 2,
|
"colspan": 2,
|
||||||
"widget": {
|
"widget": {
|
||||||
@@ -425,6 +425,17 @@
|
|||||||
"id": "bdc-endpoints"
|
"id": "bdc-endpoints"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "%title.books%",
|
||||||
|
"row": 0,
|
||||||
|
"col": 2,
|
||||||
|
"colspan": 1,
|
||||||
|
"widget": {
|
||||||
|
"modelview": {
|
||||||
|
"id": "books-widget"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -932,4 +943,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
"title.clearSearchServerResult": "Search: Clear Search Server Results",
|
"title.clearSearchServerResult": "Search: Clear Search Server Results",
|
||||||
|
|
||||||
"title.endpoints": "Service Endpoints",
|
"title.endpoints": "Service Endpoints",
|
||||||
|
"title.books": "Notebooks",
|
||||||
|
|
||||||
"mssql.configuration.title": "MSSQL configuration",
|
"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'",
|
"mssql.query.displayBitAsNumber": "Should BIT columns be displayed as numbers (1 or 0)? If false, BIT columns will be displayed as 'true' or 'false'",
|
||||||
|
|||||||
128
extensions/mssql/src/dashboard/bookWidget.ts
Normal file
128
extensions/mssql/src/dashboard/bookWidget.ts
Normal 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
||||||
@@ -35,6 +36,7 @@ import { registerSearchServerCommand } from './objectExplorerNodeProvider/comman
|
|||||||
import { MssqlIconProvider } from './iconProvider';
|
import { MssqlIconProvider } from './iconProvider';
|
||||||
import { registerServiceEndpoints } from './dashboard/serviceEndpoints';
|
import { registerServiceEndpoints } from './dashboard/serviceEndpoints';
|
||||||
import { getBookExtensionContributions } from './dashboard/bookExtensions';
|
import { getBookExtensionContributions } from './dashboard/bookExtensions';
|
||||||
|
import { registerBooksWidget } from './dashboard/bookWidget';
|
||||||
|
|
||||||
const baseConfig = require('./config.json');
|
const baseConfig = require('./config.json');
|
||||||
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
|
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
|
||||||
@@ -121,6 +123,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
|||||||
const bookContributionProvider = getBookExtensionContributions(context);
|
const bookContributionProvider = getBookExtensionContributions(context);
|
||||||
context.subscriptions.push(bookContributionProvider);
|
context.subscriptions.push(bookContributionProvider);
|
||||||
|
|
||||||
|
registerBooksWidget(bookContributionProvider);
|
||||||
|
|
||||||
let api: MssqlExtensionApi = {
|
let api: MssqlExtensionApi = {
|
||||||
getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser {
|
getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class UploadFilesCommand extends ProgressCommand {
|
|||||||
async execute(context: ICommandViewContext | ICommandObjectExplorerContext, ...args: any[]): Promise<void> {
|
async execute(context: ICommandViewContext | ICommandObjectExplorerContext, ...args: any[]): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let folderNode = await getNode<FolderNode>(context, this.appContext);
|
let folderNode = await getNode<FolderNode>(context, this.appContext);
|
||||||
const allFilesFilter = localize('allFiles', 'All Files');
|
const allFilesFilter = localize('allFiles', "All Files");
|
||||||
let filter = {};
|
let filter = {};
|
||||||
filter[allFilesFilter] = '*';
|
filter[allFilesFilter] = '*';
|
||||||
if (folderNode) {
|
if (folderNode) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||||||
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
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 { NotebookInput } from 'sql/workbench/parts/notebook/node/notebookInput';
|
||||||
import { NotebookEditor } from 'sql/workbench/parts/notebook/electron-browser/notebookEditor';
|
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 { registerComponentType } from 'sql/workbench/parts/notebook/electron-browser/outputs/mimeRegistry';
|
||||||
import { MimeRendererComponent } from 'sql/workbench/parts/notebook/electron-browser/outputs/mimeRenderer.component';
|
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 { 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
|
// Model View editor registration
|
||||||
const viewModelEditorDescriptor = new EditorDescriptor(
|
const viewModelEditorDescriptor = new EditorDescriptor(
|
||||||
@@ -45,6 +50,29 @@ actionRegistry.registerWorkbenchAction(
|
|||||||
),
|
),
|
||||||
NewNotebookAction.LABEL
|
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);
|
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigExtensions.Configuration);
|
||||||
configurationRegistry.registerConfiguration({
|
configurationRegistry.registerConfiguration({
|
||||||
'id': 'notebook',
|
'id': 'notebook',
|
||||||
|
|||||||
Reference in New Issue
Block a user