diff --git a/build/azure-pipelines/darwin/sql-product-build-darwin.yml b/build/azure-pipelines/darwin/sql-product-build-darwin.yml index b1d78cff33..19818050dc 100644 --- a/build/azure-pipelines/darwin/sql-product-build-darwin.yml +++ b/build/azure-pipelines/darwin/sql-product-build-darwin.yml @@ -92,11 +92,6 @@ steps: node build/azure-pipelines/mixin displayName: Mix in quality - - script: | - set -e - yarn gulp install-sqltoolsservice - displayName: Install sqltoolsservice - - script: | set -e yarn gulp package-rebuild-extensions diff --git a/build/azure-pipelines/docker/createDrop.sh b/build/azure-pipelines/docker/createDrop.sh new file mode 100755 index 0000000000..d03617a309 --- /dev/null +++ b/build/azure-pipelines/docker/createDrop.sh @@ -0,0 +1,13 @@ +set -e +REPO="$(pwd)" +ROOT="$REPO/.." + +PLATFORM_LINUX="linux-x64" +SERVER_BUILD_NAME="azuredatastudio-server-$PLATFORM_LINUX" + +# create docker +mkdir -p $REPO/.build/docker +docker build -t azuredatastudio-server -f $REPO/build/azure-pipelines/docker/Dockerfile $ROOT/$SERVER_BUILD_NAME +docker save azuredatastudio-server | gzip > $REPO/.build/docker/azuredatastudio-server-docker.tar.gz + +node build/azure-pipelines/common/copyArtifacts.js diff --git a/build/azure-pipelines/docker/sql-product-build-docker.yml b/build/azure-pipelines/docker/sql-product-build-docker.yml new file mode 100644 index 0000000000..ac06fa6bca --- /dev/null +++ b/build/azure-pipelines/docker/sql-product-build-docker.yml @@ -0,0 +1,96 @@ +steps: + - task: NodeTool@0 + inputs: + versionSpec: '10.15.1' + + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 + inputs: + versionSpec: "1.x" + + - task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'ClientToolsInfra_670062 (88d5392f-a34f-4769-b405-f597fc533613)' + KeyVaultName: ado-secrets + SecretsFilter: 'github-distro-mixin-password' + + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login azuredatastudio + password $(github-distro-mixin-password) + EOF + + git config user.email "andresse@microsoft.com" + git config user.name "AzureDataStudio" + displayName: Prepare tooling + + - script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules' + vstsFeed: 'BuildCache' + + - script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + env: + GITHUB_TOKEN: $(github-distro-mixin-password) + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules' + vstsFeed: 'BuildCache' + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + + - script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + targetPath: '$(Build.SourcesDirectory)/.build' + artifactName: drop + itemPattern: | + drop/linux/server/*.tar.gz + + - script: | + set -e + for f in $(Build.SourcesDirectory)/.build/linux/server/*.tar.gz + do + tar -C $(agent.builddirectory) -zxvf $f + rm $f + done + displayName: Unzip artifacts + + - script: | + set -e + ./build/azure-pipelines/docker/createDrop.sh + displayName: Create Drop + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: drop' + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + failOnAlert: true diff --git a/build/azure-pipelines/linux/createDrop.sh b/build/azure-pipelines/linux/createDrop.sh index f246cd8de3..c1b0a7c6ed 100755 --- a/build/azure-pipelines/linux/createDrop.sh +++ b/build/azure-pipelines/linux/createDrop.sh @@ -29,9 +29,4 @@ SERVER_TARBALL_PATH="$REPO/.build/linux/server/$SERVER_TARBALL_FILENAME" rm -rf $ROOT/azuredatastudio-server-*.tar.* (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) -# create docker -mkdir -p $REPO/.build/docker -docker build -t azuredatastudio-server -f $REPO/build/azure-pipelines/docker/Dockerfile $ROOT/$SERVER_BUILD_NAME -docker save azuredatastudio-server | gzip > $REPO/.build/docker/azuredatastudio-server-docker.tar.gz - node build/azure-pipelines/common/copyArtifacts.js diff --git a/build/azure-pipelines/linux/sql-product-build-linux.yml b/build/azure-pipelines/linux/sql-product-build-linux.yml index 8f4f96d39c..00a8425a64 100644 --- a/build/azure-pipelines/linux/sql-product-build-linux.yml +++ b/build/azure-pipelines/linux/sql-product-build-linux.yml @@ -85,12 +85,6 @@ steps: node build/azure-pipelines/mixin displayName: Mix in quality - - script: | - set -e - yarn gulp install-sqltoolsservice - yarn gulp install-ssmsmin - displayName: Install extension binaries - - script: | set -e yarn gulp vscode-linux-x64-min-ci diff --git a/build/azure-pipelines/sql-product-build.yml b/build/azure-pipelines/sql-product-build.yml index 93ccbdfbfb..4ace4f811f 100644 --- a/build/azure-pipelines/sql-product-build.yml +++ b/build/azure-pipelines/sql-product-build.yml @@ -37,6 +37,16 @@ jobs: - template: linux/sql-product-build-linux.yml timeoutInMinutes: 70 +- job: Docker + condition: eq(variables['VSCODE_BUILD_DOCKER'], 'true') + pool: + vmImage: 'Ubuntu-16.04' + container: linux-x64 + dependsOn: + - Linux + steps: + - template: docker/sql-product-build-docker.yml + - job: Windows condition: eq(variables['VSCODE_BUILD_WIN32'], 'true') pool: @@ -64,6 +74,7 @@ jobs: dependsOn: - macOS - Linux + - Docker - Windows - Windows_Test steps: diff --git a/build/azure-pipelines/win32/sql-product-build-win32.yml b/build/azure-pipelines/win32/sql-product-build-win32.yml index 7e9138e376..9f703d4cb0 100644 --- a/build/azure-pipelines/win32/sql-product-build-win32.yml +++ b/build/azure-pipelines/win32/sql-product-build-win32.yml @@ -90,12 +90,6 @@ steps: exec { node build/azure-pipelines/mixin } displayName: Mix in quality - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn gulp "install-sqltoolsservice" } - displayName: Install sqltoolsservice - - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index d86f486ad3..e3021c33d8 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -97,7 +97,7 @@ const indentationFilter = [ '!extensions/markdown-language-features/media/*.js', // {{SQL CARBON EDIT}} '!build/actions/**/dist/*', - '!**/*.{xlf,docx,sql,vsix,bacpac,ipynb}', + '!**/*.{xlf,docx,sql,vsix,bacpac,ipynb,jpg}', '!extensions/mssql/sqltoolsservice/**', '!extensions/import/flatfileimportservice/**', '!extensions/admin-tool-ext-win/ssmsmin/**', diff --git a/build/gulpfile.sql.js b/build/gulpfile.sql.js index 8d30fa3f6e..b73d0949d3 100644 --- a/build/gulpfile.sql.js +++ b/build/gulpfile.sql.js @@ -5,20 +5,15 @@ 'use strict'; const gulp = require('gulp'); -const util = require('./lib/util'); const tsfmt = require('typescript-formatter'); const es = require('event-stream'); const filter = require('gulp-filter'); -const serviceDownloader = require('service-downloader').ServiceDownloadProvider; -const platform = require('service-downloader/out/platform').PlatformInformation; const path = require('path'); const ext = require('./lib/extensions'); const task = require('./lib/task'); const glob = require('glob'); const vsce = require('vsce'); const mkdirp = require('mkdirp'); -const fs = require('fs').promises; -const assert = require('assert'); gulp.task('fmt', () => formatStagedFiles()); const formatFiles = (some) => { @@ -94,40 +89,6 @@ const formatStagedFiles = () => { }); }; -async function installService(configPath, runtimId) { - const absoluteConfigPath = require.resolve(configPath); - const config = require(absoluteConfigPath); - const runtime = runtimId || (await platform.getCurrent()).runtimeId; - // fix path since it won't be correct - config.installDirectory = path.join(path.dirname(absoluteConfigPath), config.installDirectory); - console.log('install diectory', config.installDirectory); - let installer = new serviceDownloader(config); - installer.eventEmitter.onAny((event, ...values) => { - console.log(`ServiceDownloader Event : ${event}${values && values.length > 0 ? ` - ${values.join(' ')}` : ''}`); - }); - let serviceInstallFolder = installer.getInstallDirectory(runtime); - console.log('Cleaning up the install folder: ' + serviceInstallFolder); - try { - await util.rimraf(serviceInstallFolder)(); - } catch (e) { - console.error('failed to delete the install folder error: ' + e); - throw e; - } - await installer.installService(runtime); - let stat; - for (const file of config.executableFiles) { - try { - stat = await fs.stat(path.join(serviceInstallFolder, file)); - } catch (e) { } - } - - assert(stat); -} - -gulp.task('install-sqltoolsservice', () => installService('../extensions/mssql/config.json')); - -gulp.task('install-ssmsmin', () => installService('../extensions/admin-tool-ext-win/config.json', 'Windows_64')); // admin-tool-ext is a windows only extension, and we only ship a 64 bit version, so locking the binaries as such - const root = path.dirname(__dirname); gulp.task('package-external-extensions', task.series( diff --git a/build/package.json b/build/package.json index 49c78e63e4..917d7fe5a8 100644 --- a/build/package.json +++ b/build/package.json @@ -47,7 +47,6 @@ "rollup": "^1.20.3", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", - "service-downloader": "0.2.1", "terser": "4.3.8", "typescript": "^3.9.0-dev.20200327", "vsce": "1.48.0", diff --git a/build/yarn.lock b/build/yarn.lock index ba4022b2f4..8ae54996d8 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -420,20 +420,6 @@ acorn@^7.0.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -agent-base@4: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== - dependencies: - es6-promisify "^5.0.0" - -agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -596,13 +582,6 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735" integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== -async-retry@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.2.3.tgz#a6521f338358d322b1a0012b79030c6f411d1ce0" - integrity sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q== - dependencies: - retry "0.12.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -834,11 +813,6 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== -chownr@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -1036,20 +1010,6 @@ debug@2.X, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -1215,18 +1175,6 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== -es6-promise@^4.0.3: - version "4.2.6" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" - integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - escape-string-regexp@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1262,11 +1210,6 @@ estree-walker@^0.6.1: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== -eventemitter2@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452" - integrity sha1-YZegldX7a1folC9v1+qtY6CclFI= - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -1457,13 +1400,6 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.2.1" -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1805,14 +1741,6 @@ htmlparser2@^3.9.1: inherits "^2.0.1" readable-stream "^3.0.6" -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-signature@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" @@ -1831,14 +1759,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" @@ -2468,13 +2388,6 @@ minipass@^2.2.1, minipass@^2.3.4: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" - integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== - dependencies: - yallist "^4.0.0" - minizlib@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" @@ -2482,14 +2395,6 @@ minizlib@^1.1.1: dependencies: minipass "^2.2.1" -minizlib@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.0.tgz#fd52c645301ef09a63a2c209697c294c6ce02cf3" - integrity sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -2505,11 +2410,6 @@ mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "0.0.8" -mkdirp@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" - integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2738,7 +2638,7 @@ os-name@^3.1.0: macos-release "^2.2.0" windows-release "^3.1.0" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -3047,11 +2947,6 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - reusify@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -3169,20 +3064,6 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -service-downloader@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/service-downloader/-/service-downloader-0.2.1.tgz#8bd756bc4bc0cbfdf04fe71d4337f19ce6196203" - integrity sha512-5IEy2nyMJj/f41pI65b8RMeJyCecGNrMmNCpUW8hckZ9cBMyX+VCp8GjYoM6Mz/X0XSaGVz7V5gtCWjfeJI7gA== - dependencies: - async-retry "^1.2.3" - eventemitter2 "^5.0.1" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.3" - mkdirp "^0.5.1" - tar "^6.0.1" - tmp "^0.0.33" - yauzl "^2.10.0" - set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -3436,18 +3317,6 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -tar@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.1.tgz#7b3bd6c313cb6e0153770108f8d70ac298607efa" - integrity sha512-bKhKrrz2FJJj5s7wynxy/fyxpE0CmCjmOQ1KV4KkgXFWOgoIT/NbTMnB1n+LFNrNk0SSBVGGxcK5AGsyC+pW5Q== - dependencies: - chownr "^1.1.3" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.0" - mkdirp "^1.0.3" - yallist "^4.0.0" - terser@*: version "4.2.1" resolved "https://registry.yarnpkg.com/terser/-/terser-4.2.1.tgz#1052cfe17576c66e7bc70fcc7119f22b155bdac1" @@ -3486,13 +3355,6 @@ tmp@0.0.29: dependencies: os-tmpdir "~1.0.1" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -3853,12 +3715,7 @@ yallist@^3.0.0, yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yauzl@^2.10.0, yauzl@^2.3.1: +yauzl@^2.3.1: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= diff --git a/docs/UX-Design-Guidelines.md b/docs/UX-Design-Guidelines.md new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/docs/UX-Design-Guidelines.md @@ -0,0 +1 @@ + diff --git a/docs/overview_screen.jpg b/docs/overview_screen.jpg new file mode 100644 index 0000000000..4da5a1f81b Binary files /dev/null and b/docs/overview_screen.jpg differ diff --git a/extensions/admin-tool-ext-win/.vscodeignore b/extensions/admin-tool-ext-win/.vscodeignore index ebcf4d2a29..e5a5f0a51c 100644 --- a/extensions/admin-tool-ext-win/.vscodeignore +++ b/extensions/admin-tool-ext-win/.vscodeignore @@ -4,6 +4,5 @@ src .gitignore coverConfig.json tsconfig.json -InstallSsmsMin.bat cgmanifest.json .vscode diff --git a/extensions/admin-tool-ext-win/InstallSsmsMin.bat b/extensions/admin-tool-ext-win/InstallSsmsMin.bat deleted file mode 100644 index 49e6dbf88a..0000000000 --- a/extensions/admin-tool-ext-win/InstallSsmsMin.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off - -REM Run this command to install SsmsMin for local development testing -gulp install-ssmsmin \ No newline at end of file diff --git a/extensions/admin-tool-ext-win/build/postinstall.js b/extensions/admin-tool-ext-win/build/postinstall.js new file mode 100644 index 0000000000..c6e7313868 --- /dev/null +++ b/extensions/admin-tool-ext-win/build/postinstall.js @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +(async () => { + const serviceDownloader = require('service-downloader').ServiceDownloadProvider; + const path = require('path'); + const fs = require('fs').promises; + const rimraf = require('rimraf'); + const assert = require('assert'); + const readline = require('readline'); + + async function installService(configPath) { + const absoluteConfigPath = require.resolve('../config.json'); + const config = require(absoluteConfigPath); + const runtime = 'Windows_64'; + // fix path since it won't be correct + config.installDirectory = path.join(path.dirname(absoluteConfigPath), config.installDirectory); + let installer = new serviceDownloader(config); + installer.eventEmitter.onAny((event, ...values) => { + readline.cursorTo(process.stdout, 0); + readline.clearLine(process.stdout, 0); + process.stdout.write(`${event}${values && values.length > 0 ? ` - ${values.join(' ')}` : ''}`); + }); + let serviceInstallFolder = installer.getInstallDirectory(runtime); + await new Promise((rs, rj) => rimraf(serviceInstallFolder, (e) => e ? rj(e) : rs())); + await installer.installService(runtime); + let stat; + for (const file of config.executableFiles) { + try { + stat = await fs.stat(path.join(serviceInstallFolder, file)); + } catch (e) { } + } + + assert(stat); + } + + await installService(); +})().catch(e => { + console.error(e); + process.exit(1); +}); diff --git a/extensions/admin-tool-ext-win/package.json b/extensions/admin-tool-ext-win/package.json index 948c3f5563..2b03d2d98b 100644 --- a/extensions/admin-tool-ext-win/package.json +++ b/extensions/admin-tool-ext-win/package.json @@ -12,6 +12,9 @@ "vscode": "^1.30.1", "azdata": ">=1.8.0" }, + "scripts": { + "postinstall": "node ./build/postinstall.js" + }, "activationEvents": [ "onCommand:adminToolExtWin.launchSsmsMinPropertiesDialog", "onCommand:adminToolExtWin.launchSsmsMinGswDialog" @@ -72,6 +75,7 @@ }, "dependencies": { "ads-extension-telemetry": "github:Charles-Gagnon/ads-extension-telemetry#0.1.0", + "service-downloader": "0.2.1", "vscode-nls": "^3.2.1" }, "devDependencies": { diff --git a/extensions/admin-tool-ext-win/yarn.lock b/extensions/admin-tool-ext-win/yarn.lock index d0b0454b63..0e801d5f96 100644 --- a/extensions/admin-tool-ext-win/yarn.lock +++ b/extensions/admin-tool-ext-win/yarn.lock @@ -28,6 +28,13 @@ abbrev@1.0.x: dependencies: vscode-extension-telemetry "0.1.1" +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + amdefine@>=0.0.4, amdefine@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -96,6 +103,13 @@ array-slice@^0.2.3: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= +async-retry@^1.2.3: + version "1.3.1" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55" + integrity sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA== + dependencies: + retry "0.12.0" + async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -119,6 +133,11 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -134,6 +153,11 @@ charenc@~0.0.1: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= +chownr@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -209,6 +233,18 @@ diff@3.5.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-string-regexp@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -241,6 +277,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter2@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452" + integrity sha1-YZegldX7a1folC9v1+qtY6CclFI= + extend-shallow@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" @@ -253,6 +294,20 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -324,6 +379,22 @@ he@1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -419,11 +490,31 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= +minipass@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" + integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.0.tgz#fd52c645301ef09a63a2c209697c294c6ce02cf3" + integrity sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -431,6 +522,18 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +mkdirp@^0.5.1: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" + integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== + mocha-junit-reporter@^1.17.0: version "1.23.1" resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.1.tgz#ba11519c0b967f404e4123dd69bc4ba022ab0f12" @@ -516,11 +619,21 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + plugin-error@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" @@ -571,11 +684,30 @@ resolve@1.1.x: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= +retry@0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + semver@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +service-downloader@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/service-downloader/-/service-downloader-0.2.1.tgz#8bd756bc4bc0cbfdf04fe71d4337f19ce6196203" + integrity sha512-5IEy2nyMJj/f41pI65b8RMeJyCecGNrMmNCpUW8hckZ9cBMyX+VCp8GjYoM6Mz/X0XSaGVz7V5gtCWjfeJI7gA== + dependencies: + async-retry "^1.2.3" + eventemitter2 "^5.0.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + mkdirp "^0.5.1" + tar "^6.0.1" + tmp "^0.0.33" + yauzl "^2.10.0" + should-equal@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" @@ -671,6 +803,18 @@ supports-color@^3.1.0: dependencies: has-flag "^1.0.0" +tar@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.1.tgz#7b3bd6c313cb6e0153770108f8d70ac298607efa" + integrity sha512-bKhKrrz2FJJj5s7wynxy/fyxpE0CmCjmOQ1KV4KkgXFWOgoIT/NbTMnB1n+LFNrNk0SSBVGGxcK5AGsyC+pW5Q== + dependencies: + chownr "^1.1.3" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.0" + mkdirp "^1.0.3" + yallist "^4.0.0" + through2@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.1.tgz#384e75314d49f32de12eebb8136b8eb6b5d59da9" @@ -679,6 +823,13 @@ through2@2.0.1: readable-stream "~2.0.0" xtend "~4.0.0" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -759,6 +910,19 @@ xtend@~4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + zone.js@0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" diff --git a/extensions/agent/package.json b/extensions/agent/package.json index 2554be8171..1df9f53801 100644 --- a/extensions/agent/package.json +++ b/extensions/agent/package.json @@ -32,6 +32,7 @@ "description": "Manage and troubleshoot SQL Agent jobs", "provider": "MSSQL", "title": "SQL Agent", + "group": "administration", "when": "connectionProvider == 'MSSQL' && !mssql:iscloud && mssql:engineedition != 11 && dashboardContext == 'server'", "container": { "controlhost-container": { @@ -91,7 +92,7 @@ "vscodetestcover": "github:corivera/vscodetestcover#1.0.5" }, "resolutions": { - "esprima": "^4.0.0" + "esprima": "^4.0.0" }, "__metadata": { "id": "10", diff --git a/extensions/azurecore/src/account-provider/auths/azureAuth.ts b/extensions/azurecore/src/account-provider/auths/azureAuth.ts index 9039c01254..673b5aeb95 100644 --- a/extensions/azurecore/src/account-provider/auths/azureAuth.ts +++ b/extensions/azurecore/src/account-provider/auths/azureAuth.ts @@ -219,12 +219,14 @@ export abstract class AzureAuth implements vscode.Disposable { console.log('Base token was empty, account is stale.'); return undefined; } + try { await this.refreshAccessToken(account.key, baseToken.refreshToken, tenant, resource); } catch (ex) { - console.log(ex); - account.isStale = true; - return undefined; + console.log(`Could not refresh access token for ${JSON.stringify(tenant)} - silently removing the tenant from the user's account.`); + azureAccount.properties.tenants = azureAccount.properties.tenants.filter(t => t.id !== tenant.id); + console.log(ex, ex?.data, ex?.response); + continue; } cachedTokens = await this.getCachedToken(account.key, resource.id, tenant.id); @@ -243,9 +245,12 @@ export abstract class AzureAuth implements vscode.Disposable { if (azureAccount.properties.subscriptions) { azureAccount.properties.subscriptions.forEach(subscription => { - response[subscription.id] = { - ...response[subscription.tenantId] - }; + // Make sure that tenant has information populated. + if (response[subscription.tenantId]) { + response[subscription.id] = { + ...response[subscription.tenantId] + }; + } }); } diff --git a/extensions/azurecore/src/azureResource/services/terminalService.ts b/extensions/azurecore/src/azureResource/services/terminalService.ts index b7f6a7e91c..9553b7acb2 100644 --- a/extensions/azurecore/src/azureResource/services/terminalService.ts +++ b/extensions/azurecore/src/azureResource/services/terminalService.ts @@ -5,13 +5,42 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import axios, { AxiosRequestConfig } from 'axios'; +import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import * as WS from 'ws'; import { IAzureTerminalService } from '../interfaces'; import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../../account-provider/interfaces'; const localize = nls.loadMessageBundle(); + + +const handleNeverUsed = async (): Promise => { + const neverUsedString = localize('azure.coudTerminal.neverUsed', "If you have not launched Azure Cloud Shell from this account before, please visit https://shell.azure.com/ to get started. Once you are set up, you can use AzureCloud Shell directly in Azure Data Studio."); + enum TerminalOption { + OPEN_SITE, + OK + } + interface TerminalMessageItem extends vscode.MessageItem { + action: TerminalOption; + } + + const openAzureShellButton: TerminalMessageItem = { + action: TerminalOption.OPEN_SITE, + title: localize('azure.cloudTerminal.openAzureShell', "Open Azure Shell") + }; + + const okButton: TerminalMessageItem = { + action: TerminalOption.OK, + title: localize('azure.cloudTerminal.ok', "OK") + }; + + const option = await vscode.window.showInformationMessage(neverUsedString, openAzureShellButton, okButton); + + if (option.action === TerminalOption.OPEN_SITE) { + vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/AA83f8f')); + } +}; + export class AzureTerminalService implements IAzureTerminalService { private readonly apiVersion = '?api-version=2018-10-01'; @@ -31,9 +60,16 @@ export class AzureTerminalService implements IAzureTerminalService { }; const metadata = account.properties.providerSettings; - const userSettingsUri = this.getConsoleUserSettingsUri(metadata.settings.armResource.endpoint); - const userSettingsResult = await axios.get(userSettingsUri, settings); + + let userSettingsResult: AxiosResponse; + try { + userSettingsResult = await axios.get(userSettingsUri, settings); + } catch (ex) { + console.log(ex, ex.response); + await handleNeverUsed(); + return; + } const preferredShell = userSettingsResult.data?.properties?.preferredShellType ?? 'bash'; const preferredLocation = userSettingsResult.data?.properties?.preferredLocation; @@ -43,7 +79,14 @@ export class AzureTerminalService implements IAzureTerminalService { settings.headers['x-ms-console-preferred-location'] = preferredLocation; } - const provisionResult = await axios.put(consoleRequestUri, {}, settings); + let provisionResult: AxiosResponse; + try { + provisionResult = await axios.put(consoleRequestUri, {}, settings); + } catch (ex) { + console.log(ex, ex.response); + await handleNeverUsed(); + return; + } if (provisionResult.data?.properties?.provisioningState !== 'Succeeded') { throw new Error(provisionResult.data); @@ -114,7 +157,7 @@ class AzureTerminal implements vscode.Pseudoterminal { } async open(initialDimensions: vscode.TerminalDimensions): Promise { - return this.resetTerminalSize(initialDimensions); + this.setDimensions(initialDimensions); } close(): void { @@ -131,24 +174,22 @@ class AzureTerminal implements vscode.Pseudoterminal { } async setDimensions(dimensions: vscode.TerminalDimensions): Promise { - return this.resetTerminalSize(dimensions); + if (!dimensions) { + return; + } + this.terminalDimensions = dimensions; + return this.resetTerminalSize(); } - private async resetTerminalSize(dimensions: vscode.TerminalDimensions): Promise { + private async resetTerminalSize(): Promise { try { - - if (!this.terminalDimensions) { // first time - this.writeEmitter.fire(localize('azure.connectingShellTerminal', "Connecting terminal...\n")); - } - - if (dimensions) { - this.terminalDimensions = dimensions; - } - // Close the shell before this and restablish a new connection this.close(); const terminalUri = await this.establishTerminal(this.terminalDimensions); + if (!terminalUri) { + return; + } this.socket = new WS(terminalUri); this.socket.on('message', (data: WS.Data) => { @@ -172,13 +213,20 @@ class AzureTerminal implements vscode.Pseudoterminal { private async establishTerminal(dimensions: vscode.TerminalDimensions): Promise { - const terminalResult = await axios.post(`${this.consoleUri}/terminals?rows=${dimensions.rows}&cols=${dimensions.columns}&shell=${this.shell}`, undefined, { - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.token}` - } - }); + let terminalResult: AxiosResponse; + try { + terminalResult = await axios.post(`${this.consoleUri}/terminals?rows=${dimensions.rows}&cols=${dimensions.columns}&shell=${this.shell}`, undefined, { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.token}` + } + }); + } catch (ex) { + console.log(ex, ex.response); + await handleNeverUsed(); + return undefined; + } const terminalUri = terminalResult.data?.socketUri; diff --git a/extensions/mssql/build/postinstall.js b/extensions/mssql/build/postinstall.js new file mode 100644 index 0000000000..b88d2ec5a2 --- /dev/null +++ b/extensions/mssql/build/postinstall.js @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +(async () => { + const serviceDownloader = require('service-downloader').ServiceDownloadProvider; + const platform = require('service-downloader/out/platform').PlatformInformation; + const path = require('path'); + const fs = require('fs').promises; + const rimraf = require('rimraf'); + const assert = require('assert'); + const readline = require('readline'); + + async function installService() { + const absoluteConfigPath = require.resolve('../config.json'); + const config = require(absoluteConfigPath); + const runtime = (await platform.getCurrent()).runtimeId; + // fix path since it won't be correct + config.installDirectory = path.join(path.dirname(absoluteConfigPath), config.installDirectory); + let installer = new serviceDownloader(config); + installer.eventEmitter.onAny((event, ...values) => { + readline.cursorTo(process.stdout, 0); + readline.clearLine(process.stdout, 0); + process.stdout.write(`${event}${values && values.length > 0 ? ` - ${values.join(' ')}` : ''}`); + }); + let serviceInstallFolder = installer.getInstallDirectory(runtime); + await new Promise((rs, rj) => rimraf(serviceInstallFolder, (e) => e ? rj(e) : rs())); + await installer.installService(runtime); + let stat; + for (const file of config.executableFiles) { + try { + stat = await fs.stat(path.join(serviceInstallFolder, file)); + } catch (e) { } + } + + assert(stat); + } + + await installService(); +})().catch(e => { + console.error(e); + process.exit(1); +}); diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index b7eaec37c6..afdb9b7109 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "2.0.0-release.53", + "version": "2.0.0-release.56", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp2.2.zip", "Windows_64": "win-x64-netcoreapp2.2.zip", diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index 1dbef5f18b..8c5a707288 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -16,7 +16,8 @@ ], "scripts": { "compile": "gulp compile-extension:mssql-client", - "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json" + "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json", + "postinstall": "node ./build/postinstall.js" }, "contributes": { "commands": [ @@ -443,6 +444,7 @@ "description": "%tab.bigDataClusterDescription%", "provider": "MSSQL", "title": "%title.bigDataCluster%", + "group": "monitoring", "when": "connectionProvider == 'MSSQL' && mssql:iscluster && dashboardContext == 'server'", "container": { "grid-container": [ @@ -493,10 +495,7 @@ "title": "%mssql.tabs.databases%", "when": "dashboardContext == 'server'", "group": "home", - "icon": { - "light": "resources/light/database.svg", - "dark": "resources/dark/database_inverse.svg" - }, + "icon": "resources/database.svg", "container": { "widgets-container": [ { diff --git a/extensions/mssql/resources/dark/database_inverse.svg b/extensions/mssql/resources/dark/database_inverse.svg deleted file mode 100644 index 5fb31021fb..0000000000 --- a/extensions/mssql/resources/dark/database_inverse.svg +++ /dev/null @@ -1 +0,0 @@ -bv \ No newline at end of file diff --git a/extensions/mssql/resources/database.svg b/extensions/mssql/resources/database.svg new file mode 100644 index 0000000000..9200009c54 --- /dev/null +++ b/extensions/mssql/resources/database.svg @@ -0,0 +1,27 @@ + + + + +Icon-databases-130 + + + + + + + + + + + + + + diff --git a/extensions/mssql/resources/light/database.svg b/extensions/mssql/resources/light/database.svg deleted file mode 100644 index bc00d48e2b..0000000000 --- a/extensions/mssql/resources/light/database.svg +++ /dev/null @@ -1 +0,0 @@ -bv \ No newline at end of file diff --git a/package.json b/package.json index 094fc4e114..5dcd53ef0e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "azuredatastudio", "version": "1.17.0", - "distro": "b5ba37f6b0c11bd7c826d81dec82c379633e0e27", + "distro": "a7c650f63c6a601fb9431941301c78a7bce34ae3", "author": { "name": "Microsoft Corporation" }, diff --git a/product.json b/product.json index 7052477516..82b6f2ec33 100644 --- a/product.json +++ b/product.json @@ -68,7 +68,7 @@ "builtInExtensions": [ { "name": "Microsoft.sqlservernotebook", - "version": "0.3.5", + "version": "0.3.6", "repo": "https://github.com/Microsoft/azuredatastudio" } ] diff --git a/samples/sqlservices/src/controllers/modelViewDashboard.ts b/samples/sqlservices/src/controllers/modelViewDashboard.ts index 0b17bc1fe9..d57b93ab93 100644 --- a/samples/sqlservices/src/controllers/modelViewDashboard.ts +++ b/samples/sqlservices/src/controllers/modelViewDashboard.ts @@ -11,37 +11,33 @@ export async function openModelViewDashboard(context: vscode.ExtensionContext): dashboard.registerTabs(async (view: azdata.ModelView) => { // Tab with toolbar const button = view.modelBuilder.button().withProperties({ - label: 'Run', + label: 'Add databases tab', iconPath: { light: context.asAbsolutePath('images/compare.svg'), dark: context.asAbsolutePath('images/compare-inverse.svg') } }).component(); - button.onDidClick(() => { - vscode.window.showInformationMessage('Run button clicked'); - }); - const toolbar = view.modelBuilder.toolbarContainer().withItems([button]).withLayout({ orientation: azdata.Orientation.Horizontal }).component(); - const textComponent1 = view.modelBuilder.text().withProperties({ value: 'text 1' }).component(); + const input1 = view.modelBuilder.inputBox().withProperties({ value: 'input 1' }).component(); const homeTab: azdata.DashboardTab = { id: 'home', toolbar: toolbar, - content: textComponent1, + content: input1, title: 'Home', icon: context.asAbsolutePath('images/home.svg') // icon can be the path of a svg file }; // Tab with nested tabbed Panel - const textComponent2 = view.modelBuilder.text().withProperties({ value: 'text 2' }).component(); - const textComponent3 = view.modelBuilder.text().withProperties({ value: 'text 3' }).component(); - + const addTabButton = view.modelBuilder.button().withProperties({ label: 'Add a tab', width: '150px' }).component(); + const removeTabButton = view.modelBuilder.button().withProperties({ label: 'Remove a tab', width: '150px' }).component(); + const container = view.modelBuilder.flexContainer().withItems([addTabButton, removeTabButton]).withLayout({ flexFlow: 'column' }).component(); const nestedTab1 = { title: 'Tab1', - content: textComponent2, + content: container, id: 'tab1', icon: { light: context.asAbsolutePath('images/user.svg'), @@ -49,9 +45,10 @@ export async function openModelViewDashboard(context: vscode.ExtensionContext): } }; + const input2 = view.modelBuilder.inputBox().withProperties({ value: 'input 2' }).component(); const nestedTab2 = { title: 'Tab2', - content: textComponent3, + content: input2, icon: { light: context.asAbsolutePath('images/group.svg'), dark: context.asAbsolutePath('images/group_inverse.svg') @@ -59,6 +56,13 @@ export async function openModelViewDashboard(context: vscode.ExtensionContext): id: 'tab2' }; + const input3 = view.modelBuilder.inputBox().withProperties({ value: 'input 4' }).component(); + const nestedTab3 = { + title: 'Tab3', + content: input3, + id: 'tab3' + }; + const tabbedPanel = view.modelBuilder.tabbedPanel().withTabs([ nestedTab1, nestedTab2 ]).withLayout({ @@ -66,6 +70,15 @@ export async function openModelViewDashboard(context: vscode.ExtensionContext): showIcon: true }).component(); + + addTabButton.onDidClick(() => { + tabbedPanel.updateTabs([nestedTab1, nestedTab2, nestedTab3]); + }); + + removeTabButton.onDidClick(() => { + tabbedPanel.updateTabs([nestedTab1, nestedTab3]); + }); + const settingsTab: azdata.DashboardTab = { id: 'settings', content: tabbedPanel, @@ -81,10 +94,23 @@ export async function openModelViewDashboard(context: vscode.ExtensionContext): ] }; + // Databases tab + const databasesText = view.modelBuilder.inputBox().withProperties({ value: 'This is databases tab', width: '200px' }).component(); + const databasesTab: azdata.DashboardTab = { + id: 'databases', + content: databasesText, + title: 'Databases', + icon: context.asAbsolutePath('images/default.svg') + }; + button.onDidClick(() => { + dashboard.updateTabs([homeTab, databasesTab, securityTabGroup]); + }); + return [ homeTab, securityTabGroup ]; }); - dashboard.open(); + await dashboard.open(); } + diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index b8bc105470..dd41fa4bdf 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -210,6 +210,12 @@ declare module 'azdata' { * The event argument is the id of the selected tab. */ onTabChanged: vscode.Event; + + /** + * update the tabs. + * @param tabs new tabs + */ + updateTabs(tabs: (Tab | TabGroup)[]): void; } /** @@ -310,6 +316,7 @@ declare module 'azdata' { export interface ModelViewDashboard { registerTabs(handler: (view: ModelView) => Thenable<(DashboardTab | DashboardTabGroup)[]>): void; open(): Thenable; + updateTabs(tabs: (DashboardTab | DashboardTabGroup)[]): void; } export function createModelViewDashboard(title: string, options?: ModelViewDashboardOptions): ModelViewDashboard; diff --git a/src/sql/base/browser/ui/breadcrumb/breadcrumb.component.ts b/src/sql/base/browser/ui/breadcrumb/breadcrumb.component.ts index 43d002d202..ea2d8cb667 100644 --- a/src/sql/base/browser/ui/breadcrumb/breadcrumb.component.ts +++ b/src/sql/base/browser/ui/breadcrumb/breadcrumb.component.ts @@ -16,7 +16,7 @@ import { subscriptionToDisposable } from 'sql/base/browser/lifecycle'; @Component({ selector: 'breadcrumb', template: ` - + diff --git a/src/sql/base/browser/ui/breadcrumb/media/breadcrumb.css b/src/sql/base/browser/ui/breadcrumb/media/breadcrumb.css index 26ebc9deb8..d2608a912d 100644 --- a/src/sql/base/browser/ui/breadcrumb/media/breadcrumb.css +++ b/src/sql/base/browser/ui/breadcrumb/media/breadcrumb.css @@ -30,3 +30,11 @@ breadcrumb .chevron-right.codicon { breadcrumb .router-link { cursor: pointer; } + +breadcrumb .breadcrumb-container { + display: flex; + flex-flow: row; + align-items: center; + margin: 10px; + margin-left: 19px +} diff --git a/src/sql/base/browser/ui/panel/media/panel.css b/src/sql/base/browser/ui/panel/media/panel.css index fe2215f198..209513521a 100644 --- a/src/sql/base/browser/ui/panel/media/panel.css +++ b/src/sql/base/browser/ui/panel/media/panel.css @@ -58,7 +58,7 @@ panel { } .tabbedPanel.vertical .tabList .tab .tabLabel { - font-size: 12px; + font-size: 13px; padding-bottom: 0px; font-weight: normal; } @@ -76,10 +76,16 @@ panel { min-width: 65px; } +.tabbedPanel.horizontal > .title .tabList .tab-header { + margin: 5px; +} + .tabbedPanel.vertical > .title .tabList .tab-header { display: block; min-width: 150px; line-height: 35px; + padding-left: 24px; + padding-right: 24px; } .tabbedPanel .tabList .tab .tabIcon.codicon { @@ -152,13 +158,12 @@ panel { } .tabbedPanel .tab-group-header { - font-weight: bold; - margin: 15px 5px 3px 5px; + font-weight: 600; + font-size: 14px; + margin: 10px 24px 5px 24px; line-height: 35px; - height: 35px; border-style: solid; border-width: 0 0 1px 0; - border-color: rgb(214, 214, 214); } .tabbedPanel .vertical-tab-action-container { diff --git a/src/sql/base/browser/ui/panel/panel.component.ts b/src/sql/base/browser/ui/panel/panel.component.ts index 2510014791..cd35561468 100644 --- a/src/sql/base/browser/ui/panel/panel.component.ts +++ b/src/sql/base/browser/ui/panel/panel.component.ts @@ -23,6 +23,9 @@ import * as nls from 'vs/nls'; import { TabHeaderComponent } from 'sql/base/browser/ui/panel/tabHeader.component'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { IThemable } from 'vs/base/common/styler'; +import { ITabbedPanelStyles } from 'sql/base/browser/ui/panel/panel'; +import { createStyleSheet } from 'vs/base/browser/dom'; export interface IPanelOptions { /** @@ -49,7 +52,7 @@ let idPool = 0; @Component({ selector: 'panel', template: ` -
+
@@ -81,7 +84,7 @@ let idPool = 0;
` }) -export class PanelComponent extends Disposable { +export class PanelComponent extends Disposable implements IThemable { @Input() public options?: IPanelOptions; @Input() public actions?: Array; @ContentChildren(TabComponent) private readonly _tabs!: QueryList; @@ -95,12 +98,15 @@ export class PanelComponent extends Disposable { private _actionbar?: ActionBar; private _mru: TabComponent[] = []; private _tabExpanded: boolean = true; + private _styleElement: HTMLStyleElement; protected AutoScrollbarVisibility = ScrollbarVisibility.Auto; // used by angular template protected HiddenScrollbarVisibility = ScrollbarVisibility.Hidden; // used by angular template protected NavigationBarLayout = NavigationBarLayout; // used by angular template @ViewChild('panelActionbar', { read: ElementRef }) private _actionbarRef!: ElementRef; + @ViewChild('rootContainer', { read: ElementRef }) private _rootContainer!: ElementRef; + constructor( @Inject(forwardRef(() => NgZone)) private _zone: NgZone, @Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef) { @@ -122,6 +128,8 @@ export class PanelComponent extends Disposable { ngOnInit(): void { this.options = mixin(this.options || {}, defaultOptions, false); + const rootContainerElement = this._rootContainer.nativeElement as HTMLElement; + this._styleElement = createStyleSheet(rootContainerElement); } ngAfterContentInit(): void { @@ -321,4 +329,70 @@ export class PanelComponent extends Disposable { return header.nativeElement === document.activeElement; }); } + + style(styles: ITabbedPanelStyles) { + if (this._styleElement) { + const content: string[] = []; + if (styles.titleInactiveForeground) { + content.push(`.tabbedPanel.horizontal > .title .tabList .tab-header { + color: ${styles.titleInactiveForeground} + }`); + } + if (styles.titleActiveBorder && styles.titleActiveForeground) { + content.push(`.tabbedPanel.horizontal > .title .tabList .tab-header:focus, + .tabbedPanel.horizontal > .title .tabList .tab-header.active { + border-color: ${styles.titleActiveBorder}; + border-style: solid; + color: ${styles.titleActiveForeground} + }`); + + content.push(`.tabbedPanel.horizontal > .title .tabList .tab-header:focus, + .tabbedPanel.horizontal > .title .tabList .tab-header.active {; + border-width: 0 0 ${styles.activeTabContrastBorder ? '0' : '2'}px 0; + }`); + + content.push(`.tabbedPanel.horizontal > .title .tabList .tab-header:hover { + color: ${styles.titleActiveForeground} + }`); + } + + if (styles.activeBackgroundForVerticalLayout) { + content.push(`.tabbedPanel.vertical > .title .tabList .tab-header.active { + background-color:${styles.activeBackgroundForVerticalLayout} + }`); + } + + if (styles.border) { + content.push(`.tabbedPanel.vertical > .title > .tabContainer { + border-right-width: 1px; + border-right-style: solid; + border-right-color: ${styles.border}; + } + + .tabbedPanel .tab-group-header { + border-color: ${styles.border}; + }`); + } + + if (styles.activeTabContrastBorder) { + content.push(` + .tabbedPanel > .title .tabList .tab-header.active { + outline: 1px solid; + outline-offset: -3px; + outline-color: ${styles.activeTabContrastBorder}; + } + `); + } else { + content.push(`.tabbedPanel.horizontal > .title .tabList .tab-header:focus { + outline-width: 0px; + }`); + } + + const newStyles = content.join('\n'); + if (newStyles !== this._styleElement.innerHTML) { + this._styleElement.innerHTML = newStyles; + } + } + } + } diff --git a/src/sql/base/browser/ui/panel/panel.ts b/src/sql/base/browser/ui/panel/panel.ts index 85921f09d3..b9ba9a6ab4 100644 --- a/src/sql/base/browser/ui/panel/panel.ts +++ b/src/sql/base/browser/ui/panel/panel.ts @@ -23,6 +23,9 @@ export interface ITabbedPanelStyles { titleInactiveForeground?: Color; focusBorder?: Color; outline?: Color; + activeBackgroundForVerticalLayout?: Color; + border?: Color; + activeTabContrastBorder?: Color; } export interface IPanelOptions { diff --git a/src/sql/base/browser/ui/panel/tabHeader.component.ts b/src/sql/base/browser/ui/panel/tabHeader.component.ts index 5da411aac2..12aa962493 100644 --- a/src/sql/base/browser/ui/panel/tabHeader.component.ts +++ b/src/sql/base/browser/ui/panel/tabHeader.component.ts @@ -19,7 +19,7 @@ import { CloseTabAction } from 'sql/base/browser/ui/panel/tabActions'; @Component({ selector: 'tab-header', template: ` -