diff --git a/extensions/azuremonitor/package.json b/extensions/azuremonitor/package.json index 8638e79032fa..130b160ce507 100644 --- a/extensions/azuremonitor/package.json +++ b/extensions/azuremonitor/package.json @@ -209,7 +209,7 @@ "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-azuremonitor ./syntaxes/azuremonitor.tmLanguage" }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "figures": "^2.0.0", "find-remove": "1.2.1", "@microsoft/ads-service-downloader": "^1.2.1", diff --git a/extensions/azuremonitor/yarn.lock b/extensions/azuremonitor/yarn.lock index cfd5ca1ee3b8..307f34fb864f 100644 --- a/extensions/azuremonitor/yarn.lock +++ b/extensions/azuremonitor/yarn.lock @@ -75,9 +75,9 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/extensions/datavirtualization/package.json b/extensions/datavirtualization/package.json index 522a8e7fbb43..438f68915208 100644 --- a/extensions/datavirtualization/package.json +++ b/extensions/datavirtualization/package.json @@ -107,7 +107,7 @@ "dependencies": { "@microsoft/ads-extension-telemetry": "^3.0.1", "@microsoft/ads-service-downloader": "^1.2.1", - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "vscode-nls": "^5.2.0" }, "devDependencies": { diff --git a/extensions/datavirtualization/yarn.lock b/extensions/datavirtualization/yarn.lock index 801c83ff7c04..1a214a018327 100644 --- a/extensions/datavirtualization/yarn.lock +++ b/extensions/datavirtualization/yarn.lock @@ -497,9 +497,9 @@ crypt@0.0.2: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/extensions/import/package.json b/extensions/import/package.json index 79c509e00d0c..771e11789142 100644 --- a/extensions/import/package.json +++ b/extensions/import/package.json @@ -77,7 +77,7 @@ } }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "htmlparser2": "^3.10.1", "@microsoft/ads-service-downloader": "^1.2.1", "@microsoft/ads-extension-telemetry": "^3.0.1", diff --git a/extensions/import/yarn.lock b/extensions/import/yarn.lock index 198c9a9829c0..6b1c6e2508c2 100644 --- a/extensions/import/yarn.lock +++ b/extensions/import/yarn.lock @@ -572,9 +572,9 @@ crypt@~0.0.1: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/extensions/kusto/package.json b/extensions/kusto/package.json index dd87942c74b6..4f5464071b66 100644 --- a/extensions/kusto/package.json +++ b/extensions/kusto/package.json @@ -427,7 +427,7 @@ } }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "figures": "^2.0.0", "find-remove": "1.2.1", "@microsoft/ads-service-downloader": "^1.2.1", diff --git a/extensions/kusto/yarn.lock b/extensions/kusto/yarn.lock index c3daa83c1682..b8de7bfddf92 100644 --- a/extensions/kusto/yarn.lock +++ b/extensions/kusto/yarn.lock @@ -124,9 +124,9 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index 6d022d2cb8cc..7d67a93b828a 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "4.9.1.2", + "version": "4.10.0.2", "downloadFileNames": { "Windows_86": "win-x86-net7.0.zip", "Windows_64": "win-x64-net7.0.zip", diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index 45575877344d..598376c044d9 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -1567,7 +1567,7 @@ "dependencies": { "@microsoft/ads-extension-telemetry": "^3.0.1", "@microsoft/ads-service-downloader": "^1.2.1", - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "find-remove": "1.2.1", "vscode-languageclient": "5.2.1", "vscode-nls": "^4.0.0" diff --git a/extensions/mssql/src/objectManagement/ui/attachDatabaseDialog.ts b/extensions/mssql/src/objectManagement/ui/attachDatabaseDialog.ts index 23d42714de00..ae6e3e4e03c0 100644 --- a/extensions/mssql/src/objectManagement/ui/attachDatabaseDialog.ts +++ b/extensions/mssql/src/objectManagement/ui/attachDatabaseDialog.ts @@ -62,16 +62,20 @@ export class AttachDatabaseDialog extends ObjectManagementDialogBase { - let selectedRow = this._databasesTable.selectedRows[0]; - let dbFile = this._databasesToAttach[selectedRow]; - dbFile.databaseName = newValue; + if (this._databasesTable.selectedRows?.length > 0) { + let selectedRow = this._databasesTable.selectedRows[0]; + let dbFile = this._databasesToAttach[selectedRow]; + dbFile.databaseName = newValue; + } }, {}); this._nameContainer = this.createLabelInputContainer(loc.AttachAsText, this._nameField); this._ownerDropdown = this.createDropdown(loc.OwnerText, async newValue => { - let selectedRow = this._databasesTable.selectedRows[0]; - let dbFile = this._databasesToAttach[selectedRow]; - dbFile.owner = newValue; + if (this._databasesTable.selectedRows?.length > 0) { + let selectedRow = this._databasesTable.selectedRows[0]; + let dbFile = this._databasesToAttach[selectedRow]; + dbFile.owner = newValue; + } }, this.viewInfo.loginNames.options, this.viewInfo.loginNames.options[this.viewInfo.loginNames.defaultValueIndex]); this._ownerContainer = this.createLabelInputContainer(loc.OwnerText, this._ownerDropdown); diff --git a/extensions/mssql/src/objectManagement/ui/databaseDialog.ts b/extensions/mssql/src/objectManagement/ui/databaseDialog.ts index bab11838c7a8..1eeb105ef300 100644 --- a/extensions/mssql/src/objectManagement/ui/databaseDialog.ts +++ b/extensions/mssql/src/objectManagement/ui/databaseDialog.ts @@ -738,8 +738,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase { private originalFileName: string; private isEditingFile: boolean; - constructor(private readonly options: NewDatabaseFileDialogOptions) { + constructor(private readonly options: NewDatabaseFileDialogOptions, private readonly objectManagementService: IObjectManagementService) { super(options.title, 'DatabaseFileDialog'); } @@ -296,23 +297,12 @@ export class DatabaseFileDialog extends DialogBase { * Creates a file browser and sets the path to the filePath */ private async createFileBrowser(): Promise { - let fileUris = await vscode.window.showOpenDialog( - { - canSelectFiles: false, - canSelectFolders: true, - canSelectMany: false, - defaultUri: vscode.Uri.file(this.options.databaseFile.path), - openLabel: localizedConstants.SelectText - } - ); - - if (!fileUris || fileUris.length === 0) { - return; + let dataFolder = await this.objectManagementService.getDataFolder(this.options.connectionUri); + let filePath = await azdata.window.openServerFileBrowserDialog(this.options.connectionUri, dataFolder, [{ label: localizedConstants.allFiles, filters: ['*'] }], true); + if (filePath?.length > 0) { + this.filePathTextBox.value = filePath; + this.result.path = filePath; } - - let fileUri = fileUris[0]; - this.filePathTextBox.value = fileUri.fsPath; - this.result.path = fileUri.fsPath; } /** @@ -332,7 +322,7 @@ export class DatabaseFileDialog extends DialogBase { if (selectedOption === localizedConstants.LogFiletype) { fileGroupDdOptions = [localizedConstants.FileGroupForLogTypeText]; fileGroupDdValue = localizedConstants.FileGroupForLogTypeText; - fileSizeInputMaxValue = fileSizeInputMaxValueInMbForLogType + fileSizeInputMaxValue = fileSizeInputMaxValueInMbForLogType; } // File Stream else if (selectedOption === localizedConstants.FilestreamFileType) { diff --git a/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts b/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts index c20d1077a718..9b7f9bca68f0 100644 --- a/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts +++ b/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts @@ -661,21 +661,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase { - const allFilesFilter = localizedConstants.allFiles; - let filter: any = {}; - filter[allFilesFilter] = '*'; - let uris = await vscode.window.showOpenDialog({ - filters: filter, - canSelectFiles: false, - canSelectMany: false, - canSelectFolders: true, - defaultUri: vscode.Uri.file(location), - openLabel: localizedConstants.labelSelectFolder - }); - if (uris && uris.length > 0) { - return uris[0].fsPath; - } - return undefined; + let dataFolder = await this.objectManagementService.getDataFolder(this.options.connectionUri); + return await azdata.window.openServerFileBrowserDialog(this.options.connectionUri, dataFolder, [{ label: localizedConstants.allFiles, filters: ['*'] }], true); } private initializeAdvancedSection(): void { diff --git a/extensions/mssql/yarn.lock b/extensions/mssql/yarn.lock index cd0919cb6379..2d4061c50554 100644 --- a/extensions/mssql/yarn.lock +++ b/extensions/mssql/yarn.lock @@ -511,9 +511,9 @@ crypt@~0.0.1: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/extensions/sql-migration/package.json b/extensions/sql-migration/package.json index 5d066ba4575e..555dbdad8aa3 100644 --- a/extensions/sql-migration/package.json +++ b/extensions/sql-migration/package.json @@ -162,7 +162,7 @@ ] }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8", "@microsoft/ads-service-downloader": "^1.2.1", "@microsoft/ads-extension-telemetry": "^3.0.1", "uuid": "^8.3.2", diff --git a/extensions/sql-migration/yarn.lock b/extensions/sql-migration/yarn.lock index 7ac8879c0b93..9054fab33124 100644 --- a/extensions/sql-migration/yarn.lock +++ b/extensions/sql-migration/yarn.lock @@ -62,9 +62,9 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7": - version "1.3.7" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8": + version "1.3.8" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d" dependencies: vscode-languageclient "5.2.1" diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index c42968dc129e..3e5553f6c396 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -2068,9 +2068,14 @@ declare module 'azdata' { * @param connectionUri The URI of the connection to the target server * @param targetPath The file path on the server machine to open by default in the dialog * @param fileFilters The filters used to limit which files are displayed in the file browser + * @param showFoldersOnly Optional argument to specify whether the browser should only show folders * @returns The path of the file chosen from the dialog, and undefined if the dialog is closed without selecting anything. */ - export function openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: FileFilters[]): Thenable; + export function openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: FileFilters[], showFoldersOnly?: boolean): Thenable; + } + + export interface FileBrowserProvider extends DataProvider { + openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Thenable; } export interface TableComponent { diff --git a/src/sql/workbench/api/browser/mainThreadDataProtocol.ts b/src/sql/workbench/api/browser/mainThreadDataProtocol.ts index db953a6e6702..c9e08a3d5329 100644 --- a/src/sql/workbench/api/browser/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/browser/mainThreadDataProtocol.ts @@ -338,8 +338,8 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData public $registerFileBrowserProvider(providerId: string, handle: number): Promise { const self = this; this._fileBrowserService.registerProvider(providerId, { - openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { - return self._proxy.$openFileBrowser(handle, ownerUri, expandPath, fileFilters, changeFilter); + openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Thenable { + return self._proxy.$openFileBrowser(handle, ownerUri, expandPath, fileFilters, changeFilter, showFoldersOnly); }, expandFolderNode(ownerUri: string, expandPath: string): Thenable { return self._proxy.$expandFolderNode(handle, ownerUri, expandPath); diff --git a/src/sql/workbench/api/browser/mainThreadWindow.ts b/src/sql/workbench/api/browser/mainThreadWindow.ts index d19c9a4fa357..07d6922bfa4f 100644 --- a/src/sql/workbench/api/browser/mainThreadWindow.ts +++ b/src/sql/workbench/api/browser/mainThreadWindow.ts @@ -20,13 +20,13 @@ export class MainThreadWindow extends Disposable implements MainThreadWindowShap super(); } - public async $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[]): Promise { + public async $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[], showFoldersOnly?: boolean): Promise { let completion = new Promise((resolve, reject) => { try { const handleOnClosed = (path: string | undefined) => { resolve(path); }; - this._fileBrowserDialogService.showDialog(connectionUri, targetPath, fileFilters, '', true, handleOnClosed); + this._fileBrowserDialogService.showDialog(connectionUri, targetPath, fileFilters, '', true, handleOnClosed, showFoldersOnly); } catch (error) { reject(error); } diff --git a/src/sql/workbench/api/common/extHostDataProtocol.ts b/src/sql/workbench/api/common/extHostDataProtocol.ts index 0e119c3686a1..78fd13944d8d 100644 --- a/src/sql/workbench/api/common/extHostDataProtocol.ts +++ b/src/sql/workbench/api/common/extHostDataProtocol.ts @@ -632,8 +632,8 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { /** * Open a file browser */ - public override $openFileBrowser(handle: number, ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { - return this._resolveProvider(handle).openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter); + public override $openFileBrowser(handle: number, ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Thenable { + return this._resolveProvider(handle).openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter, showFoldersOnly); } /** diff --git a/src/sql/workbench/api/common/extHostWindow.ts b/src/sql/workbench/api/common/extHostWindow.ts index 039639ccf1e2..dbffb9662434 100644 --- a/src/sql/workbench/api/common/extHostWindow.ts +++ b/src/sql/workbench/api/common/extHostWindow.ts @@ -17,7 +17,7 @@ export class ExtHostWindow implements ExtHostWindowShape { this._proxy = _mainContext.getProxy(SqlMainContext.MainThreadWindow); } - $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[]): Promise { - return this._proxy.$openServerFileBrowserDialog(connectionUri, targetPath, fileFilters); + $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[], showFoldersOnly?: boolean): Promise { + return this._proxy.$openServerFileBrowserDialog(connectionUri, targetPath, fileFilters, showFoldersOnly); } } diff --git a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts index e88ee30d44f9..3dacbb650d59 100644 --- a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts @@ -488,8 +488,8 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp openCustomErrorDialog(options: sqlExtHostTypes.IErrorDialogOptions): Thenable { return extHostModelViewDialog.openCustomErrorDialog(options); }, - openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[]): Thenable { - return extHostWindow.$openServerFileBrowserDialog(connectionUri, targetPath, fileFilters); + openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[], showFoldersOnly?: boolean): Thenable { + return extHostWindow.$openServerFileBrowserDialog(connectionUri, targetPath, fileFilters, showFoldersOnly); } }; diff --git a/src/sql/workbench/api/common/sqlExtHost.protocol.ts b/src/sql/workbench/api/common/sqlExtHost.protocol.ts index f9b07170c674..38cf4f15c5d4 100644 --- a/src/sql/workbench/api/common/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/common/sqlExtHost.protocol.ts @@ -355,7 +355,7 @@ export abstract class ExtHostDataProtocolShape { /** * Open a file browser */ - $openFileBrowser(handle: number, ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { throw ni(); } + $openFileBrowser(handle: number, ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Thenable { throw ni(); } /** @@ -833,7 +833,7 @@ export interface ExtHostWorkspaceShape { } export interface ExtHostWindowShape { - $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[]): Promise; + $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[], showFoldersOnly?: boolean): Promise; } export interface MainThreadWorkspaceShape { @@ -843,7 +843,7 @@ export interface MainThreadWorkspaceShape { } export interface MainThreadWindowShape { - $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[]): Promise; + $openServerFileBrowserDialog(connectionUri: string, targetPath: string, fileFilters: azdata.window.FileFilters[], showFoldersOnly?: boolean): Promise; } export interface MainThreadBackgroundTaskManagementShape extends IDisposable { diff --git a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialog.ts b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialog.ts index ac4cafeeb1c7..6a6b651ab627 100644 --- a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialog.ts +++ b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialog.ts @@ -38,6 +38,8 @@ export class FileBrowserDialog extends Modal { private _body: HTMLElement; private _filePathInputBox: InputBox; private _fileFilterSelectBox: SelectBox; + private _fileFilterRow: HTMLElement; + private _originalFilterDisplay: string; private _okButton: Button; private _onOk = new Emitter(); public onOk: Event = this._onOk.event; @@ -99,6 +101,8 @@ export class FileBrowserDialog extends Modal { this._fileFilterSelectBox.setAriaLabel(filterLabel); let filterBuilder = DialogHelper.appendRow(tableContainer, filterLabel, 'file-input-label', 'file-input-box'); DialogHelper.appendInputSelectBox(filterBuilder, this._fileFilterSelectBox); + this._fileFilterRow = tableContainer.childNodes[1] as HTMLElement; + this._originalFilterDisplay = this._fileFilterRow.style.display; this._okButton = this.addFooterButton(localize('fileBrowser.ok', "OK"), () => this.ok()); this._okButton.enabled = false; @@ -112,10 +116,17 @@ export class FileBrowserDialog extends Modal { expandPath: string, fileFilters: [{ label: string, filters: string[] }], fileValidationServiceType: string, + showFoldersOnly?: boolean ): void { - this._viewModel.initialize(ownerUri, expandPath, fileFilters, fileValidationServiceType); + this._viewModel.initialize(ownerUri, expandPath, fileFilters, fileValidationServiceType, showFoldersOnly); this._viewModel.openFileBrowser(0, false).catch(err => onUnexpectedError(err)); - this._fileFilterSelectBox.setOptions(this._viewModel.formattedFileFilters, 0); + if (showFoldersOnly) { + this._fileFilterSelectBox.setOptions([]); + this._fileFilterRow.style.display = 'none'; + } else { + this._fileFilterSelectBox.setOptions(this._viewModel.formattedFileFilters, 0); + this._fileFilterRow.style.display = this._originalFilterDisplay; + } this._filePathInputBox.value = expandPath; this._isFolderSelected = true; this.enableOkButton(); @@ -129,7 +140,7 @@ export class FileBrowserDialog extends Modal { /* enter key */ protected override onAccept() { - if (this._okButton.enabled === true) { + if (this._okButton.enabled) { this.ok(); } } @@ -140,7 +151,7 @@ export class FileBrowserDialog extends Modal { } private enableOkButton() { - if (strings.isFalsyOrWhitespace(this._selectedFilePath) || this._isFolderSelected === true) { + if (strings.isFalsyOrWhitespace(this._selectedFilePath) || (this._isFolderSelected && !this._viewModel.showFoldersOnly)) { this._okButton.enabled = false; } else { this._okButton.enabled = true; @@ -215,9 +226,11 @@ export class FileBrowserDialog extends Modal { } private registerListeners(): void { - this._register(this._fileFilterSelectBox.onDidSelect(selectData => { - this.onFilterSelectChanged(selectData.index).catch(err => onUnexpectedError(err)); - })); + if (this._fileFilterSelectBox) { + this._register(this._fileFilterSelectBox.onDidSelect(selectData => { + this.onFilterSelectChanged(selectData.index).catch(err => onUnexpectedError(err)); + })); + } this._register(this._filePathInputBox.onDidChange(e => { this.onFilePathChange(e); })); diff --git a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts index a5ec17f2e65a..756311373b1e 100644 --- a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts +++ b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts @@ -25,7 +25,8 @@ export class FileBrowserDialogController implements IFileBrowserDialogController fileFilters: [{ label: string, filters: string[] }], fileValidationServiceType: string, isWide: boolean, - handleOnClosed: (path: string | undefined) => void + handleOnClosed: (path: string | undefined) => void, + showFoldersOnly?: boolean ): void { if (!this._fileBrowserDialog) { this._fileBrowserDialog = this._instantiationService.createInstance(FileBrowserDialog, localize('filebrowser.selectFile', "Select a file")); @@ -44,6 +45,6 @@ export class FileBrowserDialogController implements IFileBrowserDialogController this._fileBrowserDialog = undefined; }); - this._fileBrowserDialog.open(ownerUri, expandPath, fileFilters, fileValidationServiceType); + this._fileBrowserDialog.open(ownerUri, expandPath, fileFilters, fileValidationServiceType, showFoldersOnly); } } diff --git a/src/sql/workbench/services/fileBrowser/browser/media/fileBrowserDialog.css b/src/sql/workbench/services/fileBrowser/browser/media/fileBrowserDialog.css index 7ce4a05929de..176ce8bf2818 100644 --- a/src/sql/workbench/services/fileBrowser/browser/media/fileBrowserDialog.css +++ b/src/sql/workbench/services/fileBrowser/browser/media/fileBrowserDialog.css @@ -9,10 +9,12 @@ padding-left: 12px; padding-right: 12px; box-sizing: border-box; + display: flex; + flex-flow: column; } .file-browser-dialog .tree-view { - height: calc(100% - 90px); + flex: 1 1 auto; } .file-table-content { @@ -21,8 +23,8 @@ .file-browser-dialog .option-section { padding-top: 10px; - height: 90px; box-sizing: border-box; + flex: 0 1 auto; } .file-input-label { diff --git a/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts b/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts index 01d195fa9692..dfb0c742af7c 100644 --- a/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts +++ b/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts @@ -16,5 +16,6 @@ export interface IFileBrowserDialogController { fileFilters: { label: string, filters: string[] }[], fileValidationServiceType: string, isWide: boolean, - handleOnOk: (path: string | undefined) => void): void; + handleOnOk: (path: string | undefined) => void, + showFoldersOnly?: boolean): void; } diff --git a/src/sql/workbench/services/fileBrowser/common/fileBrowserService.ts b/src/sql/workbench/services/fileBrowser/common/fileBrowserService.ts index 421cd953a56b..38022fe12dd2 100644 --- a/src/sql/workbench/services/fileBrowser/common/fileBrowserService.ts +++ b/src/sql/workbench/services/fileBrowser/common/fileBrowserService.ts @@ -46,11 +46,11 @@ export class FileBrowserService implements IFileBrowserService { return this._onPathValidate.event; } - public openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Promise { + public openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Promise { return new Promise((resolve, reject) => { const provider = this.getProvider(ownerUri); if (provider) { - provider.openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter).then(result => { + provider.openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter, showFoldersOnly).then(result => { resolve(result); }, error => { reject(error); diff --git a/src/sql/workbench/services/fileBrowser/common/fileBrowserViewModel.ts b/src/sql/workbench/services/fileBrowser/common/fileBrowserViewModel.ts index be5173e4c088..d550bc08b200 100644 --- a/src/sql/workbench/services/fileBrowser/common/fileBrowserViewModel.ts +++ b/src/sql/workbench/services/fileBrowser/common/fileBrowserViewModel.ts @@ -15,6 +15,7 @@ export class FileBrowserViewModel { private _expandPath: string; private _fileFilters: [{ label: string, filters: string[] }]; private _fileValidationServiceType: string; + private _showFoldersOnly: boolean; public formattedFileFilters: string[]; constructor(@IFileBrowserService private _fileBrowserService: IFileBrowserService) { @@ -28,14 +29,20 @@ export class FileBrowserViewModel { this._fileBrowserService.onPathValidate(args => onPathValidateCallback(args)); } + public get showFoldersOnly(): boolean { + return this._showFoldersOnly; + } + public initialize(ownerUri: string, expandPath: string, fileFilters: [{ label: string, filters: string[] }], fileValidationServiceType: string, + showFoldersOnly?: boolean ) { this._ownerUri = ownerUri; this._expandPath = expandPath; this._fileValidationServiceType = fileValidationServiceType; + this._showFoldersOnly = !!showFoldersOnly; if (!fileFilters) { this._fileFilters = [{ label: localize('allFiles', "All files"), filters: ['*'] }]; @@ -55,7 +62,7 @@ export class FileBrowserViewModel { public async openFileBrowser(filterIndex: number, changeFilter: boolean): Promise { if (this._fileFilters[filterIndex]) { - await this._fileBrowserService.openFileBrowser(this._ownerUri, this._expandPath, this._fileFilters[filterIndex].filters, changeFilter); + await this._fileBrowserService.openFileBrowser(this._ownerUri, this._expandPath, this._fileFilters[filterIndex].filters, changeFilter, this._showFoldersOnly); } } diff --git a/src/sql/workbench/services/fileBrowser/common/interfaces.ts b/src/sql/workbench/services/fileBrowser/common/interfaces.ts index 010599f582d8..0c33920c5887 100644 --- a/src/sql/workbench/services/fileBrowser/common/interfaces.ts +++ b/src/sql/workbench/services/fileBrowser/common/interfaces.ts @@ -24,7 +24,7 @@ export interface IFileBrowserService { /** * Open file browser */ - openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Promise; + openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean, showFoldersOnly?: boolean): Promise; /** * Event called when file browser is opened