Handle no azdata API in data-workspace extension gracefully (#15871)

This commit is contained in:
Charles Gagnon
2021-06-22 16:35:20 -07:00
committed by GitHub
parent 1e2cb1cdf9
commit 00361e52a2
8 changed files with 120 additions and 103 deletions

View File

@@ -9,7 +9,7 @@
"icon": "images/extension.png",
"aiKey": "AIF-37eefaf0-8022-4671-a3fb-64752724682e",
"engines": {
"vscode": "*",
"vscode": ">=1.48.0",
"azdata": ">=1.25.0"
},
"activationEvents": [
@@ -172,7 +172,7 @@
},
"dependencies": {
"fast-glob": "^3.1.0",
"@microsoft/ads-extension-telemetry": "^1.1.3",
"@microsoft/ads-extension-telemetry": "^1.1.5",
"vscode-nls": "^4.0.0"
},
"devDependencies": {

View File

@@ -5,6 +5,7 @@
import * as fs from 'fs';
import * as vscode from 'vscode';
import type * as azdataType from 'azdata';
export async function directoryExist(directoryPath: string): Promise<boolean> {
const stats = await getFileStatus(directoryPath);
@@ -55,3 +56,20 @@ export function getPackageInfo(packageJson: any): IPackageInfo | undefined {
return undefined;
}
// Try to load the azdata API - but gracefully handle the failure in case we're running
// in a context where the API doesn't exist (such as VS Code)
let azdataApi: typeof azdataType | undefined = undefined;
try {
azdataApi = require('azdata');
} catch {
// no-op
}
/**
* Gets the azdata API if it's available in the context this extension is running in.
* @returns The azdata API if it's available
*/
export function getAzdataApi(): typeof azdataType | undefined {
return azdataApi;
}

View File

@@ -3,12 +3,12 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import type * as azdataType from 'azdata';
import * as vscode from 'vscode';
import * as path from 'path';
import * as constants from '../common/constants';
import { IconPathHelper } from '../common/iconHelper';
import { directoryExist, fileExist, isCurrentWorkspaceUntitled } from '../common/utils';
import { directoryExist, fileExist, getAzdataApi, isCurrentWorkspaceUntitled } from '../common/utils';
interface Deferred<T> {
resolve: (result: T | Promise<T>) => void;
@@ -17,15 +17,15 @@ interface Deferred<T> {
export abstract class DialogBase {
protected _toDispose: vscode.Disposable[] = [];
public dialogObject: azdata.window.Dialog;
public dialogObject: azdataType.window.Dialog;
protected initDialogComplete: Deferred<void> | undefined;
protected initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
protected workspaceDescriptionFormComponent: azdata.FormComponent | undefined;
public workspaceInputBox: azdata.InputBoxComponent | undefined;
protected workspaceInputFormComponent: azdata.FormComponent | undefined;
protected workspaceDescriptionFormComponent: azdataType.FormComponent | undefined;
public workspaceInputBox: azdataType.InputBoxComponent | undefined;
protected workspaceInputFormComponent: azdataType.FormComponent | undefined;
constructor(dialogTitle: string, dialogName: string, okButtonText: string, dialogWidth: azdata.window.DialogWidth = 600) {
this.dialogObject = azdata.window.createModelViewDialog(dialogTitle, dialogName, dialogWidth);
constructor(dialogTitle: string, dialogName: string, okButtonText: string, dialogWidth: azdataType.window.DialogWidth = 600) {
this.dialogObject = getAzdataApi()!.window.createModelViewDialog(dialogTitle, dialogName, dialogWidth);
this.dialogObject.okButton.label = okButtonText;
this.register(this.dialogObject.cancelButton.onClick(() => this.onCancelButtonClicked()));
this.register(this.dialogObject.okButton.onClick(() => this.onOkButtonClicked()));
@@ -34,17 +34,17 @@ export abstract class DialogBase {
});
}
protected abstract initialize(view: azdata.ModelView): Promise<void>;
protected abstract initialize(view: azdataType.ModelView): Promise<void>;
abstract validate(): Promise<boolean>;
public async open(): Promise<void> {
const tab = azdata.window.createTab('');
tab.registerContent(async (view: azdata.ModelView) => {
const tab = getAzdataApi()!.window.createTab('');
tab.registerContent(async (view: azdataType.ModelView) => {
return this.initialize(view);
});
this.dialogObject.content = [tab];
azdata.window.openDialog(this.dialogObject);
getAzdataApi()!.window.openDialog(this.dialogObject);
await this.initDialogPromise;
}
@@ -71,15 +71,15 @@ export abstract class DialogBase {
protected showErrorMessage(message: string): void {
this.dialogObject.message = {
text: message,
level: azdata.window.MessageLevel.Error
level: getAzdataApi()!.window.MessageLevel.Error
};
}
public getErrorMessage(): azdata.window.DialogMessage {
public getErrorMessage(): azdataType.window.DialogMessage {
return this.dialogObject.message;
}
protected createHorizontalContainer(view: azdata.ModelView, items: azdata.Component[]): azdata.FlexContainer {
protected createHorizontalContainer(view: azdataType.ModelView, items: azdataType.Component[]): azdataType.FlexContainer {
return view.modelBuilder.flexContainer().withItems(items, { CSSStyles: { 'margin-right': '5px', 'margin-bottom': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
}
@@ -88,15 +88,15 @@ export abstract class DialogBase {
* created if no workspace is currently open
* @param view
*/
protected createWorkspaceContainer(view: azdata.ModelView): void {
const workspaceDescription = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
protected createWorkspaceContainer(view: azdataType.ModelView): void {
const workspaceDescription = view.modelBuilder.text().withProperties<azdataType.TextComponentProperties>({
value: vscode.workspace.workspaceFile ? constants.AddProjectToCurrentWorkspace : constants.NewWorkspaceWillBeCreated,
CSSStyles: { 'margin-top': '3px', 'margin-bottom': '0px' }
}).component();
const initialWorkspaceInputBoxValue = !!vscode.workspace.workspaceFile && !isCurrentWorkspaceUntitled() ? vscode.workspace.workspaceFile.fsPath : '';
this.workspaceInputBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
this.workspaceInputBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.WorkspaceLocationTitle,
width: constants.DefaultInputWidth,
enabled: !vscode.workspace.workspaceFile || isCurrentWorkspaceUntitled(), // want it editable if no saved workspace is open
@@ -104,7 +104,7 @@ export abstract class DialogBase {
title: initialWorkspaceInputBoxValue // hovertext for if file path is too long to be seen in textbox
}).component();
const browseFolderButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
const browseFolderButton = view.modelBuilder.button().withProperties<azdataType.ButtonProperties>({
ariaLabel: constants.BrowseButtonText,
iconPath: IconPathHelper.folder,
height: '16px',

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import type * as azdataType from 'azdata';
import * as vscode from 'vscode';
import * as path from 'path';
import { DialogBase } from './dialogBase';
@@ -84,11 +84,11 @@ export class NewProjectDialog extends DialogBase {
}
}
protected async initialize(view: azdata.ModelView): Promise<void> {
protected async initialize(view: azdataType.ModelView): Promise<void> {
const allProjectTypes = await this.workspaceService.getAllProjectTypes();
const projectTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties<azdata.RadioCardGroupComponentProperties>({
const projectTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties<azdataType.RadioCardGroupComponentProperties>({
cards: allProjectTypes.map((projectType: IProjectType) => {
return <azdata.RadioCard>{
return <azdataType.RadioCard>{
id: projectType.id,
label: projectType.displayName,
icon: projectType.icon,
@@ -119,7 +119,7 @@ export class NewProjectDialog extends DialogBase {
this.model.projectTypeId = e.cardId;
}));
const projectNameTextBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
const projectNameTextBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.ProjectNameTitle,
placeHolder: constants.ProjectNamePlaceholder,
required: true,
@@ -133,7 +133,7 @@ export class NewProjectDialog extends DialogBase {
this.updateWorkspaceInputbox(path.join(this.model.location, this.model.name), this.model.name);
}));
const locationTextBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
const locationTextBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.ProjectLocationTitle,
placeHolder: constants.ProjectLocationPlaceholder,
required: true,
@@ -146,7 +146,7 @@ export class NewProjectDialog extends DialogBase {
this.updateWorkspaceInputbox(path.join(this.model.location, this.model.name), this.model.name);
}));
const browseFolderButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
const browseFolderButton = view.modelBuilder.button().withProperties<azdataType.ButtonProperties>({
ariaLabel: constants.BrowseButtonText,
iconPath: IconPathHelper.folder,
height: '16px',

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import type * as azdataType from 'azdata';
import * as vscode from 'vscode';
import * as path from 'path';
import { DialogBase } from './dialogBase';
@@ -15,16 +15,16 @@ import { calculateRelativity, TelemetryActions, TelemetryReporter, TelemetryView
import { defaultProjectSaveLocation } from '../common/projectLocationHelper';
export class OpenExistingDialog extends DialogBase {
public targetTypeRadioCardGroup: azdata.RadioCardGroupComponent | undefined;
public filePathTextBox: azdata.InputBoxComponent | undefined;
public filePathAndButtonComponent: azdata.FormComponent | undefined;
public gitRepoTextBoxComponent: azdata.FormComponent | undefined;
public localClonePathComponent: azdata.FormComponent | undefined;
public localClonePathTextBox: azdata.InputBoxComponent | undefined;
public localRadioButton: azdata.RadioButtonComponent | undefined;
public remoteGitRepoRadioButton: azdata.RadioButtonComponent | undefined;
public locationRadioButtonFormComponent: azdata.FormComponent | undefined;
public formBuilder: azdata.FormBuilder | undefined;
public targetTypeRadioCardGroup: azdataType.RadioCardGroupComponent | undefined;
public filePathTextBox: azdataType.InputBoxComponent | undefined;
public filePathAndButtonComponent: azdataType.FormComponent | undefined;
public gitRepoTextBoxComponent: azdataType.FormComponent | undefined;
public localClonePathComponent: azdataType.FormComponent | undefined;
public localClonePathTextBox: azdataType.InputBoxComponent | undefined;
public localRadioButton: azdataType.RadioButtonComponent | undefined;
public remoteGitRepoRadioButton: azdataType.RadioButtonComponent | undefined;
public locationRadioButtonFormComponent: azdataType.FormComponent | undefined;
public formBuilder: azdataType.FormBuilder | undefined;
private _targetTypes = [
{
@@ -108,7 +108,7 @@ export class OpenExistingDialog extends DialogBase {
// show git output channel
vscode.commands.executeCommand('git.showOutput');
// after this executes, the git extension will show a popup asking if you want to enter the workspace
await vscode.commands.executeCommand('git.clone', (<azdata.InputBoxComponent>this.gitRepoTextBoxComponent?.component).value, this.localClonePathTextBox!.value);
await vscode.commands.executeCommand('git.clone', (<azdataType.InputBoxComponent>this.gitRepoTextBoxComponent?.component).value, this.localClonePathTextBox!.value);
} else {
await this.workspaceService.enterWorkspace(vscode.Uri.file(this.filePathTextBox!.value!));
}
@@ -124,7 +124,7 @@ export class OpenExistingDialog extends DialogBase {
.withAdditionalProperties({ selectedTarget: 'project' })
.send();
addProjectsPromise = this.workspaceService.gitCloneProject((<azdata.InputBoxComponent>this.gitRepoTextBoxComponent?.component).value!, this.localClonePathTextBox!.value!, vscode.Uri.file(this.workspaceInputBox!.value!));
addProjectsPromise = this.workspaceService.gitCloneProject((<azdataType.InputBoxComponent>this.gitRepoTextBoxComponent?.component).value!, this.localClonePathTextBox!.value!, vscode.Uri.file(this.workspaceInputBox!.value!));
} else {
if (validateWorkspace) {
telemetryProps.workspaceProjectRelativity = calculateRelativity(this.filePathTextBox!.value!, this.workspaceInputBox!.value!);
@@ -149,10 +149,10 @@ export class OpenExistingDialog extends DialogBase {
}
}
protected async initialize(view: azdata.ModelView): Promise<void> {
this.targetTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties<azdata.RadioCardGroupComponentProperties>({
protected async initialize(view: azdataType.ModelView): Promise<void> {
this.targetTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties<azdataType.RadioCardGroupComponentProperties>({
cards: this._targetTypes.map((targetType) => {
return <azdata.RadioCard>{
return <azdataType.RadioCard>{
id: targetType.name,
label: targetType.name,
icon: targetType.icon,
@@ -176,7 +176,7 @@ export class OpenExistingDialog extends DialogBase {
selectedCardId: constants.Project
}).component();
this.localRadioButton = view.modelBuilder.radioButton().withProperties<azdata.RadioButtonProperties>({
this.localRadioButton = view.modelBuilder.radioButton().withProperties<azdataType.RadioButtonProperties>({
name: 'location',
label: constants.Local,
checked: true
@@ -184,13 +184,13 @@ export class OpenExistingDialog extends DialogBase {
this.register(this.localRadioButton.onDidChangeCheckedState(checked => {
if (checked) {
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.gitRepoTextBoxComponent);
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.localClonePathComponent);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.filePathAndButtonComponent, 2);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.gitRepoTextBoxComponent);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.localClonePathComponent);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.filePathAndButtonComponent, 2);
}
}));
this.remoteGitRepoRadioButton = view.modelBuilder.radioButton().withProperties<azdata.RadioButtonProperties>({
this.remoteGitRepoRadioButton = view.modelBuilder.radioButton().withProperties<azdataType.RadioButtonProperties>({
name: 'location',
label: constants.RemoteGitRepo
}).component();
@@ -206,13 +206,13 @@ export class OpenExistingDialog extends DialogBase {
this.register(this.remoteGitRepoRadioButton.onDidChangeCheckedState(checked => {
if (checked) {
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.localClonePathComponent, 3);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.localClonePathComponent, 3);
}
}));
const gitRepoTextBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
const gitRepoTextBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.GitRepoUrlTitle,
placeHolder: constants.GitRepoUrlPlaceholder,
required: true,
@@ -229,7 +229,7 @@ export class OpenExistingDialog extends DialogBase {
component: gitRepoTextBox
};
this.localClonePathTextBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
this.localClonePathTextBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.LocalClonePathTitle,
placeHolder: constants.LocalClonePathPlaceholder,
required: true,
@@ -241,7 +241,7 @@ export class OpenExistingDialog extends DialogBase {
this.updateWorkspaceInputbox(this.localClonePathTextBox!.value!, path.basename(gitRepoTextBox!.value!, '.git'));
}));
const localClonePathBrowseFolderButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
const localClonePathBrowseFolderButton = view.modelBuilder.button().withProperties<azdataType.ButtonProperties>({
ariaLabel: constants.BrowseButtonText,
iconPath: IconPathHelper.folder,
width: '18px',
@@ -262,7 +262,7 @@ export class OpenExistingDialog extends DialogBase {
const selectedFolder = folderUris[0].fsPath;
this.localClonePathTextBox!.value = selectedFolder;
this.localClonePathTextBox!.updateProperty('title', this.localClonePathTextBox!.value);
this.updateWorkspaceInputbox(path.dirname(this.localClonePathTextBox!.value!), path.basename((<azdata.InputBoxComponent>this.gitRepoTextBoxComponent?.component)!.value!, '.git'));
this.updateWorkspaceInputbox(path.dirname(this.localClonePathTextBox!.value!), path.basename((<azdataType.InputBoxComponent>this.gitRepoTextBoxComponent?.component)!.value!, '.git'));
}));
this.localClonePathComponent = {
@@ -271,7 +271,7 @@ export class OpenExistingDialog extends DialogBase {
required: true
};
this.filePathTextBox = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
this.filePathTextBox = view.modelBuilder.inputBox().withProperties<azdataType.InputBoxProperties>({
ariaLabel: constants.LocationSelectorTitle,
placeHolder: constants.ProjectFilePlaceholder,
required: true,
@@ -283,7 +283,7 @@ export class OpenExistingDialog extends DialogBase {
this.updateWorkspaceInputbox(path.dirname(this.filePathTextBox!.value!), path.basename(this.filePathTextBox!.value!, path.extname(this.filePathTextBox!.value!)));
}));
const localProjectBrowseFolderButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
const localProjectBrowseFolderButton = view.modelBuilder.button().withProperties<azdataType.ButtonProperties>({
ariaLabel: constants.BrowseButtonText,
iconPath: IconPathHelper.folder,
width: '18px',
@@ -308,12 +308,12 @@ export class OpenExistingDialog extends DialogBase {
this.filePathTextBox!.placeHolder = constants.ProjectFilePlaceholder;
if (this.remoteGitRepoRadioButton!.checked) {
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.localClonePathComponent, 3);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.localClonePathComponent, 3);
} else {
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.gitRepoTextBoxComponent);
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.localClonePathComponent);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.gitRepoTextBoxComponent);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.localClonePathComponent);
this.formBuilder?.addFormItem(this.filePathAndButtonComponent!);
}
@@ -326,9 +326,9 @@ export class OpenExistingDialog extends DialogBase {
this.formBuilder?.removeFormItem(this.workspaceInputFormComponent!);
if (this.remoteGitRepoRadioButton!.checked) {
this.formBuilder?.removeFormItem(<azdata.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdata.FormComponent>this.localClonePathComponent, 3);
this.formBuilder?.removeFormItem(<azdataType.FormComponent>this.filePathAndButtonComponent);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.gitRepoTextBoxComponent, 2);
this.formBuilder?.insertFormItem(<azdataType.FormComponent>this.localClonePathComponent, 3);
}
}

View File

@@ -3,23 +3,23 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import type * as azdataType from 'azdata';
import { IDashboardColumnInfo, IDashboardTable, IProjectAction, IProjectActionGroup, IProjectProvider, WorkspaceTreeItem } from 'dataworkspace';
import * as path from 'path';
import * as vscode from 'vscode';
import * as constants from '../common/constants';
import { IconPathHelper } from '../common/iconHelper';
import { IWorkspaceService } from '../common/interfaces';
import { fileExist } from '../common/utils';
import { fileExist, getAzdataApi } from '../common/utils';
export class ProjectDashboard {
private dashboard: azdata.window.ModelViewDashboard | undefined;
private modelView: azdata.ModelView | undefined;
private dashboard: azdataType.window.ModelViewDashboard | undefined;
private modelView: azdataType.ModelView | undefined;
private projectProvider: IProjectProvider | undefined;
private overviewTab: azdata.DashboardTab | undefined;
private rootContainer: azdata.FlexContainer | undefined;
private tableContainer: azdata.Component | undefined;
private overviewTab: azdataType.DashboardTab | undefined;
private rootContainer: azdataType.FlexContainer | undefined;
private tableContainer: azdataType.Component | undefined;
constructor(private _workspaceService: IWorkspaceService, private _treeItem: WorkspaceTreeItem) {
}
@@ -45,8 +45,8 @@ export class ProjectDashboard {
}
private async createDashboard(title: string, projectFilePath: string): Promise<void> {
this.dashboard = azdata.window.createModelViewDashboard(title, 'ProjectDashboard', { alwaysShowTabs: false });
this.dashboard.registerTabs(async (modelView: azdata.ModelView) => {
this.dashboard = getAzdataApi()!.window.createModelViewDashboard(title, 'ProjectDashboard', { alwaysShowTabs: false });
this.dashboard.registerTabs(async (modelView: azdataType.ModelView) => {
this.modelView = modelView;
this.overviewTab = {
@@ -61,11 +61,11 @@ export class ProjectDashboard {
});
}
private createToolbarContainer(projectFilePath: string): azdata.ToolbarContainer {
private createToolbarContainer(projectFilePath: string): azdataType.ToolbarContainer {
const projectActions: (IProjectAction | IProjectActionGroup)[] = this.projectProvider!.projectToolbarActions;
// Add actions as buttons
const buttons: azdata.ToolbarComponent[] = [];
const buttons: azdataType.ToolbarComponent[] = [];
const projectActionsLength = projectActions.length;
@@ -84,7 +84,7 @@ export class ProjectDashboard {
});
const refreshButton = this.modelView!.modelBuilder.button()
.withProperties<azdata.ButtonProperties>({
.withProperties<azdataType.ButtonProperties>({
label: constants.Refresh,
iconPath: IconPathHelper.refresh,
height: '20px'
@@ -108,9 +108,9 @@ export class ProjectDashboard {
return obj.id !== undefined;
}
private createButton(projectAction: IProjectAction): azdata.ButtonComponent {
private createButton(projectAction: IProjectAction): azdataType.ButtonComponent {
let button = this.modelView!.modelBuilder.button()
.withProperties<azdata.ButtonProperties>({
.withProperties<azdataType.ButtonProperties>({
label: projectAction.id,
iconPath: projectAction.icon,
height: '20px'
@@ -123,7 +123,7 @@ export class ProjectDashboard {
return button;
}
private createContainer(title: string, projectFilePath: string): azdata.FlexContainer {
private createContainer(title: string, projectFilePath: string): azdataType.FlexContainer {
this.rootContainer = this.modelView!.modelBuilder.flexContainer().withLayout(
{
flexFlow: 'column',
@@ -143,7 +143,7 @@ export class ProjectDashboard {
/**
* Create header with title, location and background
*/
private createHeader(title: string, location: string): azdata.Component {
private createHeader(title: string, location: string): azdataType.Component {
const headerContainer = this.modelView!.modelBuilder.flexContainer().withLayout(
{
flexFlow: 'column',
@@ -159,13 +159,13 @@ export class ProjectDashboard {
}).component();
const titleLabel = this.modelView!.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({ value: title, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.withProperties<azdataType.TextComponentProperties>({ value: title, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.component();
header.addItem(titleLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'font-size': '36px', 'font-weight': '400' } });
const projectFolderPath = path.dirname(location);
const locationLabel = this.modelView!.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({ value: projectFolderPath, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.withProperties<azdataType.TextComponentProperties>({ value: projectFolderPath, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.component();
header.addItem(locationLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'padding-bottom': '50px', 'font-size': '16px' } });
@@ -188,7 +188,7 @@ export class ProjectDashboard {
/**
* Adds all the tables to the container
*/
private createTables(projectFile: string): azdata.Component {
private createTables(projectFile: string): azdataType.Component {
const dashboardData: IDashboardTable[] = this.projectProvider!.getDashboardComponents(projectFile);
const tableContainer = this.modelView!.modelBuilder.flexContainer().withLayout(
@@ -200,22 +200,22 @@ export class ProjectDashboard {
dashboardData.forEach(info => {
const tableNameLabel = this.modelView!.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({ value: info.name, CSSStyles: { 'margin-block-start': '30px', 'margin-block-end': '0px' } })
.withProperties<azdataType.TextComponentProperties>({ value: info.name, CSSStyles: { 'margin-block-start': '30px', 'margin-block-end': '0px' } })
.component();
tableContainer.addItem(tableNameLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px', ...constants.cssStyles.title } });
if (info.data.length === 0) {
const noDataText = constants.noPreviousData(info.name.toLocaleLowerCase());
const noDataLabel = this.modelView!.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({ value: noDataText })
.withProperties<azdataType.TextComponentProperties>({ value: noDataText })
.component();
tableContainer.addItem(noDataLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px' } });
} else {
const columns: azdata.DeclarativeTableColumn[] = [];
const columns: azdataType.DeclarativeTableColumn[] = [];
info.columns.forEach((column: IDashboardColumnInfo) => {
let col = {
displayName: column.displayName,
valueType: column.type === 'icon' ? azdata.DeclarativeDataType.component : azdata.DeclarativeDataType.string,
valueType: column.type === 'icon' ? getAzdataApi()!.DeclarativeDataType.component : getAzdataApi()!.DeclarativeDataType.string,
isReadOnly: true,
width: column.width,
headerCssStyles: {
@@ -229,21 +229,21 @@ export class ProjectDashboard {
columns.push(col);
});
const data: azdata.DeclarativeTableCellValue[][] = [];
const data: azdataType.DeclarativeTableCellValue[][] = [];
info.data.forEach(values => {
const columnValue: azdata.DeclarativeTableCellValue[] = [];
const columnValue: azdataType.DeclarativeTableCellValue[] = [];
values.forEach(val => {
if (typeof val === 'string') {
columnValue.push({ value: val });
} else {
const iconComponent = this.modelView!.modelBuilder.image().withProperties<azdata.ImageComponentProperties>({
const iconComponent = this.modelView!.modelBuilder.image().withProperties<azdataType.ImageComponentProperties>({
iconPath: val.icon,
width: '15px',
height: '15px',
iconHeight: '15px',
iconWidth: '15px'
}).component();
const stringComponent = this.modelView!.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
const stringComponent = this.modelView!.modelBuilder.text().withProperties<azdataType.TextComponentProperties>({
value: val.text,
CSSStyles: { 'margin-block-start': 'auto', 'block-size': 'auto', 'margin-block-end': '0px' }
}).component();
@@ -256,7 +256,7 @@ export class ProjectDashboard {
});
const table = this.modelView!.modelBuilder.declarativeTable()
.withProperties<azdata.DeclarativeTableProperties>({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component();
.withProperties<azdataType.DeclarativeTableProperties>({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component();
tableContainer.addItem(table);
}

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as dataworkspace from 'dataworkspace';
import * as path from 'path';
@@ -14,7 +13,7 @@ import { IWorkspaceService } from '../common/interfaces';
import { ProjectProviderRegistry } from '../common/projectProviderRegistry';
import Logger from '../common/logger';
import { TelemetryReporter, TelemetryViews, calculateRelativity, TelemetryActions } from '../common/telemetry';
import { isCurrentWorkspaceUntitled } from '../common/utils';
import { getAzdataApi, isCurrentWorkspaceUntitled } from '../common/utils';
const WorkspaceConfigurationName = 'dataworkspace';
const ProjectsConfigurationName = 'projects';
@@ -58,9 +57,9 @@ export class WorkspaceService implements IWorkspaceService {
if (isCurrentWorkspaceUntitled()) {
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders!.length, null, { uri: projectFolder });
await azdata.workspace.saveAndEnterWorkspace(workspaceFile!);
await getAzdataApi()?.workspace.saveAndEnterWorkspace(workspaceFile!);
} else {
await azdata.workspace.createAndEnterWorkspace(projectFolder, workspaceFile);
await getAzdataApi()?.workspace.createAndEnterWorkspace(projectFolder, workspaceFile);
}
}
@@ -98,7 +97,7 @@ export class WorkspaceService implements IWorkspaceService {
async enterWorkspace(workspaceFile: vscode.Uri): Promise<void> {
const result = await vscode.window.showWarningMessage(constants.EnterWorkspaceConfirmation, { modal: true }, constants.OkButtonText);
if (result === constants.OkButtonText) {
await azdata.workspace.enterWorkspace(workspaceFile);
await getAzdataApi()?.workspace.enterWorkspace(workspaceFile);
} else {
return;
}

View File

@@ -182,10 +182,10 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
"@microsoft/ads-extension-telemetry@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@microsoft/ads-extension-telemetry/-/ads-extension-telemetry-1.1.3.tgz#54160eefa21f2a536622b0617f3c3f2018cf9c87"
integrity sha512-+h6hM9oOA6Zj/N0nCGPzRgydR0YHiHpNJoNlv6a/ziWXO3RYSbQX+3U/PpT3gEA6+8RwByf6RVICo7uIGBy1LQ==
"@microsoft/ads-extension-telemetry@^1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@microsoft/ads-extension-telemetry/-/ads-extension-telemetry-1.1.5.tgz#4f2ec72a7730131fdd939ace307a1ff5feef16b6"
integrity sha512-Xq8qQi8CHxXPTCO5cRvJABgtVdFO42kQgVoHkBc7ByBhN4VMdw/kakbWgVtHbMl4oRARtpncE2xYCiVeZHK6XA==
dependencies:
vscode-extension-telemetry "^0.1.6"