diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e1bd558d7..7cc9ca5750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Change Log +## Version 1.2.4 +* Release date: November 6, 2018 +* Release status: General Availability + +## What's new in this version +* Update to the SQL Server 2019 Preview extension +* Introducing Paste the Plan extension +* Introducing High Color queries extension, including SSMS editor theme +* Fixes in SQL Server Agent, Profiler, and Import extensions +* Fix .Net Core Socket KeepAlive issue causing dropped inactive connections on macOS +* Upgrade SQL Tools Service to .Net Core 2.2 Preview 3 (for eventual AAD support) +* Fix customer reported GitHub issues + +## Contributions and "thank you" +We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes: + +* rdaniels6813 for `Add query plan theme support #3031` +* Ruturaj123 for `Fixed some typos and grammatical errors #3027` +* PromoFaux for `Use emoji shortcodes in CONTRIBUTING.md instead of � #3009` +* ckaczor for `Fix: DATETIMEOFFSET data types should be ISO formatted #714` +* hi-im-T0dd for `Fixed sync issue with my forked master so this commit is correct #2948` +* hi-im-T0dd for `Fixed when right clicking and selecting Manage-correct name displays #2794` + ## Version 1.1.3 * Release date: October 18, 2018 * Release status: General Availability diff --git a/README.md b/README.md index 6e10bc4b3d..43a33396d1 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Azure Data Studio is a data management tool that enables you to work with SQL Se Platform | Link -- | -- -Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2030731 -Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2030736 -macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2030738 -Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2030741 -Linux RPM | https://go.microsoft.com/fwlink/?linkid=2030746 -Linux DEB | https://go.microsoft.com/fwlink/?linkid=2030750 +Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2038320 +Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2038323 +macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2038327 +Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2038332 +Linux RPM | https://go.microsoft.com/fwlink/?linkid=2038401 +Linux DEB | https://go.microsoft.com/fwlink/?linkid=2038405 Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions. @@ -61,6 +61,12 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro ## Contributions and "Thank You" We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes: +* rdaniels6813 for `Add query plan theme support #3031` +* Ruturaj123 for `Fixed some typos and grammatical errors #3027` +* PromoFaux for `Use emoji shortcodes in CONTRIBUTING.md instead of � #3009` +* ckaczor for `Fix: DATETIMEOFFSET data types should be ISO formatted #714` +* hi-im-T0dd for `Fixed sync issue with my forked master so this commit is correct #2948` +* hi-im-T0dd for `Fixed when right clicking and selecting Manage-correct name displays #2794` * philoushka for `center the icon #2760` * anthonypants for `Typo #2775` * kstolte for `Fix Invalid Configuration in Launch.json #2789` @@ -103,7 +109,6 @@ We would like to thank all our users who raised issues, and in particular the fo * Russian: Andrey Veselov, Anton Fontanov, Anton Savin, Elena Ostrovskaia, Igor Babichev, Maxim Zelensky, Rodion Fedechkin, Tasha T, Vladimir Zyryanov * Portuguese Brazil: Daniel de Sousa, Diogo Duarte, Douglas Correa, Douglas Eccker, José Emanuel Mendes, Marcelo Fernandes, Marcondes Alexandre, Roberto Fonseca, Rodrigo Crespi - And of course, we'd like to thank the authors of all upstream dependencies. Please see a full list in the [ThirdPartyNotices.txt](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/ThirdPartyNotices.txt) ## License diff --git a/azure-pipelines-linux-mac.yml b/azure-pipelines-linux-mac.yml new file mode 100644 index 0000000000..660c03a92c --- /dev/null +++ b/azure-pipelines-linux-mac.yml @@ -0,0 +1,38 @@ +steps: +- task: NodeTool@0 + inputs: + versionSpec: '8.x' + displayName: 'Install Node.js' + +- script: | + git submodule update --init --recursive + nvm install 8.9.1 + nvm use 8.9.1 + npm i -g yarn + displayName: 'preinstall' + +- script: | + export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0 + sh -e /etc/init.d/xvfb start + sleep 3 + displayName: 'Linux preinstall' + condition: eq(variables['Agent.OS'], 'Linux') + +- script: | + yarn + displayName: 'Install' + +- script: | + node_modules/.bin/gulp electron --silent + node_modules/.bin/gulp compile --silent --max_old_space_size=4096 + node_modules/.bin/gulp optimize-vscode --silent --max_old_space_size=4096 + displayName: 'Scripts' + +- script: | + ./scripts/test.sh --reporter mocha-junit-reporter + displayName: 'Tests' + +- task: PublishTestResults@2 + inputs: + testResultsFiles: '**/test-results.xml' + condition: succeededOrFailed() \ No newline at end of file diff --git a/azure-pipelines-windows.yml b/azure-pipelines-windows.yml new file mode 100644 index 0000000000..29fc86351d --- /dev/null +++ b/azure-pipelines-windows.yml @@ -0,0 +1,27 @@ +steps: +- task: NodeTool@0 + inputs: + versionSpec: '8.9' + displayName: 'Install Node.js' + +- script: | + yarn + displayName: 'Yarn Install' + +- script: | + .\node_modules\.bin\gulp electron + displayName: 'Electron' + +- script: | + npm run compile + displayName: 'Compile' + +- script: | + .\scripts\test.bat + .\scripts\test-integration.bat + displayName: 'Test' + +- task: PublishTestResults@2 + inputs: + testResultsFiles: '**/test-results.xml' + condition: succeededOrFailed() \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..6655460296 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,29 @@ +trigger: +- master +- releases/* + +jobs: + +# All tasks on Windows +- job: build_all_windows + displayName: Build all tasks (Windows) + pool: + vmImage: vs2017-win2016 + steps: + - template: azure-pipelines-windows.yml + +# All tasks on Linux +- job: build_all_linux + displayName: Build all tasks (Linux) + pool: + vmImage: 'Ubuntu 16.04' + steps: + - template: azure-pipelines-linux-mac.yml + +# All tasks on macOS +- job: build_all_darwin + displayName: Build all tasks (macOS) + pool: + vmImage: macos-10.13 + steps: + - template: azure-pipelines-linux-mac.yml 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/extensions/agent/src/dialogs/operatorDialog.ts b/extensions/agent/src/dialogs/operatorDialog.ts index edda143b63..3c87be610a 100644 --- a/extensions/agent/src/dialogs/operatorDialog.ts +++ b/extensions/agent/src/dialogs/operatorDialog.ts @@ -35,7 +35,7 @@ export class OperatorDialog extends AgentDialog { private static readonly PagerSundayCheckBoxLabel: string = localize('createOperator.PagerSundayCheckBox', 'Sunday'); private static readonly WorkdayBeginLabel: string = localize('createOperator.workdayBegin', 'Workday begin'); private static readonly WorkdayEndLabel: string = localize('createOperator.workdayEnd', 'Workday end'); - private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schdule'); + private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schedule'); // Notifications tab strings private static readonly AlertsTableLabel: string = localize('createOperator.AlertListHeading', 'Alert list'); diff --git a/extensions/azurecore/package.json b/extensions/azurecore/package.json index 5f0aedfc23..6615f51fa8 100644 --- a/extensions/azurecore/package.json +++ b/extensions/azurecore/package.json @@ -147,7 +147,7 @@ } }, "dependencies": { - "request": "2.63.0", + "request": "2.88.0", "azure-arm-resource": "^7.0.0", "azure-arm-sql": "^5.0.1", "vscode-nls": "^4.0.0" diff --git a/extensions/azurecore/yarn.lock b/extensions/azurecore/yarn.lock index 4483da3cf8..5540b46559 100644 --- a/extensions/azurecore/yarn.lock +++ b/extensions/azurecore/yarn.lock @@ -42,21 +42,6 @@ ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -asn1@0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" - integrity sha1-VZvhg3bQik7E2+gId9J4GGObLfc= - asn1@~0.2.3: version "0.2.4" resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -69,11 +54,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert-plus@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" - integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA= - async@2.6.0: version "2.6.0" resolved "https://registry.npmjs.org/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" @@ -81,7 +61,7 @@ async@2.6.0: dependencies: lodash "^4.14.0" -async@>=0.6.0, async@^2.0.1: +async@>=0.6.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== @@ -93,11 +73,6 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -aws-sign2@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" - integrity sha1-xXED96F/wDfwLXwuZLYC6iI/fWM= - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -136,25 +111,6 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bl@~1.0.0: - version "1.0.3" - resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" - integrity sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4= - dependencies: - readable-stream "~2.0.5" - -bluebird@^2.9.30: - version "2.11.0" - resolved "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= - dependencies: - hoek "2.x.x" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -173,27 +129,11 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c= - caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^1.0.0: - version "1.1.3" - resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - circular-json@^0.3.1: version "0.3.3" resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -211,7 +151,7 @@ combined-stream@1.0.6: dependencies: delayed-stream "~1.0.0" -combined-stream@^1.0.5, combined-stream@~1.0.1, combined-stream@~1.0.6: +combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== @@ -223,33 +163,16 @@ commander@2.15.1: resolved "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== -commander@^2.8.1: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= - dependencies: - boom "2.x.x" - -ctype@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" - integrity sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8= - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -299,12 +222,12 @@ ecdsa-sig-formatter@1.0.10: dependencies: safe-buffer "^5.0.1" -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2: +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" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -extend@~3.0.0, extend@~3.0.2: +extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -329,20 +252,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -forever-agent@~0.6.0, forever-agent@~0.6.1: +forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@~1.0.0-rc1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - integrity sha1-rjFduaSQf6BlUCMEpm13M0de43w= - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - form-data@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" @@ -357,20 +271,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -generate-function@^2.0.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA= - dependencies: - is-property "^1.0.0" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -400,16 +300,6 @@ har-schema@^2.0.0: resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= -har-validator@^1.6.1: - version "1.8.0" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2" - integrity sha1-2DhCsOtMQ1lgrrEIoGejqpTA7rI= - dependencies: - bluebird "^2.9.30" - chalk "^1.0.0" - commander "^2.8.1" - is-my-json-valid "^2.12.0" - har-validator@~5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" @@ -418,47 +308,16 @@ har-validator@~5.1.0: ajv "^5.3.0" har-schema "^2.0.0" -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -hawk@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - he@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= - -http-signature@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6" - integrity sha1-F5bPZ6ABrVzWhJ3KCZFIXwkIn+Y= - dependencies: - asn1 "0.1.11" - assert-plus "^0.1.5" - ctype "0.5.3" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -476,7 +335,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.1: +inherits@2: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -486,27 +345,6 @@ is-buffer@^1.1.6: resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== - -is-my-json-valid@^2.12.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" - integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-property@^1.0.0, is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= - is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -517,12 +355,7 @@ is-typedarray@~1.0.0: resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isstream@~0.1.1, isstream@~0.1.2: +isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= @@ -542,16 +375,11 @@ json-schema@0.2.3: resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -589,7 +417,7 @@ mime-db@~1.36.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw== -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.2: +mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.20" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A== @@ -668,16 +496,6 @@ ms@2.0.0: resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -node-uuid@~1.4.0: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= - -oauth-sign@~0.8.0: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -705,11 +523,6 @@ postinstall-build@^5.0.1: resolved "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7" integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg== -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= - psl@^1.1.24: version "1.1.29" resolved "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" @@ -720,56 +533,14 @@ punycode@^1.4.1: resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -qs@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9" - integrity sha1-TZMuXH6kEcynajEtOaYGIA/VDNk= - qs@~6.5.2: version "6.5.2" resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -readable-stream@~2.0.5: - version "2.0.6" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -request@2.63.0: - version "2.63.0" - resolved "http://registry.npmjs.org/request/-/request-2.63.0.tgz#c83e7c3485e5d9bf9b146318429bc48f1253d8be" - integrity sha1-yD58NIXl2b+bFGMYQpvEjxJT2L4= - dependencies: - aws-sign2 "~0.5.0" - bl "~1.0.0" - caseless "~0.11.0" - combined-stream "~1.0.1" - extend "~3.0.0" - forever-agent "~0.6.0" - form-data "~1.0.0-rc1" - har-validator "^1.6.1" - hawk "~3.1.0" - http-signature "~0.11.0" - isstream "~0.1.1" - json-stringify-safe "~5.0.0" - mime-types "~2.1.2" - node-uuid "~1.4.0" - oauth-sign "~0.8.0" - qs "~5.1.0" - stringstream "~0.0.4" - tough-cookie ">=0.12.0" - tunnel-agent "~0.4.0" - -"request@>= 2.52.0", request@^2.88.0: +request@2.88.0, "request@>= 2.52.0", request@^2.88.0: version "2.88.0" - resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" @@ -847,13 +618,6 @@ should@^13.2.1: should-type-adaptors "^1.0.1" should-util "^1.0.0" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= - dependencies: - hoek "2.x.x" - sshpk@^1.7.0: version "1.14.2" resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" @@ -870,23 +634,6 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -stringstream@~0.0.4: - version "0.0.6" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" - integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - supports-color@5.4.0: version "5.4.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" @@ -894,17 +641,12 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - through@^2.3.8: version "2.3.8" resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -tough-cookie@>=0.12.0, tough-cookie@~2.4.3: +tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== @@ -919,11 +661,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tunnel-agent@~0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us= - tunnel@0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.5.tgz#d1532254749ed36620fcd1010865495a1fa9d0ae" @@ -948,11 +685,6 @@ typemoq@^2.1.0: resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -985,9 +717,3 @@ wrappy@1: xpath.js@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" - integrity sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ== - -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index 023e235259..f1822193b1 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -345,7 +345,7 @@ "specialValueType": null, "isIdentity": false, "name": "asynchronousProcessing", - "displayName": "Asynchronous processing enabled", + "displayName": "Asynchronous processing", "description": "When true, enables usage of the Asynchronous functionality in the .Net Framework Data Provider", "groupName": "Initialization", "valueType": "boolean", @@ -387,7 +387,7 @@ "specialValueType": null, "isIdentity": false, "name": "columnEncryptionSetting", - "displayName": "Column encryption setting", + "displayName": "Column encryption", "description": "Default column encryption setting for all the commands on the connection", "groupName": "Security", "valueType": "category", diff --git a/extensions/mssql/src/config.json b/extensions/mssql/src/config.json index f4b626b481..e55de8fa86 100644 --- a/extensions/mssql/src/config.json +++ b/extensions/mssql/src/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "1.5.0-alpha.52", + "version": "1.5.0-alpha.53", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp2.2.zip", "Windows_64": "win-x64-netcoreapp2.2.zip", diff --git a/extensions/profiler/client/src/dialogs/profilerCreateSessionDialog.ts b/extensions/profiler/client/src/dialogs/profilerCreateSessionDialog.ts index 4906a48b21..d4d0193f49 100644 --- a/extensions/profiler/client/src/dialogs/profilerCreateSessionDialog.ts +++ b/extensions/profiler/client/src/dialogs/profilerCreateSessionDialog.ts @@ -12,9 +12,7 @@ import { CreateSessionData } from '../data/createSessionData'; const localize = nls.loadMessageBundle(); export class CreateSessionDialog { - // Top level - private readonly DialogTitle: string = localize('createSessionDialog.newSession', 'New Session'); private readonly CancelButtonText: string = localize('createSessionDialog.cancel', 'Cancel'); private readonly CreateButtonText: string = localize('createSessionDialog.create', 'Create'); private readonly DialogTitleText: string = localize('createSessionDialog.title', 'Create New Profiler Session'); @@ -25,23 +23,28 @@ export class CreateSessionDialog { private sessionNameBox: sqlops.InputBoxComponent; private model: CreateSessionData; + private readonly _providerType: string; private _onSuccess: vscode.EventEmitter = new vscode.EventEmitter(); public readonly onSuccess: vscode.Event = this._onSuccess.event; - constructor(ownerUri: string, templates: Array) { + constructor(ownerUri: string, providerType: string, templates: Array) { if (typeof (templates) === 'undefined' || templates === null) { throw new Error(localize('createSessionDialog.templatesInvalid', "Invalid templates list, cannot open dialog")); } if (typeof (ownerUri) === 'undefined' || ownerUri === null) { throw new Error(localize('createSessionDialog.dialogOwnerInvalid', "Invalid dialog owner, cannot open dialog")); } + if (typeof (providerType) === 'undefined' || providerType === null) { + throw new Error(localize('createSessionDialog.invalidProviderType', "Invalid provider type, cannot open dialog")); + } + this._providerType = providerType; this.model = new CreateSessionData(ownerUri, templates); } public async showDialog(): Promise { - this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle); + this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitleText); this.initializeContent(); this.dialog.okButton.onClick(() => this.execute()); this.dialog.cancelButton.onClick(() => { }); @@ -76,7 +79,7 @@ export class CreateSessionDialog { title: localize('createSessionDialog.enterSessionName', "Enter session name:") }], - title: this.DialogTitleText + title: '' }]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); @@ -97,8 +100,7 @@ export class CreateSessionDialog { } private async execute(): Promise { - let currentConnection = await sqlops.connection.getCurrentConnection(); - let profilerService = sqlops.dataprotocol.getProvider(currentConnection.providerName, sqlops.DataProviderType.ProfilerProvider); + let profilerService = sqlops.dataprotocol.getProvider(this._providerType, sqlops.DataProviderType.ProfilerProvider); let name = this.sessionNameBox.value; let selected = this.templatesBox.value.toString(); diff --git a/extensions/profiler/client/src/mainController.ts b/extensions/profiler/client/src/mainController.ts index 8b95404b9a..b4e57b8376 100644 --- a/extensions/profiler/client/src/mainController.ts +++ b/extensions/profiler/client/src/mainController.ts @@ -29,8 +29,8 @@ export class MainController { } public activate(): void { - vscode.commands.registerCommand('profiler.openCreateSessionDialog', (ownerUri: string, templates: Array) => { - let dialog = new CreateSessionDialog(ownerUri, templates); + vscode.commands.registerCommand('profiler.openCreateSessionDialog', (ownerUri: string, providerType: string, templates: Array) => { + let dialog = new CreateSessionDialog(ownerUri, providerType, templates); dialog.showDialog(); }); } diff --git a/extensions/profiler/package.json b/extensions/profiler/package.json index f2cdd86357..58d78adeff 100644 --- a/extensions/profiler/package.json +++ b/extensions/profiler/package.json @@ -2,7 +2,7 @@ "name": "profiler", "displayName": "SQL Server Profiler", "description": "SQL Server Profiler for Azure Data Studio", - "version": "0.3.0", + "version": "0.4.0", "publisher": "Microsoft", "preview": true, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt", @@ -26,11 +26,10 @@ "Microsoft.mssql" ], "contributes": { - "commands": [ { "command": "profiler.newProfiler", - "title": "New Profiler", + "title": "Launch Profiler", "category": "Profiler" }, { @@ -49,6 +48,15 @@ "category": "Profiler" } ], + "menus": { + "objectExplorer/item/context": [ + { + "command": "profiler.newProfiler", + "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", + "group": "profiler" + } + ] + }, "outputChannels": [ "sqlprofiler" ] @@ -59,4 +67,4 @@ "devDependencies": { "vscode": "1.0.1" } -} +} \ No newline at end of file diff --git a/extensions/theme-carbon/themes/dark_carbon.json b/extensions/theme-carbon/themes/dark_carbon.json index 674c8b176d..a7d421b0d7 100644 --- a/extensions/theme-carbon/themes/dark_carbon.json +++ b/extensions/theme-carbon/themes/dark_carbon.json @@ -67,7 +67,8 @@ "panel.background": "#212121", "panel.border": "#515151", "panelTitle.activeForeground": "#ffffff", - "panelTitle.inactiveForeground": "#888888" + "panelTitle.inactiveForeground": "#888888", + "panelTitle.activeBorder": "#026dc8" }, "tokenColors": [ { diff --git a/extensions/theme-carbon/themes/light_carbon.json b/extensions/theme-carbon/themes/light_carbon.json index 4db0a032b2..86c838cbdc 100644 --- a/extensions/theme-carbon/themes/light_carbon.json +++ b/extensions/theme-carbon/themes/light_carbon.json @@ -77,7 +77,8 @@ "panel.background": "#ffffff", "panel.border": "#c8c8c8", "panelTitle.activeForeground": "#212121", - "panelTitle.inactiveForeground": "#757575" + "panelTitle.inactiveForeground": "#757575", + "panelTitle.activeBorder": "#026dc8" }, "tokenColors": [ { diff --git a/package.json b/package.json index 1a05cc19af..e2d9c8e81f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azuredatastudio", - "version": "1.2.4", + "version": "1.3.1", "distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee", "author": { "name": "Microsoft Corporation" diff --git a/resources/xlf/sqlops-core/sql.xlf b/resources/xlf/sqlops-core/sql.xlf index da0ecd7c64..a1791f64c6 100644 --- a/resources/xlf/sqlops-core/sql.xlf +++ b/resources/xlf/sqlops-core/sql.xlf @@ -611,7 +611,7 @@ - Clear Recent Connections List + Clear List Recent connections list cleared @@ -1039,10 +1039,10 @@ Connection - Recent connections + Recent Connections - Saved connections + Saved Connections Connection type @@ -1520,9 +1520,6 @@ - - Connect - Disconnect @@ -1533,16 +1530,13 @@ Start - Create - - - Pause Capture + New Session - Resume Capture + Resume - Pause Capture + Pause Stop @@ -1550,9 +1544,6 @@ Clear Data - - Auto Scroll: On - Auto Scroll: On @@ -1572,7 +1563,7 @@ Find Previous String - New Profiler + Launch Profiler @@ -1644,7 +1635,7 @@ - Advanced properties + Advanced Properties Discard diff --git a/resources/xlf/vscode-extensions/profiler.xlf b/resources/xlf/vscode-extensions/profiler.xlf index 58859dffdc..726ae550e3 100644 --- a/resources/xlf/vscode-extensions/profiler.xlf +++ b/resources/xlf/vscode-extensions/profiler.xlf @@ -1,9 +1,6 @@ - - New Session - Cancel diff --git a/scripts/test.bat b/scripts/test.bat index 3335c6e9f7..2ef3a49ed2 100644 --- a/scripts/test.bat +++ b/scripts/test.bat @@ -12,12 +12,18 @@ set CODE=".build\electron\%NAMESHORT%" rem TFS Builds if not "%BUILD_BUILDID%" == "" ( - %CODE% .\node_modules\mocha\bin\_mocha %* + if not "%ADD_REPORTER%" == "" ( + %CODE% .\node_modules\mocha\bin\_mocha --reporter mocha-junit-reporter %* + ) + + if "%ADD_REPORTER%" == "" ( + %CODE% .\node_modules\mocha\bin\_mocha %* + ) ) rem Otherwise if "%BUILD_BUILDID%" == "" ( - %CODE% .\node_modules\mocha\bin\_mocha --reporter dot %* + %CODE% .\node_modules\mocha\bin\_mocha --reporter mocha-junit-reporter %* ) popd diff --git a/scripts/test.sh b/scripts/test.sh index c38bc3d110..929f812f55 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,7 +1,7 @@ #!/bin/bash -if [[ "$OSTYPE" == "darwin"* ]]; then +if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } ROOT=$(dirname $(dirname $(realpath "$0"))) @@ -14,7 +14,7 @@ fi cd $ROOT -if [[ "$OSTYPE" == "darwin"* ]]; then +if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then NAME=`node -p "require('./product.json').nameLong"` CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron" else @@ -30,7 +30,7 @@ node build/lib/electron.js || ./node_modules/.bin/gulp electron # Unit Tests export ELECTRON_RUN_AS_NODE=1 -if [[ "$OSTYPE" == "darwin"* ]]; then +if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then cd $ROOT ; ulimit -n 4096 ; \ "$CODE" \ node_modules/mocha/bin/_mocha "$@" diff --git a/src/sql/base/browser/ui/modal/media/modal.css b/src/sql/base/browser/ui/modal/media/modal.css index abe53a1d80..684e331f3b 100644 --- a/src/sql/base/browser/ui/modal/media/modal.css +++ b/src/sql/base/browser/ui/modal/media/modal.css @@ -56,6 +56,7 @@ .modal .modal-title { font-size: 15px; + font-weight: 600; } .modal .modal-title-icon { @@ -147,7 +148,7 @@ } .modal .footer-button { - margin-right: 5px; + margin-left: 5px; } .modal .right-footer .footer-button:last-of-type { @@ -235,8 +236,8 @@ .modal.flyout-dialog .dialog-message-detail { margin-top: 5px; - white-space: normal; - -webkit-user-select: text; + white-space: pre-wrap; + user-select: text; font-size: 11px; } diff --git a/src/sql/base/browser/ui/modal/media/optionsDialog.css b/src/sql/base/browser/ui/modal/media/optionsDialog.css index 1c13032185..c87a8ea065 100644 --- a/src/sql/base/browser/ui/modal/media/optionsDialog.css +++ b/src/sql/base/browser/ui/modal/media/optionsDialog.css @@ -20,11 +20,34 @@ } .optionsDialog-options-groups { - padding: 15px; - height: calc(100% - 150px); + margin-top: 10px; + flex: 1 1; overflow-y: auto; } +.optionsDialog-options-groups { + margin: 10px 0px; + flex: 1 1; + overflow-y: auto; +} + +.vs .optionsDialog-options-groups { + box-shadow: 0 1px 4px 1px rgba(220, 220, 220, 0.71); +} + +.vs-dark .optionsDialog-options-groups { + box-shadow: 0 4px 5px 0px rgba(0, 0, 0, 0.71); +} + +.optionsDialog-options-groups .split-view-view .header { + padding-left: 28px !important; + background-position-x: 8px !important; +} + +.optionsDialog-options-groups .split-view-view .body { + padding-left: 5px !important; +} + .backButtonIcon { content: url('back.svg'); width: 20px; @@ -33,21 +56,42 @@ cursor: pointer; } -.vs-dark.monaco-shell .backButtonIcon { +.hc-black .backButtonIcon, +.vs-dark .backButtonIcon { content: url('back_inverse.svg'); } .optionsDialog-description { - padding: 15px; - overflow-y: auto; + height: 90px; + margin: 15px; + overflow-y: auto; +} + +.optionsDialog-description .modal-title { + background-repeat: no-repeat; + background-position: 2px center; + padding-left: 25px; + background-size: 16px; +} + +.vs .optionsDialog-description .modal-title { + background-image: url('info_notification.svg') +} + +.vs-dark .optionsDialog-description .modal-title, +.hc-black .optionsDialog-description .modal-title { + background-image: url('info_notification_inverse.svg') } .optionsDialog-options { - height: calc(100% - 30px); + height: 100%; + display: flex; + flex-direction: column; } .optionsDialog-description-content { - padding: 10px; + padding-top: 10px; + padding-left: 25px; } .optionsDialog-table{ diff --git a/src/sql/base/browser/ui/modal/modal.ts b/src/sql/base/browser/ui/modal/modal.ts index 016e9968ce..bd33c5f816 100644 --- a/src/sql/base/browser/ui/modal/modal.ts +++ b/src/sql/base/browser/ui/modal/modal.ts @@ -72,8 +72,8 @@ const defaultOptions: IModalOptions = { }; export abstract class Modal extends Disposable implements IThemable { - - private _messageElement: HTMLElement; + protected _useDefaultMessageBoxLocation: boolean = true; + protected _messageElement: HTMLElement; private _messageIcon: HTMLElement; private _messageSeverity: Builder; private _messageSummary: Builder; @@ -253,7 +253,9 @@ export abstract class Modal extends Disposable implements IThemable { this._messageElement = this._modalMessageSection.getHTMLElement(); this.updateElementVisibility(this._messageElement, false); - parts.push(this._messageElement); + if (this._useDefaultMessageBoxLocation) { + parts.push(this._messageElement); + } } // This modal body section refers to the body of of the dialog diff --git a/src/sql/base/browser/ui/modal/optionsDialog.ts b/src/sql/base/browser/ui/modal/optionsDialog.ts index 602d554ff6..30e3767164 100644 --- a/src/sql/base/browser/ui/modal/optionsDialog.ts +++ b/src/sql/base/browser/ui/modal/optionsDialog.ts @@ -125,7 +125,7 @@ export class OptionsDialog extends Modal { }); let builder = new Builder(this._body); - builder.div({ class: 'Connection-divider' }, (dividerContainer) => { + builder.div({}, (dividerContainer) => { this._dividerBuilder = dividerContainer; }); diff --git a/src/sql/base/browser/ui/panel/media/panel.css b/src/sql/base/browser/ui/panel/media/panel.css index 56b8ca2216..78a0e08024 100644 --- a/src/sql/base/browser/ui/panel/media/panel.css +++ b/src/sql/base/browser/ui/panel/media/panel.css @@ -46,9 +46,9 @@ panel { } .tabbedPanel .tabList .tab .tabLabel { - text-transform: uppercase; - font-size: 13px; + font-size: 14px; padding-bottom: 4px; + font-weight: 600; } .tabbedPanel.vertical .tabList .tab .tabLabel { diff --git a/src/sql/base/browser/ui/panel/panel.ts b/src/sql/base/browser/ui/panel/panel.ts index e2680be62d..1167895a7c 100644 --- a/src/sql/base/browser/ui/panel/panel.ts +++ b/src/sql/base/browser/ui/panel/panel.ts @@ -36,7 +36,6 @@ export interface IPanelTab { interface IInternalPanelTab extends IPanelTab { header: HTMLElement; label: HTMLElement; - dispose(): void; } const defaultOptions: IPanelOptions = { @@ -143,8 +142,6 @@ export class TabbedPanel extends Disposable implements IThemable { this.tabList.appendChild(tabHeaderElement); tab.header = tabHeaderElement; tab.label = tabLabel; - tab.dispose = () => { }; - this._register(tab); } public showTab(id: PanelTabIdentifier): void { diff --git a/src/sql/base/browser/ui/panel/panelStyles.ts b/src/sql/base/browser/ui/panel/panelStyles.ts index c385fcd843..f34407b983 100644 --- a/src/sql/base/browser/ui/panel/panelStyles.ts +++ b/src/sql/base/browser/ui/panel/panelStyles.ts @@ -19,6 +19,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { .tabbedPanel > .title .tabList .tab .tabLabel.active { color: ${titleActive}; border-bottom-color: ${titleActiveBorder}; + border-bottom-width: 2px; } .tabbedPanel > .title .tabList .tab-header.active { diff --git a/src/sql/base/browser/ui/table/asyncDataView.ts b/src/sql/base/browser/ui/table/asyncDataView.ts index 9299f10e35..5777dc2f36 100644 --- a/src/sql/base/browser/ui/table/asyncDataView.ts +++ b/src/sql/base/browser/ui/table/asyncDataView.ts @@ -3,11 +3,14 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces'; + export interface IObservableCollection { getLength(): number; at(index: number): T; getRange(start: number, end: number): T[]; setCollectionChangedCallback(callback: (change: CollectionChange, startIndex: number, count: number) => void): void; + dispose(): void; } export interface IGridDataRow { @@ -24,24 +27,27 @@ class LoadCancellationToken { } class DataWindow { - private _dataSourceLength: number; private _data: TData[]; private _length: number = 0; private _offsetFromDataSource: number = -1; - private loadFunction: (offset: number, count: number) => Thenable; private lastLoadCancellationToken: LoadCancellationToken; - private loadCompleteCallback: (start: number, end: number) => void; - private placeholderItemGenerator: (index: number) => TData; - constructor(dataSourceLength: number, - loadFunction: (offset: number, count: number) => Thenable, - placeholderItemGenerator: (index: number) => TData, - loadCompleteCallback: (start: number, end: number) => void) { - this._dataSourceLength = dataSourceLength; - this.loadFunction = loadFunction; - this.placeholderItemGenerator = placeholderItemGenerator; - this.loadCompleteCallback = loadCompleteCallback; + constructor( + private loadFunction: (offset: number, count: number) => Thenable, + private placeholderItemGenerator: (index: number) => TData, + private loadCompleteCallback: (start: number, end: number) => void + ) { + } + + dispose() { + this._data = undefined; + this.loadFunction = undefined; + this.placeholderItemGenerator = undefined; + this.loadCompleteCallback = undefined; + if (this.lastLoadCancellationToken) { + this.lastLoadCancellationToken.isCancelled = true; + } } getStartIndex(): number { @@ -76,10 +82,9 @@ class DataWindow { return; } - let cancellationToken = new LoadCancellationToken(); - this.lastLoadCancellationToken = cancellationToken; + this.lastLoadCancellationToken = new LoadCancellationToken(); this.loadFunction(offset, length).then(data => { - if (!cancellationToken.isCancelled) { + if (!this.lastLoadCancellationToken.isCancelled) { this._data = data; this.loadCompleteCallback(this._offsetFromDataSource, this._offsetFromDataSource + this._length); } @@ -97,10 +102,12 @@ export class VirtualizedCollection implements IObservableCollection void; - constructor(windowSize: number, + constructor( + windowSize: number, length: number, loadFn: (offset: number, count: number) => Thenable, - private _placeHolderGenerator: (index: number) => TData) { + private _placeHolderGenerator: (index: number) => TData + ) { this._windowSize = windowSize; this._length = length; @@ -110,9 +117,15 @@ export class VirtualizedCollection implements IObservableCollection void): void { @@ -197,7 +210,7 @@ export class VirtualizedCollection implements IObservableCollection implements Slick.DataProvider { +export class AsyncDataProvider implements IDisposableDataProvider { constructor(private dataRows: IObservableCollection) { } @@ -212,4 +225,8 @@ export class AsyncDataProvider implements Slick.Data public getRange(start: number, end: number): TData[] { return !this.dataRows ? undefined : this.dataRows.getRange(start, end); } + + dispose() { + this.dataRows.dispose(); + } } diff --git a/src/sql/base/browser/ui/table/interfaces.ts b/src/sql/base/browser/ui/table/interfaces.ts new file mode 100644 index 0000000000..3cb0f916e7 --- /dev/null +++ b/src/sql/base/browser/ui/table/interfaces.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; +import { Color } from 'vs/base/common/color'; + +export interface IDisposableDataProvider extends Slick.DataProvider { + dispose(): void; +} + +export interface ITableMouseEvent { + anchor: HTMLElement | { x: number, y: number }; + cell?: { row: number, cell: number }; +} + +export interface ITableStyles extends IListStyles { + tableHeaderBackground?: Color; + tableHeaderForeground?: Color; +} + +export interface ITableSorter { + sort(args: Slick.OnSortEventArgs); +} + +export interface ITableConfiguration { + dataProvider?: IDisposableDataProvider | Array; + columns?: Slick.Column[]; + sorter?: ITableSorter; +} diff --git a/src/sql/base/browser/ui/table/table.ts b/src/sql/base/browser/ui/table/table.ts index 12ea8923b6..56cd790bb6 100644 --- a/src/sql/base/browser/ui/table/table.ts +++ b/src/sql/base/browser/ui/table/table.ts @@ -5,28 +5,18 @@ import 'vs/css!./media/table'; import { TableDataView } from './tableDataView'; +import { IDisposableDataProvider, ITableSorter, ITableMouseEvent, ITableConfiguration, ITableStyles } from 'sql/base/browser/ui/table/interfaces'; import { IThemable } from 'vs/platform/theme/common/styler'; -import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; import * as DOM from 'vs/base/browser/dom'; -import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { Widget } from 'vs/base/browser/ui/widget'; import { isArray, isBoolean } from 'vs/base/common/types'; import { Event, Emitter } from 'vs/base/common/event'; import { range } from 'vs/base/common/arrays'; - -export interface ITableMouseEvent { - anchor: HTMLElement | { x: number, y: number }; - cell?: { row: number, cell: number }; -} - -export interface ITableStyles extends IListStyles { - tableHeaderBackground?: Color; - tableHeaderForeground?: Color; -} +import { $ } from 'vs/base/browser/builder'; function getDefaultOptions(): Slick.GridOptions { return >{ @@ -35,23 +25,13 @@ function getDefaultOptions(): Slick.GridOptions { }; } -export interface ITableSorter { - sort(args: Slick.OnSortEventArgs); -} - -export interface ITableConfiguration { - dataProvider?: Slick.DataProvider | Array; - columns?: Slick.Column[]; - sorter?: ITableSorter; -} - export class Table extends Widget implements IThemable, IDisposable { private styleElement: HTMLStyleElement; private idPrefix: string; private _grid: Slick.Grid; private _columns: Slick.Column[]; - private _data: Slick.DataProvider; + private _data: IDisposableDataProvider; private _sorter: ITableSorter; private _autoscroll: boolean; @@ -60,8 +40,6 @@ export class Table extends Widget implements IThemabl private _classChangeTimeout: number; - private _disposables: IDisposable[] = []; - private _onContextMenu = new Emitter(); public readonly onContextMenu: Event = this._onContextMenu.event; @@ -76,6 +54,8 @@ export class Table extends Widget implements IThemabl this._data = configuration.dataProvider; } + this._register(this._data); + if (configuration && configuration.columns) { this._columns = configuration.columns; } else { @@ -117,6 +97,12 @@ export class Table extends Widget implements IThemabl }); } + this._register({ + dispose: () => { + this._grid.destroy(); + } + }); + this.mapMouseEvent(this._grid.onContextMenu, this._onContextMenu); this.mapMouseEvent(this._grid.onClick, this._onClick); } @@ -131,7 +117,8 @@ export class Table extends Widget implements IThemabl } public dispose() { - dispose(this._disposables); + $(this._container).dispose(); + super.dispose(); } public invalidateRows(rows: number[], keepEditor: boolean) { @@ -166,7 +153,7 @@ export class Table extends Widget implements IThemabl this._grid.setData(this._data, true); } - getData(): Slick.DataProvider { + getData(): IDisposableDataProvider { return this._data; } diff --git a/src/sql/base/browser/ui/table/tableDataView.ts b/src/sql/base/browser/ui/table/tableDataView.ts index 25682b6e1c..0507a18d8b 100644 --- a/src/sql/base/browser/ui/table/tableDataView.ts +++ b/src/sql/base/browser/ui/table/tableDataView.ts @@ -9,6 +9,8 @@ import { Event, Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import * as types from 'vs/base/common/types'; +import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces'; + export interface IFindPosition { col: number; row: number; @@ -20,7 +22,7 @@ function defaultSort(args: Slick.OnSortEventArgs, data: Array): Array (a[field] === b[field] ? 0 : (a[field] > b[field] ? 1 : -1)) * sign); } -export class TableDataView implements Slick.DataProvider { +export class TableDataView implements IDisposableDataProvider { private _data: Array; private _findArray: Array; private _findObs: Observable; @@ -154,4 +156,10 @@ export class TableDataView implements Slick.DataProvi get findCount(): number { return types.isUndefinedOrNull(this._findArray) ? 0 : this._findArray.length; } + + dispose() { + this._data = undefined; + this._findArray = undefined; + this._findObs = undefined; + } } diff --git a/src/sql/base/browser/ui/taskbar/media/taskbar.css b/src/sql/base/browser/ui/taskbar/media/taskbar.css index c257a2b065..2773aa3cf5 100644 --- a/src/sql/base/browser/ui/taskbar/media/taskbar.css +++ b/src/sql/base/browser/ui/taskbar/media/taskbar.css @@ -23,7 +23,7 @@ .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container { justify-content: flex-start; - padding-left: 15px; + padding: 5px 5px 5px 15px; flex-wrap: wrap; } diff --git a/src/sql/media/icons/check.svg b/src/sql/media/icons/check.svg new file mode 100644 index 0000000000..3f365c4800 --- /dev/null +++ b/src/sql/media/icons/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/sql/media/icons/check_inverse.svg b/src/sql/media/icons/check_inverse.svg new file mode 100644 index 0000000000..c225b2f597 --- /dev/null +++ b/src/sql/media/icons/check_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/sql/media/icons/common-icons.css b/src/sql/media/icons/common-icons.css index 3062a6eee7..8a762d2bf7 100644 --- a/src/sql/media/icons/common-icons.css +++ b/src/sql/media/icons/common-icons.css @@ -227,6 +227,51 @@ background: url('unpin.svg') center center no-repeat; } +.vs .sql.icon.pause { + background-image: url('pause.svg') +} + +.vs-dark .sql.icon.pause, +.hc-black .sql.icon.pause { + background-image: url('pause_inverse.svg') +} + +.vs .sql.icon.continue { + background-image: url('continue.svg') +} + +.vs-dark .sql.icon.continue, +.hc-black .sql.icon.continue { + background-image: url('continue_inverse.svg') +} + +.vs .sql.icon.checked { + background-image: url('check.svg') +} + +.vs-dark .sql.icon.checked, +.hc-black .sql.icon.checked { + background-image: url('check_inverse.svg') +} + +.vs .sql.icon.start { + background-image: url('start.svg') +} + +.vs-dark .sql.icon.start, +.hc-black .sql.icon.start { + background-image: url('start_inverse.svg') +} + +.vs .sql.icon.stop { + background-image: url('stop.svg') +} + +.vs-dark .sql.icon.stop, +.hc-black .sql.icon.stop { + background-image: url('stop_inverse.svg') +} + .small { width: 16px; height: 16px; diff --git a/src/sql/media/icons/continue.svg b/src/sql/media/icons/continue.svg new file mode 100644 index 0000000000..ca0f30e628 --- /dev/null +++ b/src/sql/media/icons/continue.svg @@ -0,0 +1 @@ +continue \ No newline at end of file diff --git a/src/sql/media/icons/continue_inverse.svg b/src/sql/media/icons/continue_inverse.svg new file mode 100644 index 0000000000..2aab216f07 --- /dev/null +++ b/src/sql/media/icons/continue_inverse.svg @@ -0,0 +1 @@ +continue \ No newline at end of file diff --git a/src/sql/media/icons/pause.svg b/src/sql/media/icons/pause.svg new file mode 100644 index 0000000000..0875d60cb8 --- /dev/null +++ b/src/sql/media/icons/pause.svg @@ -0,0 +1 @@ +pause \ No newline at end of file diff --git a/src/sql/media/icons/pause_inverse.svg b/src/sql/media/icons/pause_inverse.svg new file mode 100644 index 0000000000..5072d2f8cd --- /dev/null +++ b/src/sql/media/icons/pause_inverse.svg @@ -0,0 +1 @@ +pause \ No newline at end of file diff --git a/src/sql/media/icons/start.svg b/src/sql/media/icons/start.svg new file mode 100644 index 0000000000..9ef467f2c0 --- /dev/null +++ b/src/sql/media/icons/start.svg @@ -0,0 +1 @@ +continue \ No newline at end of file diff --git a/src/sql/media/icons/start_inverse.svg b/src/sql/media/icons/start_inverse.svg new file mode 100644 index 0000000000..3be0c24f6f --- /dev/null +++ b/src/sql/media/icons/start_inverse.svg @@ -0,0 +1 @@ +continue \ No newline at end of file diff --git a/src/sql/media/icons/stop.svg b/src/sql/media/icons/stop.svg new file mode 100644 index 0000000000..57c29044b1 --- /dev/null +++ b/src/sql/media/icons/stop.svg @@ -0,0 +1 @@ +stop \ No newline at end of file diff --git a/src/sql/media/icons/stop_inverse.svg b/src/sql/media/icons/stop_inverse.svg new file mode 100644 index 0000000000..c8e3720287 --- /dev/null +++ b/src/sql/media/icons/stop_inverse.svg @@ -0,0 +1 @@ +stop \ No newline at end of file diff --git a/src/sql/parts/connection/common/connectionActions.ts b/src/sql/parts/connection/common/connectionActions.ts index 1ff3c4582b..656e924b6b 100644 --- a/src/sql/parts/connection/common/connectionActions.ts +++ b/src/sql/parts/connection/common/connectionActions.ts @@ -26,7 +26,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService export class ClearRecentConnectionsAction extends Action { public static ID = 'clearRecentConnectionsAction'; - public static LABEL = nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List'); + public static LABEL = nls.localize('ClearRecentlyUsedLabel', 'Clear List'); public static ICON = 'search-action clear-search-results'; private _onRecentConnectionsRemoved = new Emitter(); @@ -83,7 +83,7 @@ export class ClearRecentConnectionsAction extends Action { { key: nls.localize('connectionAction.no', 'No'), value: false } ]; - self._quickOpenService.pick(choices.map(x => x.key), { placeHolder: nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List'), ignoreFocusLost: true }).then((choice) => { + self._quickOpenService.pick(choices.map(x => x.key), { placeHolder: nls.localize('ClearRecentlyUsedLabel', 'Clear List'), ignoreFocusLost: true }).then((choice) => { let confirm = choices.find(x => x.key === choice); resolve(confirm && confirm.value); }); diff --git a/src/sql/parts/connection/connectionDialog/advancedPropertiesController.ts b/src/sql/parts/connection/connectionDialog/advancedPropertiesController.ts index 66a9f82e61..3ee33eac9f 100644 --- a/src/sql/parts/connection/connectionDialog/advancedPropertiesController.ts +++ b/src/sql/parts/connection/connectionDialog/advancedPropertiesController.ts @@ -38,7 +38,7 @@ export class AdvancedPropertiesController { public get advancedDialog() { if (!this._advancedDialog) { this._advancedDialog = this._instantiationService.createInstance( - OptionsDialog, localize('connectionAdvancedProperties', 'Advanced properties'), TelemetryKeys.ConnectionAdvancedProperties, { hasBackButton: true }); + OptionsDialog, localize('connectionAdvancedProperties', 'Advanced Properties'), TelemetryKeys.ConnectionAdvancedProperties, { hasBackButton: true }); this._advancedDialog.cancelLabel = localize('advancedProperties.discard', 'Discard'); this._advancedDialog.onCloseEvent(() => this._onCloseAdvancedProperties()); this._advancedDialog.onOk(() => this.handleOnOk()); diff --git a/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts b/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts index 88237805a2..f52c8ca294 100644 --- a/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts +++ b/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts @@ -37,6 +37,7 @@ import * as styler from 'vs/platform/theme/common/styler'; import * as DOM from 'vs/base/browser/dom'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; export interface OnShowUIResponse { selectedProviderType: string; @@ -49,7 +50,7 @@ export class ConnectionDialogWidget extends Modal { private _noRecentConnectionBuilder: Builder; private _savedConnectionBuilder: Builder; private _noSavedConnectionBuilder: Builder; - private _dividerBuilder: Builder; + private _connectionDetailTitle: Builder; private _connectButton: Button; private _closeButton: Button; private _providerTypeSelectBox: SelectBox; @@ -143,7 +144,7 @@ export class ConnectionDialogWidget extends Modal { this._panel = new TabbedPanel(connectionContainer.getHTMLElement()); this._recentConnectionTabId = this._panel.pushTab({ identifier: 'recent_connection', - title: localize('recentConnectionTitle', 'Recent connections'), + title: localize('recentConnectionTitle', 'Recent Connections'), view: { render: c => { recentConnectionTab.appendTo(c); @@ -154,7 +155,7 @@ export class ConnectionDialogWidget extends Modal { let savedConnectionTabId = this._panel.pushTab({ identifier: 'saved_connection', - title: localize('savedConnectionTitle', 'Saved connections'), + title: localize('savedConnectionTitle', 'Saved Connections'), view: { layout: () => { }, render: c => { @@ -179,8 +180,9 @@ export class ConnectionDialogWidget extends Modal { } }); - this._bodyBuilder.div({ class: 'Connection-divider' }, (dividerContainer) => { - this._dividerBuilder = dividerContainer; + this._bodyBuilder.div({ class: 'connection-details-title' }, (dividerContainer) => { + this._connectionDetailTitle = dividerContainer; + this._connectionDetailTitle.text(localize('connectionDetailsTitle', 'Connection Details')); }); this._bodyBuilder.div({ class: 'connection-type' }, (modelTableContent) => { @@ -217,10 +219,12 @@ export class ConnectionDialogWidget extends Modal { private updateTheme(theme: IColorTheme): void { let borderColor = theme.getColor(contrastBorder); let border = borderColor ? borderColor.toString() : null; - if (this._dividerBuilder) { - this._dividerBuilder.style('border-top-width', border ? '1px' : null); - this._dividerBuilder.style('border-top-style', border ? 'solid' : null); - this._dividerBuilder.style('border-top-color', border); + let backgroundColor = theme.getColor(SIDE_BAR_BACKGROUND); + if (this._connectionDetailTitle) { + this._connectionDetailTitle.style('border-width', border ? '1px 0px' : null); + this._connectionDetailTitle.style('border-style', border ? 'solid none' : null); + this._connectionDetailTitle.style('border-color', border); + this._connectionDetailTitle.style('background-color', backgroundColor ? backgroundColor.toString() : null); } } @@ -277,17 +281,13 @@ export class ConnectionDialogWidget extends Modal { private createRecentConnectionList(): void { this._recentConnectionBuilder.div({ class: 'connection-recent-content' }, (recentConnectionContainer) => { - let recentHistoryLabel = localize('recentHistory', 'Recent history'); recentConnectionContainer.div({ class: 'recent-titles-container' }, (container) => { - container.div({ class: 'connection-history-label' }, (recentTitle) => { - recentTitle.text(recentHistoryLabel); - }); container.div({ class: 'connection-history-actions' }, (actionsContainer) => { this._actionbar = this._register(new ActionBar(actionsContainer.getHTMLElement(), { animated: false })); let clearAction = this._instantiationService.createInstance(ClearRecentConnectionsAction, ClearRecentConnectionsAction.ID, ClearRecentConnectionsAction.LABEL); clearAction.useConfirmationMessage = true; clearAction.onRecentConnectionsRemoved(() => this.open(false)); - this._actionbar.push(clearAction, { icon: true, label: false }); + this._actionbar.push(clearAction, { icon: true, label: true }); }); }); recentConnectionContainer.div({ class: 'server-explorer-viewlet' }, (divContainer: Builder) => { diff --git a/src/sql/parts/connection/connectionDialog/media/connectionDialog.css b/src/sql/parts/connection/connectionDialog/media/connectionDialog.css index 3e7d15fb92..7f652c7450 100644 --- a/src/sql/parts/connection/connectionDialog/media/connectionDialog.css +++ b/src/sql/parts/connection/connectionDialog/media/connectionDialog.css @@ -9,25 +9,35 @@ } .connection-input { - padding-right:8px; width: 200px; padding-bottom: 5px; } .connection-dialog { - height: calc(100% - 20px); + height: 100%; + display: flex; + flex-direction: column; + overflow-x: hidden; + overflow-y: auto; } .connection-dialog .tabbedPanel { border-top-color: transparent; - height: calc(100% - 350px); - display: block; + flex: 1 1; min-height: 120px; + overflow: hidden; + margin: 0px 11px; +} +.connection-dialog .tabBody { + overflow: hidden; + flex: 1 1; + display: flex; + flex-direction: column; } .connection-recent, .connection-saved { - margin: 15px; - height: calc(100% - 60px); + margin: 5px; + flex: 1 1; overflow-y: auto; } @@ -45,6 +55,8 @@ .recent-titles-container { display: flex; justify-content: space-between; + margin: 5px; + flex: 0 0 auto; } .connection-provider-info { @@ -53,7 +65,13 @@ } .connection-recent-content { - height: calc(100% - 20px); + height: 100%; + display: flex; + flex-direction: column; +} + +.connection-recent-content .server-explorer-viewlet { + flex: 1 1; } .connection-table-content { @@ -66,8 +84,9 @@ } .connection-type { - margin: 15px; - overflow-y: hidden; + flex: 0 0 auto; + overflow: hidden; + margin: 0px 13px; } .connection-dialog .connection-history-actions .action-label.icon { @@ -76,8 +95,9 @@ line-height: 20px; min-width: 20px; background-size: 16px; - background-position: center center; + background-position: 2px center; background-repeat: no-repeat; + padding-left: 25px; } .search-action.clear-search-results { @@ -87,4 +107,11 @@ .vs-dark .search-action.clear-search-results, .hc-black .search-action.clear-search-results { background: url('clear-search-results-dark.svg'); +} + +.connection-details-title { + font-size: 14px; + margin: 5px 0px; + padding: 5px 15px; + font-weight: 600; } \ No newline at end of file diff --git a/src/sql/parts/connection/connectionDialog/media/sqlConnection.css b/src/sql/parts/connection/connectionDialog/media/sqlConnection.css index e25c3b72d5..295b6e55d4 100644 --- a/src/sql/parts/connection/connectionDialog/media/sqlConnection.css +++ b/src/sql/parts/connection/connectionDialog/media/sqlConnection.css @@ -5,6 +5,5 @@ .advanced-button { width: 100px; - padding-right:8px; padding-bottom: 5px; } \ No newline at end of file diff --git a/src/sql/parts/jobManagement/views/alertsView.component.ts b/src/sql/parts/jobManagement/views/alertsView.component.ts index 682fde78b3..57979b22f1 100644 --- a/src/sql/parts/jobManagement/views/alertsView.component.ts +++ b/src/sql/parts/jobManagement/views/alertsView.component.ts @@ -15,7 +15,7 @@ import 'vs/css!sql/base/browser/ui/table/media/table'; import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as sqlops from 'sqlops'; -import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit } from '@angular/core'; +import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { TabChild } from 'sql/base/browser/ui/panel/tab.component'; import { Table } from 'sql/base/browser/ui/table/table'; import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component'; @@ -41,7 +41,7 @@ export const ROW_HEIGHT: number = 45; templateUrl: decodeURI(require.toUrl('./alertsView.component.html')), providers: [{ provide: TabChild, useExisting: forwardRef(() => AlertsViewComponent) }], }) -export class AlertsViewComponent extends JobManagementView implements OnInit { +export class AlertsViewComponent extends JobManagementView implements OnInit, OnDestroy { private columns: Array> = [ { @@ -69,6 +69,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { private _isCloud: boolean; private _alertsCacheObject: AlertsCacheObject; + private _didTabChange: boolean; @ViewChild('jobalertsgrid') _gridEl: ElementRef; public alerts: sqlops.AgentAlertInfo[]; @@ -86,6 +87,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { @Inject(IKeybindingService) keybindingService: IKeybindingService, @Inject(IDashboardService) _dashboardService: IDashboardService) { super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService); + this._didTabChange = false; this._isCloud = commonService.connectionManagementService.connectionInfo.serverInfo.isCloud; let alertsCacheObjectMap = this._jobManagementService.alertsCacheObjectMap; let alertsCache = alertsCacheObjectMap[this._serverName]; @@ -102,7 +104,11 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { // set base class elements this._visibilityElement = this._gridEl; this._parentComponent = this._agentViewComponent; - } + } + + ngOnDestroy() { + this._didTabChange = true; + } public layout() { let height = dom.getContentHeight(this._gridEl.nativeElement) - 10; @@ -166,8 +172,10 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { // TODO: handle error } this._showProgressWheel = false; - if (this.isVisible) { + if (this.isVisible && !this._didTabChange) { this._cd.detectChanges(); + } else if (this._didTabChange) { + return; } }); } diff --git a/src/sql/parts/jobManagement/views/jobsView.component.ts b/src/sql/parts/jobManagement/views/jobsView.component.ts index ebaa2bb3bc..ebb8ae22d3 100644 --- a/src/sql/parts/jobManagement/views/jobsView.component.ts +++ b/src/sql/parts/jobManagement/views/jobsView.component.ts @@ -15,7 +15,7 @@ import 'vs/css!sql/base/browser/ui/table/media/table'; import * as sqlops from 'sqlops'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit } from '@angular/core'; +import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { TabChild } from 'sql/base/browser/ui/panel/tab.component'; import { Table } from 'sql/base/browser/ui/table/table'; import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component'; @@ -47,7 +47,7 @@ export const ROW_HEIGHT: number = 45; providers: [{ provide: TabChild, useExisting: forwardRef(() => JobsViewComponent) }], }) -export class JobsViewComponent extends JobManagementView implements OnInit { +export class JobsViewComponent extends JobManagementView implements OnInit, OnDestroy { private columns: Array> = [ { @@ -91,6 +91,8 @@ export class JobsViewComponent extends JobManagementView implements OnInit { private jobSchedules: { [jobId: string]: sqlops.AgentJobScheduleInfo[]; } = Object.create(null); public contextAction = NewJobAction; + private _didTabChange: boolean; + @ViewChild('jobsgrid') _gridEl: ElementRef; constructor( @@ -107,6 +109,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit { @Inject(IDashboardService) _dashboardService: IDashboardService ) { super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService); + this._didTabChange = false; let jobCacheObjectMap = this._jobManagementService.jobCacheObjectMap; let jobCache = jobCacheObjectMap[this._serverName]; if (jobCache) { @@ -126,6 +129,10 @@ export class JobsViewComponent extends JobManagementView implements OnInit { this._register(this._themeService.onDidColorThemeChange(e => this.updateTheme(e))); } + ngOnDestroy() { + this._didTabChange = true; + } + public layout() { let jobsViewToolbar = $('jobsview-component .actionbar-container').get(0); let statusBar = $('.part.statusbar').get(0); @@ -208,8 +215,10 @@ export class JobsViewComponent extends JobManagementView implements OnInit { } this._showProgressWheel = false; - if (this.isVisible) { + if (this.isVisible && !this._didTabChange) { this._cd.detectChanges(); + } else if (this._didTabChange) { + return; } }); } @@ -579,7 +588,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit { private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) { const self = this; jobs.forEach(async (job) => { - await this._jobManagementService.getJobHistory(ownerUri, job.jobId, job.name).then((result) => { + await this._jobManagementService.getJobHistory(ownerUri, job.jobId, job.name).then(async(result) => { if (result) { self.jobSteps[job.jobId] = result.steps ? result.steps : []; self.jobAlerts[job.jobId] = result.alerts ? result.alerts : []; @@ -594,7 +603,10 @@ export class JobsViewComponent extends JobManagementView implements OnInit { } else { previousRuns = jobHistories; } - self.createJobChart(job.jobId, previousRuns); + // dont create the charts if the tab changed + if (!self._didTabChange) { + self.createJobChart(job.jobId, previousRuns); + } if (self._agentViewComponent.expanded.has(job.jobId)) { let lastJobHistory = jobHistories[jobHistories.length - 1]; let item = self.dataView.getItemById(job.jobId + '.error'); diff --git a/src/sql/parts/jobManagement/views/operatorsView.component.ts b/src/sql/parts/jobManagement/views/operatorsView.component.ts index 9b33c1f1d4..dfd3b6512e 100644 --- a/src/sql/parts/jobManagement/views/operatorsView.component.ts +++ b/src/sql/parts/jobManagement/views/operatorsView.component.ts @@ -15,7 +15,7 @@ import 'vs/css!sql/base/browser/ui/table/media/table'; import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as sqlops from 'sqlops'; -import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit } from '@angular/core'; +import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { Table } from 'sql/base/browser/ui/table/table'; import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component'; import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces'; @@ -42,7 +42,7 @@ export const ROW_HEIGHT: number = 45; providers: [{ provide: TabChild, useExisting: forwardRef(() => OperatorsViewComponent) }], }) -export class OperatorsViewComponent extends JobManagementView implements OnInit { +export class OperatorsViewComponent extends JobManagementView implements OnInit, OnDestroy { private columns: Array> = [ { @@ -68,6 +68,7 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit private _isCloud: boolean; private _operatorsCacheObject: OperatorsCacheObject; + private _didTabChange: boolean; @ViewChild('operatorsgrid') _gridEl: ElementRef; public operators: sqlops.AgentOperatorInfo[]; @@ -104,6 +105,10 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit this._parentComponent = this._agentViewComponent; } + ngOnDestroy() { + this._didTabChange = true; + } + public layout() { let height = dom.getContentHeight(this._gridEl.nativeElement) - 10; if (height < 0) { @@ -169,8 +174,10 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit // TODO: handle error } this._showProgressWheel = false; - if (this.isVisible) { + if (this.isVisible && !this._didTabChange) { this._cd.detectChanges(); + } else if (this._didTabChange) { + return; } }); } diff --git a/src/sql/parts/jobManagement/views/proxiesView.component.ts b/src/sql/parts/jobManagement/views/proxiesView.component.ts index 9ebdf0ab5f..bc5e1a43df 100644 --- a/src/sql/parts/jobManagement/views/proxiesView.component.ts +++ b/src/sql/parts/jobManagement/views/proxiesView.component.ts @@ -15,7 +15,7 @@ import 'vs/css!sql/base/browser/ui/table/media/table'; import * as dom from 'vs/base/browser/dom'; import * as sqlops from 'sqlops'; import * as nls from 'vs/nls'; -import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit } from '@angular/core'; +import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { Table } from 'sql/base/browser/ui/table/table'; import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component'; import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces'; @@ -42,7 +42,7 @@ export const ROW_HEIGHT: number = 45; providers: [{ provide: TabChild, useExisting: forwardRef(() => ProxiesViewComponent) }], }) -export class ProxiesViewComponent extends JobManagementView implements OnInit { +export class ProxiesViewComponent extends JobManagementView implements OnInit, OnDestroy { private NewProxyText: string = nls.localize('jobProxyToolbar-NewItem', "New Proxy"); private RefreshText: string = nls.localize('jobProxyToolbar-Refresh', "Refresh"); @@ -75,6 +75,7 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit { public proxies: sqlops.AgentProxyInfo[]; public readonly contextAction = NewProxyAction; + private _didTabChange: boolean; @ViewChild('proxiesgrid') _gridEl: ElementRef; constructor( @@ -108,6 +109,10 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit { this._parentComponent = this._agentViewComponent; } + ngOnDestroy() { + this._didTabChange = true; + } + public layout() { let height = dom.getContentHeight(this._gridEl.nativeElement) - 10; if (height < 0) { @@ -172,8 +177,10 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit { // TODO: handle error } this._showProgressWheel = false; - if (this.isVisible) { + if (this.isVisible && !this._didTabChange) { this._cd.detectChanges(); + } else if (this._didTabChange) { + return; } }); } diff --git a/src/sql/parts/objectExplorer/viewlet/serverTreeActionProvider.ts b/src/sql/parts/objectExplorer/viewlet/serverTreeActionProvider.ts index 258a4b0aa5..0c63ac8307 100644 --- a/src/sql/parts/objectExplorer/viewlet/serverTreeActionProvider.ts +++ b/src/sql/parts/objectExplorer/viewlet/serverTreeActionProvider.ts @@ -24,7 +24,6 @@ import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode'; import { NodeType } from 'sql/parts/objectExplorer/common/nodeType'; import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup'; import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile'; -import { NewProfilerAction } from 'sql/parts/profiler/contrib/profilerActions'; import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils'; import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; import { MenuId, IMenuService } from 'vs/platform/actions/common/actions'; @@ -90,9 +89,11 @@ export class ServerTreeActionProvider extends ContributableActionProvider { * Return actions for connection elements */ public getConnectionActions(tree: ITree, profile: ConnectionProfile): IAction[] { + let node = new TreeNode(NodeType.Server, '', false, '', '', '', undefined, undefined, undefined, undefined); return this.getAllActions({ tree: tree, - profile: profile + profile: profile, + treeNode: node }, (context) => this.getBuiltinConnectionActions(context)); } @@ -125,10 +126,6 @@ export class ServerTreeActionProvider extends ContributableActionProvider { actions.push(this._instantiationService.createInstance(DeleteConnectionAction, DeleteConnectionAction.ID, DeleteConnectionAction.DELETE_CONNECTION_LABEL, context.profile)); actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.profile)); - if (process.env['VSCODE_DEV'] && constants.MssqlProviderId === context.profile.providerName) { - actions.push(this._instantiationService.createInstance(OEAction, NewProfilerAction.ID, NewProfilerAction.LABEL)); - } - return actions; } diff --git a/src/sql/parts/objectExplorer/viewlet/treeCreationUtils.ts b/src/sql/parts/objectExplorer/viewlet/treeCreationUtils.ts index d0828319d3..e10c2f4f78 100644 --- a/src/sql/parts/objectExplorer/viewlet/treeCreationUtils.ts +++ b/src/sql/parts/objectExplorer/viewlet/treeCreationUtils.ts @@ -31,8 +31,8 @@ export class TreeCreationUtils { return new Tree(treeContainer, { dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider }, { - indentPixels: 10, - twistiePixels: 20, + indentPixels: 0, + twistiePixels: 0, ariaLabel: nls.localize('treeAriaLabel', "Recent Connections") }); } diff --git a/src/sql/parts/profiler/contrib/profilerActions.contribution.ts b/src/sql/parts/profiler/contrib/profilerActions.contribution.ts index 8b0ba03c17..a9c33b59c6 100644 --- a/src/sql/parts/profiler/contrib/profilerActions.contribution.ts +++ b/src/sql/parts/profiler/contrib/profilerActions.contribution.ts @@ -9,7 +9,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati import * as nls from 'vs/nls'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; +import { IConnectionManagementService, IConnectionDialogService} from 'sql/parts/connection/common/connectionManagement'; import { IObjectExplorerService } from '../../objectExplorer/common/objectExplorerService'; import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -18,6 +18,10 @@ import { IProfilerService } from '../service/interfaces'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/editor/editor.api'; import { ProfilerEditor } from '../editor/profilerEditor'; +import { ObjectExplorerActionsContext } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions'; +import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile'; +import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; +import { mssqlProviderName } from 'sql/parts/connection/common/constants'; // Contribute Global Actions const category = nls.localize('profilerCategory', "Profiler"); @@ -30,15 +34,45 @@ const newProfilerSchema: IJSONSchema = { CommandsRegistry.registerCommand({ id: 'profiler.newProfiler', - handler: (accessor: ServicesAccessor) => { - let editorService: IEditorService = accessor.get(IEditorService); + handler: (accessor: ServicesAccessor, ...args: any[]) => { + let connectionProfile: ConnectionProfile = undefined; let instantiationService: IInstantiationService = accessor.get(IInstantiationService); + let editorService: IEditorService = accessor.get(IEditorService); let connectionService: IConnectionManagementService = accessor.get(IConnectionManagementService); let objectExplorerService: IObjectExplorerService = accessor.get(IObjectExplorerService); + let connectionDialogService: IConnectionDialogService = accessor.get(IConnectionDialogService); + let capabilitiesService: ICapabilitiesService = accessor.get(ICapabilitiesService); - let connectionProfile = TaskUtilities.getCurrentGlobalConnection(objectExplorerService, connectionService, editorService); - let profilerInput = instantiationService.createInstance(ProfilerInput, connectionProfile); - return editorService.openEditor(profilerInput, { pinned: true }, ACTIVE_GROUP).then(() => TPromise.as(true)); + // If a context is available if invoked from the context menu, we will use the connection profiler of the server node + if (args && args.length === 1 && args[0] && args[0] instanceof ObjectExplorerActionsContext) { + let context = args[0] as ObjectExplorerActionsContext; + connectionProfile = ConnectionProfile.fromIConnectionProfile(capabilitiesService, context.connectionProfile); + } + else { + // No context available, we will try to get the current global active connection + connectionProfile = TaskUtilities.getCurrentGlobalConnection(objectExplorerService, connectionService, editorService) as ConnectionProfile; + } + + let promise; + if (connectionProfile) { + promise = connectionService.connectIfNotConnected(connectionProfile); + } else { + // if still no luck, we will open the Connection dialog and let user connect to a server + promise = connectionDialogService.openDialogAndWait(connectionService, { connectionType: 1, providers: [mssqlProviderName] }).then((profile) => { + connectionProfile = profile as ConnectionProfile; + }); + } + + return promise.then(() => { + if (!connectionProfile) { + connectionProfile = TaskUtilities.getCurrentGlobalConnection(objectExplorerService, connectionService, editorService) as ConnectionProfile; + } + + if (connectionProfile && connectionProfile.providerName === mssqlProviderName) { + let profilerInput = instantiationService.createInstance(ProfilerInput, connectionProfile); + editorService.openEditor(profilerInput, { pinned: true }, ACTIVE_GROUP).then(() => TPromise.as(true)); + } + }); } }); diff --git a/src/sql/parts/profiler/contrib/profilerActions.ts b/src/sql/parts/profiler/contrib/profilerActions.ts index 80ff675f23..9b35c2e766 100644 --- a/src/sql/parts/profiler/contrib/profilerActions.ts +++ b/src/sql/parts/profiler/contrib/profilerActions.ts @@ -10,7 +10,6 @@ import { IProfilerController } from 'sql/parts/profiler/editor/controller/interf import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput'; import { BaseActionContext } from 'sql/workbench/common/actions'; import { Task } from 'sql/platform/tasks/common/tasks'; -import { ObjectExplorerActionsContext } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions'; import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile'; import { IConnectionManagementService, IConnectionCompletionOptions, ConnectionType } from 'sql/parts/connection/common/connectionManagement'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; @@ -25,8 +24,11 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { INotificationService } from 'vs/platform/notification/common/notification'; export class ProfilerConnect extends Action { + private static readonly ConnectText = nls.localize('profilerAction.connect', 'Connect'); + private static readonly DisconnectText = nls.localize('profilerAction.disconnect', 'Disconnect'); + public static ID = 'profiler.connect'; - public static LABEL = nls.localize('profiler.connect', "Connect"); + public static LABEL = ProfilerConnect.ConnectText; private _connected: boolean = false; @@ -59,7 +61,7 @@ export class ProfilerConnect extends Action { public set connected(value: boolean) { this._connected = value; this._setClass(value ? 'disconnect' : 'connect'); - this._setLabel(value ? nls.localize('profilerAction.disconnect', 'Disconnect') : nls.localize('profilerAction.connect', "Connect")); + this._setLabel(value ? ProfilerConnect.DisconnectText : ProfilerConnect.ConnectText); } public get connected(): boolean { @@ -75,7 +77,7 @@ export class ProfilerStart extends Action { id: string, label: string, @IProfilerService private _profilerService: IProfilerService ) { - super(id, label, 'start'); + super(id, label, 'sql start'); } public run(input: ProfilerInput): TPromise { @@ -86,7 +88,7 @@ export class ProfilerStart extends Action { export class ProfilerCreate extends Action { public static ID = 'profiler.create'; - public static LABEL = nls.localize('create', "Create"); + public static LABEL = nls.localize('create', "New Session"); constructor( id: string, label: string, @@ -105,8 +107,13 @@ export class ProfilerCreate extends Action { } export class ProfilerPause extends Action { + private static readonly PauseText = nls.localize('profilerAction.pauseCapture', 'Pause'); + private static readonly ResumeText = nls.localize('profilerAction.resumeCapture', 'Resume'); + private static readonly PauseCssClass = 'sql pause'; + private static readonly ResumeCssClass = 'sql continue'; + public static ID = 'profiler.pause'; - public static LABEL = nls.localize('profiler.capture', "Pause Capture"); + public static LABEL = ProfilerPause.PauseText; private _paused: boolean = false; @@ -114,7 +121,7 @@ export class ProfilerPause extends Action { id: string, label: string, @IProfilerService private _profilerService: IProfilerService ) { - super(id, label, 'stop'); + super(id, label, ProfilerPause.PauseCssClass); } public run(input: ProfilerInput): TPromise { @@ -127,8 +134,8 @@ export class ProfilerPause extends Action { public set paused(value: boolean) { this._paused = value; - this._setClass(value ? 'start' : 'stop'); - this._setLabel(value ? nls.localize('profilerAction.resumeCapture', "Resume Capture") : nls.localize('profilerAction.pauseCapture', "Pause Capture")); + this._setClass(value ? ProfilerPause.ResumeCssClass : ProfilerPause.PauseCssClass); + this._setLabel(value ? ProfilerPause.ResumeText : ProfilerPause.PauseText); } public get paused(): boolean { @@ -144,7 +151,7 @@ export class ProfilerStop extends Action { id: string, label: string, @IProfilerService private _profilerService: IProfilerService ) { - super(id, label, 'stop'); + super(id, label, 'sql stop'); } public run(input: ProfilerInput): TPromise { @@ -167,16 +174,21 @@ export class ProfilerClear extends Action { } export class ProfilerAutoScroll extends Action { + private static readonly AutoScrollOnText = nls.localize('profilerAction.autoscrollOn', 'Auto Scroll: On'); + private static readonly AutoScrollOffText = nls.localize('profilerAction.autoscrollOff', 'Auto Scroll: Off'); + private static readonly CheckedCssClass = 'sql checked'; + public static ID = 'profiler.autoscroll'; - public static LABEL = nls.localize('profiler.autoscrollOn', "Auto Scroll: On"); + public static LABEL = ProfilerAutoScroll.AutoScrollOnText; constructor(id: string, label: string) { - super(id, label); + super(id, label, ProfilerAutoScroll.CheckedCssClass); } run(input: ProfilerInput): TPromise { this.checked = !this.checked; - this._setLabel(this.checked ? nls.localize('profilerAction.autoscrollOn', "Auto Scroll: On") : nls.localize('profilerAction.autoscrollOff', "Auto Scroll: Off")); + this._setLabel(this.checked ? ProfilerAutoScroll.AutoScrollOnText : ProfilerAutoScroll.AutoScrollOffText); + this._setClass(this.checked ? ProfilerAutoScroll.CheckedCssClass : ''); input.state.change({ autoscroll: this.checked }); return TPromise.as(true); } @@ -256,7 +268,7 @@ export class ProfilerFindPrevious implements IEditorAction { export class NewProfilerAction extends Task { public static readonly ID = 'profiler.newProfiler'; - public static readonly LABEL = nls.localize('profilerAction.newProfiler', 'New Profiler'); + public static readonly LABEL = nls.localize('profilerAction.newProfiler', 'Launch Profiler'); public static readonly ICON = 'profile'; private _connectionProfile: ConnectionProfile; diff --git a/src/sql/parts/profiler/contrib/profilerWorkbenchActions.ts b/src/sql/parts/profiler/contrib/profilerWorkbenchActions.ts deleted file mode 100644 index 02e913132a..0000000000 --- a/src/sql/parts/profiler/contrib/profilerWorkbenchActions.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput'; - -import { TPromise } from 'vs/base/common/winjs.base'; -import { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; - -import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; -import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; - -export class GlobalNewProfilerAction extends Action { - public static ID = 'explorer.newProfiler'; - public static LABEL = nls.localize('profilerWorkbenchAction.newProfiler', "New Profiler"); - - constructor( - id: string, label: string, - @IEditorService private _editorService: IEditorService, - @IInstantiationService private _instantiationService: IInstantiationService, - @IConnectionManagementService private _connectionService: IConnectionManagementService - ) { - super(id, label); - } - - run(context?: any): TPromise { - // TODO: for test-only, grab the first MSSQL active connection for the profiler session - // TODO: when finishing the feature the connection should come from the launch context - let connectionProfile: IConnectionProfile; - if (context && context.connectionProfile) { - connectionProfile = context.connectionProfile; - } else { - let activeConnections = this._connectionService.getActiveConnections(); - if (activeConnections) { - for (let i = 0; i < activeConnections.length; ++i) { - if (activeConnections[i].providerName === 'MSSQL') { - connectionProfile = activeConnections[i]; - break; - } - } - } - } - - let profilerInput = this._instantiationService.createInstance(ProfilerInput, connectionProfile); - return this._editorService.openEditor(profilerInput, { pinned: true }, ACTIVE_GROUP).then(() => TPromise.as(true)); - } -} diff --git a/src/sql/parts/profiler/editor/profilerEditor.ts b/src/sql/parts/profiler/editor/profilerEditor.ts index d59a941b6f..14005b6fb8 100644 --- a/src/sql/parts/profiler/editor/profilerEditor.ts +++ b/src/sql/parts/profiler/editor/profilerEditor.ts @@ -122,7 +122,6 @@ export class ProfilerEditor extends BaseEditor { private _viewTemplates: Array; private _sessionSelector: SelectBox; private _sessionsList: Array; - private _connectionInfoText: HTMLElement; // Actions private _connectAction: Actions.ProfilerConnect; @@ -211,6 +210,7 @@ export class ProfilerEditor extends BaseEditor { this._viewTemplates = this._profilerService.getViewTemplates(); this._viewTemplateSelector = new SelectBox(this._viewTemplates.map(i => i.name), 'Standard View', this._contextViewService); + this._viewTemplateSelector.setAriaLabel(nls.localize('profiler.viewSelectAccessibleName', 'Select View')); this._register(this._viewTemplateSelector.onDidSelect(e => { if (this.input) { this.input.viewTemplate = this._viewTemplates.find(i => i.name === e.selected); @@ -223,6 +223,7 @@ export class ProfilerEditor extends BaseEditor { this._sessionsList = ['']; this._sessionSelector = new SelectBox(this._sessionsList, '', this._contextViewService); + this._sessionSelector.setAriaLabel(nls.localize('profiler.sessionSelectAccessibleName', 'Select Session')); this._register(this._sessionSelector.onDidSelect(e => { if (this.input) { this.input.sessionName = e.selected; @@ -233,32 +234,36 @@ export class ProfilerEditor extends BaseEditor { sessionsContainer.style.paddingRight = '5px'; this._sessionSelector.render(sessionsContainer); - this._connectionInfoText = document.createElement('div'); - this._connectionInfoText.style.paddingRight = '5px'; - this._connectionInfoText.innerText = ''; - this._connectionInfoText.style.textAlign = 'center'; - this._connectionInfoText.style.display = 'flex'; - this._connectionInfoText.style.alignItems = 'center'; - this._register(attachSelectBoxStyler(this._viewTemplateSelector, this.themeService)); this._register(attachSelectBoxStyler(this._sessionSelector, this.themeService)); this._actionBar.setContent([ - { action: this._startAction }, - { action: this._stopAction }, - { element: sessionsContainer }, { action: this._createAction }, { element: Taskbar.createTaskbarSeparator() }, + { element: this._createTextElement(nls.localize('profiler.sessionSelectLabel', 'Select Session:')) }, + { element: sessionsContainer }, + { action: this._startAction }, + { action: this._stopAction }, { action: this._pauseAction }, - { action: this._autoscrollAction }, - { action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) }, { element: Taskbar.createTaskbarSeparator() }, + { element: this._createTextElement(nls.localize('profiler.viewSelectLabel', 'Select View:')) }, { element: viewTemplateContainer }, { element: Taskbar.createTaskbarSeparator() }, - { element: this._connectionInfoText } + { action: this._autoscrollAction }, + { action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) } ]); } + private _createTextElement(text: string): HTMLDivElement { + let textElement = document.createElement('div'); + textElement.style.paddingRight = '10px'; + textElement.innerText = text; + textElement.style.textAlign = 'center'; + textElement.style.display = 'flex'; + textElement.style.alignItems = 'center'; + return textElement; + } + private _createProfilerTable(): HTMLElement { let profilerTableContainer = document.createElement('div'); profilerTableContainer.className = 'profiler-table monaco-editor'; @@ -417,7 +422,6 @@ export class ProfilerEditor extends BaseEditor { autoscroll: true, isPanelCollapsed: true }); - this._connectionInfoText.innerText = input.connectionName; this._profilerTableEditor.updateState(); this._splitView.layout(); this._profilerTableEditor.focus(); @@ -464,34 +468,16 @@ export class ProfilerEditor extends BaseEditor { this._connectAction.connected = this.input.state.isConnected; if (this.input.state.isConnected) { - this._updateToolbar(); - this._sessionSelector.enable(); - this._profilerService.getXEventSessions(this.input.id).then((r) => { - // set undefined result to empty list - if (!r) { - r = []; - } - this._sessionSelector.setOptions(r); - this._sessionsList = r; - if ((this.input.sessionName === undefined || this.input.sessionName === '') && this._sessionsList.length > 0) { - let sessionIndex: number = 0; - let uiState = this._profilerService.getSessionViewState(this.input.id); - if (uiState && uiState.previousSessionName) { - sessionIndex = this._sessionsList.indexOf(uiState.previousSessionName); - } else { - this._profilerService.launchCreateSessionDialog(this.input); - } + // Launch the create session dialog if openning a new window. + let uiState = this._profilerService.getSessionViewState(this.input.id); + let previousSessionName = uiState && uiState.previousSessionName; + if (!this.input.sessionName && !previousSessionName) { + this._profilerService.launchCreateSessionDialog(this.input); + } - if (sessionIndex < 0) { - sessionIndex = 0; - } - - this.input.sessionName = this._sessionsList[sessionIndex]; - this._sessionSelector.selectWithOptionName(this.input.sessionName); - } - }); + this._updateSessionSelector(previousSessionName); } else { this._startAction.enabled = false; this._stopAction.enabled = false; @@ -517,23 +503,35 @@ export class ProfilerEditor extends BaseEditor { } if (this.input.state.isStopped) { this._updateToolbar(); - this._sessionSelector.enable(); - this._profilerService.getXEventSessions(this.input.id).then((r) => { - // set undefined result to empty list - if (!r) { - r = []; - } - - this._sessionsList = r; - this._sessionSelector.setOptions(r); - if ((this.input.sessionName === undefined || this.input.sessionName === '') && this._sessionsList.length > 0) { - this.input.sessionName = this._sessionsList[0]; - } - }); + this._updateSessionSelector(); } } } + private _updateSessionSelector(previousSessionName: string = undefined) { + this._sessionSelector.enable(); + this._profilerService.getXEventSessions(this.input.id).then((r) => { + if (!r) { + r = []; + } + + this._sessionSelector.setOptions(r); + this._sessionsList = r; + if (this._sessionsList.length > 0) { + if (!this.input.sessionName) { + this.input.sessionName = previousSessionName; + } + + if (this._sessionsList.indexOf(this.input.sessionName) === -1) { + this.input.sessionName = this._sessionsList[0]; + } + + this._sessionSelector.selectWithOptionName(this.input.sessionName); + }; + }); + + } + private _updateToolbar(): void { this._startAction.enabled = !this.input.state.isRunning && !this.input.state.isPaused && this.input.state.isConnected; this._createAction.enabled = !this.input.state.isRunning && !this.input.state.isPaused && this.input.state.isConnected; diff --git a/src/sql/parts/profiler/editor/profilerInput.ts b/src/sql/parts/profiler/editor/profilerInput.ts index 08f8002971..2d3b00ed21 100644 --- a/src/sql/parts/profiler/editor/profilerInput.ts +++ b/src/sql/parts/profiler/editor/profilerInput.ts @@ -12,7 +12,7 @@ import * as sqlops from 'sqlops'; import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { EditorInput } from 'vs/workbench/common/editor'; +import { EditorInput, ConfirmResult } from 'vs/workbench/common/editor'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -22,6 +22,7 @@ import { IDialogService, IConfirmation, IConfirmationResult } from 'vs/platform/ import { escape } from 'sql/base/common/strings'; import * as types from 'vs/base/common/types'; import URI from 'vs/base/common/uri'; +import Severity from 'vs/base/common/severity'; export class ProfilerInput extends EditorInput implements IProfilerSession { @@ -41,7 +42,7 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { public onColumnsChanged: Event[]> = this._onColumnsChanged.event; constructor( - private _connection: IConnectionProfile, + public connection: IConnectionProfile, @IInstantiationService private _instantiationService: IInstantiationService, @IProfilerService private _profilerService: IProfilerService, @INotificationService private _notificationService: INotificationService, @@ -58,7 +59,7 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { autoscroll: true }); - this._profilerService.registerSession(generateUuid(), _connection, this).then((id) => { + this._profilerService.registerSession(generateUuid(), connection, this).then((id) => { this._id = id; this.state.change({ isConnected: true }); }); @@ -72,23 +73,10 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { return ret; }; this._data = new TableDataView(undefined, searchFn); + } - this.onDispose(() => { - if (this._state.isRunning || this.state.isPaused) { - let confirm: IConfirmation = { - message: nls.localize('confirmStopProfilerSession', "Would you like to stop the running XEvent session?"), - primaryButton: nls.localize('profilerClosingActions.yes', 'Yes'), - secondaryButton: nls.localize('profilerClosingActions.no', 'No'), - type: 'question' - }; - - this._dialogService.confirm(confirm).then(result => { - if (result.confirmed) { - this._profilerService.stopSession(this.id); - } - }); - } - }); + public get providerType(): string { + return this.connection ? this.connection.providerName : undefined; } public set viewTemplate(template: IProfilerViewTemplate) { @@ -114,7 +102,7 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { } public set sessionName(name: string) { - if (!this._state.isRunning || !this.state.isPaused) { + if (!this.state.isRunning || !this.state.isPaused) { this._sessionName = name; } } @@ -133,10 +121,10 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { public getName(): string { let name: string = nls.localize('profilerInput.profiler', 'Profiler'); - if (!this._connection) { + if (!this.connection) { return name; } - name += ': ' + this._connection.serverName.substring(0, 20); + name += ': ' + this.connection.serverName.substring(0, 20); return name; } @@ -178,11 +166,11 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { } public get connectionName(): string { - if (!types.isUndefinedOrNull(this._connection)) { - if (this._connection.databaseName) { - return `${this._connection.serverName} ${this._connection.databaseName}`; + if (!types.isUndefinedOrNull(this.connection)) { + if (this.connection.databaseName) { + return `${this.connection.serverName} ${this.connection.databaseName}`; } else { - return `${this._connection.serverName}`; + return `${this.connection.serverName}`; } } else { @@ -199,7 +187,7 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { } public onSessionStopped(notification: sqlops.ProfilerSessionStoppedParams) { - this._notificationService.error(nls.localize("profiler.sessionStopped", "XEvent Profiler Session stopped unexpectedly on the server {0}.", this._connection.serverName)); + this._notificationService.error(nls.localize("profiler.sessionStopped", "XEvent Profiler Session stopped unexpectedly on the server {0}.", this.connection.serverName)); this.state.change({ isStopped: true, @@ -240,7 +228,7 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { public onMoreRows(eventMessage: sqlops.ProfilerSessionEvents) { if (eventMessage.eventsLost) { - this._notificationService.warn(nls.localize("profiler.eventsLost", "The XEvent Profiler session for {0} has lost events.", this._connection.serverName)); + this._notificationService.warn(nls.localize("profiler.eventsLost", "The XEvent Profiler session for {0} has lost events.", this.connection.serverName)); } for (let i: number = 0; i < eventMessage.events.length && i < 500; ++i) { @@ -264,4 +252,31 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { } } + + confirmSave(): TPromise { + if (this.state.isRunning || this.state.isPaused) { + return this._dialogService.show(Severity.Warning, + nls.localize('confirmStopProfilerSession', "Would you like to stop the running XEvent session?"), + [ + nls.localize('profilerClosingActions.yes', 'Yes'), + nls.localize('profilerClosingActions.no', 'No'), + nls.localize('profilerClosingActions.cancel', 'Cancel') + ]).then((selection: number) => { + if (selection === 0) { + this._profilerService.stopSession(this.id); + return ConfirmResult.DONT_SAVE; + } else if (selection === 1) { + return ConfirmResult.DONT_SAVE; + } else { + return ConfirmResult.CANCEL; + } + });; + } else { + return TPromise.wrap(ConfirmResult.DONT_SAVE); + } + } + + isDirty(): boolean { + return this.state.isRunning || this.state.isPaused; + } } diff --git a/src/sql/parts/profiler/service/profilerService.ts b/src/sql/parts/profiler/service/profilerService.ts index 6fd36b7ae8..021ea9a52d 100644 --- a/src/sql/parts/profiler/service/profilerService.ts +++ b/src/sql/parts/profiler/service/profilerService.ts @@ -141,7 +141,10 @@ export class ProfilerService implements IProfilerService { this._sessionMap.get(this._idMap.reverseGet(id)).onSessionStateChanged({ isStopped: true, isPaused: false, isRunning: false }); return true; }, (reason) => { - this._notificationService.error(reason.message); + // The error won't be actionable to the user, so only log it to console. + // In case of error, the state of the UI is not usable, makes more sense to + // set it to stopped so that user can restart it or pick a different session + this._sessionMap.get(this._idMap.reverseGet(id)).onSessionStateChanged({ isStopped: true, isPaused: false, isRunning: false }); }); } @@ -228,6 +231,6 @@ export class ProfilerService implements IProfilerService { } public launchCreateSessionDialog(input?: ProfilerInput): Thenable { - return this._commandService.executeCommand('profiler.openCreateSessionDialog', input.id, this.getSessionTemplates()); + return this._commandService.executeCommand('profiler.openCreateSessionDialog', input.id, input.providerType, this.getSessionTemplates()); } } diff --git a/src/sql/parts/query/common/query.contribution.ts b/src/sql/parts/query/common/query.contribution.ts index cd8fd2066c..75a2ee130e 100644 --- a/src/sql/parts/query/common/query.contribution.ts +++ b/src/sql/parts/query/common/query.contribution.ts @@ -339,7 +339,7 @@ let registryProperties = { 'sql.showConnectionInfoInTitle': { 'type': 'boolean', 'description': localize('showConnectionInfoInTitle', "Controls whether to show the connection info for a tab in the title."), - 'default': false + 'default': true }, 'mssql.intelliSense.enableIntelliSense': { 'type': 'boolean', diff --git a/src/sql/parts/query/common/queryEditorService.ts b/src/sql/parts/query/common/queryEditorService.ts index 7701b7f1f9..33cbffd8c7 100644 --- a/src/sql/parts/query/common/queryEditorService.ts +++ b/src/sql/parts/query/common/queryEditorService.ts @@ -32,9 +32,6 @@ export interface IQueryEditorService { // Creates new edit data session newEditDataEditor(schemaName: string, tableName: string, queryString: string): Promise; - // Clears any QueryEditor data for the given URI held by this service - onQueryInputClosed(uri: string): void; - /** * Handles updating of SQL files on a save as event. These need special consideration * due to query results and other information being tied to the URI of the file diff --git a/src/sql/parts/query/common/queryInput.ts b/src/sql/parts/query/common/queryInput.ts index 50ee9f2b94..7b26ea1d5d 100644 --- a/src/sql/parts/query/common/queryInput.ts +++ b/src/sql/parts/query/common/queryInput.ts @@ -116,11 +116,11 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec } if (this._configurationService) { - this._configurationService.onDidChangeConfiguration(e => { + this._toDispose.push(this._configurationService.onDidChangeConfiguration(e => { if (e.affectedKeys.includes('sql.showConnectionInfoInTitle')) { this._onDidChangeLabel.fire(); } - }); + })); } this.onDisconnect(); @@ -196,17 +196,17 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec // State update funtions public runQuery(selection: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void { - this._queryModelService.runQuery(this.uri, selection, this.uri, this, executePlanOptions); + this._queryModelService.runQuery(this.uri, selection, this, executePlanOptions); this.showQueryResultsEditor(); } public runQueryStatement(selection: ISelectionData): void { - this._queryModelService.runQueryStatement(this.uri, selection, this.uri, this); + this._queryModelService.runQueryStatement(this.uri, selection, this); this.showQueryResultsEditor(); } public runQueryString(text: string): void { - this._queryModelService.runQueryString(this.uri, text, this.uri, this); + this._queryModelService.runQueryString(this.uri, text, this); this.showQueryResultsEditor(); } @@ -276,7 +276,6 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec // Clean up functions public dispose(): void { - this._queryModelService.disposeQuery(this.uri); this._sql.dispose(); this._results.dispose(); this._toDispose = dispose(this._toDispose); @@ -285,7 +284,7 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec } public close(): void { - this._queryEditorService.onQueryInputClosed(this.uri); + this._queryModelService.disposeQuery(this.uri); this._connectionManagementService.disconnectEditor(this, true); this._sql.close(); diff --git a/src/sql/parts/query/common/queryManagement.ts b/src/sql/parts/query/common/queryManagement.ts index 7f8baa1c87..65ea8ff449 100644 --- a/src/sql/parts/query/common/queryManagement.ts +++ b/src/sql/parts/query/common/queryManagement.ts @@ -215,6 +215,7 @@ export class QueryManagementService implements IQueryManagementService { }); } public disposeQuery(ownerUri: string): Thenable { + this._queryRunners.delete(ownerUri); return this._runAction(ownerUri, (runner) => { return runner.disposeQuery(ownerUri); }); diff --git a/src/sql/parts/query/common/queryResultsInput.ts b/src/sql/parts/query/common/queryResultsInput.ts index e826cd86e0..096a3d12b3 100644 --- a/src/sql/parts/query/common/queryResultsInput.ts +++ b/src/sql/parts/query/common/queryResultsInput.ts @@ -29,6 +29,13 @@ export class ResultsViewState { constructor(@IConfigurationService private configurationService: IConfigurationService) { } + + dispose() { + this.gridPanelState.dispose(); + this.messagePanelState.dispose(); + this.chartState.dispose(); + this.queryPlanState.dispose(); + } } /** @@ -50,7 +57,11 @@ export class QueryResultsInput extends EditorInput { public readonly onRestoreViewStateEmitter = new Emitter(); public readonly onSaveViewStateEmitter = new Emitter(); - public readonly state = new ResultsViewState(this.configurationService); + private _state = new ResultsViewState(this.configurationService); + + public get state(): ResultsViewState { + return this._state; + } constructor(private _uri: string, @IConfigurationService private configurationService: IConfigurationService @@ -60,6 +71,12 @@ export class QueryResultsInput extends EditorInput { this._hasBootstrapped = false; } + close() { + this.state.dispose(); + this._state = undefined; + super.close(); + } + getTypeId(): string { return QueryResultsInput.ID; } diff --git a/src/sql/parts/query/editor/charting/chartTab.ts b/src/sql/parts/query/editor/charting/chartTab.ts index f3e5a1d199..911ff0dc38 100644 --- a/src/sql/parts/query/editor/charting/chartTab.ts +++ b/src/sql/parts/query/editor/charting/chartTab.ts @@ -33,4 +33,8 @@ export class ChartTab implements IPanelTab { public dispose() { this.view.dispose(); } + + public clear() { + this.view.clear(); + } } diff --git a/src/sql/parts/query/editor/charting/chartView.ts b/src/sql/parts/query/editor/charting/chartView.ts index 0ae7471d44..842ecad986 100644 --- a/src/sql/parts/query/editor/charting/chartView.ts +++ b/src/sql/parts/query/editor/charting/chartView.ts @@ -35,6 +35,10 @@ export class ChartState { options: IInsightOptions = { type: ChartType.Bar }; + + dispose() { + + } } declare class Proxy { @@ -134,6 +138,15 @@ export class ChartView extends Disposable implements IPanelView { this.buildOptions(); } + public clear() { + + } + + public dispose() { + dispose(this.optionDisposables); + super.dispose(); + } + render(container: HTMLElement): void { if (!this.container) { this.container = $('div.chart-parent-container'); diff --git a/src/sql/parts/query/editor/gridPanel.ts b/src/sql/parts/query/editor/gridPanel.ts index ee2f2e0b47..098ce82117 100644 --- a/src/sql/parts/query/editor/gridPanel.ts +++ b/src/sql/parts/query/editor/gridPanel.ts @@ -7,7 +7,7 @@ import { attachTableStyler } from 'sql/common/theme/styler'; import QueryRunner from 'sql/parts/query/execution/queryRunner'; import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView'; -import { Table, ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/table'; +import { Table } from 'sql/base/browser/ui/table/table'; import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview'; import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin'; import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin'; @@ -19,6 +19,7 @@ import { escape } from 'sql/base/common/strings'; import { hyperLinkFormatter, textFormatter } from 'sql/parts/grid/services/sharedServices'; import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin'; import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin'; +import { ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/interfaces'; import * as sqlops from 'sqlops'; import * as pretty from 'pretty-data'; @@ -61,6 +62,10 @@ export class GridPanelState { public tableStates: GridTableState[] = []; public scrollPosition: number; public collapsed = false; + + dispose() { + dispose(this.tableStates); + } } export interface IGridTableState { @@ -68,14 +73,14 @@ export interface IGridTableState { maximized: boolean; } -export class GridTableState { +export class GridTableState extends Disposable { private _maximized: boolean; - private _onMaximizedChange = new Emitter(); + private _onMaximizedChange = this._register(new Emitter()); public onMaximizedChange: Event = this._onMaximizedChange.event; - private _onCanBeMaximizedChange = new Emitter(); + private _onCanBeMaximizedChange = this._register(new Emitter()); public onCanBeMaximizedChange: Event = this._onCanBeMaximizedChange.event; private _canBeMaximized: boolean; @@ -86,6 +91,7 @@ export class GridTableState { public activeCell: Slick.Cell; constructor(public readonly resultId: number, public readonly batchId: number) { + super(); } public get canBeMaximized(): boolean { @@ -217,13 +223,13 @@ export class GridPanel extends ViewletPanel { } let table = this.instantiationService.createInstance(GridTable, this.runner, set); table.state = tableState; - tableState.onMaximizedChange(e => { + this.tableDisposable.push(tableState.onMaximizedChange(e => { if (e) { this.maximizeTable(table.id); } else { this.minimizeTables(); } - }); + })); this.tableDisposable.push(attachTableStyler(table, this.themeService)); tables.push(table); @@ -238,11 +244,17 @@ export class GridPanel extends ViewletPanel { this.tables = this.tables.concat(tables); } + public clear() { + this.reset(); + } + private reset() { for (let i = this.splitView.length - 1; i >= 0; i--) { this.splitView.removeView(i); } dispose(this.tables); + dispose(this.tableDisposable); + this.tableDisposable = []; this.tables = []; this.maximizedGrid = undefined; @@ -293,6 +305,15 @@ export class GridPanel extends ViewletPanel { public get state(): GridPanelState { return this._state; } + + public dispose() { + dispose(this.queryRunnerDisposables); + dispose(this.tableDisposable); + dispose(this.tables); + this.tableDisposable = undefined; + this.tables = undefined; + super.dispose(); + } } class GridTable extends Disposable implements IView { @@ -444,9 +465,9 @@ class GridTable extends Disposable implements IView { private setupState() { // change actionbar on maximize change - this.state.onMaximizedChange(this.rebuildActionBar, this); + this._register(this.state.onMaximizedChange(this.rebuildActionBar, this)); - this.state.onCanBeMaximizedChange(this.rebuildActionBar, this); + this._register(this.state.onCanBeMaximizedChange(this.rebuildActionBar, this)); if (this.state.scrollPosition) { // most of the time this won't do anything @@ -656,6 +677,8 @@ class GridTable extends Disposable implements IView { public dispose() { $(this.container).destroy(); + this.table.dispose(); + this.actionBar.dispose(); super.dispose(); } } diff --git a/src/sql/parts/query/editor/messagePanel.ts b/src/sql/parts/query/editor/messagePanel.ts index 231ff1b9a6..9a375ca4ac 100644 --- a/src/sql/parts/query/editor/messagePanel.ts +++ b/src/sql/parts/query/editor/messagePanel.ts @@ -7,6 +7,7 @@ import 'vs/css!./media/messagePanel'; import { IMessagesActionContext, SelectAllMessagesAction, CopyMessagesAction } from './actions'; import QueryRunner from 'sql/parts/query/execution/queryRunner'; +import { QueryInput } from 'sql/parts/query/common/queryInput'; import { IResultMessage, ISelectionData } from 'sqlops'; @@ -28,8 +29,6 @@ import { $ } from 'vs/base/browser/builder'; import { isArray, isUndefinedOrNull } from 'vs/base/common/types'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditor } from 'vs/editor/common/editorCommon'; -import { QueryInput } from 'sql/parts/query/common/queryInput'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; export interface IResultMessageIntern extends IResultMessage { @@ -71,6 +70,10 @@ export class MessagePanelState { this.collapsed = !messagesOpenedSettings; } } + + dispose() { + + } } export class MessagePanel extends ViewletPanel { @@ -102,6 +105,7 @@ export class MessagePanel extends ViewletPanel { renderer: this.renderer, controller: this.controller }, { keyboardSupport: false, horizontalScrollMode: ScrollbarVisibility.Auto }); + this.disposables.push(this.tree); this.tree.onDidScroll(e => { if (this.state) { this.state.scrollPosition = this.tree.getScrollPosition(); @@ -117,7 +121,7 @@ export class MessagePanel extends ViewletPanel { protected renderBody(container: HTMLElement): void { this.container.style.width = '100%'; this.container.style.height = '100%'; - attachListStyler(this.tree, this.themeService); + this.disposables.push(attachListStyler(this.tree, this.themeService)); container.appendChild(this.container); this.tree.setInput(this.model); } @@ -193,9 +197,19 @@ export class MessagePanel extends ViewletPanel { } this.setExpanded(!this.state.collapsed); } + public get state(): MessagePanelState { return this._state; } + + public clear() { + this.reset(); + } + + public dispose() { + dispose(this.queryRunnerDisposables); + super.dispose(); + } } class MessageDataSource implements IDataSource { diff --git a/src/sql/parts/query/editor/queryEditor.ts b/src/sql/parts/query/editor/queryEditor.ts index 4135438f43..767cb5570d 100644 --- a/src/sql/parts/query/editor/queryEditor.ts +++ b/src/sql/parts/query/editor/queryEditor.ts @@ -478,11 +478,11 @@ export class QueryEditor extends BaseEditor { this.setTaskbarContent(); - this._configurationService.onDidChangeConfiguration(e => { + this._toDispose.push(this._configurationService.onDidChangeConfiguration(e => { if (e.affectedKeys.includes('workbench.enablePreviewFeatures')) { this.setTaskbarContent(); } - }); + })); } private setTaskbarContent(): void { diff --git a/src/sql/parts/query/editor/queryResultsEditor.ts b/src/sql/parts/query/editor/queryResultsEditor.ts index 2b66039600..0dc51277c5 100644 --- a/src/sql/parts/query/editor/queryResultsEditor.ts +++ b/src/sql/parts/query/editor/queryResultsEditor.ts @@ -90,7 +90,6 @@ export class QueryResultsEditor extends BaseEditor { public static ID: string = 'workbench.editor.queryResultsEditor'; public static AngularSelectorString: string = 'slickgrid-container.slickgridContainer'; protected _rawOptions: BareResultsGridInfo; - protected _input: QueryResultsInput; private resultsView: QueryResultsView; private styleSheet = DOM.createStyleSheet(); @@ -104,17 +103,17 @@ export class QueryResultsEditor extends BaseEditor { ) { super(QueryResultsEditor.ID, telemetryService, themeService); this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel()); - this._configurationService.onDidChangeConfiguration(e => { + this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('resultsGrid')) { this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel()); this.applySettings(); } - }); + })); this.applySettings(); } public get input(): QueryResultsInput { - return this._input; + return this._input as QueryResultsInput; } private applySettings() { @@ -133,10 +132,16 @@ export class QueryResultsEditor extends BaseEditor { this.styleSheet.remove(); parent.appendChild(this.styleSheet); if (!this.resultsView) { - this.resultsView = new QueryResultsView(parent, this._instantiationService, this._queryModelService); + this.resultsView = this._register(new QueryResultsView(parent, this._instantiationService, this._queryModelService)); } } + dispose() { + this.styleSheet.remove(); + this.styleSheet = undefined; + super.dispose(); + } + layout(dimension: DOM.Dimension): void { this.resultsView.layout(dimension); } @@ -147,6 +152,11 @@ export class QueryResultsEditor extends BaseEditor { return TPromise.wrap(null); } + clearInput() { + this.resultsView.clearInput(); + super.clearInput(); + } + public chart(dataId: { batchId: number, resultId: number }) { this.resultsView.chartData(dataId); } @@ -154,11 +164,4 @@ export class QueryResultsEditor extends BaseEditor { public showQueryPlan(xml: string) { this.resultsView.showPlan(xml); } - - public dispose(): void { - super.dispose(); - if (this.resultsView) { - this.resultsView.dispose(); - } - } } diff --git a/src/sql/parts/query/editor/queryResultsView.ts b/src/sql/parts/query/editor/queryResultsView.ts index 1272e27ad3..57c3ad5106 100644 --- a/src/sql/parts/query/editor/queryResultsView.ts +++ b/src/sql/parts/query/editor/queryResultsView.ts @@ -111,6 +111,15 @@ class ResultsView extends Disposable implements IPanelView { } } + dispose() { + super.dispose(); + } + + public clear() { + this.gridPanel.clear(); + this.messagePanel.clear(); + } + remove(): void { this.container.remove(); } @@ -151,6 +160,10 @@ class ResultsTab implements IPanelTab { public dispose() { dispose(this.view); } + + public clear() { + this.view.clear(); + } } export class QueryResultsView extends Disposable { @@ -221,8 +234,11 @@ export class QueryResultsView extends Disposable { } } - public dispose() { - this._panelView.dispose(); + clearInput() { + this._input = undefined; + this.resultsTab.clear(); + this.qpTab.clear(); + this.chartTab.clear(); } public get input(): QueryResultsInput { @@ -264,4 +280,8 @@ export class QueryResultsView extends Disposable { this._panelView.removeTab(this.qpTab.identifier); } } + + public dispose() { + super.dispose(); + } } diff --git a/src/sql/parts/query/execution/queryModel.ts b/src/sql/parts/query/execution/queryModel.ts index 6049954a20..a48b995bf5 100644 --- a/src/sql/parts/query/execution/queryModel.ts +++ b/src/sql/parts/query/execution/queryModel.ts @@ -35,9 +35,9 @@ export interface IQueryModelService { getConfig(): Promise<{ [key: string]: any }>; getShortcuts(): Promise; getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Thenable; - runQuery(uri: string, selection: ISelectionData, title: string, queryInput: QueryInput, runOptions?: ExecutionPlanOptions): void; - runQueryStatement(uri: string, selection: ISelectionData, title: string, queryInput: QueryInput): void; - runQueryString(uri: string, selection: string, title: string, queryInput: QueryInput); + runQuery(uri: string, selection: ISelectionData, queryInput: QueryInput, runOptions?: ExecutionPlanOptions): void; + runQueryStatement(uri: string, selection: ISelectionData, queryInput: QueryInput): void; + runQueryString(uri: string, selection: string, queryInput: QueryInput); cancelQuery(input: QueryRunner | string): void; disposeQuery(uri: string): void; isRunningQuery(uri: string): boolean; diff --git a/src/sql/parts/query/execution/queryModelService.ts b/src/sql/parts/query/execution/queryModelService.ts index af062d48f8..3c3e2638af 100644 --- a/src/sql/parts/query/execution/queryModelService.ts +++ b/src/sql/parts/query/execution/queryModelService.ts @@ -209,32 +209,28 @@ export class QueryModelService implements IQueryModelService { /** * Run a query for the given URI with the given text selection */ - public runQuery(uri: string, selection: sqlops.ISelectionData, - title: string, queryInput: QueryInput, runOptions?: sqlops.ExecutionPlanOptions): void { - this.doRunQuery(uri, selection, title, queryInput, false, runOptions); + public runQuery(uri: string, selection: sqlops.ISelectionData, queryInput: QueryInput, runOptions?: sqlops.ExecutionPlanOptions): void { + this.doRunQuery(uri, selection, queryInput, false, runOptions); } /** * Run the current SQL statement for the given URI */ - public runQueryStatement(uri: string, selection: sqlops.ISelectionData, - title: string, queryInput: QueryInput): void { - this.doRunQuery(uri, selection, title, queryInput, true); + public runQueryStatement(uri: string, selection: sqlops.ISelectionData, queryInput: QueryInput): void { + this.doRunQuery(uri, selection, queryInput, true); } /** * Run the current SQL statement for the given URI */ - public runQueryString(uri: string, selection: string, - title: string, queryInput: QueryInput): void { - this.doRunQuery(uri, selection, title, queryInput, true); + public runQueryString(uri: string, selection: string, queryInput: QueryInput): void { + this.doRunQuery(uri, selection, queryInput, true); } /** * Run Query implementation */ - private doRunQuery(uri: string, selection: sqlops.ISelectionData | string, - title: string, queryInput: QueryInput, + private doRunQuery(uri: string, selection: sqlops.ISelectionData | string, queryInput: QueryInput, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): void { // Reuse existing query runner if it exists let queryRunner: QueryRunner; @@ -256,7 +252,7 @@ export class QueryModelService implements IQueryModelService { } else { // We do not have a query runner for this editor, so create a new one // and map it to the results uri - info = this.initQueryRunner(uri, title); + info = this.initQueryRunner(uri); queryRunner = info.queryRunner; } @@ -277,8 +273,8 @@ export class QueryModelService implements IQueryModelService { } } - private initQueryRunner(uri: string, title: string): QueryInfo { - let queryRunner = this._instantiationService.createInstance(QueryRunner, uri, title); + private initQueryRunner(uri: string): QueryInfo { + let queryRunner = this._instantiationService.createInstance(QueryRunner, uri); let info = new QueryInfo(); queryRunner.addListener(QREvents.RESULT_SET, e => { this._fireQueryEvent(uri, 'resultSet', e); @@ -363,6 +359,10 @@ export class QueryModelService implements IQueryModelService { if (queryRunner) { queryRunner.disposeQuery(); } + // remove our info map + if (this._queryInfoMap.has(ownerUri)) { + this._queryInfoMap.delete(ownerUri); + } } // EDIT DATA METHODS ///////////////////////////////////////////////////// @@ -386,7 +386,7 @@ export class QueryModelService implements IQueryModelService { // We do not have a query runner for this editor, so create a new one // and map it to the results uri - queryRunner = this._instantiationService.createInstance(QueryRunner, ownerUri, ownerUri); + queryRunner = this._instantiationService.createInstance(QueryRunner, ownerUri); queryRunner.addListener(QREvents.RESULT_SET, resultSet => { this._fireQueryEvent(ownerUri, 'resultSet', resultSet); }); diff --git a/src/sql/parts/query/execution/queryRunner.ts b/src/sql/parts/query/execution/queryRunner.ts index 96be349085..cfda2c605d 100644 --- a/src/sql/parts/query/execution/queryRunner.ts +++ b/src/sql/parts/query/execution/queryRunner.ts @@ -20,7 +20,7 @@ import * as nls from 'vs/nls'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import * as types from 'vs/base/common/types'; import { EventEmitter } from 'sql/base/common/eventEmitter'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { Emitter, Event } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -62,7 +62,7 @@ export interface IGridMessage extends sqlops.IResultMessage { * Query Runner class which handles running a query, reports the results to the content manager, * and handles getting more rows from the service layer and disposing when the content is closed. */ -export default class QueryRunner { +export default class QueryRunner extends Disposable { // MEMBER VARIABLES //////////////////////////////////////////////////// private _resultLineOffset: number; private _totalElapsedMilliseconds: number = 0; @@ -76,7 +76,7 @@ export default class QueryRunner { private _planXml = new Deferred(); public get planXml(): Thenable { return this._planXml.promise; } - private _onMessage = new Emitter(); + private _onMessage = this._register(new Emitter()); private _debouncedMessage = debounceEvent(this._onMessage.event, (l, e) => { // on first run if (types.isUndefinedOrNull(l)) { @@ -88,7 +88,7 @@ export default class QueryRunner { private _echoedMessages = echo(this._debouncedMessage.event); public readonly onMessage = this._echoedMessages.event; - private _onResultSet = new Emitter(); + private _onResultSet = this._register(new Emitter()); private _debouncedResultSet = debounceEvent(this._onResultSet.event, (l, e) => { // on first run if (types.isUndefinedOrNull(l)) { @@ -100,16 +100,16 @@ export default class QueryRunner { private _echoedResultSet = echo(this._debouncedResultSet.event); public readonly onResultSet = this._echoedResultSet.event; - private _onQueryStart = new Emitter(); + private _onQueryStart = this._register(new Emitter()); public readonly onQueryStart: Event = this._onQueryStart.event; - private _onQueryEnd = new Emitter(); + private _onQueryEnd = this._register(new Emitter()); public readonly onQueryEnd: Event = this._onQueryEnd.event; - private _onBatchStart = new Emitter(); + private _onBatchStart = this._register(new Emitter()); public readonly onBatchStart: Event = this._onBatchStart.event; - private _onBatchEnd = new Emitter(); + private _onBatchEnd = this._register(new Emitter()); public readonly onBatchEnd: Event = this._onBatchEnd.event; private _queryStartTime: Date; @@ -124,13 +124,14 @@ export default class QueryRunner { // CONSTRUCTOR ///////////////////////////////////////////////////////// constructor( public uri: string, - public title: string, @IQueryManagementService private _queryManagementService: IQueryManagementService, @INotificationService private _notificationService: INotificationService, @IWorkspaceConfigurationService private _workspaceConfigurationService: IWorkspaceConfigurationService, @IClipboardService private _clipboardService: IClipboardService, @IInstantiationService private instantiationService: IInstantiationService - ) { } + ) { + super(); + } get isExecuting(): boolean { return this._isExecuting; @@ -504,10 +505,16 @@ export default class QueryRunner { /** * Disposes the Query from the service client - * @returns A promise that will be rejected if a problem occured */ public disposeQuery(): void { - this._queryManagementService.disposeQuery(this.uri); + this._queryManagementService.disposeQuery(this.uri).then(() => { + this.dispose(); + }); + } + + public dispose() { + this._batchSets = undefined; + super.dispose(); } get totalElapsedMilliseconds(): number { diff --git a/src/sql/parts/query/services/queryEditorService.ts b/src/sql/parts/query/services/queryEditorService.ts index a5e7378884..f11438782c 100644 --- a/src/sql/parts/query/services/queryEditorService.ts +++ b/src/sql/parts/query/services/queryEditorService.ts @@ -152,12 +152,6 @@ export class QueryEditorService implements IQueryEditorService { }); } - /** - * Clears any QueryEditor data for the given URI held by this service - */ - public onQueryInputClosed(uri: string): void { - } - onSaveAsCompleted(oldResource: URI, newResource: URI): void { let oldResourceString: string = oldResource.toString(); diff --git a/src/sql/parts/queryPlan/queryPlan.ts b/src/sql/parts/queryPlan/queryPlan.ts index 737daad64f..c63cb9913c 100644 --- a/src/sql/parts/queryPlan/queryPlan.ts +++ b/src/sql/parts/queryPlan/queryPlan.ts @@ -15,6 +15,9 @@ import { dispose, Disposable } from 'vs/base/common/lifecycle'; export class QueryPlanState { xml: string; + dispose() { + + } } export class QueryPlanTab implements IPanelTab { @@ -29,6 +32,10 @@ export class QueryPlanTab implements IPanelTab { public dispose() { dispose(this.view); } + + public clear() { + this.view.clear(); + } } export class QueryPlanView implements IPanelView { @@ -59,6 +66,12 @@ export class QueryPlanView implements IPanelView { this.container.style.height = dimension.height + 'px'; } + public clear() { + if (this.qp) { + this.qp.xml = undefined; + } + } + public showPlan(xml: string) { if (this.qp) { this.qp.xml = xml; diff --git a/src/sql/platform/dialog/media/dialogModal.css b/src/sql/platform/dialog/media/dialogModal.css index 4f0e201e11..d0954903a7 100644 --- a/src/sql/platform/dialog/media/dialogModal.css +++ b/src/sql/platform/dialog/media/dialogModal.css @@ -16,6 +16,18 @@ min-width: 800px; } +.dialog-message-and-page-container { + display: flex; + flex-direction: column; + flex: 1 1; + overflow: hidden; +} + +.dialogModal-page-container { + flex: 1 1; + overflow: hidden; +} + .dialogModal-pane { display: flex; flex-direction: column; diff --git a/src/sql/platform/dialog/wizardModal.ts b/src/sql/platform/dialog/wizardModal.ts index 2b639aa1d5..1580e0f3d1 100644 --- a/src/sql/platform/dialog/wizardModal.ts +++ b/src/sql/platform/dialog/wizardModal.ts @@ -34,6 +34,9 @@ export class WizardModal extends Modal { // Wizard HTML elements private _body: HTMLElement; + private _messageAndPageContainer: HTMLElement; + private _pageContainer: HTMLElement; + // Buttons private _previousButton: Button; private _nextButton: Button; @@ -53,6 +56,7 @@ export class WizardModal extends Modal { @IClipboardService clipboardService: IClipboardService ) { super(_wizard.title, name, partService, telemetryService, clipboardService, themeService, contextKeyService, options); + this._useDefaultMessageBoxLocation = false; } public layout(): void { @@ -126,12 +130,21 @@ export class WizardModal extends Modal { } protected renderBody(container: HTMLElement): void { + let bodyBuilderObj; new Builder(container).div({ class: 'dialogModal-body' }, (bodyBuilder) => { + bodyBuilderObj = bodyBuilder; this._body = bodyBuilder.getHTMLElement(); }); this.initializeNavigation(this._body); + bodyBuilderObj.div({ class: 'dialog-message-and-page-container' }, (mpContainer) => { + this._messageAndPageContainer = mpContainer.getHTMLElement(); + mpContainer.append(this._messageElement); + this._pageContainer = mpContainer.div({ class: 'dialogModal-page-container' }).getHTMLElement(); + }); + + this._wizard.pages.forEach(page => { this.registerPage(page); }); @@ -159,7 +172,7 @@ export class WizardModal extends Modal { private registerPage(page: WizardPage): void { let dialogPane = new DialogPane(page.title, page.content, valid => page.notifyValidityChanged(valid), this._instantiationService, this._wizard.displayPageTitles, page.description); - dialogPane.createBody(this._body); + dialogPane.createBody(this._pageContainer); this._dialogPanes.set(page, dialogPane); page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage)); } diff --git a/src/sql/workbench/common/taskUtilities.ts b/src/sql/workbench/common/taskUtilities.ts index 05f3469fde..415d1b72ac 100644 --- a/src/sql/workbench/common/taskUtilities.ts +++ b/src/sql/workbench/common/taskUtilities.ts @@ -28,6 +28,7 @@ import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectEx import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { QueryInput } from 'sql/parts/query/common/queryInput'; import { DashboardInput } from 'sql/parts/dashboard/dashboardInput'; +import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput'; // map for the version of SQL Server (default is 140) const scriptCompatibilityOptionMap = { @@ -400,6 +401,9 @@ export function getCurrentGlobalConnection(objectExplorerService: IObjectExplore if (activeInput instanceof QueryInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput) { connection = connectionManagementService.getConnectionProfile(activeInput.uri); } + else if (activeInput instanceof ProfilerInput) { + connection = activeInput.connection; + } } return connection; diff --git a/src/sql/workbench/errorMessageDialog/errorMessageDialog.ts b/src/sql/workbench/errorMessageDialog/errorMessageDialog.ts index 3b33361759..82ca24f3ad 100644 --- a/src/sql/workbench/errorMessageDialog/errorMessageDialog.ts +++ b/src/sql/workbench/errorMessageDialog/errorMessageDialog.ts @@ -14,7 +14,7 @@ import { attachButtonStyler, attachModalDialogStyler } from 'sql/common/theme/st import { Builder } from 'vs/base/browser/builder'; import Severity from 'vs/base/common/severity'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { Event, Emitter } from 'vs/base/common/event'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -76,7 +76,7 @@ export class ErrorMessageDialog extends Modal { this._copyButton = this.addFooterButton(copyButtonLabel, () => this._clipboardService.writeText(this._messageDetails), 'left'); this._copyButton.icon = 'icon scriptToClipboard'; this._copyButton.element.title = copyButtonLabel; - this._register(attachButtonStyler(this._copyButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND })); + this._register(attachButtonStyler(this._copyButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND, buttonForeground: SIDE_BAR_FOREGROUND })); } private createStandardButton(label: string, onSelect: () => void): Button { diff --git a/src/sqltest/parts/query/editor/queryEditor.test.ts b/src/sqltest/parts/query/editor/queryEditor.test.ts index 123a07d78e..a923fffe56 100644 --- a/src/sqltest/parts/query/editor/queryEditor.test.ts +++ b/src/sqltest/parts/query/editor/queryEditor.test.ts @@ -141,6 +141,8 @@ suite('SQL QueryEditor Tests', () => { connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined); connectionManagementService.callBase = true; connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAny())).returns(() => false); + connectionManagementService.setup(x => x.disconnectEditor(TypeMoq.It.isAny())).returns(() => void 0); + connectionManagementService.setup(x => x.ensureDefaultLanguageFlavor(TypeMoq.It.isAnyString())).returns(() => void 0); // Create a QueryModelService queryModelService = new QueryModelService(instantiationService.object, notificationService.object); @@ -328,6 +330,9 @@ suite('SQL QueryEditor Tests', () => { queryConnectionService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined); queryConnectionService.callBase = true; + queryConnectionService.setup(x => x.disconnectEditor(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => void 0); + queryConnectionService.setup(x => x.ensureDefaultLanguageFlavor(TypeMoq.It.isAnyString())).returns(() => void 0); + // Mock InstantiationService to give us the actions queryActionInstantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose); @@ -354,12 +359,13 @@ suite('SQL QueryEditor Tests', () => { let fileInput = new UntitledEditorInput(URI.parse('testUri'), false, '', '', '', instantiationService.object, undefined, undefined, undefined); queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose, undefined, undefined); queryModelService.callBase = true; + queryModelService.setup(x => x.disposeQuery(TypeMoq.It.isAny())).returns(() => void 0); queryInput = new QueryInput( '', fileInput, undefined, undefined, - undefined, + connectionManagementService.object, queryModelService.object, undefined, undefined @@ -395,7 +401,7 @@ suite('SQL QueryEditor Tests', () => { test('Test that we attempt to dispose query when the queryInput is disposed', (done) => { let queryResultsInput = new QueryResultsInput('testUri', configurationService.object); queryInput['_results'] = queryResultsInput; - queryInput.dispose(); + queryInput.close(); queryModelService.verify(x => x.disposeQuery(TypeMoq.It.isAnyString()), TypeMoq.Times.once()); done(); }); diff --git a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts index 8691f093e5..dfd375d02a 100644 --- a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts @@ -199,7 +199,7 @@ suite('Keybindings Editor Model test', () => { }); }); - test('convert with title and wihtout binding to entry', () => { + test('convert with title and without binding to entry', () => { const id = 'a' + uuid.generateUuid(); registerCommandWithTitle(id, 'some title'); prepareKeybindingService();