diff --git a/extensions/data-workspace/package.json b/extensions/data-workspace/package.json index 195461d985..68e14c465c 100644 --- a/extensions/data-workspace/package.json +++ b/extensions/data-workspace/package.json @@ -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": { diff --git a/extensions/data-workspace/src/common/utils.ts b/extensions/data-workspace/src/common/utils.ts index a983b8e3b4..f42ee8fb14 100644 --- a/extensions/data-workspace/src/common/utils.ts +++ b/extensions/data-workspace/src/common/utils.ts @@ -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 { 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; +} diff --git a/extensions/data-workspace/src/dialogs/dialogBase.ts b/extensions/data-workspace/src/dialogs/dialogBase.ts index d340289245..b4adb6d15f 100644 --- a/extensions/data-workspace/src/dialogs/dialogBase.ts +++ b/extensions/data-workspace/src/dialogs/dialogBase.ts @@ -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 { resolve: (result: T | Promise) => void; @@ -17,15 +17,15 @@ interface Deferred { export abstract class DialogBase { protected _toDispose: vscode.Disposable[] = []; - public dialogObject: azdata.window.Dialog; + public dialogObject: azdataType.window.Dialog; protected initDialogComplete: Deferred | undefined; protected initDialogPromise: Promise = new Promise((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; + protected abstract initialize(view: azdataType.ModelView): Promise; abstract validate(): Promise; public async open(): Promise { - 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({ + protected createWorkspaceContainer(view: azdataType.ModelView): void { + const workspaceDescription = view.modelBuilder.text().withProperties({ 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({ + this.workspaceInputBox = view.modelBuilder.inputBox().withProperties({ 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({ + const browseFolderButton = view.modelBuilder.button().withProperties({ ariaLabel: constants.BrowseButtonText, iconPath: IconPathHelper.folder, height: '16px', diff --git a/extensions/data-workspace/src/dialogs/newProjectDialog.ts b/extensions/data-workspace/src/dialogs/newProjectDialog.ts index 16cae778bf..803b46bf62 100644 --- a/extensions/data-workspace/src/dialogs/newProjectDialog.ts +++ b/extensions/data-workspace/src/dialogs/newProjectDialog.ts @@ -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 { + protected async initialize(view: azdataType.ModelView): Promise { const allProjectTypes = await this.workspaceService.getAllProjectTypes(); - const projectTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties({ + const projectTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties({ cards: allProjectTypes.map((projectType: IProjectType) => { - return { + return { 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({ + const projectNameTextBox = view.modelBuilder.inputBox().withProperties({ 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({ + const locationTextBox = view.modelBuilder.inputBox().withProperties({ 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({ + const browseFolderButton = view.modelBuilder.button().withProperties({ ariaLabel: constants.BrowseButtonText, iconPath: IconPathHelper.folder, height: '16px', diff --git a/extensions/data-workspace/src/dialogs/openExistingDialog.ts b/extensions/data-workspace/src/dialogs/openExistingDialog.ts index 5bbb2d7377..efcb51b991 100644 --- a/extensions/data-workspace/src/dialogs/openExistingDialog.ts +++ b/extensions/data-workspace/src/dialogs/openExistingDialog.ts @@ -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', (this.gitRepoTextBoxComponent?.component).value, this.localClonePathTextBox!.value); + await vscode.commands.executeCommand('git.clone', (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((this.gitRepoTextBoxComponent?.component).value!, this.localClonePathTextBox!.value!, vscode.Uri.file(this.workspaceInputBox!.value!)); + addProjectsPromise = this.workspaceService.gitCloneProject((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 { - this.targetTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties({ + protected async initialize(view: azdataType.ModelView): Promise { + this.targetTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProperties({ cards: this._targetTypes.map((targetType) => { - return { + return { 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({ + this.localRadioButton = view.modelBuilder.radioButton().withProperties({ 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(this.gitRepoTextBoxComponent); - this.formBuilder?.removeFormItem(this.localClonePathComponent); - this.formBuilder?.insertFormItem(this.filePathAndButtonComponent, 2); + this.formBuilder?.removeFormItem(this.gitRepoTextBoxComponent); + this.formBuilder?.removeFormItem(this.localClonePathComponent); + this.formBuilder?.insertFormItem(this.filePathAndButtonComponent, 2); } })); - this.remoteGitRepoRadioButton = view.modelBuilder.radioButton().withProperties({ + this.remoteGitRepoRadioButton = view.modelBuilder.radioButton().withProperties({ 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(this.filePathAndButtonComponent); - this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); - this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); + this.formBuilder?.removeFormItem(this.filePathAndButtonComponent); + this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); + this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); } })); - const gitRepoTextBox = view.modelBuilder.inputBox().withProperties({ + const gitRepoTextBox = view.modelBuilder.inputBox().withProperties({ 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({ + this.localClonePathTextBox = view.modelBuilder.inputBox().withProperties({ 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({ + const localClonePathBrowseFolderButton = view.modelBuilder.button().withProperties({ 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((this.gitRepoTextBoxComponent?.component)!.value!, '.git')); + this.updateWorkspaceInputbox(path.dirname(this.localClonePathTextBox!.value!), path.basename((this.gitRepoTextBoxComponent?.component)!.value!, '.git')); })); this.localClonePathComponent = { @@ -271,7 +271,7 @@ export class OpenExistingDialog extends DialogBase { required: true }; - this.filePathTextBox = view.modelBuilder.inputBox().withProperties({ + this.filePathTextBox = view.modelBuilder.inputBox().withProperties({ 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({ + const localProjectBrowseFolderButton = view.modelBuilder.button().withProperties({ 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(this.filePathAndButtonComponent); - this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); - this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); + this.formBuilder?.removeFormItem(this.filePathAndButtonComponent); + this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); + this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); } else { - this.formBuilder?.removeFormItem(this.gitRepoTextBoxComponent); - this.formBuilder?.removeFormItem(this.localClonePathComponent); + this.formBuilder?.removeFormItem(this.gitRepoTextBoxComponent); + this.formBuilder?.removeFormItem(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(this.filePathAndButtonComponent); - this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); - this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); + this.formBuilder?.removeFormItem(this.filePathAndButtonComponent); + this.formBuilder?.insertFormItem(this.gitRepoTextBoxComponent, 2); + this.formBuilder?.insertFormItem(this.localClonePathComponent, 3); } } diff --git a/extensions/data-workspace/src/dialogs/projectDashboard.ts b/extensions/data-workspace/src/dialogs/projectDashboard.ts index 05b1572897..fb4daa7314 100644 --- a/extensions/data-workspace/src/dialogs/projectDashboard.ts +++ b/extensions/data-workspace/src/dialogs/projectDashboard.ts @@ -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 { - 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({ + .withProperties({ 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({ + .withProperties({ 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({ value: title, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } }) + .withProperties({ 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({ value: projectFolderPath, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } }) + .withProperties({ 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({ value: info.name, CSSStyles: { 'margin-block-start': '30px', 'margin-block-end': '0px' } }) + .withProperties({ 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({ value: noDataText }) + .withProperties({ 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({ + const iconComponent = this.modelView!.modelBuilder.image().withProperties({ iconPath: val.icon, width: '15px', height: '15px', iconHeight: '15px', iconWidth: '15px' }).component(); - const stringComponent = this.modelView!.modelBuilder.text().withProperties({ + const stringComponent = this.modelView!.modelBuilder.text().withProperties({ 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({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component(); + .withProperties({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component(); tableContainer.addItem(table); } diff --git a/extensions/data-workspace/src/services/workspaceService.ts b/extensions/data-workspace/src/services/workspaceService.ts index c7859b3b5c..522ffbbb5b 100644 --- a/extensions/data-workspace/src/services/workspaceService.ts +++ b/extensions/data-workspace/src/services/workspaceService.ts @@ -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 { 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; } diff --git a/extensions/data-workspace/yarn.lock b/extensions/data-workspace/yarn.lock index 3fe8d34d3f..b96df92702 100644 --- a/extensions/data-workspace/yarn.lock +++ b/extensions/data-workspace/yarn.lock @@ -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"