mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Support installing SQL Server Notebook extension (#6432)
This adds SQL Server Notebook as a built-in extension by pulling it from blob storage. It also adds support in mssql extension for reading the contribution points from other extensions. This will contribute troubleshooting and other books as widgets. In this commit: - Bundle the extension in the build - Bundle in sql.sh / sql.bat so it appears in local testing - Avoid installing in Stable. Should only appear in Dev/Insiders builds - Extensions with `notebook.books` contribution point will be discovered & their books available in MSSQL Coming later: - Integrate this with Maddy's work to show a Notebooks widget in the SQL Server big data cluster UI - When clause isn't supported yet for filtering. Will be done as we refactor towards more books for different server types
This commit is contained in:
@@ -33,6 +33,8 @@ import { MssqlObjectExplorerNodeProvider, mssqlOutputChannel } from './objectExp
|
||||
import { CmsService } from './cms/cmsService';
|
||||
import { registerSearchServerCommand } from './objectExplorerNodeProvider/command';
|
||||
import { MssqlIconProvider } from './iconProvider';
|
||||
import { registerServiceEndpoints } from './dashboard/serviceEndpoints';
|
||||
import { getBookExtensionContributions } from './dashboard/bookExtensions';
|
||||
|
||||
const baseConfig = require('./config.json');
|
||||
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
|
||||
@@ -63,23 +65,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
||||
|
||||
serverdownloader.eventEmitter.onAny(generateHandleServerProviderEvent());
|
||||
|
||||
let clientOptions: ClientOptions = {
|
||||
documentSelector: ['sql'],
|
||||
synchronize: {
|
||||
configurationSection: Constants.extensionConfigSectionName
|
||||
},
|
||||
providerId: Constants.providerId,
|
||||
errorHandler: new LanguageClientErrorHandler(),
|
||||
features: [
|
||||
// we only want to add new features
|
||||
...SqlOpsDataClient.defaultFeatures,
|
||||
TelemetryFeature,
|
||||
AgentServicesFeature,
|
||||
DacFxServicesFeature,
|
||||
SchemaCompareServicesFeature
|
||||
],
|
||||
outputChannel: new CustomOutputChannel()
|
||||
};
|
||||
let clientOptions: ClientOptions = getClientOptions();
|
||||
|
||||
let prompter: IPrompter = new CodeAdapter();
|
||||
let appContext = new AppContext(context, new ApiWrapper());
|
||||
@@ -102,6 +88,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
||||
totalTime: String(processEnd - installationStart),
|
||||
beginningTimestamp: String(installationStart)
|
||||
});
|
||||
|
||||
});
|
||||
statusView.show();
|
||||
statusView.text = 'Starting service';
|
||||
@@ -126,105 +113,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
||||
context.subscriptions.push(contextProvider);
|
||||
context.subscriptions.push(credentialsStore);
|
||||
context.subscriptions.push(resourceProvider);
|
||||
context.subscriptions.push(new UploadFilesCommand(prompter, appContext));
|
||||
context.subscriptions.push(new MkDirCommand(prompter, appContext));
|
||||
context.subscriptions.push(new SaveFileCommand(prompter, appContext));
|
||||
context.subscriptions.push(new PreviewFileCommand(prompter, appContext));
|
||||
context.subscriptions.push(new CopyPathCommand(appContext));
|
||||
context.subscriptions.push(new DeleteFilesCommand(prompter, appContext));
|
||||
registerHdfsCommands(context, prompter, appContext);
|
||||
context.subscriptions.push({ dispose: () => languageClient.stop() });
|
||||
|
||||
azdata.ui.registerModelViewProvider('bdc-endpoints', async (view) => {
|
||||
|
||||
const endpointsArray: Array<Utils.IEndpoint> = Object.assign([], view.serverInfo.options['clusterEndpoints']);
|
||||
endpointsArray.forEach(endpointInfo => {
|
||||
endpointInfo.isHyperlink = true;
|
||||
endpointInfo.hyperlink = 'https://' + endpointInfo.ipAddress + ':' + endpointInfo.port;
|
||||
|
||||
});
|
||||
if (endpointsArray.length > 0) {
|
||||
const managementProxyEp = endpointsArray.find(e => e.serviceName === 'management-proxy' || e.serviceName === 'mgmtproxy');
|
||||
if (managementProxyEp) {
|
||||
endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("grafana", "Metrics Dashboard"), '/grafana/d/wZx3OUdmz'));
|
||||
endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("kibana", "Log Search Dashboard"), '/kibana/app/kibana#/discover'));
|
||||
}
|
||||
|
||||
const gatewayEp = endpointsArray.find(e => e.serviceName === 'gateway');
|
||||
if (gatewayEp) {
|
||||
endpointsArray.push(getCustomEndpoint(gatewayEp, localize("sparkHostory", "Spark Job Monitoring"), '/gateway/default/sparkhistory'));
|
||||
endpointsArray.push(getCustomEndpoint(gatewayEp, localize("yarnHistory", "Spark Resource Management"), '/gateway/default/yarn'));
|
||||
}
|
||||
|
||||
const container = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component();
|
||||
endpointsArray.forEach(endpointInfo => {
|
||||
const endPointRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
||||
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: getFriendlyEndpointNames(endpointInfo.serviceName) }).component();
|
||||
endPointRow.addItem(nameCell, { CSSStyles: { 'width': '35%', 'font-weight': '600', 'user-select': 'text' } });
|
||||
if (endpointInfo.isHyperlink) {
|
||||
const linkCell = view.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({ label: endpointInfo.hyperlink, url: endpointInfo.hyperlink }).component();
|
||||
endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px' } });
|
||||
}
|
||||
else {
|
||||
const endpointCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: endpointInfo.ipAddress + ':' + endpointInfo.port }).component();
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': '62%', 'user-select': 'text' } });
|
||||
}
|
||||
const copyValueCell = view.modelBuilder.button().component();
|
||||
copyValueCell.iconPath = { light: context.asAbsolutePath('resources/light/copy.png'), dark: context.asAbsolutePath('resources/dark/copy_inverse.png') };
|
||||
copyValueCell.onDidClick(() => {
|
||||
vscode.env.clipboard.writeText(endpointInfo.hyperlink);
|
||||
});
|
||||
copyValueCell.title = localize("copyText", "Copy");
|
||||
copyValueCell.iconHeight = '14px';
|
||||
copyValueCell.iconWidth = '14px';
|
||||
endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '3%', 'padding-top': '10px' } });
|
||||
|
||||
container.addItem(endPointRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||
});
|
||||
const endpointsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '540px', height: '100%', alignItems: 'left', position: 'absolute' }).component();
|
||||
endpointsContainer.addItem(container, { CSSStyles: { 'padding-top': '25px', 'padding-left': '5px' } });
|
||||
|
||||
await view.initializeModel(endpointsContainer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function getCustomEndpoint(parentEndpoint: Utils.IEndpoint, serviceName: string, serviceUrl?: string): Utils.IEndpoint {
|
||||
if (parentEndpoint) {
|
||||
let endpoint: Utils.IEndpoint = {
|
||||
serviceName: serviceName,
|
||||
ipAddress: parentEndpoint.ipAddress,
|
||||
port: parentEndpoint.port,
|
||||
isHyperlink: serviceUrl ? true : false,
|
||||
hyperlink: 'https://' + parentEndpoint.ipAddress + ':' + parentEndpoint.port + serviceUrl
|
||||
};
|
||||
return endpoint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFriendlyEndpointNames(name: string): string {
|
||||
let friendlyName: string = name;
|
||||
switch (name) {
|
||||
case 'app-proxy':
|
||||
friendlyName = localize("appproxy", "Application Proxy");
|
||||
break;
|
||||
case 'controller':
|
||||
friendlyName = localize("controller", "Cluster Management Service");
|
||||
break;
|
||||
case 'gateway':
|
||||
friendlyName = localize("gateway", "HDFS and Spark");
|
||||
break;
|
||||
case 'management-proxy':
|
||||
friendlyName = localize("managementproxy", "Management Proxy");
|
||||
break;
|
||||
case 'mgmtproxy':
|
||||
friendlyName = localize("mgmtproxy", "Management Proxy");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return friendlyName;
|
||||
}
|
||||
registerServiceEndpoints(context);
|
||||
// Get book contributions - in the future this will be integrated with the Books/Notebook widget to show as a dashboard widget
|
||||
const bookContributionProvider = getBookExtensionContributions(context);
|
||||
context.subscriptions.push(bookContributionProvider);
|
||||
|
||||
let api: MssqlExtensionApi = {
|
||||
getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser {
|
||||
@@ -242,6 +137,35 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
||||
return api;
|
||||
}
|
||||
|
||||
function getClientOptions(): ClientOptions {
|
||||
return {
|
||||
documentSelector: ['sql'],
|
||||
synchronize: {
|
||||
configurationSection: Constants.extensionConfigSectionName
|
||||
},
|
||||
providerId: Constants.providerId,
|
||||
errorHandler: new LanguageClientErrorHandler(),
|
||||
features: [
|
||||
// we only want to add new features
|
||||
...SqlOpsDataClient.defaultFeatures,
|
||||
TelemetryFeature,
|
||||
AgentServicesFeature,
|
||||
DacFxServicesFeature,
|
||||
SchemaCompareServicesFeature
|
||||
],
|
||||
outputChannel: new CustomOutputChannel()
|
||||
};
|
||||
}
|
||||
|
||||
function registerHdfsCommands(context: vscode.ExtensionContext, prompter: IPrompter, appContext: AppContext) {
|
||||
context.subscriptions.push(new UploadFilesCommand(prompter, appContext));
|
||||
context.subscriptions.push(new MkDirCommand(prompter, appContext));
|
||||
context.subscriptions.push(new SaveFileCommand(prompter, appContext));
|
||||
context.subscriptions.push(new PreviewFileCommand(prompter, appContext));
|
||||
context.subscriptions.push(new CopyPathCommand(appContext));
|
||||
context.subscriptions.push(new DeleteFilesCommand(prompter, appContext));
|
||||
}
|
||||
|
||||
function activateSparkFeatures(appContext: AppContext): void {
|
||||
let extensionContext = appContext.extensionContext;
|
||||
let apiWrapper = appContext.apiWrapper;
|
||||
|
||||
Reference in New Issue
Block a user