mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -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 { }
|
||||
|
||||
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);
|
||||
|
||||
@@ -1572,8 +1573,8 @@ export class ProjectsController {
|
||||
return updateProjectFromDatabaseDialog;
|
||||
}
|
||||
|
||||
public getUpdateProjectFromDatabaseDialog(connection: azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, project: Project | undefined): UpdateProjectFromDatabaseDialog {
|
||||
return new UpdateProjectFromDatabaseDialog(connection, project);
|
||||
public getUpdateProjectFromDatabaseDialog(connection: azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined, project: Project | undefined, workspaceProjects: vscode.Uri[]): UpdateProjectFromDatabaseDialog {
|
||||
return new UpdateProjectFromDatabaseDialog(connection, project, workspaceProjects);
|
||||
}
|
||||
|
||||
public async updateProjectFromDatabaseCallback(model: UpdateProjectDataModel) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
public dialog: azdata.window.Dialog;
|
||||
public serverDropdown: azdata.DropDownComponent | undefined;
|
||||
public databaseDropdown: azdata.DropDownComponent | undefined;
|
||||
public projectFileTextBox: azdata.InputBoxComponent | undefined;
|
||||
public projectFileDropdown: azdata.DropDownComponent | undefined;
|
||||
public compareActionRadioButton: azdata.RadioButtonComponent | undefined;
|
||||
private updateProjectFromDatabaseTab: azdata.window.DialogTab;
|
||||
private connectionButton: azdata.ButtonComponent | undefined;
|
||||
@@ -39,7 +39,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
|
||||
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) {
|
||||
this.profile = connection;
|
||||
}
|
||||
@@ -365,17 +365,23 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
private createProjectLocationRow(view: azdata.ModelView): azdata.FlexContainer {
|
||||
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,
|
||||
ariaLabel: constants.projectLocationLabel,
|
||||
placeHolder: constants.projectToUpdatePlaceholderText,
|
||||
values: values,
|
||||
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
||||
}).component();
|
||||
|
||||
this.projectFileTextBox.onTextChanged(async () => {
|
||||
await this.projectFileTextBox!.updateProperty('title', this.projectFileTextBox!.value);
|
||||
this.projectFileDropdown.onValueChanged(async () => {
|
||||
await this.projectFileDropdown!.updateProperty('title', this.projectFileDropdown!.value);
|
||||
this.tryEnableUpdateButton();
|
||||
});
|
||||
|
||||
@@ -386,7 +392,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
}).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' } });
|
||||
|
||||
return projectLocationRow;
|
||||
@@ -416,8 +422,8 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
return;
|
||||
}
|
||||
|
||||
this.projectFileTextBox!.value = fileUris[0].fsPath;
|
||||
await this.projectFileTextBox!.updateProperty('title', fileUris[0].fsPath);
|
||||
this.projectFileDropdown!.value = fileUris[0].fsPath;
|
||||
await this.projectFileDropdown!.updateProperty('title', fileUris[0].fsPath);
|
||||
});
|
||||
|
||||
return browseFolderButton;
|
||||
@@ -426,7 +432,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
private createFolderStructureRow(view: azdata.ModelView): azdata.FlexContainer {
|
||||
this.folderStructureDropDown = view.modelBuilder.dropDown().withProps({
|
||||
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,
|
||||
required: true,
|
||||
width: cssStyles.updateProjectFromDatabaseTextboxWidth
|
||||
@@ -493,7 +499,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
public tryEnableUpdateButton(): void {
|
||||
if (this.serverDropdown?.value
|
||||
&& this.databaseDropdown?.value
|
||||
&& this.projectFileTextBox?.value
|
||||
&& this.projectFileDropdown?.value
|
||||
&& this.folderStructureDropDown?.value
|
||||
&& this.action !== undefined) {
|
||||
this.dialog.okButton.enabled = true;
|
||||
@@ -547,7 +553,7 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
|
||||
const targetEndpointInfo: mssql.SchemaCompareEndpointInfo = {
|
||||
endpointType: mssql.SchemaCompareEndpointType.Project,
|
||||
projectFilePath: this.projectFileTextBox!.value!,
|
||||
projectFilePath: this.projectFileDropdown!.value! as string,
|
||||
folderStructure: mapExtractTargetEnum(<string>this.folderStructureDropDown!.value),
|
||||
targetScripts: [],
|
||||
dataSchemaProvider: '',
|
||||
@@ -575,14 +581,14 @@ export class UpdateProjectFromDatabaseDialog {
|
||||
return false;
|
||||
}
|
||||
// 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) {
|
||||
this.showErrorMessage(constants.ProjectParentDirectoryNotExistError(this.projectFileTextBox!.value!));
|
||||
this.showErrorMessage(constants.ProjectParentDirectoryNotExistError(this.projectFileDropdown!.value! as string));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
this.showErrorMessage(constants.noSqlProjFile);
|
||||
return false;
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as baselines from '../baselines/baselines';
|
||||
import * as testUtils from '../testUtils';
|
||||
|
||||
import { UpdateProjectFromDatabaseDialog } from '../../dialogs/updateProjectFromDatabaseDialog';
|
||||
import { mockConnectionProfile } from '../testContext';
|
||||
import { mockConnectionProfile, mockURIList } from '../testContext';
|
||||
|
||||
describe('Update Project From Database Dialog', () => {
|
||||
before(async function (): Promise<void> {
|
||||
@@ -21,28 +21,28 @@ describe('Update Project From Database Dialog', () => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
after(async function(): Promise<void> {
|
||||
after(async function (): Promise<void> {
|
||||
await testUtils.deleteGeneratedTestFolder();
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
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.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.');
|
||||
});
|
||||
|
||||
it('Should populate endpoints correctly when Project context is passed', async function (): Promise<void> {
|
||||
const project = await testUtils.createTestProject(baselines.openProjectFileBaseline);
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(undefined, project);
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(undefined, project, mockURIList);
|
||||
await dialog.openDialog();
|
||||
|
||||
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.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.');
|
||||
});
|
||||
|
||||
@@ -51,13 +51,13 @@ describe('Update Project From Database Dialog', () => {
|
||||
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
||||
|
||||
const profile = mockConnectionProfile;
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, undefined);
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, undefined, []);
|
||||
await dialog.openDialog();
|
||||
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(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.');
|
||||
});
|
||||
|
||||
@@ -67,13 +67,19 @@ describe('Update Project From Database Dialog', () => {
|
||||
sinon.stub(azdata.connection, 'listDatabases').resolves([mockConnectionProfile.databaseName!]);
|
||||
|
||||
const profile = mockConnectionProfile;
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, project);
|
||||
const dialog = new UpdateProjectFromDatabaseDialog(profile, project, mockURIList);
|
||||
await dialog.openDialog();
|
||||
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(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.');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,3 +127,9 @@ export const mockConnectionProfile: azdata.IConnectionProfile = {
|
||||
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