mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Add project dropdown to Update project from database dialog (#21446)
* Add dropdown populated with projects in current workspace in Update Project from database dialog for target project location * Select first from the list if no project is preselected * Address comments
This commit is contained in:
@@ -1563,7 +1563,8 @@ export class ProjectsController {
|
|||||||
}
|
}
|
||||||
} catch { }
|
} catch { }
|
||||||
|
|
||||||
const updateProjectFromDatabaseDialog = this.getUpdateProjectFromDatabaseDialog(connection, project);
|
const workspaceProjects = await utils.getSqlProjectsInWorkspace();
|
||||||
|
const updateProjectFromDatabaseDialog = this.getUpdateProjectFromDatabaseDialog(connection, project, workspaceProjects);
|
||||||
|
|
||||||
updateProjectFromDatabaseDialog.updateProjectFromDatabaseCallback = async (model) => await this.updateProjectFromDatabaseCallback(model);
|
updateProjectFromDatabaseDialog.updateProjectFromDatabaseCallback = async (model) => await this.updateProjectFromDatabaseCallback(model);
|
||||||
|
|
||||||
@@ -1572,8 +1573,8 @@ export class ProjectsController {
|
|||||||
return updateProjectFromDatabaseDialog;
|
return updateProjectFromDatabaseDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUpdateProjectFromDatabaseDialog(connection: azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, project: Project | undefined): UpdateProjectFromDatabaseDialog {
|
public getUpdateProjectFromDatabaseDialog(connection: azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, project: Project | undefined, workspaceProjects: vscode.Uri[]): UpdateProjectFromDatabaseDialog {
|
||||||
return new UpdateProjectFromDatabaseDialog(connection, project);
|
return new UpdateProjectFromDatabaseDialog(connection, project, workspaceProjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProjectFromDatabaseCallback(model: UpdateProjectDataModel) {
|
public async updateProjectFromDatabaseCallback(model: UpdateProjectDataModel) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
public dialog: azdata.window.Dialog;
|
public dialog: azdata.window.Dialog;
|
||||||
public serverDropdown: azdata.DropDownComponent | undefined;
|
public serverDropdown: azdata.DropDownComponent | undefined;
|
||||||
public databaseDropdown: azdata.DropDownComponent | undefined;
|
public databaseDropdown: azdata.DropDownComponent | undefined;
|
||||||
public projectFileTextBox: azdata.InputBoxComponent | undefined;
|
public projectFileDropdown: azdata.DropDownComponent | undefined;
|
||||||
public compareActionRadioButton: azdata.RadioButtonComponent | undefined;
|
public compareActionRadioButton: azdata.RadioButtonComponent | undefined;
|
||||||
private updateProjectFromDatabaseTab: azdata.window.DialogTab;
|
private updateProjectFromDatabaseTab: azdata.window.DialogTab;
|
||||||
private connectionButton: azdata.ButtonComponent | undefined;
|
private connectionButton: azdata.ButtonComponent | undefined;
|
||||||
@@ -39,7 +39,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
|
|
||||||
public updateProjectFromDatabaseCallback: ((model: UpdateProjectDataModel) => any) | undefined;
|
public updateProjectFromDatabaseCallback: ((model: UpdateProjectDataModel) => any) | undefined;
|
||||||
|
|
||||||
constructor(connection: azdata.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, private project: Project | undefined) {
|
constructor(connection: azdata.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, private project: Project | undefined, private workspaceProjects: vscode.Uri[]) {
|
||||||
if (connection && 'connectionName' in connection) {
|
if (connection && 'connectionName' in connection) {
|
||||||
this.profile = connection;
|
this.profile = connection;
|
||||||
}
|
}
|
||||||
@@ -365,17 +365,23 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
private createProjectLocationRow(view: azdata.ModelView): azdata.FlexContainer {
|
private createProjectLocationRow(view: azdata.ModelView): azdata.FlexContainer {
|
||||||
const browseFolderButton: azdata.Component = this.createBrowseFileButton(view);
|
const browseFolderButton: azdata.Component = this.createBrowseFileButton(view);
|
||||||
|
|
||||||
const value = this.project ? this.project.projectFilePath : '';
|
let values: string[] = [];
|
||||||
|
this.workspaceProjects.forEach(projectUri => {
|
||||||
|
values.push(projectUri.fsPath);
|
||||||
|
});
|
||||||
|
|
||||||
this.projectFileTextBox = view.modelBuilder.inputBox().withProps({
|
const value = this.project ? this.project.projectFilePath : (values[0] ?? '');
|
||||||
|
|
||||||
|
this.projectFileDropdown = view.modelBuilder.dropDown().withProps({
|
||||||
|
editable: true,
|
||||||
|
fireOnTextChange: true,
|
||||||
value: value,
|
value: value,
|
||||||
ariaLabel: constants.projectLocationLabel,
|
values: values,
|
||||||
placeHolder: constants.projectToUpdatePlaceholderText,
|
|
||||||
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.projectFileTextBox.onTextChanged(async () => {
|
this.projectFileDropdown.onValueChanged(async () => {
|
||||||
await this.projectFileTextBox!.updateProperty('title', this.projectFileTextBox!.value);
|
await this.projectFileDropdown!.updateProperty('title', this.projectFileDropdown!.value);
|
||||||
this.tryEnableUpdateButton();
|
this.tryEnableUpdateButton();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -386,7 +392,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
const projectLocationRow = view.modelBuilder.flexContainer().withItems([projectLocationLabel,], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px', 'margin-bottom': '-5px', 'margin-top': '-7px' } }).component();
|
const projectLocationRow = view.modelBuilder.flexContainer().withItems([projectLocationLabel,], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px', 'margin-bottom': '-5px', 'margin-top': '-7px' } }).component();
|
||||||
projectLocationRow.addItem(this.projectFileTextBox, { CSSStyles: { 'margin-right': '10px' } });
|
projectLocationRow.addItem(this.projectFileDropdown, { CSSStyles: { 'margin-right': '10px' } });
|
||||||
projectLocationRow.addItem(browseFolderButton, { CSSStyles: { 'margin-top': '2px' } });
|
projectLocationRow.addItem(browseFolderButton, { CSSStyles: { 'margin-top': '2px' } });
|
||||||
|
|
||||||
return projectLocationRow;
|
return projectLocationRow;
|
||||||
@@ -416,8 +422,8 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.projectFileTextBox!.value = fileUris[0].fsPath;
|
this.projectFileDropdown!.value = fileUris[0].fsPath;
|
||||||
await this.projectFileTextBox!.updateProperty('title', fileUris[0].fsPath);
|
await this.projectFileDropdown!.updateProperty('title', fileUris[0].fsPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
return browseFolderButton;
|
return browseFolderButton;
|
||||||
@@ -426,7 +432,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
private createFolderStructureRow(view: azdata.ModelView): azdata.FlexContainer {
|
private createFolderStructureRow(view: azdata.ModelView): azdata.FlexContainer {
|
||||||
this.folderStructureDropDown = view.modelBuilder.dropDown().withProps({
|
this.folderStructureDropDown = view.modelBuilder.dropDown().withProps({
|
||||||
values: [constants.file, constants.flat, constants.objectType, constants.schema, constants.schemaObjectType],
|
values: [constants.file, constants.flat, constants.objectType, constants.schema, constants.schemaObjectType],
|
||||||
value: constants.schemaObjectType,
|
value: constants.schemaObjectType, //TODO: Read this value from project info after fixing https://github.com/microsoft/azuredatastudio/issues/20332
|
||||||
ariaLabel: constants.folderStructureLabel,
|
ariaLabel: constants.folderStructureLabel,
|
||||||
required: true,
|
required: true,
|
||||||
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
||||||
@@ -493,7 +499,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
public tryEnableUpdateButton(): void {
|
public tryEnableUpdateButton(): void {
|
||||||
if (this.serverDropdown?.value
|
if (this.serverDropdown?.value
|
||||||
&& this.databaseDropdown?.value
|
&& this.databaseDropdown?.value
|
||||||
&& this.projectFileTextBox?.value
|
&& this.projectFileDropdown?.value
|
||||||
&& this.folderStructureDropDown?.value
|
&& this.folderStructureDropDown?.value
|
||||||
&& this.action !== undefined) {
|
&& this.action !== undefined) {
|
||||||
this.dialog.okButton.enabled = true;
|
this.dialog.okButton.enabled = true;
|
||||||
@@ -547,7 +553,7 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
|
|
||||||
const targetEndpointInfo: mssql.SchemaCompareEndpointInfo = {
|
const targetEndpointInfo: mssql.SchemaCompareEndpointInfo = {
|
||||||
endpointType: mssql.SchemaCompareEndpointType.Project,
|
endpointType: mssql.SchemaCompareEndpointType.Project,
|
||||||
projectFilePath: this.projectFileTextBox!.value!,
|
projectFilePath: this.projectFileDropdown!.value! as string,
|
||||||
folderStructure: mapExtractTargetEnum(<string>this.folderStructureDropDown!.value),
|
folderStructure: mapExtractTargetEnum(<string>this.folderStructureDropDown!.value),
|
||||||
targetScripts: [],
|
targetScripts: [],
|
||||||
dataSchemaProvider: '',
|
dataSchemaProvider: '',
|
||||||
@@ -575,14 +581,14 @@ export class UpdateProjectFromDatabaseDialog {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// the selected location should be an existing directory
|
// the selected location should be an existing directory
|
||||||
const parentDirectoryExists = await exists(path.dirname(this.projectFileTextBox!.value!));
|
const parentDirectoryExists = await exists(path.dirname(this.projectFileDropdown!.value! as string));
|
||||||
if (!parentDirectoryExists) {
|
if (!parentDirectoryExists) {
|
||||||
this.showErrorMessage(constants.ProjectParentDirectoryNotExistError(this.projectFileTextBox!.value!));
|
this.showErrorMessage(constants.ProjectParentDirectoryNotExistError(this.projectFileDropdown!.value! as string));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the selected location must contain a .sqlproj file
|
// the selected location must contain a .sqlproj file
|
||||||
const fileExists = await exists(this.projectFileTextBox!.value!);
|
const fileExists = await exists(this.projectFileDropdown!.value! as string);
|
||||||
if (!fileExists) {
|
if (!fileExists) {
|
||||||
this.showErrorMessage(constants.noSqlProjFile);
|
this.showErrorMessage(constants.noSqlProjFile);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as baselines from '../baselines/baselines';
|
|||||||
import * as testUtils from '../testUtils';
|
import * as testUtils from '../testUtils';
|
||||||
|
|
||||||
import { UpdateProjectFromDatabaseDialog } from '../../dialogs/updateProjectFromDatabaseDialog';
|
import { UpdateProjectFromDatabaseDialog } from '../../dialogs/updateProjectFromDatabaseDialog';
|
||||||
import { mockConnectionProfile } from '../testContext';
|
import { mockConnectionProfile, mockURIList } from '../testContext';
|
||||||
|
|
||||||
describe('Update Project From Database Dialog', () => {
|
describe('Update Project From Database Dialog', () => {
|
||||||
before(async function (): Promise<void> {
|
before(async function (): Promise<void> {
|
||||||
@@ -26,23 +26,23 @@ describe('Update Project From Database Dialog', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should populate endpoints correctly when no context passed', async function (): Promise<void> {
|
it('Should populate endpoints correctly when no context passed', async function (): Promise<void> {
|
||||||
const dialog = new UpdateProjectFromDatabaseDialog(undefined, undefined);
|
const dialog = new UpdateProjectFromDatabaseDialog(undefined, undefined, []);
|
||||||
await dialog.openDialog();
|
await dialog.openDialog();
|
||||||
|
|
||||||
should.equal(dialog.serverDropdown!.value, undefined, `Server dropdown should not be populated, but instead was "${dialog.serverDropdown!.value}".`);
|
should.equal(dialog.serverDropdown!.value, undefined, `Server dropdown should not be populated, but instead was "${dialog.serverDropdown!.value}".`);
|
||||||
should.equal(dialog.databaseDropdown!.value, undefined, `Database dropdown should not be populated, but instead was "${dialog.databaseDropdown!.value}".`);
|
should.equal(dialog.databaseDropdown!.value, undefined, `Database dropdown should not be populated, but instead was "${dialog.databaseDropdown!.value}".`);
|
||||||
should.equal(dialog.projectFileTextBox!.value, '', `Project file textbox should not be populated, but instead was "${dialog.projectFileTextBox!.value}".`);
|
should.equal(dialog.projectFileDropdown!.value, '', `Project file dropdown should not be populated, but instead was "${dialog.projectFileDropdown!.value}".`);
|
||||||
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should populate endpoints correctly when Project context is passed', async function (): Promise<void> {
|
it('Should populate endpoints correctly when Project context is passed', async function (): Promise<void> {
|
||||||
const project = await testUtils.createTestProject(baselines.openProjectFileBaseline);
|
const project = await testUtils.createTestProject(baselines.openProjectFileBaseline);
|
||||||
const dialog = new UpdateProjectFromDatabaseDialog(undefined, project);
|
const dialog = new UpdateProjectFromDatabaseDialog(undefined, project, mockURIList);
|
||||||
await dialog.openDialog();
|
await dialog.openDialog();
|
||||||
|
|
||||||
should.equal(dialog.serverDropdown!.value, undefined, `Server dropdown should not be populated, but instead was "${dialog.serverDropdown!.value}".`);
|
should.equal(dialog.serverDropdown!.value, undefined, `Server dropdown should not be populated, but instead was "${dialog.serverDropdown!.value}".`);
|
||||||
should.equal(dialog.databaseDropdown!.value, undefined, `Database dropdown should not be populated, but instead was "${dialog.databaseDropdown!.value}".`);
|
should.equal(dialog.databaseDropdown!.value, undefined, `Database dropdown should not be populated, but instead was "${dialog.databaseDropdown!.value}".`);
|
||||||
should.equal(dialog.projectFileTextBox!.value, project.projectFilePath, `Project file textbox should be the sqlproj path (${project.projectFilePath}), but instead was "${dialog.projectFileTextBox!.value}".`);
|
should.equal(dialog.projectFileDropdown!.value, project.projectFilePath, `Project file dropdown should be the sqlproj path (${project.projectFilePath}), but instead was "${dialog.projectFileDropdown!.value}".`);
|
||||||
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -51,13 +51,13 @@ describe('Update Project From Database Dialog', () => {
|
|||||||
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
||||||
|
|
||||||
const profile = mockConnectionProfile;
|
const profile = mockConnectionProfile;
|
||||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, undefined);
|
const dialog = new UpdateProjectFromDatabaseDialog(profile, undefined, []);
|
||||||
await dialog.openDialog();
|
await dialog.openDialog();
|
||||||
await dialog.populatedInputsPromise;
|
await dialog.populatedInputsPromise;
|
||||||
|
|
||||||
should.equal((<any>dialog.serverDropdown!.value).displayName, profile.options['connectionName'], `Server dropdown should be "${profile.options['connectionName']}", but instead was "${(<any>dialog.serverDropdown!.value).displayName}".`);
|
should.equal((<any>dialog.serverDropdown!.value).displayName, profile.options['connectionName'], `Server dropdown should be "${profile.options['connectionName']}", but instead was "${(<any>dialog.serverDropdown!.value).displayName}".`);
|
||||||
should.equal(dialog.databaseDropdown!.value, profile.databaseName, `Database dropdown should be "${profile.databaseName}", but instead was "${dialog.databaseDropdown!.value}".`);
|
should.equal(dialog.databaseDropdown!.value, profile.databaseName, `Database dropdown should be "${profile.databaseName}", but instead was "${dialog.databaseDropdown!.value}".`);
|
||||||
should.equal(dialog.projectFileTextBox!.value, '', `Project file textbox should not be populated, but instead was "${dialog.projectFileTextBox!.value}".`);
|
should.equal(dialog.projectFileDropdown!.value, '', `Project file dropdown should not be populated, but instead was "${dialog.projectFileDropdown!.value}".`);
|
||||||
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
should.equal(dialog.dialog.okButton.enabled, false, 'Okay button should be disabled.');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,13 +67,19 @@ describe('Update Project From Database Dialog', () => {
|
|||||||
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
||||||
|
|
||||||
const profile = mockConnectionProfile;
|
const profile = mockConnectionProfile;
|
||||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, project);
|
const dialog = new UpdateProjectFromDatabaseDialog(profile, project, mockURIList);
|
||||||
await dialog.openDialog();
|
await dialog.openDialog();
|
||||||
await dialog.populatedInputsPromise;
|
await dialog.populatedInputsPromise;
|
||||||
|
|
||||||
|
let uriList: string[] = [];
|
||||||
|
mockURIList.forEach(projectUri => {
|
||||||
|
uriList.push(projectUri.fsPath as string);
|
||||||
|
});
|
||||||
|
|
||||||
should.equal((<any>dialog.serverDropdown!.value).displayName, profile.options['connectionName'], `Server dropdown should be "${profile.options['connectionName']}", but instead was "${(<any>dialog.serverDropdown!.value).displayName}".`);
|
should.equal((<any>dialog.serverDropdown!.value).displayName, profile.options['connectionName'], `Server dropdown should be "${profile.options['connectionName']}", but instead was "${(<any>dialog.serverDropdown!.value).displayName}".`);
|
||||||
should.equal(dialog.databaseDropdown!.value, profile.databaseName, `Database dropdown should as "${profile.databaseName}", but instead was "${dialog.databaseDropdown!.value}".`);
|
should.equal(dialog.databaseDropdown!.value, profile.databaseName, `Database dropdown should as "${profile.databaseName}", but instead was "${dialog.databaseDropdown!.value}".`);
|
||||||
should.equal(dialog.projectFileTextBox!.value, project.projectFilePath, `Project file textbox should be the sqlproj path (${project.projectFilePath}), but instead was "${dialog.projectFileTextBox!.value}".`);
|
should.equal(dialog.projectFileDropdown!.value, project.projectFilePath, `Project file dropdown should be the sqlproj path (${project.projectFilePath}), but instead was "${dialog.projectFileDropdown!.value}".`);
|
||||||
|
should.deepEqual(dialog.projectFileDropdown!.values, uriList, `Project file dropdown list should be the sqlproj path (${mockURIList}), but instead was "${dialog.projectFileDropdown!.values}".`);
|
||||||
should.equal(dialog.dialog.okButton.enabled, true, 'Okay button should be enabled when dialog is complete.');
|
should.equal(dialog.dialog.okButton.enabled, true, 'Okay button should be enabled when dialog is complete.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -127,3 +127,9 @@ export const mockConnectionProfile: azdata.IConnectionProfile = {
|
|||||||
connectionName: 'My Connection Name'
|
connectionName: 'My Connection Name'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockURIList: vscode.Uri[] = [
|
||||||
|
vscode.Uri.file('/test/folder/abc.sqlproj'),
|
||||||
|
vscode.Uri.file('/test/folder/folder1/abc1.sqlproj'),
|
||||||
|
vscode.Uri.file('/test/folder/folder2/abc2.sqlproj')
|
||||||
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user