Compare commits

..

22 Commits

Author SHA1 Message Date
Chris LaFreniere
0b9ef714c8 Fix not being able to type in code cell after switching from text (#17590) (#17592)
* Fix not being able to type in code cell after switching from text

* comment

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
2021-11-04 10:13:23 -07:00
Karl Burtram
36684b87e1 Bump non-builtin extensions in release/1.33 (#17568) 2021-11-02 14:24:11 -07:00
Karl Burtram
78d4398b32 Add support for restricted mode (#17559)
* Update reference to html-query-plan to use npm.js (#17558)

* Update reference to html-query-plan to use npm.js

* Change some references to html-query-plan package

* Add untrusted workspace supported flags (#17557)

* Bump version 1.33.1
2021-11-02 10:20:03 -07:00
Charles Gagnon
ee9fa17149 Fix localized titles in VS Code marketplace (#17515) 2021-10-27 14:09:45 -07:00
Charles Gagnon
737ad2c631 Fix publisher for VS Code extensions (#17505) (#17507) 2021-10-27 10:51:22 -07:00
brian-harris
6783aa6967 improve account and tenant selection error handling (#17476) (#17489)
* improve account/tenant selection error handling

* remove extra space from user string
2021-10-26 09:39:05 -07:00
brian-harris
ccbc2f74fe apply unique filter to getLocations api's (#17454) (#17473)
* apply unique filter to getLocations api's

* filter resource locations to distinct list

* simplify location filter
2021-10-26 09:38:38 -07:00
Daniel Grajeda
d7283a6e56 Notebook Views initialization fix (#17109) (#17471)
Separate the Views load from the initialization. This way we can load previously created views, and only add the new views data to the document when needed. For now, this happens only when a view is created.
2021-10-22 15:29:22 -07:00
Charles Gagnon
0684040d34 Fix backups not restoring in correct editor (#17466) (#17468) 2021-10-22 13:36:29 -07:00
Karl Burtram
625eb00be2 Remove duplicate Getting Started contributions (#17465) (#17470) 2021-10-22 12:55:09 -07:00
brian-harris
c5a27a89f3 Retry sql migration (#17376) (#17448) 2021-10-21 21:14:15 -07:00
Charles Gagnon
b9a7d5e4bd Fix URL protocol for non-insiders builds (#17446) 2021-10-21 17:12:39 -07:00
Alan Ren
f876c00ca1 fix scrolling issue (#17443) (#17449) 2021-10-21 16:25:09 -07:00
Z Chen
83ae789aa0 Warning when .NET 6 SDK is detected (#17422) (#17447)
* Check for max supported version

* Separate dialog for downgrade warning

* Address PR comments

* Use markdown link

* Update warning message
2021-10-21 16:24:14 -07:00
Maddy
6fe4d0a561 add path.posix while reading relative paths (#17326) (#17441)
* path.posix

* add test for nested folders scenario

* update message and remove the redundant check
2021-10-21 14:11:33 -07:00
Benjin Dubishar
2eaec9f41d Use correct string when checking "browse" option (#17432) (#17440)
* Correct browse string match

* Deduping const
2021-10-21 14:10:47 -07:00
rajeshka
2edafe50bb remove trailing line after the cursor (#17431) (#17436)
* remove trailing line after the cursor

* Addressed PR

(cherry picked from commit 914ac2b09d)
2021-10-21 11:38:23 -07:00
rajeshka
24c5686bd6 fixing the svg (#17427) (#17429)
(cherry picked from commit d196588661)
2021-10-20 20:11:04 -07:00
rajeshka
1731aeffbe Fix for Split Cell duplicates cell #17400 (#17417) (#17425)
(cherry picked from commit d251bbd1a1)
2021-10-20 16:28:47 -07:00
Lucy Zhang
b35ff6451a add listener for celltype change (#17414) (#17418) 2021-10-20 14:38:35 -07:00
Vasu Bhog
07aa256f4c Move split cell icon (#17383) (#17392)
* move split cell icon before delete icon
2021-10-19 13:01:57 -07:00
Lucy Zhang
473764de9a use setContent instead of addElement (#17386) (#17388) 2021-10-19 10:28:19 -07:00
505 changed files with 7316 additions and 37112 deletions

25
.vscode/launch.json vendored
View File

@@ -269,31 +269,6 @@
"presentation": { "presentation": {
"group": "4_web" "group": "4_web"
} }
},
{
"name": "Run Sample Resource Deployment Extension",
"type": "sqlopsExtensionHost",
"request": "launch",
"windows": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.bat"
},
"osx": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
},
"linux": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
},
"args": [
"--extensionDevelopmentPath=${workspaceRoot}/samples/sample-resource-deployment"
],
"outFiles": [
"${workspaceRoot}/samples/sample-resource-deployment/out/**/*.js"
],
"preLaunchTask": "Watch sample-resource-deployment",
"presentation": {
"group": "5_samples"
},
"timeout": 30000
} }
], ],
"compounds": [ "compounds": [

12
.vscode/tasks.json vendored
View File

@@ -231,18 +231,6 @@
"group": "build", "group": "build",
"label": "npm: tsec-compile-check", "label": "npm: tsec-compile-check",
"detail": "node_modules/tsec/bin/tsec -p src/tsconfig.json --noEmit" "detail": "node_modules/tsec/bin/tsec -p src/tsconfig.json --noEmit"
},
{
"type": "npm",
"script": "watch",
"label": "Watch sample-resource-deployment",
"path": "./samples/sample-resource-deployment/package.json",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": "build"
} }
] ]
} }

View File

@@ -1,61 +1,5 @@
# Change Log # Change Log
## Version 1.33.1
* Release date: Nov 4, 2021
* Release status: General Availability
## Hotfix release
- Fix for [#16535 Unable to See Saved Connections in Restricted Mode](https://github.com/microsoft/azuredatastudio/issues/17535)
- Fix for [#17579 Can't type in Notebook code cell after editing text cell](https://github.com/microsoft/azuredatastudio/issues/17579)
| Platform |
| --------------------------------------- |
| [Windows User Installer][win-user] |
| [Windows System Installer][win-system] |
| [Windows ZIP][win-zip] |
| [macOS ZIP][osx-zip] |
| [Linux TAR.GZ][linux-zip] |
| [Linux RPM][linux-rpm] |
| [Linux DEB][linux-deb] |
[win-user]: https://go.microsoft.com/fwlink/?linkid=2176805
[win-system]: https://go.microsoft.com/fwlink/?linkid=2175910
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2176806
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2176807
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2176505
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2176005
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2176006
## Version 1.33.0
* Release date: October 27, 2021
* Release status: General Availability
## What's new in this version
* New Notebook Features:
* Notebook Views
* Split cell support
* Keyboard shortcuts for Markdown Toolbar Cells
* Ctrl/Cmd + B = Bold Text
* Ctrl/Cmd + I = Italicize Text
* Ctrl/Cmd + U = Underline Text
* Ctrl/Cmd + Shift + K = Add Code Block
* Ctrl/Cmd + Shift + H = Highlight Text
* Book improvements
* Add a new section
* Drag and Drop
* Extension Updates:
* Import
* Langpacks
* Schema Compare
* Sql Database Projects
* Bug Fixes
* Notebook linking improvements
* Horizontal Scrollbar improvement (when word wrap is off in MD Splitview / MD mode) in Notebooks
* Vertical Scrollbar improvement for MD Splitview in Notebooks
## Version 1.32.0 ## Version 1.32.0
* Release date: August 18, 2021 * Release date: August 18, 2021
* Release status: General Availability * Release status: General Availability

View File

@@ -131,10 +131,10 @@ Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [Source EULA](LICENSE.txt). Licensed under the [Source EULA](LICENSE.txt).
[win-user]: https://go.microsoft.com/fwlink/?linkid=2176805 [win-user]: https://go.microsoft.com/fwlink/?linkid=2170400
[win-system]: https://go.microsoft.com/fwlink/?linkid=2175910 [win-system]: https://go.microsoft.com/fwlink/?linkid=2170401
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2176806 [win-zip]: https://go.microsoft.com/fwlink/?linkid=2170402
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2176807 [osx-zip]: https://go.microsoft.com/fwlink/?linkid=2169955
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2176505 [linux-zip]: https://go.microsoft.com/fwlink/?linkid=2170045
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2176005 [linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2170403
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2176006 [linux-deb]: https://go.microsoft.com/fwlink/?linkid=2169956

View File

@@ -1 +1 @@
2021-11-19T02:27:18.022Z 2021-08-23T03:52:18.011Z

View File

@@ -61,7 +61,6 @@ steps:
key: 'nodeModules | $(Agent.OS) | .build/yarnlockhash' key: 'nodeModules | $(Agent.OS) | .build/yarnlockhash'
path: .build/node_modules_cache path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED cacheHitVar: NODE_MODULES_RESTORED
continueOnError: true
- script: | - script: |
set -e set -e

View File

@@ -57,7 +57,6 @@ steps:
key: 'nodeModules | $(Agent.OS) | .build/yarnlockhash' key: 'nodeModules | $(Agent.OS) | .build/yarnlockhash'
path: .build/node_modules_cache path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED cacheHitVar: NODE_MODULES_RESTORED
continueOnError: true
- script: | - script: |
set -e set -e
@@ -188,7 +187,7 @@ steps:
displayName: 'Install .NET Core sdk for signing' displayName: 'Install .NET Core sdk for signing'
inputs: inputs:
packageType: sdk packageType: sdk
version: 5.0.x version: 2.1.x
installationPath: $(Agent.ToolsDirectory)/dotnet installationPath: $(Agent.ToolsDirectory)/dotnet
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1

View File

@@ -52,7 +52,6 @@ steps:
# Sync up to latest from the DT repo # Sync up to latest from the DT repo
git remote add upstream https://github.com/DefinitelyTyped/DefinitelyTyped.git git remote add upstream https://github.com/DefinitelyTyped/DefinitelyTyped.git
git fetch upstream
git merge upstream/master git merge upstream/master
git push origin git push origin

View File

@@ -2,7 +2,7 @@ resources:
containers: containers:
- container: linux-x64 - container: linux-x64
image: sqltoolscontainers.azurecr.io/linux-build-agent:3 image: sqltoolscontainers.azurecr.io/linux-build-agent:3
endpoint: SqlToolsContainers endpoint: ContainerRegistry
jobs: jobs:
- job: Compile - job: Compile
@@ -20,7 +20,7 @@ jobs:
- job: macOS - job: macOS
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), ne(variables['VSCODE_QUALITY'], 'saw')) condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), ne(variables['VSCODE_QUALITY'], 'saw'))
pool: pool:
vmImage: 'macOS-10.15' vmImage: macOS-latest
dependsOn: dependsOn:
- Compile - Compile
steps: steps:
@@ -30,7 +30,7 @@ jobs:
- job: macOS_Signing - job: macOS_Signing
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), eq(variables['signed'], true), ne(variables['VSCODE_QUALITY'], 'saw')) condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), eq(variables['signed'], true), ne(variables['VSCODE_QUALITY'], 'saw'))
pool: pool:
vmImage: 'macOS-10.15' vmImage: macOS-latest
dependsOn: dependsOn:
- macOS - macOS
steps: steps:
@@ -53,7 +53,7 @@ jobs:
- job: Windows - job: Windows
condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32'], 'true'))
pool: pool:
vmImage: 'windows-2019' vmImage: VS2017-Win2016
dependsOn: dependsOn:
- Compile - Compile
steps: steps:

View File

@@ -2,7 +2,7 @@ resources:
containers: containers:
- container: linux-x64 - container: linux-x64
image: sqltoolscontainers.azurecr.io/web-build-image:2 image: sqltoolscontainers.azurecr.io/web-build-image:2
endpoint: SqlToolsContainers endpoint: ContainerRegistry
jobs: jobs:
- job: LinuxWeb - job: LinuxWeb

View File

@@ -43,7 +43,6 @@ steps:
path: .build/node_modules_cache path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore Cache - Node Modules displayName: Restore Cache - Node Modules
continueOnError: true
- script: | - script: |
set -e set -e
@@ -109,7 +108,7 @@ steps:
set -e set -e
node ./node_modules/playwright/install.js node ./node_modules/playwright/install.js
APP_ROOT=$(Agent.BuildDirectory)/vscode-reh-web-linux-x64 APP_ROOT=$(Agent.BuildDirectory)/vscode-reh-web-linux-x64
xvfb-run yarn smoketest --build "$(Agent.BuildDirectory)/vscode-reh-web-linux-x64" --web --headless --screenshots "$(Build.ArtifactStagingDirectory)/smokeshots" --log "$(Build.ArtifactStagingDirectory)/logs/web/smoke.log" xvfb-run yarn smoketest --build "$(Agent.BuildDirectory)/vscode-reh-web-linux-x64" --web --headless --screenshots "$(Build.ArtifactStagingDirectory)/smokeshots"
displayName: Run smoke tests (Browser) displayName: Run smoke tests (Browser)
continueOnError: true continueOnError: true
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true')) condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
@@ -171,7 +170,7 @@ steps:
displayName: 'Install .NET Core sdk for signing' displayName: 'Install .NET Core sdk for signing'
inputs: inputs:
packageType: sdk packageType: sdk
version: 5.0.x version: 2.1.x
installationPath: $(Agent.ToolsDirectory)/dotnet installationPath: $(Agent.ToolsDirectory)/dotnet
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1

View File

@@ -27,7 +27,7 @@ steps:
- powershell: | - powershell: |
. build/azure-pipelines/win32/exec.ps1 . build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
exec { tar -xf $(Pipeline.Workspace)/compilation.tar.gz } exec { tar --force-local -xzf $(Pipeline.Workspace)/compilation.tar.gz }
displayName: Extract compilation output displayName: Extract compilation output
- powershell: | - powershell: |
@@ -57,7 +57,6 @@ steps:
path: .build/node_modules_cache path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore Cache - Node Modules displayName: Restore Cache - Node Modules
continueOnError: true
- powershell: | - powershell: |
. build/azure-pipelines/win32/exec.ps1 . build/azure-pipelines/win32/exec.ps1

View File

@@ -65,8 +65,5 @@
"watch": "tsc -p tsconfig.build.json --watch", "watch": "tsc -p tsconfig.build.json --watch",
"npmCheckJs": "tsc --noEmit" "npmCheckJs": "tsc --noEmit"
}, },
"dependencies": {}, "dependencies": {}
"resolutions": {
"json-schema": "0.4.0"
}
} }

View File

@@ -1382,10 +1382,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1: json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"

View File

@@ -2,7 +2,7 @@
"name": "agent", "name": "agent",
"displayName": "SQL Server Agent", "displayName": "SQL Server Agent",
"description": "Manage and troubleshoot SQL Server Agent jobs", "description": "Manage and troubleshoot SQL Server Agent jobs",
"version": "0.49.0", "version": "0.49.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -1,10 +1,27 @@
{ {
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python",
"version": "3.6.6",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "82e60c1a-7acf-47ee-877f-9e85e92e11da"
},
"source": [ "source": [
"![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/main/extensions/arc/images/microsoft-small-logo.png)\n", "![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/main/extensions/arc/images/microsoft-small-logo.png)\n",
" \n", " \n",
@@ -16,13 +33,13 @@
"* The **Required information** will check and prompt you for password if it is not set in the environment variable. The password can be used to access the data controller.\n", "* The **Required information** will check and prompt you for password if it is not set in the environment variable. The password can be used to access the data controller.\n",
"\n", "\n",
"<span style=\"color:red\"><font size=\"3\">Please press the \"Run All\" button to run the notebook</font></span>" "<span style=\"color:red\"><font size=\"3\">Please press the \"Run All\" button to run the notebook</font></span>"
] ],
"metadata": {
"azdata_cell_guid": "82e60c1a-7acf-47ee-877f-9e85e92e11da"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "714582b9-10ee-409e-ab12-15a4825c9471"
},
"source": [ "source": [
"### **Prerequisites** \n", "### **Prerequisites** \n",
"Ensure the following tools are installed and added to PATH before proceeding.\n", "Ensure the following tools are installed and added to PATH before proceeding.\n",
@@ -32,25 +49,23 @@
"|kubectl | Command-line tool for monitoring the underlying Kubernetes cluster | [Installation](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-using-native-package-management) |\n", "|kubectl | Command-line tool for monitoring the underlying Kubernetes cluster | [Installation](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-using-native-package-management) |\n",
"|Azure CLI (az) | Command-line tool for installing and managing resources in an Azure Arc cluster |[Installation](https://docs.microsoft.com/cli/azure/install-azure-cli-windows?tabs=azure-cli) |\n", "|Azure CLI (az) | Command-line tool for installing and managing resources in an Azure Arc cluster |[Installation](https://docs.microsoft.com/cli/azure/install-azure-cli-windows?tabs=azure-cli) |\n",
"|Azure CLI arcdata extension | Commands for using Azure Arc for Azure data services. | [Installation](https://docs.microsoft.com/azure/azure-arc/data/install-arcdata-extension)" "|Azure CLI arcdata extension | Commands for using Azure Arc for Azure data services. | [Installation](https://docs.microsoft.com/azure/azure-arc/data/install-arcdata-extension)"
] ],
"metadata": {
"azdata_cell_guid": "714582b9-10ee-409e-ab12-15a4825c9471"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2"
},
"source": [ "source": [
"### **Setup**" "### **Setup**"
] ],
"metadata": {
"azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "d973d5b4-7f0a-4a9d-b204-a16480f3940d",
"tags": []
},
"outputs": [],
"source": [ "source": [
"import sys,os,getpass\n", "import sys,os,getpass\n",
"def run_command(command):\n", "def run_command(command):\n",
@@ -59,56 +74,56 @@
" if _exit_code != 0:\n", " if _exit_code != 0:\n",
" sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{command}\\n')\n", " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{command}\\n')\n",
" print(f'Successfully executed: {command}')" " print(f'Successfully executed: {command}')"
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "d973d5b4-7f0a-4a9d-b204-a16480f3940d",
"tags": []
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "4b266b2d-bd1b-4565-92c9-3fc146cdce6d"
},
"source": [ "source": [
"### **Set variables**\n", "### **Set variables**\n",
"Generated by Azure Data Studio using the values collected in the 'Create Azure Arc data controller' wizard." "Generated by Azure Data Studio using the values collected in the 'Create Azure Arc data controller' wizard."
] ],
"metadata": {
"azdata_cell_guid": "4b266b2d-bd1b-4565-92c9-3fc146cdce6d"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "2544648b-59c9-4ce5-a3b6-87086e214d4c"
},
"source": [ "source": [
"### **Check dependencies**" "### **Check dependencies**"
] ],
"metadata": {
"azdata_cell_guid": "2544648b-59c9-4ce5-a3b6-87086e214d4c"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"source": [
"run_command('az --version')"
],
"outputs": [],
"metadata": { "metadata": {
"azdata_cell_guid": "691671d7-3f05-406c-a183-4cff7d17f83d", "azdata_cell_guid": "691671d7-3f05-406c-a183-4cff7d17f83d",
"tags": [] "tags": []
}, }
"outputs": [],
"source": [
"run_command('az --version')"
]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "0bb02e76-fee8-4dbc-a75b-d5b9d1b187d0"
},
"source": [ "source": [
"### **Required information**" "### **Required information**"
] ],
"metadata": {
"azdata_cell_guid": "0bb02e76-fee8-4dbc-a75b-d5b9d1b187d0"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "e7e10828-6cae-45af-8c2f-1484b6d4f9ac",
"tags": []
},
"outputs": [],
"source": [ "source": [
"if \"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\" in os.environ:\n", "if \"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\" in os.environ:\n",
" arc_admin_password = os.environ[\"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\"]\n", " arc_admin_password = os.environ[\"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\"]\n",
@@ -120,130 +135,85 @@
" confirm_password = getpass.getpass(prompt = 'Confirm password')\n", " confirm_password = getpass.getpass(prompt = 'Confirm password')\n",
" if arc_admin_password != confirm_password:\n", " if arc_admin_password != confirm_password:\n",
" sys.exit(f'Passwords do not match.')" " sys.exit(f'Passwords do not match.')"
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "e7e10828-6cae-45af-8c2f-1484b6d4f9ac",
"tags": []
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "127c8042-181f-4862-a390-96e59c181d09"
},
"source": [ "source": [
"### **Set and show current context**" "### **Set and show current context**"
] ],
"metadata": {
"azdata_cell_guid": "127c8042-181f-4862-a390-96e59c181d09"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "7d1a03d4-1df8-48eb-bff0-0042603b95b1",
"tags": []
},
"outputs": [],
"source": [ "source": [
"os.environ[\"KUBECONFIG\"] = arc_config_file\n", "os.environ[\"KUBECONFIG\"] = arc_config_file\n",
"run_command(f'kubectl config use-context {arc_cluster_context}')\n", "run_command(f'kubectl config use-context {arc_cluster_context}')\n",
"run_command('kubectl config current-context')" "run_command('kubectl config current-context')"
] ],
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### **Log in to Azure CLI**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "metadata": {
"is_indirect = arc_data_controller_connectivity_mode == 'Indirect'\n", "azdata_cell_guid": "7d1a03d4-1df8-48eb-bff0-0042603b95b1",
"\n", "tags": []
"if not is_indirect:\n", }
"\trun_command('az login')"
]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "efe78cd3-ed73-4c9b-b586-fdd6c07dd37f"
},
"source": [ "source": [
"### **Create Azure Arc Data Controller**" "### **Create Azure Arc Data Controller**"
] ],
"metadata": {
"azdata_cell_guid": "efe78cd3-ed73-4c9b-b586-fdd6c07dd37f"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "373947a1-90b9-49ee-86f4-17a4c7d4ca76",
"tags": []
},
"outputs": [],
"source": [ "source": [
"print (f'Creating Azure Arc Data Controller: {arc_data_controller_name} using configuration {arc_cluster_context}')\n", "print (f'Creating Azure Arc Data Controller: {arc_data_controller_name} using configuration {arc_cluster_context}')\n",
"os.environ[\"AZDATA_USERNAME\"] = arc_admin_username\n", "os.environ[\"AZDATA_USERNAME\"] = arc_admin_username\n",
"os.environ[\"AZDATA_PASSWORD\"] = arc_admin_password\n", "os.environ[\"AZDATA_PASSWORD\"] = arc_admin_password\n",
"\n", "\n",
"namespace = f' --k8s-namespace {arc_data_controller_namespace}' if is_indirect else ''\n",
"use_k8s = ' --use-k8s' if is_indirect else ''\n",
"\n",
"custom_location = f' --custom-location {arc_data_controller_custom_location}' if not is_indirect else ''\n",
"\n",
"auto_upload_metrics_value = 'true' if arc_data_controller_auto_upload_metrics == 'true' else 'false'\n",
"auto_upload_logs_value = 'true' if arc_data_controller_auto_upload_logs == 'true' else 'false'\n",
"\n",
"auto_upload_metrics = f' --auto-upload-metrics {auto_upload_metrics_value}' if not is_indirect else ''\n",
"auto_upload_logs = f' --auto-upload-logs {auto_upload_logs_value}' if not is_indirect else ''\n",
"\n",
"if os.name == 'nt':\n", "if os.name == 'nt':\n",
" print(f'If you don\\'t see output produced by az, you can run the following command in a terminal window to check the deployment status:\\n\\t {os.environ[\"AZDATA_NB_VAR_KUBECTL\"]} get pods -n {arc_data_controller_namespace}')\n", " print(f'If you don\\'t see output produced by az, you can run the following command in a terminal window to check the deployment status:\\n\\t {os.environ[\"AZDATA_NB_VAR_KUBECTL\"]} get pods -n {arc_data_controller_namespace}')\n",
"run_command(f'az arcdata dc create --connectivity-mode {arc_data_controller_connectivity_mode} --name {arc_data_controller_name}{namespace} --subscription {arc_subscription} --resource-group {arc_resource_group} --location {arc_data_controller_location} --storage-class {arc_data_controller_storage_class} --profile-name {arc_profile} --infrastructure {arc_infrastructure}{custom_location}{auto_upload_metrics}{auto_upload_logs}{use_k8s}')\n", "run_command(f'az arcdata dc create --connectivity-mode indirect --name {arc_data_controller_name} --k8s-namespace {arc_data_controller_namespace} --subscription {arc_subscription} --resource-group {arc_resource_group} --location {arc_data_controller_location} --storage-class {arc_data_controller_storage_class} --profile-name {arc_profile} --infrastructure {arc_infrastructure} --use-k8s')\n",
"print(f'Azure Arc Data Controller: {arc_data_controller_name} created.') " "print(f'Azure Arc Data Controller: {arc_data_controller_name} created.') "
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "373947a1-90b9-49ee-86f4-17a4c7d4ca76",
"tags": []
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "a3ddc701-811d-4058-b3fb-b7295fcf50ae"
},
"source": [ "source": [
"### **Setting context to created Azure Arc Data Controller**" "### **Setting context to created Azure Arc Data Controller**"
] ],
"metadata": {
"azdata_cell_guid": "a3ddc701-811d-4058-b3fb-b7295fcf50ae"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "c974561f-13d0-4e7a-b74b-d781c2e06d68"
},
"outputs": [],
"source": [ "source": [
"# Setting context to Data Controller.\n", "# Setting context to Data Controller.\n",
"#\n", "#\n",
"run_command(f'kubectl config set-context --current --namespace {arc_data_controller_namespace}')" "run_command(f'kubectl config set-context --current --namespace {arc_data_controller_namespace}')"
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "c974561f-13d0-4e7a-b74b-d781c2e06d68"
}
} }
], ]
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
} }

View File

@@ -1,10 +1,28 @@
{ {
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3",
"language": "python"
},
"language_info": {
"name": "python",
"version": "3.6.6",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "e4ed0892-7b5a-4d95-bd0d-a6c3eb0b2c99"
},
"source": [ "source": [
"![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/main/extensions/arc/images/microsoft-small-logo.png)\n", "![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/main/extensions/arc/images/microsoft-small-logo.png)\n",
" \n", " \n",
@@ -16,13 +34,13 @@
"* Make sure you have the target Azure Arc Data Controller already created.\n", "* Make sure you have the target Azure Arc Data Controller already created.\n",
"\n", "\n",
"<span style=\"color:red\"><font size=\"3\">Please press the \"Run All\" button to run the notebook</font></span>" "<span style=\"color:red\"><font size=\"3\">Please press the \"Run All\" button to run the notebook</font></span>"
] ],
"metadata": {
"azdata_cell_guid": "e4ed0892-7b5a-4d95-bd0d-a6c3eb0b2c99"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "d1c8258e-9efd-4380-a48c-cd675423ed2f"
},
"source": [ "source": [
"### **Prerequisites** \n", "### **Prerequisites** \n",
"Ensure the following tools are installed and added to PATH before proceeding.\n", "Ensure the following tools are installed and added to PATH before proceeding.\n",
@@ -31,25 +49,23 @@
"|---|---|---|\n", "|---|---|---|\n",
"|Azure CLI (az) | Command-line tool for installing and managing resources in an Azure Arc cluster |[Installation](https://docs.microsoft.com/cli/azure/install-azure-cli-windows?tabs=azure-cli) |\n", "|Azure CLI (az) | Command-line tool for installing and managing resources in an Azure Arc cluster |[Installation](https://docs.microsoft.com/cli/azure/install-azure-cli-windows?tabs=azure-cli) |\n",
"|Azure CLI arcdata extension | Commands for using Azure Arc for Azure data services. | [Installation](https://docs.microsoft.com/azure/azure-arc/data/install-arcdata-extension)" "|Azure CLI arcdata extension | Commands for using Azure Arc for Azure data services. | [Installation](https://docs.microsoft.com/azure/azure-arc/data/install-arcdata-extension)"
] ],
"metadata": {
"azdata_cell_guid": "d1c8258e-9efd-4380-a48c-cd675423ed2f"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "68531b91-ddce-47d7-a1d8-2ddc3d17f3e7"
},
"source": [ "source": [
"### **Setup and Check Prerequisites**" "### **Setup and Check Prerequisites**"
] ],
"metadata": {
"azdata_cell_guid": "68531b91-ddce-47d7-a1d8-2ddc3d17f3e7"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "749d8dba-3da8-46e9-ae48-2b38056ab7a2",
"tags": []
},
"outputs": [],
"source": [ "source": [
"import sys,os,json,subprocess\n", "import sys,os,json,subprocess\n",
"def run_command():\n", "def run_command():\n",
@@ -64,37 +80,38 @@
" return output.stdout.decode(\"utf-8\")\n", " return output.stdout.decode(\"utf-8\")\n",
"cmd = 'az --version'\n", "cmd = 'az --version'\n",
"out = run_command()\n" "out = run_command()\n"
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "749d8dba-3da8-46e9-ae48-2b38056ab7a2",
"tags": []
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "68ec0760-27d1-4ded-9a9f-89077c40b8bb"
},
"source": [ "source": [
"### **Set variables**\n", "### **Set variables**\n",
"\n", "\n",
"#### \n", "#### \n",
"\n", "\n",
"Generated by Azure Data Studio using the values collected in the 'Deploy Azure SQL managed instance - Azure Arc' wizard" "Generated by Azure Data Studio using the values collected in the 'Deploy Azure SQL managed instance - Azure Arc' wizard"
] ],
"metadata": {
"azdata_cell_guid": "68ec0760-27d1-4ded-9a9f-89077c40b8bb"
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"azdata_cell_guid": "90b0e162-2987-463f-9ce6-12dda1267189"
},
"source": [ "source": [
"### **Creating the SQL managed instance - Azure Arc instance**" "### **Creating the SQL managed instance - Azure Arc instance**"
] ],
"metadata": {
"azdata_cell_guid": "90b0e162-2987-463f-9ce6-12dda1267189"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {
"azdata_cell_guid": "4fbaf071-55a1-40bc-be7e-7b9b5547b886"
},
"outputs": [],
"source": [ "source": [
"print (f'Creating the SQL managed instance - Azure Arc instance')\n", "print (f'Creating the SQL managed instance - Azure Arc instance')\n",
"\n", "\n",
@@ -107,44 +124,24 @@
"storage_class_datalogs_option = f' --storage-class-datalogs \"{sql_storage_class_datalogs}\"'if sql_storage_class_datalogs else \"\"\n", "storage_class_datalogs_option = f' --storage-class-datalogs \"{sql_storage_class_datalogs}\"'if sql_storage_class_datalogs else \"\"\n",
"storage_class_logs_option = f' --storage-class-logs \"{sql_storage_class_logs}\"'if sql_storage_class_logs else \"\"\n", "storage_class_logs_option = f' --storage-class-logs \"{sql_storage_class_logs}\"'if sql_storage_class_logs else \"\"\n",
"storage_class_backup_option = f' --storage-class-backups \"{sql_storage_class_backups}\"'if sql_storage_class_backups else \"\"\n", "storage_class_backup_option = f' --storage-class-backups \"{sql_storage_class_backups}\"'if sql_storage_class_backups else \"\"\n",
"retention_days = f' --retention-days \"{sql_retention_days}\"' if sql_retention_days else \"\"\n", "retention_days = f' --retention-days \"{sql_retention_days}\"' if sql_retention_days else \"\"\n",
"\n", "\n",
"volume_size_data = f' --volume-size-data {sql_volume_size_data}Gi'\n", "volume_size_data = f' --volume-size-data {sql_volume_size_data}Gi'\n",
"volume_size_datalogs = f' --volume-size-datalogs {sql_volume_size_datalogs}Gi'\n", "volume_size_datalogs = f' --volume-size-datalogs {sql_volume_size_datalogs}Gi'\n",
"volume_size_logs = f' --volume-size-logs {sql_volume_size_logs}Gi'\n", "volume_size_logs = f' --volume-size-logs {sql_volume_size_logs}Gi'\n",
"volume_size_backups = f' --volume-size-backups {sql_volume_size_backups}Gi'\n", "volume_size_backups = f' --volume-size-backups {sql_volume_size_backups}Gi'\n",
"\n", "\n",
"service_tier = f' --tier {sql_service_tier}'\n",
"cores_limit = f' --cores-limit {sql_cores_limit}'\n",
"dev_use = ' --dev' if sql_dev_use else ''\n",
"license_type = ' --license-type BasePrice' if sql_license_type else ' --license-type LicenseIncluded'\n",
"\n",
"os.environ[\"AZDATA_USERNAME\"] = sql_username\n", "os.environ[\"AZDATA_USERNAME\"] = sql_username\n",
"os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_SQL_PASSWORD\"]\n", "os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_SQL_PASSWORD\"]\n",
"cmd = f'az sql mi-arc create --name {sql_instance_name} --k8s-namespace {arc_data_controller_namespace} --replicas {sql_replicas}{cores_request_option}{cores_limit_option}{memory_request_option}{memory_limit_option}{storage_class_data_option}{storage_class_datalogs_option}{storage_class_logs_option}{storage_class_backup_option}{volume_size_data}{volume_size_datalogs}{volume_size_logs}{volume_size_backups}{retention_days}{service_tier}{dev_use}{license_type}{cores_limit} --use-k8s'\n", "cmd = f'az sql mi-arc create --name {sql_instance_name} --k8s-namespace {arc_data_controller_namespace} --replicas {sql_replicas}{cores_request_option}{cores_limit_option}{memory_request_option}{memory_limit_option}{storage_class_data_option}{storage_class_datalogs_option}{storage_class_logs_option}{storage_class_backup_option}{volume_size_data}{volume_size_datalogs}{volume_size_logs}{volume_size_backups}{retention_days} --use-k8s'\n",
"out=run_command()" "out=run_command()"
] ],
"outputs": [],
"metadata": {
"azdata_cell_guid": "4fbaf071-55a1-40bc-be7e-7b9b5547b886"
}
} }
], ]
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
} }

View File

@@ -261,20 +261,6 @@
"label": "%arc.data.controller.details.description%", "label": "%arc.data.controller.details.description%",
"labelWidth": "600px" "labelWidth": "600px"
}, },
{
"type": "options",
"label": "%arc.data.controller.connectivity.mode%",
"required": true,
"variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE",
"options": {
"values": [
"Indirect",
"Direct"
],
"defaultValue": "Indirect",
"optionsType": "radio"
}
},
{ {
"type": "text", "type": "text",
"label": "%arc.data.controller.namespace%", "label": "%arc.data.controller.namespace%",
@@ -287,11 +273,7 @@
], ],
"defaultValue": "arc", "defaultValue": "arc",
"required": true, "required": true,
"variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAMESPACE", "variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAMESPACE"
"enabled": {
"target": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE",
"value": "Indirect"
}
}, },
{ {
"type": "text", "type": "text",
@@ -328,39 +310,6 @@
"onpremises", "onpremises",
"other" "other"
] ]
},
{
"type": "text",
"label": "%arc.data.controller.custom.location%",
"description": "%arc.data.controller.custom.location.description%",
"required": true,
"variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CUSTOM_LOCATION",
"enabled": {
"target": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE",
"value": "Direct"
}
},
{
"type": "checkbox",
"label": "%arc.data.controller.auto.upload.metrics%",
"variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_AUTO_UPLOAD_METRICS",
"description": "%arc.data.controller.auto.upload.metrics.description%",
"defaultValue": false,
"enabled": {
"target": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE",
"value": "Direct"
}
},
{
"type": "checkbox",
"label": "%arc.data.controller.auto.upload.logs%",
"variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_AUTO_UPLOAD_LOGS",
"description": "%arc.data.controller.auto.upload.logs.description%",
"defaultValue": false,
"enabled": {
"target": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE",
"value": "Direct"
}
} }
] ]
}, },
@@ -1040,7 +989,7 @@
"fields": [ "fields": [
{ {
"type": "options", "type": "options",
"label": "%arc.sql.replicas%", "label": "%arc.sql.high.availability.label%",
"description": "%arc.sql.high.availability.description%", "description": "%arc.sql.high.availability.description%",
"required": true, "required": true,
"variableName": "AZDATA_NB_VAR_SQL_REPLICAS", "variableName": "AZDATA_NB_VAR_SQL_REPLICAS",
@@ -1136,7 +1085,6 @@
"variableName": "AZDATA_NB_VAR_SQL_CORES_REQUEST", "variableName": "AZDATA_NB_VAR_SQL_CORES_REQUEST",
"type": "number", "type": "number",
"min": 1, "min": 1,
"defaultValue": 2,
"required": false, "required": false,
"validations": [ "validations": [
{ {
@@ -1153,7 +1101,6 @@
"type": "number", "type": "number",
"min": 1, "min": 1,
"required": false, "required": false,
"defaultValue": 4,
"validations": [ "validations": [
{ {
"type": ">=", "type": ">=",
@@ -1168,7 +1115,6 @@
"variableName": "AZDATA_NB_VAR_SQL_MEMORY_REQUEST", "variableName": "AZDATA_NB_VAR_SQL_MEMORY_REQUEST",
"type": "number", "type": "number",
"min": 2, "min": 2,
"defaultValue": 4,
"required": false, "required": false,
"validations": [ "validations": [
{ {
@@ -1184,7 +1130,6 @@
"variableName": "AZDATA_NB_VAR_SQL_MEMORY_LIMIT", "variableName": "AZDATA_NB_VAR_SQL_MEMORY_LIMIT",
"type": "number", "type": "number",
"min": 2, "min": 2,
"defaultValue": 8,
"required": false, "required": false,
"validations": [ "validations": [
{ {
@@ -1197,9 +1142,9 @@
{ {
"type": "options", "type": "options",
"label": "%arc.sql.service.tier.label%", "label": "%arc.sql.service.tier.label%",
"variableName": "AZDATA_NB_VAR_SQL_SERVICE_TIER",
"description": "%arc.sql.service.tier.description%", "description": "%arc.sql.service.tier.description%",
"required": true, "required": true,
"variableName": "AZDATA_NB_VAR_SQL_SERVICE_TIER",
"options": { "options": {
"values": [ "values": [
"%arc.sql.service.tier.business.critical%", "%arc.sql.service.tier.business.critical%",
@@ -1212,16 +1157,10 @@
{ {
"type": "checkbox", "type": "checkbox",
"label": "%arc.sql.dev.use.label%", "label": "%arc.sql.dev.use.label%",
"variableName": "AZDATA_NB_VAR_SQL_DEV_USE",
"description": "%arc.sql.dev.use.description%", "description": "%arc.sql.dev.use.description%",
"defaultValue": false "defaultValue": "false",
}, "variableName": "AZDATA_NB_VAR_SQL_DEV_USE",
{ "required": true
"type": "checkbox",
"label": "%arc.sql.license.type.label%",
"variableName": "AZDATA_NB_VAR_SQL_LICENSE_TYPE",
"description": "%arc.sql.license.type.description%",
"defaultValue": false
} }
] ]
}, },
@@ -1246,85 +1185,13 @@
"description": "%arc.sql.retention.days.description%", "description": "%arc.sql.retention.days.description%",
"variableName": "AZDATA_NB_VAR_SQL_RETENTION_DAYS", "variableName": "AZDATA_NB_VAR_SQL_RETENTION_DAYS",
"type": "number", "type": "number",
"min": 0, "min": 1,
"max": 35, "max": 35,
"required": false "required": false
} }
] ]
},
{
"title": "%arc.sql.cost.summary%",
"fields": [
{
"label": "%arc.sql.cost.summary.additional.charge%",
"type": "readonly_text",
"enabled": true,
"labelWidth": "750px",
"links": [
{
"text": "%arc.sql.cost.summary.pricing.details%",
"url": "https://aka.ms/ArcSQLBilling"
}
]
},
{
"label": "%arc.sql.cost.summary.cost.vcore%",
"type": "readonly_text",
"isEvaluated": true,
"defaultValue": "0.00 USD",
"valueProvider": {
"providerId": "params-to-cost-per-vcore",
"triggerFields": [
"AZDATA_NB_VAR_SQL_DEV_USE",
"AZDATA_NB_VAR_SQL_SERVICE_TIER"
]
}
},
{
"label": "%arc.sql.cost.summary.vcore.limit%",
"type": "readonly_text",
"isEvaluated": true,
"defaultValue": "x 4",
"valueProvider": {
"providerId": "params-to-vcore-limit",
"triggerFields": [
"AZDATA_NB_VAR_SQL_CORES_LIMIT"
]
}
},
{
"label": "%arc.sql.cost.summary.azure.hybrid.benefit.discount%",
"type": "readonly_text",
"isEvaluated": true,
"defaultValue": "- 0",
"valueProvider": {
"providerId": "params-to-hybrid-benefit-discount",
"triggerFields": [
"AZDATA_NB_VAR_SQL_CORES_LIMIT",
"AZDATA_NB_VAR_SQL_DEV_USE",
"AZDATA_NB_VAR_SQL_SERVICE_TIER",
"AZDATA_NB_VAR_SQL_LICENSE_TYPE"
]
}
},
{
"label": "%arc.sql.cost.summary.estimated.cost.per.month%",
"type": "readonly_text",
"defaultValue": "0.00 USD",
"valueProvider": {
"providerId": "params-to-estimated-cost",
"triggerFields": [
"AZDATA_NB_VAR_SQL_REPLICAS",
"AZDATA_NB_VAR_SQL_CORES_LIMIT",
"AZDATA_NB_VAR_SQL_DEV_USE",
"AZDATA_NB_VAR_SQL_SERVICE_TIER",
"AZDATA_NB_VAR_SQL_LICENSE_TYPE"
]
}
}
]
} }
] ]
} }
] ]
}, },
@@ -1374,6 +1241,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"request": "^2.88.0",
"uuid": "^8.3.0", "uuid": "^8.3.0",
"vscode-nls": "^4.1.2", "vscode-nls": "^4.1.2",
"yamljs": "^0.3.0" "yamljs": "^0.3.0"
@@ -1381,6 +1249,7 @@
"devDependencies": { "devDependencies": {
"@types/mocha": "^5.2.5", "@types/mocha": "^5.2.5",
"@types/node": "^12.11.7", "@types/node": "^12.11.7",
"@types/request": "^2.48.3",
"@types/sinon": "^9.0.4", "@types/sinon": "^9.0.4",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/yamljs": "^0.2.31", "@types/yamljs": "^0.2.31",

View File

@@ -10,7 +10,6 @@
"command.removeController.title": "Remove Controller", "command.removeController.title": "Remove Controller",
"command.refresh.title": "Refresh", "command.refresh.title": "Refresh",
"command.editConnection.title": "Edit Connection", "command.editConnection.title": "Edit Connection",
"command.estimateCostSqlMiaa.title": "Estimate Cost of SQL Managed Instance - Azure Arc",
"arc.openDashboard": "Manage", "arc.openDashboard": "Manage",
"resource.type.azure.arc.display.name": "Azure Arc data controller (preview)", "resource.type.azure.arc.display.name": "Azure Arc data controller (preview)",
@@ -28,22 +27,13 @@
"arc.data.controller.project.details.title": "Azure details", "arc.data.controller.project.details.title": "Azure details",
"arc.data.controller.project.details.description": "Select the subscription to manage deployed resources and costs. Use resource groups like folders to organize and manage all your resources.", "arc.data.controller.project.details.description": "Select the subscription to manage deployed resources and costs. Use resource groups like folders to organize and manage all your resources.",
"arc.data.controller.details.title": "Data controller details", "arc.data.controller.details.title": "Data controller details",
"arc.data.controller.details.description": "For indirect mode, provide a namespace, name and storage class for your Azure Arc data controller. This name will be used to identify your Arc instance for remote management and monitoring. For direct mode you do not need to provide a namespace, but please provide the custom location name.", "arc.data.controller.details.description": "Provide a namespace, name and storage class for your Azure Arc data controller. This name will be used to identify your Arc instance for remote management and monitoring.",
"arc.data.controller.connectivity.mode": "Connectivity mode",
"arc.data.controller.namespace": "Data controller namespace", "arc.data.controller.namespace": "Data controller namespace",
"arc.data.controller.namespace.description": "Indirect mode only.",
"arc.data.controller.namespace.validation.description": "Namespace must consist of lower case alphanumeric characters or '-', start/end with an alphanumeric character, and be 63 characters or fewer in length.", "arc.data.controller.namespace.validation.description": "Namespace must consist of lower case alphanumeric characters or '-', start/end with an alphanumeric character, and be 63 characters or fewer in length.",
"arc.data.controller.name": "Data controller name", "arc.data.controller.name": "Data controller name",
"arc.data.controller.name.validation.description": "Name must consist of lower case alphanumeric characters, '-' or '.', start/end with an alphanumeric character and be 253 characters or less in length.", "arc.data.controller.name.validation.description": "Name must consist of lower case alphanumeric characters, '-' or '.', start/end with an alphanumeric character and be 253 characters or less in length.",
"arc.data.controller.location": "Location", "arc.data.controller.location": "Location",
"arc.data.controller.infrastructure": "Infrastructure", "arc.data.controller.infrastructure": "Infrastructure",
"arc.data.controller.custom.location": "Custom Location",
"arc.data.controller.custom.location.description": "The name of the custom location. Direct mode only.",
"arc.data.controller.auto.upload.metrics": "Auto-upload Metrics",
"arc.data.controller.auto.upload.metrics.description": "Enable the automatic upload of metrics. Direct mode only.",
"arc.data.controller.auto.upload.logs": "Auto-upload Logs",
"arc.data.controller.auto.upload.logs.description": "Enable the automatic upload of logs. Direct mode only.",
"arc.data.controller.admin.account.title": "Administrator account", "arc.data.controller.admin.account.title": "Administrator account",
"arc.data.controller.admin.account.name": "Data controller login", "arc.data.controller.admin.account.name": "Data controller login",
"arc.data.controller.admin.account.password": "Password", "arc.data.controller.admin.account.password": "Password",
@@ -97,39 +87,15 @@
"arc.sql.invalid.instance.name": "Instance name must consist of lower case alphanumeric characters or '-', start with a letter, end with an alphanumeric character, and be 13 characters or fewer in length.", "arc.sql.invalid.instance.name": "Instance name must consist of lower case alphanumeric characters or '-', start with a letter, end with an alphanumeric character, and be 13 characters or fewer in length.",
"arc.storage-class.dc.label": "Storage Class", "arc.storage-class.dc.label": "Storage Class",
"arc.sql.storage-class.dc.description": "The storage class to be used for all data and logs persistent volumes for all data controller pods that require them.", "arc.sql.storage-class.dc.description": "The storage class to be used for all data and logs persistent volumes for all data controller pods that require them.",
"arc.sql.replicas": "Replicas", "arc.sql.high.availability.label": "High Availability",
"arc.sql.high.availability.description": "Enable additional replicas for high availabilty. The compute and storage configuration selected below will be applied to all replicas. Choose from: General Purpose (Up to 24 vCores and 128 Gi of RAM, standard high availability) or [PREVIEW] Business Critical (Unlimited vCores and RAM, advanced high availability).", "arc.sql.high.availability.description": "Enable additional replicas for high availabilty. The compute and storage configuration selected below will be applied to all replicas.",
"arc.sql.service.tier.general.purpose": "GeneralPurpose", "arc.sql.service.tier.general.purpose": "General Purpose (Up to 24 vCores and 128 Gi of RAM, standard high availability)",
"arc.sql.service.tier.business.critical": "BusinessCritical", "arc.sql.service.tier.business.critical": "[PREVIEW] Business Critical (Unlimited vCores and RAM, advanced high availability)",
"arc.sql.one.replica": "1", "arc.sql.one.replica": "1 replica",
"arc.sql.two.replicas": "2", "arc.sql.two.replicas": "2 replicas",
"arc.sql.three.replicas": "3", "arc.sql.three.replicas": "3 replicas",
"arc.storage-class.data.label": "Storage Class (Data)", "arc.storage-class.data.label": "Storage Class (Data)",
"arc.sql.storage-class.data.description": "The storage class to be used for data (.mdf). If no value is specified, the default storage class will be used.", "arc.sql.storage-class.data.description": "The storage class to be used for data (.mdf). If no value is specified, the default storage class will be used.",
"arc.sql.cost.summary.sql.miaa.cost.summary": "SQL Managed Instance - Azure Arc Cost Summary",
"arc.sql.cost.summary.sql.miaa": "SQL managed instance - Azure Arc",
"arc.sql.cost.summary.estimated.cost.per.month": "Estimated cost per month",
"arc.sql.summary.arc.by.microsoft" : "by Microsoft",
"arc.sql.cost.summary": "Cost Summary",
"arc.sql.cost.summary.service.tier": "Service Tier",
"arc.sql.cost.summary.general.purpose": "General Purpose",
"arc.sql.cost.summary.business.critical": "Business Critical",
"arc.sql.cost.summary.cost.vcore": "Cost per vCore (in USD)",
"arc.sql.cost.summary.vcore.limit": "CPU vCores Limit",
"arc.sql.cost.summary.azure.hybrid.benefit.discount": "Azure Hybrid Benefit discount (in USD)",
"arc.sql.cost.summary.sql.connection.info": "SQL Connection Information",
"arc.sql.cost.summary.sql.instance.settings": "SQL Instance Settings",
"arc.sql.cost.summary.service.tier.learn.more.description": "Select from the latest vCore service tiers available for SQL Managed Instance - Azure Arc including General Purpose and Business Critical. {0}",
"arc.sql.cost.summary.service.tier.learn.more.text": "Learn more",
"arc.sql.cost.summary.basics": "Basics",
"arc.sql.cost.summary.subscription": "Subscription",
"arc.sql.cost.summary.resource.group": "Resource group",
"arc.sql.cost.summary.instance.name": "Instance name",
"arc.sql.cost.summary.custom.location": "Custom location",
"arc.sql.cost.summary.admin.account": "Administrator account",
"arc.sql.cost.summary.managed.instance.admin.login": "Managed Instance admin login",
"arc.sql.cost.summary.additional.charge": "Additional charge per usage. See {0} for more detail.",
"arc.sql.cost.summary.pricing.details": "pricing details",
"arc.postgres.storage-class.data.description": "The storage class to be used for data persistent volumes", "arc.postgres.storage-class.data.description": "The storage class to be used for data persistent volumes",
"arc.storage-class.datalogs.label": "Storage Class (Database logs)", "arc.storage-class.datalogs.label": "Storage Class (Database logs)",
"arc.sql.storage-class.datalogs.description": "The storage class to be used for database logs (.ldf). If no value is specified, the default storage class will be used.", "arc.sql.storage-class.datalogs.description": "The storage class to be used for database logs (.ldf). If no value is specified, the default storage class will be used.",
@@ -157,10 +123,8 @@
"arc.sql.service.tier.label": "Service Tier", "arc.sql.service.tier.label": "Service Tier",
"arc.sql.service.tier.description": "Select from the latest vCore service tiers available for SQL Managed Instance - Azure Arc including General Purpose and Business Critical. {0}", "arc.sql.service.tier.description": "Select from the latest vCore service tiers available for SQL Managed Instance - Azure Arc including General Purpose and Business Critical. {0}",
"arc.sql.dev.use.label": "For development use only", "arc.sql.dev.use.label": "For development use only",
"arc.sql.license.type.label": "I already have a SQL Server License",
"arc.sql.license.type.description": "Apply the Azure Hybrid Benefit if you already own a SQL Server License",
"arc.sql.pitr.description": "Point in time restore", "arc.sql.pitr.description": "Point in time restore",
"arc.sql.retention.days.label": "Point in time retention (days)", "arc.sql.retention.days.label": "PITR retention (days)",
"arc.sql.retention.days.description": "Specify how long you want to keep your point-in-time backups.", "arc.sql.retention.days.description": "Specify how long you want to keep your point-in-time backups.",
"arc.sql.dev.use.description": "Check the box to indicate this instance will be used for development or testing purposes only. This instance will not be billed.", "arc.sql.dev.use.description": "Check the box to indicate this instance will be used for development or testing purposes only. This instance will not be billed.",
"arc.postgres.storage-class.backups.description": "The storage class to be used for backup persistent volumes", "arc.postgres.storage-class.backups.description": "The storage class to be used for backup persistent volumes",

View File

@@ -1,117 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InputValueType } from 'resource-deployment';
import * as loc from '../localizedConstants';
export const SqlManagedInstanceGeneralPurpose = {
tierName: loc.generalPurposeLabel,
basePricePerCore: 80,
licenseIncludedPricePerCore: 153,
maxMemorySize: 128,
maxVCores: 24,
replicaOptions: [
{
text: loc.replicaOne,
value: 1,
}
],
defaultReplicaValue: 1
};
const SqlManagedInstanceBusinessCritical = {
tierName: loc.businessCriticalLabel,
// Set to real values when BC is ready
basePricePerCore: 0,
licenseIncludedPricePerCore: 0,
replicaOptions: [
{
text: loc.replicaTwo,
value: 2,
},
{
text: loc.replicaThree,
value: 3,
}
],
defaultReplicaValue: 3
};
export const SqlManagedInstancePricingLink: string = 'https://aka.ms/ArcSQLBilling';
export const serviceTierVarName = 'AZDATA_NB_VAR_SQL_SERVICE_TIER';
export const devUseVarName = 'AZDATA_NB_VAR_SQL_DEV_USE';
export const vcoresLimitVarName = 'AZDATA_NB_VAR_SQL_CORES_LIMIT';
export const licenseTypeVarName = 'AZDATA_NB_VAR_SQL_LICENSE_TYPE';
// Estimated base price for one vCore.
export function estimatedBasePriceForOneVCore(mapping: { [key: string]: InputValueType }): number {
let price = 0;
if (mapping[devUseVarName] === 'true') {
price = 0;
} else if (mapping[devUseVarName] === 'false') {
if (mapping[serviceTierVarName] === SqlManagedInstanceGeneralPurpose.tierName) {
price = SqlManagedInstanceGeneralPurpose.basePricePerCore;
} else if (mapping[serviceTierVarName] === SqlManagedInstanceBusinessCritical.tierName) {
price = SqlManagedInstanceBusinessCritical.basePricePerCore;
}
}
return price;
}
// Estimated SQL server license price for one vCore.
export function estimatedSqlServerLicensePriceForOneVCore(mapping: { [key: string]: InputValueType }): number {
let price = 0;
if (mapping[devUseVarName] === 'true') {
price = 0;
} else if (mapping[devUseVarName] === 'false') {
if (mapping[serviceTierVarName] === SqlManagedInstanceGeneralPurpose.tierName) {
price = SqlManagedInstanceGeneralPurpose.licenseIncludedPricePerCore - SqlManagedInstanceGeneralPurpose.basePricePerCore;
} else if (mapping[serviceTierVarName] === SqlManagedInstanceBusinessCritical.tierName) {
price = SqlManagedInstanceBusinessCritical.licenseIncludedPricePerCore - SqlManagedInstanceBusinessCritical.basePricePerCore;
}
}
return price;
}
// Full price for one vCore. This is shown on the cost summary card.
export function fullPriceForOneVCore(mapping: { [key: string]: InputValueType }): number {
return estimatedBasePriceForOneVCore(mapping) + estimatedSqlServerLicensePriceForOneVCore(mapping);
}
// Gets number of vCores limit specified
export function numCores(mapping: { [key: string]: InputValueType }): number {
return mapping[vcoresLimitVarName] ? <number>mapping[vcoresLimitVarName] : 0;
}
// Full price for all selected vCores.
export function vCoreFullPriceForAllCores(mapping: { [key: string]: InputValueType }): number {
return fullPriceForOneVCore(mapping) * numCores(mapping);
}
// SQL Server License price for all vCores. This is shown on the cost summary card if customer has SQL server license.
export function vCoreSqlServerLicensePriceForAllCores(mapping: { [key: string]: InputValueType }): number {
return estimatedSqlServerLicensePriceForOneVCore(mapping) * numCores(mapping);
}
// If the customer doesn't already have SQL Server License, AHB discount is set to zero because the price will be included
// in the total cost. If they already have it (they checked the box), then a discount will be applied.
export function azureHybridBenefitDiscount(mapping: { [key: string]: InputValueType }): number {
if (mapping[licenseTypeVarName] === 'true') {
return vCoreSqlServerLicensePriceForAllCores(mapping);
} else {
return 0;
}
}
// Total price that will be charged to a customer. Is shown on the cost summary card.
export function total(mapping: { [key: string]: InputValueType }): number {
return vCoreFullPriceForAllCores(mapping) - azureHybridBenefitDiscount(mapping);
}

View File

@@ -363,11 +363,3 @@ export function debounce(delay: number): Function {
}; };
}); });
} }
export function getTimeStamp(dateTime: string | undefined): number {
return dateTime ? (new Date(dateTime)).getTime() : 0;
}
export function checkISOTimeString(dateTime: string): boolean {
return /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d.*Z/.test(dateTime);
}

View File

@@ -14,7 +14,6 @@ import { ConnectToControllerDialog } from './ui/dialogs/connectControllerDialog'
import { AzureArcTreeDataProvider } from './ui/tree/azureArcTreeDataProvider'; import { AzureArcTreeDataProvider } from './ui/tree/azureArcTreeDataProvider';
import { ControllerTreeNode } from './ui/tree/controllerTreeNode'; import { ControllerTreeNode } from './ui/tree/controllerTreeNode';
import { TreeNode } from './ui/tree/treeNode'; import { TreeNode } from './ui/tree/treeNode';
import * as pricing from './common/pricingUtils';
export async function activate(context: vscode.ExtensionContext): Promise<arc.IExtension> { export async function activate(context: vscode.ExtensionContext): Promise<arc.IExtension> {
IconPathHelper.setExtensionContext(context); IconPathHelper.setExtensionContext(context);
@@ -62,38 +61,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<arc.IE
const rdApi = <rd.IExtension>vscode.extensions.getExtension(rd.extension.name)?.exports; const rdApi = <rd.IExtension>vscode.extensions.getExtension(rd.extension.name)?.exports;
context.subscriptions.push(rdApi.registerOptionsSourceProvider(new ArcControllersOptionsSourceProvider(treeDataProvider))); context.subscriptions.push(rdApi.registerOptionsSourceProvider(new ArcControllersOptionsSourceProvider(treeDataProvider)));
// Register valueprovider for getting the calculated cost per VCore.
context.subscriptions.push(rdApi.registerValueProvider({
id: 'params-to-cost-per-vcore',
getValue: async (mapping: { [key: string]: rd.InputValueType }) => {
return pricing.fullPriceForOneVCore(mapping);
}
}));
// Register valueprovider for getting the number of CPU VCores Limit input by the user.
context.subscriptions.push(rdApi.registerValueProvider({
id: 'params-to-vcore-limit',
getValue: async (mapping: { [key: string]: rd.InputValueType }) => {
return 'x ' + pricing.numCores(mapping).toString();
}
}));
// Register valueprovider for getting the amount of hybrid benefit discount to be applied.
context.subscriptions.push(rdApi.registerValueProvider({
id: 'params-to-hybrid-benefit-discount',
getValue: async (mapping: { [key: string]: rd.InputValueType }) => {
return '- ' + pricing.azureHybridBenefitDiscount(mapping).toString();
}
}));
// Register valueprovider for getting the total estimated cost.
context.subscriptions.push(rdApi.registerValueProvider({
id: 'params-to-estimated-cost',
getValue: async (mapping: { [key: string]: rd.InputValueType }) => {
return pricing.total(mapping).toString() + ' ' + loc.USD;
}
}));
return arcApi(treeDataProvider); return arcApi(treeDataProvider);
} }

View File

@@ -60,19 +60,18 @@ export const type = localize('arc.type', "Type");
export const status = localize('arc.status', "Status"); export const status = localize('arc.status', "Status");
export const database = localize('arc.database', "Database"); export const database = localize('arc.database', "Database");
export const sourceDatabase = localize('arc.sourceDatabase', "Source database"); export const sourceDatabase = localize('arc.sourceDatabase', "Source database");
export const earliestPitrRestorePoint = localize('arc.earliestPitrRestorePoint', "Earliest point in time"); export const earliestPitrRestorePoint = localize('arc.earliestPitrRestorePoint', "Earliest PITR restore point");
export const latestpitrRestorePoint = localize('arc.latestpitrRestorePoint', "Latest point in time"); export const latestpitrRestorePoint = localize('arc.latestpitrRestorePoint', "Latest PITR restore point");
export const pitr = localize('arc.pitr', "Point in time restore"); export const pitr = localize('arc.pitr', "Point-in-time restore (PITR)");
export const projectDetails = localize('arc.projectDetails', "Project Details"); export const projectDetails = localize('arc.projectDetails', "Project Details");
export const projectDetailsText = localize('arc.projectDetailsText', "Select the subscription to manage deployed resources. Use resource groups like folders to organize and manage all your resources."); export const projectDetailsText = localize('arc.projectDetailsText', "Select the subscription to manage deployed resources. Use resource groups like folders to organize and manage all your resources.");
export const sourceDetails = localize('arc.sourceDetails', "Source Details"); export const sourceDetails = localize('arc.sourceDetails', "Source Details");
export const sourceDetailsText = localize('arc.sourceDetailsText', "Select a backup source and provide details. Additional settings will be defaulted where possible based on the selected database."); export const sourceDetailsText = localize('arc.sourceDetailsText', "Select a backup source and provide details. Additional settings will be defaulted where possible based on the selected backup.");
export const databaseDetails = localize('arc.databaseDetails', "Destination Details"); export const databaseDetails = localize('arc.databaseDetails', "Database Details");
export const restorePointDetails = localize('arc.restorePointDetails', "Restore Point Details"); export const databaseDetailsText = localize('arc.databaseDetailsText', "Enter the required settings for this database, including a name and a target managed instance. By default, the source instance is selected.");
export const databaseDetailsText = localize('arc.databaseDetailsText', "Enter the required settings for target database name and SQL managed instance. By default, the source managed instance is selected.");
export const restore = localize('arc.restore', "Restore"); export const restore = localize('arc.restore', "Restore");
export const instance = localize('arc.instance', "Instance"); export const instance = localize('arc.instance', "Instance");
export const restorePoint = localize('arc.restorePoint', "Restore point (UTC), in a time format: 'YYYY-MM-DDTHH:MM:SSZ"); export const restorePoint = localize('arc.restorePoint', "Restore point (UTC)");
export const restoreDatabase = localize('arc.restoreDatabase', "Restore Database"); export const restoreDatabase = localize('arc.restoreDatabase', "Restore Database");
export const miaaAdmin = localize('arc.miaaAdmin', "Managed instance admin"); export const miaaAdmin = localize('arc.miaaAdmin', "Managed instance admin");
export const extensionName = localize('arc.extensionName', "Extension name"); export const extensionName = localize('arc.extensionName', "Extension name");
@@ -80,7 +79,6 @@ export const extensionsDescription = localize('arc.extensionsDescription', "Post
export const extensionsFunction = localize('arc.extensionsFunction', "Some extensions must be loaded into PostgreSQL at startup time before they can be used. These preloaded extensions can be viewed and edited below."); export const extensionsFunction = localize('arc.extensionsFunction', "Some extensions must be loaded into PostgreSQL at startup time before they can be used. These preloaded extensions can be viewed and edited below.");
export function extensionsAddFunction(extensions: string): string { return localize('arc.extensionsAddFunction', "Some extensions must be loaded into PostgreSQL at startup time before they can be used. To edit, type in comma separated list of valid extensions: ({0}).", extensions); } export function extensionsAddFunction(extensions: string): string { return localize('arc.extensionsAddFunction', "Some extensions must be loaded into PostgreSQL at startup time before they can be used. To edit, type in comma separated list of valid extensions: ({0}).", extensions); }
export function extensionsAddErrorrMessage(extensions: string): string { return localize('arc.extensionsAddErrorrMessage', "Value should be either of the following: ({0}).", extensions); } export function extensionsAddErrorrMessage(extensions: string): string { return localize('arc.extensionsAddErrorrMessage', "Value should be either of the following: ({0}).", extensions); }
export function restorePointErrorMessage(earliestPoint: string, latestPoint: string) { return localize('arc.restorePointErrorrMessage', "Provide time in correct format and within range: {0} to {1}", earliestPoint, latestPoint); }
export const extensionsLearnMore = localize('arc.extensionsLearnMore', "Learn more about PostgreSQL extensions."); export const extensionsLearnMore = localize('arc.extensionsLearnMore', "Learn more about PostgreSQL extensions.");
export const extensionsTableLoading = localize('arc.extensionsTableLoading', "Table of preloaded extensions are loading."); export const extensionsTableLoading = localize('arc.extensionsTableLoading', "Table of preloaded extensions are loading.");
export const extensionsTableLabel = localize('arc.extensionsTableLabel', "Table of preloaded extensions."); export const extensionsTableLabel = localize('arc.extensionsTableLabel', "Table of preloaded extensions.");
@@ -194,8 +192,7 @@ export const postgresComputeAndStorageDescriptionPartOne = localize('arc.postgre
export const miaaComputeAndStorageDescriptionPartOne = localize('arc.miaaComputeAndStorageDescriptionPartOne', "You can scale your Azure SQL managed instance - Azure Arc by"); export const miaaComputeAndStorageDescriptionPartOne = localize('arc.miaaComputeAndStorageDescriptionPartOne', "You can scale your Azure SQL managed instance - Azure Arc by");
export const miaaBackupsDatabasesDescription = localize('arc.miaaBackupsDatabasesDescription', "Databases with available backups are displayed below. Restore databases to this instance or any other instance within the same custom location."); export const miaaBackupsDatabasesDescription = localize('arc.miaaBackupsDatabasesDescription', "Databases with available backups are displayed below. Restore databases to this instance or any other instance within the same custom location.");
export const pitrInfo = localize('arc.pitrInfo', "Specify how long you want to keep your point-in-time backups. Customize this for backup availability."); export const pitrInfo = localize('arc.pitrInfo', "Specify how long you want to keep your point-in-time backups. Customize this for backup availability.");
export const restoreInfo = localize('arc.restoreInfo', "Restore a database to an Azure Arc enabled SQL Managed Instance."); export const restoreInfo = localize('arc.restoreInfo', "Restore a database to an Azure Arc enabled SQL Managed Instance of your choice.");
export const restorePointText = localize('arc.restorePointText', "Enter a restore point in the specified time format within given range of earliest and latest restore time.");
export const postgresComputeAndStorageDescriptionPartTwo = localize('arc.postgres.computeAndStorageDescriptionPartTwo', "PostgreSQL Hyperscale server group by"); export const postgresComputeAndStorageDescriptionPartTwo = localize('arc.postgres.computeAndStorageDescriptionPartTwo', "PostgreSQL Hyperscale server group by");
export const computeAndStorageDescriptionPartThree = localize('arc.computeAndStorageDescriptionPartThree', "without downtime and by"); export const computeAndStorageDescriptionPartThree = localize('arc.computeAndStorageDescriptionPartThree', "without downtime and by");
export const computeAndStorageDescriptionPartFour = localize('arc.computeAndStorageDescriptionPartFour', "Before doing so, you need to ensure"); export const computeAndStorageDescriptionPartFour = localize('arc.computeAndStorageDescriptionPartFour', "Before doing so, you need to ensure");
@@ -277,14 +274,6 @@ export function connectionString(type: string): string { return localize({ key:
export function copyConnectionStringToClipboard(type: string): string { return localize({ key: 'arc.copyConnectionStringToClipboard', comment: ['{0} is the name of the type of connection string (e.g. Java)'] }, "Copy {0} Connection String to clipboard", type); } export function copyConnectionStringToClipboard(type: string): string { return localize({ key: 'arc.copyConnectionStringToClipboard', comment: ['{0} is the name of the type of connection string (e.g. Java)'] }, "Copy {0} Connection String to clipboard", type); }
export function copyValueToClipboard(valueName: string): string { return localize({ key: 'arc.copyValueToClipboard', comment: ['{0} is the name of the type of value being copied (e.g. Coordinator endpoint)'] }, "Copy {0} to clipboard", valueName); } export function copyValueToClipboard(valueName: string): string { return localize({ key: 'arc.copyValueToClipboard', comment: ['{0} is the name of the type of value being copied (e.g. Coordinator endpoint)'] }, "Copy {0} to clipboard", valueName); }
// Pricing Constants
export const replicaOne = localize('arc.replicaOne', "1");
export const replicaTwo = localize('arc.replicaTwo', "2");
export const replicaThree = localize('arc.replicaThree', "3");
export const generalPurposeLabel = localize('arc.generalPurposeLabel', "GeneralPurpose");
export const businessCriticalLabel = localize('arc.businessCriticalLabel', "BusinessCritical");
export const USD = localize('arc.USD', "USD");
// Errors // Errors
export const pgConnectionRequired = localize('arc.pgConnectionRequired', "A connection is required to show and set database engine settings."); export const pgConnectionRequired = localize('arc.pgConnectionRequired', "A connection is required to show and set database engine settings.");
export const miaaConnectionRequired = localize('arc.miaaConnectionRequired', "A connection is required to list the databases on this instance."); export const miaaConnectionRequired = localize('arc.miaaConnectionRequired', "A connection is required to list the databases on this instance.");
@@ -292,7 +281,6 @@ export const couldNotFindControllerRegistration = localize('arc.couldNotFindCont
export const dropMultipleExtensions = localize('arc.dropMultipleExtensions', "Currently dropping another extension, try again once that is completed."); export const dropMultipleExtensions = localize('arc.dropMultipleExtensions', "Currently dropping another extension, try again once that is completed.");
export function updateExtensionsFailed(error: any): string { return localize('arc.updateExtensionsFailed', "Editing extensions failed. {0}", getErrorMessage(error)); } export function updateExtensionsFailed(error: any): string { return localize('arc.updateExtensionsFailed', "Editing extensions failed. {0}", getErrorMessage(error)); }
export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", getErrorMessage(error)); } export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", getErrorMessage(error)); }
export function restoreTimeWindowUpdateFailed(error: any): string { return localize('arc.restoreTimeWindowUpdateFailed', "Point in time restore time window update failed. {0}", getErrorMessage(error)); }
export function resetFailed(error: any): string { return localize('arc.resetFailed', "Reset failed. {0}", getErrorMessage(error)); } export function resetFailed(error: any): string { return localize('arc.resetFailed', "Reset failed. {0}", getErrorMessage(error)); }
export function openDashboardFailed(error: any): string { return localize('arc.openDashboardFailed', "Error opening dashboard. {0}", getErrorMessage(error)); } export function openDashboardFailed(error: any): string { return localize('arc.openDashboardFailed', "Error opening dashboard. {0}", getErrorMessage(error)); }
export function instanceDeletionFailed(name: string, error: any): string { return localize('arc.instanceDeletionFailed', "Failed to delete instance {0}. {1}", name, getErrorMessage(error)); } export function instanceDeletionFailed(name: string, error: any): string { return localize('arc.instanceDeletionFailed', "Failed to delete instance {0}. {1}", name, getErrorMessage(error)); }

View File

@@ -9,14 +9,14 @@ import * as azExt from 'az-ext';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { UserCancelledError } from '../common/api'; import { UserCancelledError } from '../common/api';
import { Deferred } from '../common/promise'; import { Deferred } from '../common/promise';
import { getTimeStamp, parseIpAndPort } from '../common/utils'; import { parseIpAndPort } from '../common/utils';
import * as loc from '../localizedConstants'; import * as loc from '../localizedConstants';
import { ConnectToMiaaSqlDialog } from '../ui/dialogs/connectMiaaDialog'; import { ConnectToMiaaSqlDialog } from '../ui/dialogs/connectMiaaDialog';
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider'; import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
import { ControllerModel, Registration } from './controllerModel'; import { ControllerModel, Registration } from './controllerModel';
import { ResourceModel } from './resourceModel'; import { ResourceModel } from './resourceModel';
export type DatabaseModel = { name: string, status: string, earliestBackup: string, lastBackup: string }; export type DatabaseModel = { name: string, status: string, lastBackup: string };
export type RPModel = { recoveryPointObjective: string, retentionDays: string }; export type RPModel = { recoveryPointObjective: string, retentionDays: string };
export type PITRModel = { export type PITRModel = {
instanceName: string, instanceName: string,
@@ -27,9 +27,7 @@ export type PITRModel = {
restorePoint: string, restorePoint: string,
earliestPitr: string, earliestPitr: string,
latestPitr: string, latestPitr: string,
destDbName: string
}; };
export const systemDbs = ['master', 'msdb', 'tempdb', 'model']; export const systemDbs = ['master', 'msdb', 'tempdb', 'model'];
export class MiaaModel extends ResourceModel { export class MiaaModel extends ResourceModel {
@@ -46,20 +44,12 @@ export class MiaaModel extends ResourceModel {
recoveryPointObjective: '', recoveryPointObjective: '',
retentionDays: '' retentionDays: ''
}; };
private _databaseTimeWindow: Map<string, string[]>;
private _refreshPromise: Deferred<void> | undefined = undefined; private _refreshPromise: Deferred<void> | undefined = undefined;
private _pitrArgs = {
destName: '',
managedInstance: '',
time: '',
noWait: true,
dryRun: false
};
constructor(_controllerModel: ControllerModel, private _miaaInfo: MiaaResourceInfo, registration: Registration, private _treeDataProvider: AzureArcTreeDataProvider) { constructor(_controllerModel: ControllerModel, private _miaaInfo: MiaaResourceInfo, registration: Registration, private _treeDataProvider: AzureArcTreeDataProvider) {
super(_controllerModel, _miaaInfo, registration); super(_controllerModel, _miaaInfo, registration);
this._azApi = <azExt.IExtension>vscode.extensions.getExtension(azExt.extension.name)?.exports; this._azApi = <azExt.IExtension>vscode.extensions.getExtension(azExt.extension.name)?.exports;
this._databaseTimeWindow = new Map<string, string[]>();
} }
/** /**
@@ -102,7 +92,6 @@ export class MiaaModel extends ResourceModel {
this.configLastUpdated = new Date(); this.configLastUpdated = new Date();
this.rpSettings.retentionDays = this._config?.spec?.backup?.retentionPeriodInDays?.toString() ?? ''; this.rpSettings.retentionDays = this._config?.spec?.backup?.retentionPeriodInDays?.toString() ?? '';
this._onConfigUpdated.fire(this._config); this._onConfigUpdated.fire(this._config);
this._onDatabasesUpdated.fire(this._databases);
} catch (err) { } catch (err) {
// If an error occurs show a message so the user knows something failed but still // If an error occurs show a message so the user knows something failed but still
// fire the event so callers can know to update (e.g. so dashboards don't show the // fire the event so callers can know to update (e.g. so dashboards don't show the
@@ -149,12 +138,6 @@ export class MiaaModel extends ResourceModel {
throw error; throw error;
} }
} }
/**
* Gets the list of databases and adds backup earliest and latest point in time
* information, this could be used as an upper and lower time limit for restoring
* backup.
*/
public async getDatabases(promptForConnection: boolean = true): Promise<void> { public async getDatabases(promptForConnection: boolean = true): Promise<void> {
if (!this._connectionProfile) { if (!this._connectionProfile) {
await this.getConnectionProfile(promptForConnection); await this.getConnectionProfile(promptForConnection);
@@ -175,21 +158,10 @@ export class MiaaModel extends ResourceModel {
if (!databases) { if (!databases) {
throw new Error('Could not fetch databases'); throw new Error('Could not fetch databases');
} }
else { if (databases.length > 0 && typeof (databases[0]) === 'object') {
if (databases.length > 0 && typeof (databases[0]) === 'object') { this._databases = (<azdata.DatabaseInfo[]>databases).map(db => { return { name: db.options['name'], status: db.options['state'], lastBackup: db.options['lastBackup'] }; });
for (let i in databases) { } else {
const di: azdata.DatabaseInfo = <azdata.DatabaseInfo>databases[i]; this._databases = (<string[]>databases).map(db => { return { name: db, status: '-', lastBackup: '' }; });
const name = di.options['name'];
await this.executeDryRun(di.options['name']);
const dm: DatabaseModel = {
name: name, status: di.options['state'], earliestBackup: this._databaseTimeWindow.get(name)?.[0] ?? '',
lastBackup: this._databaseTimeWindow.get(name)?.[1] ?? ''
};
this._databases[i] = dm;
}
} else {
this._databases = (<string[]>databases).map(db => { return { name: db, status: '-', earliestBackup: '', lastBackup: '' }; });
}
} }
this.databasesLastUpdated = new Date(); this.databasesLastUpdated = new Date();
this._onDatabasesUpdated.fire(this._databases); this._onDatabasesUpdated.fire(this._databases);
@@ -234,33 +206,4 @@ export class MiaaModel extends ResourceModel {
await this._treeDataProvider.saveControllers(); await this._treeDataProvider.saveControllers();
} }
protected async executeDryRun(dbName: string): Promise<void> {
// Allow next dry Run to be executed only after 5(300000 ms ) minutes from current time as the log backups are
// generated only at 5 minutes interval
if ((systemDbs.indexOf(dbName) === -1) && (Date.now() - getTimeStamp(this._databaseTimeWindow.get(dbName)?.[1]) >= 300000)) {
try {
//Execute dryRun for earliestTime and save latest time as well so there is one call to az cli
this._pitrArgs.destName = dbName + '-' + Date.now().toString();
this._pitrArgs.managedInstance = this.info.name;
this._pitrArgs.time = new Date().toISOString();
this._pitrArgs.noWait = false;
this._pitrArgs.dryRun = true;
const result = await this._azApi.az.sql.midbarc.restore(
dbName, this._pitrArgs, this.controllerModel.info.namespace, this.controllerModel.azAdditionalEnvVars);
const restoreResult = result.stdout;
if (restoreResult) {
const earliestTime = restoreResult['earliestRestoreTime'];
const latestTime = restoreResult['latestRestoreTime'];
console.log(loc.earliestPitrRestorePoint + '-' + dbName + ':' + earliestTime);
console.log(loc.latestpitrRestorePoint + '-' + dbName + ':' + latestTime);
this._databaseTimeWindow.set(dbName, [earliestTime, latestTime]);
}
}
catch (err) {
console.log(loc.pitr + ' ' + loc.failed + ':' + err);
this._databaseTimeWindow.set(dbName, ['', '']);
}
}
}
} }

View File

@@ -20,6 +20,7 @@ export class MiaaBackupsPage extends DashboardPage {
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports; this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.disposables.push( this.disposables.push(
this._miaaModel.onDatabasesUpdated(() => this.eventuallyRunOnInitialized(() => this.handleDatabasesUpdated())), this._miaaModel.onDatabasesUpdated(() => this.eventuallyRunOnInitialized(() => this.handleDatabasesUpdated())),
this._miaaModel.onConfigUpdated(() => this.eventuallyRunOnInitialized(() => this.handleDatabasesUpdated()))
); );
} }
private _databasesContainer!: azdata.DivContainer; private _databasesContainer!: azdata.DivContainer;
@@ -31,17 +32,16 @@ export class MiaaBackupsPage extends DashboardPage {
private _databasesMessage!: azdata.TextComponent; private _databasesMessage!: azdata.TextComponent;
private readonly _azApi: azExt.IExtension; private readonly _azApi: azExt.IExtension;
private _saveArgs: RPModel = { public saveArgs: RPModel = {
recoveryPointObjective: '', recoveryPointObjective: '',
retentionDays: '' retentionDays: ''
}; };
private _pitrArgs = { public pitrArgs = {
destName: '', destName: '',
managedInstance: '', managedInstance: '',
time: '', time: '',
noWait: true, noWait: true
dryRun: false
}; };
public get title(): string { public get title(): string {
@@ -66,7 +66,7 @@ export class MiaaBackupsPage extends DashboardPage {
.component(); .component();
const content = this.modelView.modelBuilder.divContainer().component(); const content = this.modelView.modelBuilder.divContainer().component();
this._databasesContainer = this.modelView.modelBuilder.divContainer().component(); this._databasesContainer = this.modelView.modelBuilder.divContainer().component();
root.addItem(content, { CSSStyles: { 'margin': '5px' } }); root.addItem(content, { CSSStyles: { 'margin': '20px' } });
const databaseTitle = this.modelView.modelBuilder.text().withProps({ const databaseTitle = this.modelView.modelBuilder.text().withProps({
value: loc.databases, value: loc.databases,
CSSStyles: { ...cssStyles.title }, CSSStyles: { ...cssStyles.title },
@@ -130,19 +130,11 @@ export class MiaaBackupsPage extends DashboardPage {
headerCssStyles: cssStyles.tableHeader, headerCssStyles: cssStyles.tableHeader,
rowCssStyles: cssStyles.tableRow rowCssStyles: cssStyles.tableRow
}, },
{
displayName: loc.earliestPitrRestorePoint,
valueType: azdata.DeclarativeDataType.string,
isReadOnly: true,
width: '30%',
headerCssStyles: cssStyles.tableHeader,
rowCssStyles: cssStyles.tableRow
},
{ {
displayName: loc.latestpitrRestorePoint, displayName: loc.latestpitrRestorePoint,
valueType: azdata.DeclarativeDataType.string, valueType: azdata.DeclarativeDataType.string,
isReadOnly: true, isReadOnly: true,
width: '30%', width: '50%',
headerCssStyles: cssStyles.tableHeader, headerCssStyles: cssStyles.tableHeader,
rowCssStyles: cssStyles.tableRow rowCssStyles: cssStyles.tableRow
}, },
@@ -150,7 +142,7 @@ export class MiaaBackupsPage extends DashboardPage {
displayName: loc.restore, displayName: loc.restore,
valueType: azdata.DeclarativeDataType.component, valueType: azdata.DeclarativeDataType.component,
isReadOnly: true, isReadOnly: true,
width: '10%', width: '20%',
headerCssStyles: cssStyles.tableHeader, headerCssStyles: cssStyles.tableHeader,
rowCssStyles: cssStyles.tableRow, rowCssStyles: cssStyles.tableRow,
} }
@@ -206,13 +198,13 @@ export class MiaaBackupsPage extends DashboardPage {
this._configureRetentionPolicyButton.onDidClick(async () => { this._configureRetentionPolicyButton.onDidClick(async () => {
const retentionPolicySqlDialog = new ConfigureRPOSqlDialog(this._miaaModel); const retentionPolicySqlDialog = new ConfigureRPOSqlDialog(this._miaaModel);
this.refreshRD(); this.refreshRD();
retentionPolicySqlDialog.showDialog(loc.configureRP, this._saveArgs.retentionDays); retentionPolicySqlDialog.showDialog(loc.configureRP, this.saveArgs.retentionDays);
let rpArg = await retentionPolicySqlDialog.waitForClose(); let rpArg = await retentionPolicySqlDialog.waitForClose();
if (rpArg) { if (rpArg) {
try { try {
this._configureRetentionPolicyButton.enabled = false; this._configureRetentionPolicyButton.enabled = false;
this._saveArgs.retentionDays = rpArg.retentionDays; this.saveArgs.retentionDays = rpArg.retentionDays;
await vscode.window.withProgress( await vscode.window.withProgress(
{ {
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
@@ -221,7 +213,7 @@ export class MiaaBackupsPage extends DashboardPage {
}, },
async (_progress, _token): Promise<void> => { async (_progress, _token): Promise<void> => {
await this._azApi.az.sql.miarc.edit( await this._azApi.az.sql.miarc.edit(
this._miaaModel.info.name, this._saveArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars); this._miaaModel.info.name, this.saveArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
try { try {
await this._miaaModel.refresh(); await this._miaaModel.refresh();
@@ -252,16 +244,13 @@ export class MiaaBackupsPage extends DashboardPage {
// If we were able to get the databases it means we have a good connection so update the username too // If we were able to get the databases it means we have a good connection so update the username too
let databaseDisplay = this._miaaModel.databases.map(d => [ let databaseDisplay = this._miaaModel.databases.map(d => [
d.name, d.name,
d.earliestBackup,
d.lastBackup, d.lastBackup,
this.createRestoreButton(d)]); this.createRestoreButton(d)]);
let databasesValues = databaseDisplay.map(d => { let databasesValues = databaseDisplay.map(d => {
return d.map((value): azdata.DeclarativeTableCellValue => { return d.map((value): azdata.DeclarativeTableCellValue => {
return { value: value }; return { value: value };
}); });
}); });
this._databasesTable.setDataValues(databasesValues); this._databasesTable.setDataValues(databasesValues);
this._databasesTableLoading.loading = false; this._databasesTableLoading.loading = false;
@@ -282,7 +271,7 @@ export class MiaaBackupsPage extends DashboardPage {
} }
private refreshRD(): void { private refreshRD(): void {
this._saveArgs.retentionDays = this._miaaModel.config?.spec?.backup?.retentionPeriodInDays.toString() ?? ''; this.saveArgs.retentionDays = this._miaaModel.config?.spec?.backup?.retentionPeriodInDays.toString() ?? '';
} }
// Create restore button for every database entry in the database table // Create restore button for every database entry in the database table
@@ -303,9 +292,9 @@ export class MiaaBackupsPage extends DashboardPage {
if (args) { if (args) {
try { try {
restoreButton.enabled = false; restoreButton.enabled = false;
this._pitrArgs.destName = args.destDbName; this.pitrArgs.destName = args.dbName;
this._pitrArgs.managedInstance = args.instanceName; this.pitrArgs.managedInstance = args.instanceName;
this._pitrArgs.time = `"${args.restorePoint}"`; this.pitrArgs.time = `"${args.restorePoint}"`;
await vscode.window.withProgress( await vscode.window.withProgress(
{ {
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
@@ -314,7 +303,7 @@ export class MiaaBackupsPage extends DashboardPage {
}, },
async (_progress, _token): Promise<void> => { async (_progress, _token): Promise<void> => {
await this._azApi.az.sql.midbarc.restore( await this._azApi.az.sql.midbarc.restore(
db.name, this._pitrArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars); db.name, this.pitrArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
try { try {
await this._miaaModel.refresh(); await this._miaaModel.refresh();
} catch (error) { } catch (error) {
@@ -331,6 +320,4 @@ export class MiaaBackupsPage extends DashboardPage {
})); }));
return restoreButton; return restoreButton;
} }
} }

View File

@@ -32,7 +32,7 @@ export class ConfigureRPOSqlDialog extends InitializingComponent {
this.retentionDaysInputBox = this.modelBuilder.inputBox() this.retentionDaysInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
readOnly: false, readOnly: false,
min: 0, min: 1,
max: 35, max: 35,
inputType: 'number', inputType: 'number',
ariaLabel: loc.retentionDays, ariaLabel: loc.retentionDays,

View File

@@ -5,7 +5,6 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { Deferred } from '../../common/promise'; import { Deferred } from '../../common/promise';
import { getTimeStamp, checkISOTimeString } from '../../common/utils';
import * as loc from '../../localizedConstants'; import * as loc from '../../localizedConstants';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { cssStyles } from '../../constants'; import { cssStyles } from '../../constants';
@@ -25,7 +24,6 @@ export class RestoreSqlDialog extends InitializingComponent {
restorePoint: '-', restorePoint: '-',
earliestPitr: '-', earliestPitr: '-',
latestPitr: '-', latestPitr: '-',
destDbName: '-',
}; };
private earliestRestorePointInputBox!: azdata.InputBoxComponent; private earliestRestorePointInputBox!: azdata.InputBoxComponent;
@@ -38,11 +36,10 @@ export class RestoreSqlDialog extends InitializingComponent {
private instanceInputBox!: azdata.InputBoxComponent; private instanceInputBox!: azdata.InputBoxComponent;
protected _completionPromise = new Deferred<PITRModel | undefined>(); protected _completionPromise = new Deferred<PITRModel | undefined>();
private _azurecoreApi: azurecore.IExtension; private _azurecoreApi: azurecore.IExtension;
protected disposables: vscode.Disposable[] = [];
constructor(protected _miaaModel: MiaaModel, protected _controllerModel: ControllerModel, protected _database: DatabaseModel) { constructor(protected _miaaModel: MiaaModel, protected _controllerModel: ControllerModel, protected _database: DatabaseModel) {
super(); super();
this._azurecoreApi = vscode.extensions.getExtension(azurecore.extension.name)?.exports; this._azurecoreApi = vscode.extensions.getExtension(azurecore.extension.name)?.exports;
this.refreshPitrSettings();
} }
public showDialog(dialogTitle: string): azdata.window.Dialog { public showDialog(dialogTitle: string): azdata.window.Dialog {
@@ -53,15 +50,14 @@ export class RestoreSqlDialog extends InitializingComponent {
this.refreshPitrSettings(); this.refreshPitrSettings();
const pitrTitle = this.modelBuilder.text().withProps({ const pitrTitle = this.modelBuilder.text().withProps({
value: loc.pitr, value: loc.pitr,
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }, CSSStyles: { ...cssStyles.title }
}).component(); }).component();
const projectDetailsTitle = this.modelBuilder.text().withProps({ const projectDetailsTitle = this.modelBuilder.text().withProps({
value: loc.projectDetails, value: loc.projectDetails,
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' } CSSStyles: { ...cssStyles.title }
}).component(); }).component();
const projectDetailsTextLabel = this.modelBuilder.text().withProps({ const projectDetailsTextLabel = this.modelBuilder.text().withProps({
value: loc.projectDetailsText, value: loc.projectDetailsText,
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
}).component(); }).component();
this.subscriptionInputBox = this.modelBuilder.inputBox() this.subscriptionInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
@@ -78,11 +74,10 @@ export class RestoreSqlDialog extends InitializingComponent {
const sourceDetailsTitle = this.modelBuilder.text().withProps({ const sourceDetailsTitle = this.modelBuilder.text().withProps({
value: loc.sourceDetails, value: loc.sourceDetails,
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' } CSSStyles: { ...cssStyles.title }
}).component(); }).component();
const sourceDetailsTextLabel = this.modelBuilder.text().withProps({ const sourceDetailsTextLabel = this.modelBuilder.text().withProps({
value: loc.sourceDetailsText, value: loc.sourceDetailsText,
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
}).component(); }).component();
this.sourceDbInputBox = this.modelBuilder.inputBox() this.sourceDbInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
@@ -90,15 +85,12 @@ export class RestoreSqlDialog extends InitializingComponent {
ariaLabel: loc.sourceDatabase, ariaLabel: loc.sourceDatabase,
value: this._database.name value: this._database.name
}).component(); }).component();
const restoreDetailsTextLabel = this.modelBuilder.text().withProps({
value: loc.restorePointText,
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
}).component();
this.earliestRestorePointInputBox = this.modelBuilder.inputBox() this.earliestRestorePointInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
enabled: false, enabled: false,
ariaLabel: loc.earliestPitrRestorePoint, ariaLabel: loc.earliestPitrRestorePoint,
value: this._database.earliestBackup value: ''
}).component(); }).component();
this.latestRestorePointInputBox = this.modelBuilder.inputBox() this.latestRestorePointInputBox = this.modelBuilder.inputBox()
@@ -112,39 +104,14 @@ export class RestoreSqlDialog extends InitializingComponent {
.withProps({ .withProps({
readOnly: false, readOnly: false,
ariaLabel: loc.restorePoint, ariaLabel: loc.restorePoint,
value: '', value: ''
validationErrorMessage: loc.restorePointErrorMessage(this.earliestRestorePointInputBox.value ?? loc.earliestPitrRestorePoint, this.latestRestorePointInputBox.value ?? loc.latestpitrRestorePoint),
}).withValidation(async () => {
try {
if (!checkISOTimeString(this.restorePointInputBox.value ?? '')) { return false; }
if (this.earliestRestorePointInputBox.value) {
if ((getTimeStamp(this.restorePointInputBox.value) >= getTimeStamp(this.earliestRestorePointInputBox.value)
&& getTimeStamp(this.restorePointInputBox.value) <= getTimeStamp(this.latestRestorePointInputBox.value))) {
this.pitrSettings.restorePoint = this.restorePointInputBox.value ?? '';
return true;
}
else {
return false;
}
}
}
catch (err) {
throw err;
return false;
}
return true;
}).component(); }).component();
const pitrDetailsTitle = this.modelBuilder.text().withProps({ const databaseDetailsTitle = this.modelBuilder.text().withProps({
value: loc.restorePointDetails,
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' }
}).component();
const destinationDetailsTitle = this.modelBuilder.text().withProps({
value: loc.databaseDetails, value: loc.databaseDetails,
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' } CSSStyles: { ...cssStyles.title }
}).component(); }).component();
const databaseDetailsTextLabel = this.modelBuilder.text().withProps({ const databaseDetailsTextLabel = this.modelBuilder.text().withProps({
value: loc.databaseDetailsText, value: loc.databaseDetailsText,
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
}).component(); }).component();
this.databaseNameInputBox = this.modelBuilder.inputBox() this.databaseNameInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
@@ -152,10 +119,7 @@ export class RestoreSqlDialog extends InitializingComponent {
ariaLabel: loc.databaseName, ariaLabel: loc.databaseName,
value: '' value: ''
}).component(); }).component();
this.disposables.push(
this.databaseNameInputBox.onTextChanged(() => {
this.pitrSettings.destDbName = this.databaseNameInputBox.value ?? '';
}));
this.instanceInputBox = this.modelBuilder.inputBox() this.instanceInputBox = this.modelBuilder.inputBox()
.withProps({ .withProps({
enabled: false, enabled: false,
@@ -164,7 +128,7 @@ export class RestoreSqlDialog extends InitializingComponent {
}).component(); }).component();
const info = this.modelBuilder.text().withProps({ const info = this.modelBuilder.text().withProps({
value: loc.restoreInfo, value: loc.restoreInfo,
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'max-width': 'auto' } CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
}).component(); }).component();
const link = this.modelBuilder.hyperlink().withProps({ const link = this.modelBuilder.hyperlink().withProps({
@@ -213,28 +177,6 @@ export class RestoreSqlDialog extends InitializingComponent {
title: loc.sourceDatabase, title: loc.sourceDatabase,
}, },
{
component: destinationDetailsTitle,
},
{
component: databaseDetailsTextLabel,
},
{
component: this.databaseNameInputBox,
title: loc.databaseName,
required: true
},
{
component: this.instanceInputBox,
title: loc.instance,
},
{
component: pitrDetailsTitle
},
{
component: restoreDetailsTextLabel,
},
{ {
component: this.earliestRestorePointInputBox, component: this.earliestRestorePointInputBox,
title: loc.earliestPitrRestorePoint, title: loc.earliestPitrRestorePoint,
@@ -250,6 +192,22 @@ export class RestoreSqlDialog extends InitializingComponent {
title: loc.restorePoint, title: loc.restorePoint,
required: true required: true
}, },
{
component: databaseDetailsTitle,
},
{
component: databaseDetailsTextLabel,
},
{
component: this.databaseNameInputBox,
title: loc.databaseName,
required: true
},
{
component: this.instanceInputBox,
title: loc.instance,
},
], ],
title: '' title: ''
}]).withLayout({ width: '100%' }).component(); }]).withLayout({ width: '100%' }).component();
@@ -311,9 +269,4 @@ export class RestoreSqlDialog extends InitializingComponent {
this.pitrSettings.restorePoint = this._database.lastBackup; this.pitrSettings.restorePoint = this._database.lastBackup;
this.pitrSettings.earliestPitr = ''; this.pitrSettings.earliestPitr = '';
} }
public updatePitrTimeWindow(earliestPitr: string, latestPitr: string): void {
this.earliestRestorePointInputBox.value = earliestPitr;
this.latestRestorePointInputBox.value = latestPitr;
}
} }

View File

@@ -228,16 +228,36 @@
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
"@types/caseless@*":
version "0.12.2"
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==
"@types/mocha@^5.2.5": "@types/mocha@^5.2.5":
version "5.2.7" version "5.2.7"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
"@types/node@*":
version "13.11.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.1.tgz#49a2a83df9d26daacead30d0ccc8762b128d53c7"
integrity sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==
"@types/node@^12.11.7": "@types/node@^12.11.7":
version "12.12.47" version "12.12.47"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.47.tgz#5007b8866a2f9150de82335ca7e24dd1d59bdfb5" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.47.tgz#5007b8866a2f9150de82335ca7e24dd1d59bdfb5"
integrity sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A== integrity sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==
"@types/request@^2.48.3":
version "2.48.4"
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.4.tgz#df3d43d7b9ed3550feaa1286c6eabf0738e6cf7e"
integrity sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==
dependencies:
"@types/caseless" "*"
"@types/node" "*"
"@types/tough-cookie" "*"
form-data "^2.5.0"
"@types/sinon@^9.0.4": "@types/sinon@^9.0.4":
version "9.0.4" version "9.0.4"
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1"
@@ -250,6 +270,11 @@
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e" resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA== integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
"@types/tough-cookie@*":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d"
integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==
"@types/uuid@^8.3.0": "@types/uuid@^8.3.0":
version "8.3.0" version "8.3.0"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
@@ -267,6 +292,16 @@ agent-base@4, agent-base@^4.3.0:
dependencies: dependencies:
es6-promisify "^5.0.0" es6-promisify "^5.0.0"
ajv@^6.5.5:
version "6.12.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-regex@^3.0.0: ansi-regex@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
@@ -293,11 +328,45 @@ argparse@^1.0.7:
dependencies: dependencies:
sprintf-js "~1.0.2" sprintf-js "~1.0.2"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
dependencies:
tweetnacl "^0.14.3"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -316,6 +385,11 @@ callsite@^1.0.0:
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^2.0.0: chalk@^2.0.0:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -347,6 +421,13 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
commander@2.15.1: commander@2.15.1:
version "2.15.1" version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@@ -364,11 +445,23 @@ convert-source-map@^1.7.0:
dependencies: dependencies:
safe-buffer "~5.1.1" safe-buffer "~5.1.1"
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=
crypt@~0.0.1: crypt@~0.0.1:
version "0.0.2" version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
dependencies:
assert-plus "^1.0.0"
debug@3.1.0: debug@3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -411,6 +504,11 @@ default-require-extensions@^3.0.0:
dependencies: dependencies:
strip-bom "^4.0.0" strip-bom "^4.0.0"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
diff@3.5.0: diff@3.5.0:
version "3.5.0" version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@@ -421,6 +519,14 @@ diff@^4.0.2:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
es6-promise@^4.0.3: es6-promise@^4.0.3:
version "4.2.8" version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
@@ -438,6 +544,54 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
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==
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
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@^2.5.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -448,6 +602,13 @@ gensync@^1.0.0-beta.1:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
dependencies:
assert-plus "^1.0.0"
glob@7.1.2: glob@7.1.2:
version "7.1.2" version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
@@ -482,6 +643,19 @@ growl@1.10.5:
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
dependencies:
ajv "^6.5.5"
har-schema "^2.0.0"
has-flag@^3.0.0: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -510,6 +684,15 @@ http-proxy-agent@^2.1.0:
agent-base "4" agent-base "4"
debug "3.1.0" debug "3.1.0"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@^2.2.4: https-proxy-agent@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
@@ -536,11 +719,21 @@ is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
isarray@0.0.1: isarray@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
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=
istanbul-lib-coverage@^2.0.5: istanbul-lib-coverage@^2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
@@ -601,11 +794,31 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jsesc@^2.5.1: jsesc@^2.5.1:
version "2.5.2" version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
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=
json5@^2.1.2: json5@^2.1.2:
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
@@ -613,6 +826,16 @@ json5@^2.1.2:
dependencies: dependencies:
minimist "^1.2.5" minimist "^1.2.5"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
just-extend@^4.0.2: just-extend@^4.0.2:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4"
@@ -652,6 +875,18 @@ md5@^2.1.0:
crypt "~0.0.1" crypt "~0.0.1"
is-buffer "~1.1.1" is-buffer "~1.1.1"
mime-db@1.43.0:
version "1.43.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.26"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
dependencies:
mime-db "1.43.0"
minimatch@3.0.4, minimatch@^3.0.4: minimatch@3.0.4, minimatch@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -740,6 +975,11 @@ nise@^4.0.1:
just-extend "^4.0.2" just-extend "^4.0.2"
path-to-regexp "^1.7.0" path-to-regexp "^1.7.0"
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
once@^1.3.0: once@^1.3.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -764,6 +1004,11 @@ path-to-regexp@^1.7.0:
dependencies: dependencies:
isarray "0.0.1" isarray "0.0.1"
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
pify@^4.0.1: pify@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
@@ -774,6 +1019,47 @@ postinstall-build@^5.0.1:
resolved "https://registry.yarnpkg.com/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7" resolved "https://registry.yarnpkg.com/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7"
integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg== integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg==
psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
request@^2.88.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
resolve@^1.3.2: resolve@^1.3.2:
version "1.17.0" version "1.17.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
@@ -788,11 +1074,21 @@ rimraf@^2.6.3:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
safe-buffer@~5.1.1: safe-buffer@~5.1.1:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.4.1, semver@^5.6.0: semver@^5.4.1, semver@^5.6.0:
version "5.7.1" version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
@@ -875,6 +1171,21 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
bcrypt-pbkdf "^1.0.0"
dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
getpass "^0.1.1"
jsbn "~0.1.0"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
strip-ansi@^4.0.0: strip-ansi@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
@@ -913,6 +1224,26 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
dependencies:
psl "^1.1.28"
punycode "^2.1.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
type-detect@4.0.8, type-detect@^4.0.8: type-detect@4.0.8, type-detect@^4.0.8:
version "4.0.8" version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
@@ -927,11 +1258,32 @@ typemoq@2.1.0, typemoq@^2.1.0:
lodash "^4.17.4" lodash "^4.17.4"
postinstall-build "^5.0.1" postinstall-build "^5.0.1"
uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
dependencies:
punycode "^2.1.0"
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.0: uuid@^8.3.0:
version "8.3.0" version "8.3.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-nls@^4.1.2: vscode-nls@^4.1.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"

View File

@@ -2,7 +2,7 @@
"name": "asde-deployment", "name": "asde-deployment",
"displayName": "%extension-displayName%", "displayName": "%extension-displayName%",
"description": "%extension-description%", "description": "%extension-description%",
"version": "0.4.2", "version": "0.4.3",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -18,12 +18,12 @@
"type": "git", "type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git" "url": "https://github.com/Microsoft/azuredatastudio.git"
}, },
"capabilities": { "capabilities": {
"virtualWorkspaces": false, "virtualWorkspaces": false,
"untrustedWorkspaces": { "untrustedWorkspaces": {
"supported": true "supported": true
} }
}, },
"extensionDependencies": [ "extensionDependencies": [
"microsoft.resource-deployment" "microsoft.resource-deployment"
], ],
@@ -111,9 +111,6 @@
"typemoq": "^2.1.0", "typemoq": "^2.1.0",
"vscodetestcover": "^1.1.0" "vscodetestcover": "^1.1.0"
}, },
"resolutions": {
"json-schema": "0.4.0"
},
"__metadata": { "__metadata": {
"id": "84", "id": "84",
"publisherDisplayName": "Microsoft", "publisherDisplayName": "Microsoft",

View File

@@ -140,7 +140,6 @@ export function getAzApi(localAzDiscovered: Promise<IAzTool | undefined>, azTool
managedInstance?: string, managedInstance?: string,
time?: string, time?: string,
noWait?: boolean, noWait?: boolean,
dryRun?: boolean
}, },
namespace: string, additionalEnvVars?: azExt.AdditionalEnvVars) => { namespace: string, additionalEnvVars?: azExt.AdditionalEnvVars) => {
await localAzDiscovered; await localAzDiscovered;

View File

@@ -185,18 +185,16 @@ export class AzTool implements azExt.IAzApi {
managedInstance?: string, managedInstance?: string,
time?: string, time?: string,
noWait?: boolean, noWait?: boolean,
dryRun?: boolean
}, },
namespace: string, namespace: string,
additionalEnvVars?: azExt.AdditionalEnvVars additionalEnvVars?: azExt.AdditionalEnvVars
): Promise<azExt.AzOutput<azExt.SqlMiDbRestoreResult>> => { ): Promise<azExt.AzOutput<void>> => {
const argsArray = ['sql', 'midb-arc', 'restore', '--name', name, '--k8s-namespace', namespace, '--use-k8s']; const argsArray = ['sql', 'midb-arc', 'restore', '--name', name, '--k8s-namespace', namespace, '--use-k8s'];
if (args.destName) { argsArray.push('--dest-name', args.destName); } if (args.destName) { argsArray.push('--dest-name', args.destName); }
if (args.managedInstance) { argsArray.push('--managed-instance', args.managedInstance); } if (args.managedInstance) { argsArray.push('--managed-instance', args.managedInstance); }
if (args.time) { argsArray.push('--time', args.time); } if (args.time) { argsArray.push('--time', args.time); }
if (args.noWait) { argsArray.push('--no-wait'); } if (args.noWait) { argsArray.push('--no-wait'); }
if (args.dryRun) { argsArray.push('--dry-run'); } return this.executeCommand<void>(argsArray, additionalEnvVars);
return this.executeCommand<azExt.SqlMiDbRestoreResult>(argsArray, additionalEnvVars);
} }
} }
}; };

View File

@@ -173,17 +173,6 @@ declare module 'az-ext' {
} }
} }
export interface SqlMiDbRestoreResult {
destDatabase: string, //testDbToRestore
earliestRestoreTime: string, // "2020-08-19T20:25:11Z"
latestRestoreTime: string, //"2020-08-19T20:25:11Z"
message: string, //Dry run for restore operation succeeded.
observedGeneration: number, //1
restorePoint: string, // "2020-08-19T20:25:11Z"
sourceDatabase: string, //testDb
state: string //Completed
}
export interface PostgresServerShowResult { export interface PostgresServerShowResult {
apiVersion: string, // "arcdata.microsoft.com/v1alpha1" apiVersion: string, // "arcdata.microsoft.com/v1alpha1"
kind: string, // "postgresql" kind: string, // "postgresql"
@@ -347,11 +336,10 @@ declare module 'az-ext' {
managedInstance?: string, //sqlmi1 managedInstance?: string, //sqlmi1
time?: string, //2021-10-12T11:16:30.000Z time?: string, //2021-10-12T11:16:30.000Z
noWait?: boolean, //true noWait?: boolean, //true
dryRun?: boolean, //true
}, },
namespace?: string, namespace?: string,
additionalEnvVars?: AdditionalEnvVars additionalEnvVars?: AdditionalEnvVars
): Promise<AzOutput<SqlMiDbRestoreResult>> ): Promise<AzOutput<void>>
} }
}, },
getPath(): Promise<string>, getPath(): Promise<string>,

View File

@@ -768,10 +768,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"

View File

@@ -328,6 +328,11 @@
} }
] ]
}, },
"resourceDeploymentValueProviders": [
{
"id": "subscription-id-to-tenant-id"
}
],
"hasAzureResourceProviders": true "hasAzureResourceProviders": true
}, },
"dependencies": { "dependencies": {

View File

@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import * as resourceDeployment from 'resource-deployment';
import { AppContext } from './appContext'; import { AppContext } from './appContext';
import { AzureAccountProviderService } from './account-provider/azureAccountProviderService'; import { AzureAccountProviderService } from './account-provider/azureAccountProviderService';
@@ -114,6 +115,40 @@ export async function activate(context: vscode.ExtensionContext): Promise<azurec
} }
}); });
// Don't block on this since there's a bit of a circular dependency here with the extension activation since resource deployment
// depends on this extension too. It's fine to wait a bit for that to finish before registering the provider
vscode.extensions.getExtension(resourceDeployment.extension.name).activate().then((api: resourceDeployment.IExtension) => {
context.subscriptions.push(api.registerValueProvider({
id: 'subscription-id-to-tenant-id',
getValue: async (triggerValue: string) => {
if (triggerValue === '') {
return '';
}
let accounts: azurecore.AzureAccount[] = [];
try {
accounts = await azdata.accounts.getAllAccounts();
} catch (err) {
console.warn(`Error fetching accounts for subscription-id-to-tenant-id provider : ${err}`);
return '';
}
for (const account of accounts) {
// Ignore any errors - they'll be logged in the called function and we still want to look
// at any subscriptions that are returned - worst case we'll just return an empty string if we didn't
// find the matching subscription
const subs = await azureResourceUtils.getSubscriptions(appContext, account, true);
const sub = subs.subscriptions.find(sub => sub.id === triggerValue);
if (sub) {
return sub.tenant;
}
}
console.error(`Unable to find subscription with ID ${triggerValue} when mapping subscription ID to tenant ID`);
return '';
}
}));
}).then(undefined, err => console.error('Error registering Azure ResourceDeployment value provider ', err));
return { return {
getSubscriptions(account?: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly: boolean = false): Promise<azurecore.GetSubscriptionsResult> { getSubscriptions(account?: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly: boolean = false): Promise<azurecore.GetSubscriptionsResult> {
return selectedOnly return selectedOnly

View File

@@ -7,4 +7,5 @@
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/> /// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
/// <reference path='../../../../src/sql/azdata.d.ts'/> /// <reference path='../../../../src/sql/azdata.d.ts'/>
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/> /// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
/// <reference path='../../../resource-deployment/src/typings/resource-deployment.d.ts'/>
/// <reference types='@types/node'/> /// <reference types='@types/node'/>

View File

@@ -1,7 +1,7 @@
{ {
"name": "azuremonitor", "name": "azuremonitor",
"description": "%azuremonitor.description%", "description": "%azuremonitor.description%",
"version": "0.1.8", "version": "0.1.9",
"publisher": "Microsoft", "publisher": "Microsoft",
"aiKey": "AIF-444c3af9-8e69-4462-ab49-4191e6ad1916", "aiKey": "AIF-444c3af9-8e69-4462-ab49-4191e6ad1916",
"activationEvents": [ "activationEvents": [
@@ -115,6 +115,20 @@
"categoryValues": null, "categoryValues": null,
"isRequired": true, "isRequired": true,
"isArray": false "isArray": false
},
{
"specialValueType": "databaseName",
"isIdentity": true,
"name": "database",
"displayName": "%azuremonitor.connectionOptions.databaseName.displayName%",
"description": "%azuremonitor.connectionOptions.databaseName.description%",
"groupName": "%azuremonitor.connectionProperties.groupName.source%",
"valueType": "string",
"defaultValue": null,
"objectType": null,
"categoryValues": null,
"isRequired": false,
"isArray": false
} }
] ]
}, },

View File

@@ -2,7 +2,7 @@
"name": "big-data-cluster", "name": "big-data-cluster",
"displayName": "%text.sqlServerBigDataClusters%", "displayName": "%text.sqlServerBigDataClusters%",
"description": "%description%", "description": "%description%",
"version": "1.0.0", "version": "1.0.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
@@ -27,12 +27,12 @@
"type": "git", "type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git" "url": "https://github.com/Microsoft/azuredatastudio.git"
}, },
"capabilities": { "capabilities": {
"virtualWorkspaces": false, "virtualWorkspaces": false,
"untrustedWorkspaces": { "untrustedWorkspaces": {
"supported": true "supported": true
} }
}, },
"main": "./out/extension", "main": "./out/extension",
"contributes": { "contributes": {
"dataExplorer": { "dataExplorer": {
@@ -254,7 +254,7 @@
}, },
{ {
"name": "azdata", "name": "azdata",
"version": "20.3.9" "version": "20.3.4"
} }
], ],
"when": "target=new-aks&&version=bdc2019" "when": "target=new-aks&&version=bdc2019"
@@ -272,7 +272,7 @@
}, },
{ {
"name": "azdata", "name": "azdata",
"version": "20.3.9" "version": "20.3.4"
} }
], ],
"when": "target=existing-aks&&version=bdc2019" "when": "target=existing-aks&&version=bdc2019"
@@ -290,7 +290,7 @@
}, },
{ {
"name": "azdata", "name": "azdata",
"version": "20.3.9" "version": "20.3.4"
} }
], ],
"when": "target=existing-kubeadm&&version=bdc2019" "when": "target=existing-kubeadm&&version=bdc2019"
@@ -308,7 +308,7 @@
}, },
{ {
"name": "azdata", "name": "azdata",
"version": "20.3.9" "version": "20.3.4"
} }
], ],
"when": "target=existing-aro&&version=bdc2019" "when": "target=existing-aro&&version=bdc2019"
@@ -326,7 +326,7 @@
}, },
{ {
"name": "azdata", "name": "azdata",
"version": "20.3.9" "version": "20.3.4"
} }
], ],
"when": "target=existing-openshift&&version=bdc2019" "when": "target=existing-openshift&&version=bdc2019"
@@ -362,8 +362,5 @@
}, },
"devDependencies": { "devDependencies": {
"@types/request": "^2.48.3" "@types/request": "^2.48.3"
},
"resolutions": {
"json-schema": "0.4.0"
} }
} }

View File

@@ -212,10 +212,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1: json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"

View File

@@ -2,7 +2,7 @@
"name": "cms", "name": "cms",
"displayName": "%cms.displayName%", "displayName": "%cms.displayName%",
"description": "%cms.description%", "description": "%cms.description%",
"version": "0.9.1", "version": "0.9.2",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
@@ -22,12 +22,12 @@
"type": "git", "type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git" "url": "https://github.com/Microsoft/azuredatastudio.git"
}, },
"capabilities": { "capabilities": {
"virtualWorkspaces": false, "virtualWorkspaces": false,
"untrustedWorkspaces": { "untrustedWorkspaces": {
"supported": true "supported": true
} }
}, },
"main": "./out/extension", "main": "./out/extension",
"contributes": { "contributes": {
"configuration": { "configuration": {
@@ -624,8 +624,7 @@
"when": "viewItem == cms.resource.itemType.databaseServerContainer", "when": "viewItem == cms.resource.itemType.databaseServerContainer",
"group": "navigation@10" "group": "navigation@10"
} }
], ],"commandPalette": [
"commandPalette": [
{ {
"command": "cms.resource.addRegisteredServer", "command": "cms.resource.addRegisteredServer",
"when": "false" "when": "false"
@@ -654,6 +653,7 @@
} }
}, },
"dependencies": { "dependencies": {
"request": "2.88.0",
"vscode-nls": "^4.0.0" "vscode-nls": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -192,6 +192,16 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11"
integrity sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w== integrity sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==
ajv@^5.3.0:
version "5.5.2"
resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ansi-regex@^3.0.0: ansi-regex@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
@@ -211,11 +221,45 @@ append-transform@^2.0.0:
dependencies: dependencies:
default-require-extensions "^3.0.0" default-require-extensions "^3.0.0"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
dependencies:
tweetnacl "^0.14.3"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -234,6 +278,11 @@ callsite@^1.0.0:
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
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@^2.0.0: chalk@^2.0.0:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -253,6 +302,11 @@ circular-json@^0.3.1:
resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
co@^4.6.0:
version "4.6.0"
resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -265,6 +319,20 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
combined-stream@1.0.6:
version "1.0.6"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
integrity sha1-cj599ugBrFYTETp+RFqbactjKBg=
dependencies:
delayed-stream "~1.0.0"
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==
dependencies:
delayed-stream "~1.0.0"
commander@2.15.1: commander@2.15.1:
version "2.15.1" version "2.15.1"
resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@@ -282,11 +350,23 @@ convert-source-map@^1.7.0:
dependencies: dependencies:
safe-buffer "~5.1.1" safe-buffer "~5.1.1"
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=
crypt@~0.0.1: crypt@~0.0.1:
version "0.0.2" version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
dependencies:
assert-plus "^1.0.0"
debug@3.1.0: debug@3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -329,16 +409,68 @@ default-require-extensions@^3.0.0:
dependencies: dependencies:
strip-bom "^4.0.0" strip-bom "^4.0.0"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
diff@3.5.0: diff@3.5.0:
version "3.5.0" version "3.5.0"
resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
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==
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
fast-json-stable-stringify@^2.0.0:
version "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.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@~2.3.2:
version "2.3.2"
resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
integrity sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -349,6 +481,13 @@ gensync@^1.0.0-beta.1:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
dependencies:
assert-plus "^1.0.0"
glob@7.1.2: glob@7.1.2:
version "7.1.2" version "7.1.2"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
@@ -395,6 +534,19 @@ growl@1.10.5:
resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29"
integrity sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==
dependencies:
ajv "^5.3.0"
har-schema "^2.0.0"
has-flag@^3.0.0: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -415,6 +567,15 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
inflight@^1.0.4: inflight@^1.0.4:
version "1.0.6" version "1.0.6"
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -433,6 +594,16 @@ is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
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=
istanbul-lib-coverage@^2.0.5: istanbul-lib-coverage@^2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
@@ -496,11 +667,31 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jsesc@^2.5.1: jsesc@^2.5.1:
version "2.5.2" version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-schema-traverse@^0.3.0:
version "0.3.1"
resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
json-schema@0.2.3:
version "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.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=
json5@^2.1.2: json5@^2.1.2:
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
@@ -508,6 +699,16 @@ json5@^2.1.2:
dependencies: dependencies:
minimist "^1.2.5" minimist "^1.2.5"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4: lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@@ -537,6 +738,18 @@ md5@^2.1.0:
crypt "~0.0.1" crypt "~0.0.1"
is-buffer "~1.1.1" is-buffer "~1.1.1"
mime-db@~1.36.0:
version "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.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==
dependencies:
mime-db "~1.36.0"
minimatch@3.0.4, minimatch@^3.0.4: minimatch@3.0.4, minimatch@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -607,6 +820,11 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
once@^1.3.0: once@^1.3.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -624,6 +842,11 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
pify@^4.0.1: pify@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
@@ -634,6 +857,47 @@ postinstall-build@^5.0.1:
resolved "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7" resolved "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7"
integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg== integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg==
psl@^1.1.24:
version "1.1.29"
resolved "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
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==
request@2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.0"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.4.3"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
resolve@^1.3.2: resolve@^1.3.2:
version "1.15.1" version "1.15.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
@@ -648,11 +912,16 @@ rimraf@^2.6.3:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
safe-buffer@~5.1.1: safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.1:
version "5.1.2" version "5.1.2"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.4.1, semver@^5.6.0: semver@^5.4.1, semver@^5.6.0:
version "5.7.1" version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
@@ -717,6 +986,22 @@ source-map@^0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sshpk@^1.7.0:
version "1.14.2"
resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
integrity sha1-xvxhZIo9nE52T9P8306hBeSSupg=
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
safer-buffer "^2.0.2"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
jsbn "~0.1.0"
tweetnacl "~0.14.0"
strip-ansi@^4.0.0: strip-ansi@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
@@ -755,6 +1040,26 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
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==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
typemoq@^2.1.0: typemoq@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8" resolved "https://registry.npmjs.org/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8"
@@ -764,6 +1069,20 @@ typemoq@^2.1.0:
lodash "^4.17.4" lodash "^4.17.4"
postinstall-build "^5.0.1" postinstall-build "^5.0.1"
uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
verror@1.10.0:
version "1.10.0"
resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-nls@^4.0.0: vscode-nls@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" resolved "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"

View File

@@ -2,7 +2,7 @@
"name": "dacpac", "name": "dacpac",
"displayName": "SQL Server Dacpac", "displayName": "SQL Server Dacpac",
"description": "SQL Server Dacpac for Azure Data Studio.", "description": "SQL Server Dacpac for Azure Data Studio.",
"version": "1.10.0", "version": "1.9.2",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": false, "preview": false,
"engines": { "engines": {

View File

@@ -1,17 +1,3 @@
# Microsoft Data Workspace for Azure Data Studio and VS Code
## Overview
This extension provides additional common functionality for database projects in Azure Data Studio and VS Code. It requires other extensions to contribute support for specific project types.
### VS Code
This extension is bundled into the `SQL Server (MSSQL)` extension for VS Code and is required by the `SQL Database Projects` extension. It will be installed automatically when those extensions are updated or installed.
### Azure Data Studio
This extension is built into Azure Data Studio and will show up under the list of builtin extensions.
## Code of Conduct ## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@@ -2,7 +2,7 @@
"name": "data-workspace", "name": "data-workspace",
"displayName": "Data Workspace", "displayName": "Data Workspace",
"description": "Additional common functionality for database projects", "description": "Additional common functionality for database projects",
"version": "0.1.0", "version": "0.1.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -1,6 +1,6 @@
{ {
"data-workspace-view-container-name": "Database Projects", "data-workspace-view-container-name": "Projects",
"main-view-name": "Database Projects", "main-view-name": "Projects",
"new-command": "New", "new-command": "New",
"refresh-workspace-command": "Refresh", "refresh-workspace-command": "Refresh",
"close-workspace-command": "Close Workspace", "close-workspace-command": "Close Workspace",

View File

@@ -2,7 +2,7 @@
"name": "import", "name": "import",
"displayName": "SQL Server Import", "displayName": "SQL Server Import",
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.", "description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
"version": "1.5.0", "version": "1.5.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"engines": { "engines": {

View File

@@ -9,7 +9,7 @@
"azdata": "*" "azdata": "*"
}, },
"activationEvents": [ "activationEvents": [
"onFileSystem:memfs", "onFileSystem:memfs",
"onDebug", "onDebug",
"onCommand:integration-tests.onboarding.showDevelopers" "onCommand:integration-tests.onboarding.showDevelopers"
], ],
@@ -26,7 +26,7 @@
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json" "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json"
}, },
"contributes": { "contributes": {
"commands": [ "commands":[
{ {
"command": "integration-tests.onboarding.showDevelopers", "command": "integration-tests.onboarding.showDevelopers",
"title": "Show Developers" "title": "Show Developers"
@@ -44,8 +44,5 @@
"mocha-multi-reporters": "^1.1.7", "mocha-multi-reporters": "^1.1.7",
"ms-rest-azure": "^2.6.0", "ms-rest-azure": "^2.6.0",
"vscodetestcover": "^1.1.0" "vscodetestcover": "^1.1.0"
},
"resolutions": {
"json-schema": "0.4.0"
} }
} }

View File

@@ -54,10 +54,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
let target: mssql.SchemaCompareEndpointInfo = { let target: mssql.SchemaCompareEndpointInfo = {
@@ -67,10 +63,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -122,10 +114,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: sourceDB, databaseName: sourceDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
let target: mssql.SchemaCompareEndpointInfo = { let target: mssql.SchemaCompareEndpointInfo = {
@@ -135,10 +123,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: targetDB, databaseName: targetDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -195,10 +179,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
let target: mssql.SchemaCompareEndpointInfo = { let target: mssql.SchemaCompareEndpointInfo = {
@@ -208,10 +188,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: targetDB, databaseName: targetDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -255,10 +231,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
let target: mssql.SchemaCompareEndpointInfo = { let target: mssql.SchemaCompareEndpointInfo = {
@@ -268,10 +240,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -329,10 +297,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
const target: mssql.SchemaCompareEndpointInfo = { const target: mssql.SchemaCompareEndpointInfo = {
@@ -342,10 +306,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: targetDB, databaseName: targetDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -363,7 +323,7 @@ suite('Schema compare integration test suite @DacFx@', () => {
assertIncludeExcludeResult(includeResult, true, 0, 0); assertIncludeExcludeResult(includeResult, true, 0, 0);
//publish the updated changes. Function1 should not be added to the target database //publish the updated changes. Function1 should not be added to the target database
const publishChangesResult = await schemaCompareService.schemaComparePublishDatabaseChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute); const publishChangesResult = await schemaCompareService.schemaComparePublishChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute);
assert(publishChangesResult.success === true, `Publish changes should complete successfully. But it failed with error : ${publishChangesResult.errorMessage}`); assert(publishChangesResult.success === true, `Publish changes should complete successfully. But it failed with error : ${publishChangesResult.errorMessage}`);
//verify table Table3 is added //verify table Table3 is added
@@ -412,10 +372,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
const target: mssql.SchemaCompareEndpointInfo = { const target: mssql.SchemaCompareEndpointInfo = {
@@ -425,10 +381,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: targetDB, databaseName: targetDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
@@ -438,7 +390,7 @@ suite('Schema compare integration test suite @DacFx@', () => {
assertSchemaCompareResult(schemaCompareResult, operationId, 4); assertSchemaCompareResult(schemaCompareResult, operationId, 4);
//publish all the changes //publish all the changes
const publishChangesResult = await schemaCompareService.schemaComparePublishDatabaseChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute); const publishChangesResult = await schemaCompareService.schemaComparePublishChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute);
assert(publishChangesResult.success === true, `Publish changes should complete successfully. But it failed with error : ${publishChangesResult.errorMessage}`); assert(publishChangesResult.success === true, `Publish changes should complete successfully. But it failed with error : ${publishChangesResult.errorMessage}`);
//verify table Table3 is added //verify table Table3 is added
@@ -483,10 +435,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };
const target: mssql.SchemaCompareEndpointInfo = { const target: mssql.SchemaCompareEndpointInfo = {
@@ -496,10 +444,6 @@ suite('Schema compare integration test suite @DacFx@', () => {
serverName: server.serverName, serverName: server.serverName,
databaseName: targetDB, databaseName: targetDB,
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
connectionDetails: undefined connectionDetails: undefined
}; };

View File

@@ -202,11 +202,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.45.tgz#4c49ba34106bc7dced77ff6bae8eb6543cde8351" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.45.tgz#4c49ba34106bc7dced77ff6bae8eb6543cde8351"
integrity sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ== integrity sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ==
"@xmldom/xmldom@^0.7.0":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d"
integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==
adal-node@^0.1.28: adal-node@^0.1.28:
version "0.1.28" version "0.1.28"
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.28.tgz#468c4bb3ebbd96b1270669f4b9cba4e0065ea485" resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.28.tgz#468c4bb3ebbd96b1270669f4b9cba4e0065ea485"
@@ -222,20 +217,6 @@ adal-node@^0.1.28:
xmldom ">= 0.1.x" xmldom ">= 0.1.x"
xpath.js "~1.1.0" xpath.js "~1.1.0"
adal-node@^0.2.2:
version "0.2.3"
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.2.3.tgz#87ed3dbed344f6e114e36bf18fe1c4e7d3cc6069"
integrity sha512-gMKr8RuYEYvsj7jyfCv/4BfKToQThz20SP71N3AtFn3ia3yAR8Qt2T3aVQhuJzunWs2b38ZsQV0qsZPdwZr7VQ==
dependencies:
"@xmldom/xmldom" "^0.7.0"
async "^2.6.3"
axios "^0.21.1"
date-utils "*"
jws "3.x.x"
underscore ">= 1.3.1"
uuid "^3.1.0"
xpath.js "~1.1.0"
ajv@^6.5.5: ajv@^6.5.5:
version "6.10.0" version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
@@ -294,13 +275,6 @@ async@>=0.6.0:
dependencies: dependencies:
lodash "^4.17.11" lodash "^4.17.11"
async@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
dependencies:
lodash "^4.17.14"
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -316,13 +290,6 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
axios@^0.21.1:
version "0.21.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
dependencies:
follow-redirects "^1.14.0"
azure-keyvault@^3.0.4: azure-keyvault@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/azure-keyvault/-/azure-keyvault-3.0.4.tgz#b7733d8f58d99a66f9ae766451556eb3b058dae5" resolved "https://registry.yarnpkg.com/azure-keyvault/-/azure-keyvault-3.0.4.tgz#b7733d8f58d99a66f9ae766451556eb3b058dae5"
@@ -548,11 +515,6 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
follow-redirects@^1.14.0:
version "1.14.5"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
forever-agent@~0.6.1: forever-agent@~0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -780,10 +742,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1: json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"
@@ -824,7 +786,7 @@ jws@3.x.x:
jwa "^1.4.1" jwa "^1.4.1"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
lodash@^4.14.0, lodash@^4.16.4, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14: lodash@^4.14.0, lodash@^4.16.4, lodash@^4.17.11, lodash@^4.17.13:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -942,7 +904,7 @@ moment@^2.21.0, moment@^2.22.2:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
ms-rest-azure@^2.5.5: ms-rest-azure@^2.5.5, ms-rest-azure@^2.6.0:
version "2.6.0" version "2.6.0"
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-2.6.0.tgz#2098efec529eecfa0c6e215b69143abcaba12140" resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-2.6.0.tgz#2098efec529eecfa0c6e215b69143abcaba12140"
integrity sha512-J6386a9krZ4VtU7CRt+Ypgo9RGf8+d3gjMBkH7zbkM4zzkhbbMOYiPRaZ+bHZcfihkKLlktTgA6rjshTjF329A== integrity sha512-J6386a9krZ4VtU7CRt+Ypgo9RGf8+d3gjMBkH7zbkM4zzkhbbMOYiPRaZ+bHZcfihkKLlktTgA6rjshTjF329A==
@@ -954,17 +916,6 @@ ms-rest-azure@^2.5.5:
request "^2.88.0" request "^2.88.0"
uuid "^3.2.1" uuid "^3.2.1"
ms-rest-azure@^2.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-2.6.1.tgz#f59911da931902d0d22f3f44b2a76cc317d02038"
integrity sha512-LRpluf3wI/GQiuPe8PorhuwKt7YP2atG0wMOdyqSM2SQQH3+VMl9crjEBRe19CNa9zdoxOIPsAdyMwKtDs8Ung==
dependencies:
adal-node "^0.2.2"
async "2.6.0"
ms-rest "^2.3.2"
request "^2.88.0"
uuid "^3.2.1"
ms-rest@^2.3.2: ms-rest@^2.3.2:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/ms-rest/-/ms-rest-2.5.0.tgz#d483c003f7de7703ade6bc19c3b4319affac2687" resolved "https://registry.yarnpkg.com/ms-rest/-/ms-rest-2.5.0.tgz#d483c003f7de7703ade6bc19c3b4319affac2687"

View File

@@ -1,6 +1,6 @@
{ {
"name": "kusto", "name": "kusto",
"version": "0.5.7", "version": "0.5.8",
"publisher": "Microsoft", "publisher": "Microsoft",
"aiKey": "AIF-444c3af9-8e69-4462-ab49-4191e6ad1916", "aiKey": "AIF-444c3af9-8e69-4462-ab49-4191e6ad1916",
"activationEvents": [ "activationEvents": [

View File

@@ -2,7 +2,7 @@
"name": "machine-learning", "name": "machine-learning",
"displayName": "%displayName%", "displayName": "%displayName%",
"description": "%description%", "description": "%description%",
"version": "0.12.0", "version": "0.12.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"engines": { "engines": {
@@ -23,12 +23,12 @@
"type": "git", "type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git" "url": "https://github.com/Microsoft/azuredatastudio.git"
}, },
"capabilities": { "capabilities": {
"virtualWorkspaces": false, "virtualWorkspaces": false,
"untrustedWorkspaces": { "untrustedWorkspaces": {
"supported": true "supported": true
} }
}, },
"extensionDependencies": [ "extensionDependencies": [
"Microsoft.mssql", "Microsoft.mssql",
"Microsoft.notebook" "Microsoft.notebook"
@@ -156,9 +156,6 @@
"typemoq": "^2.1.0", "typemoq": "^2.1.0",
"vscodetestcover": "^1.1.0" "vscodetestcover": "^1.1.0"
}, },
"resolutions": {
"json-schema": "0.4.0"
},
"__metadata": { "__metadata": {
"id": "65", "id": "65",
"publisherDisplayName": "Microsoft", "publisherDisplayName": "Microsoft",

View File

@@ -303,7 +303,6 @@ export function createViewContext(): ViewTestContext {
registerCloseValidator: () => { }, registerCloseValidator: () => { },
registerOperation: () => { }, registerOperation: () => { },
onValidityChanged: new vscode.EventEmitter<boolean>().event, onValidityChanged: new vscode.EventEmitter<boolean>().event,
onClosed: new vscode.EventEmitter<azdata.window.CloseReason>().event,
registerContent: () => { }, registerContent: () => { },
modelView: undefined!, modelView: undefined!,
valid: true valid: true

View File

@@ -769,10 +769,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1: json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "3.0.0-release.174", "version": "3.0.0-release.139",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-net5.0.zip", "Windows_86": "win-x86-net5.0.zip",
"Windows_64": "win-x64-net5.0.zip", "Windows_64": "win-x64-net5.0.zip",

View File

@@ -498,11 +498,6 @@
"command": "mssqlCluster.livy.cmd.submitFileToSparkJob", "command": "mssqlCluster.livy.cmd.submitFileToSparkJob",
"when": "nodeType == mssqlCluster:file && nodeSubType =~/:spark:/", "when": "nodeType == mssqlCluster:file && nodeSubType =~/:spark:/",
"group": "1mssqlCluster@6" "group": "1mssqlCluster@6"
},
{
"command": "mssql.designTable",
"when": "connectionProvider == MSSQL && nodeType == Table && config.tableDesigner.enableFeature",
"group": "0_query@3"
} }
], ],
"notebook/toolbar": [ "notebook/toolbar": [
@@ -1315,8 +1310,5 @@
"should": "^13.2.3", "should": "^13.2.3",
"typemoq": "^2.1.0", "typemoq": "^2.1.0",
"vscodetestcover": "^1.1.0" "vscodetestcover": "^1.1.0"
},
"resolutions": {
"json-schema": "0.4.0"
} }
} }

View File

@@ -628,20 +628,13 @@ export interface SchemaCompareGenerateScriptParams {
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
} }
export interface SchemaComparePublishDatabaseChangesParams { export interface SchemaComparePublishChangesParams {
operationId: string; operationId: string;
targetServerName: string; targetServerName: string;
targetDatabaseName: string; targetDatabaseName: string;
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
} }
export interface SchemaComparePublishProjectChangesParams {
operationId: string;
targetProjectPath: string;
targetFolderStructure: mssql.ExtractTarget;
taskExecutionMode: TaskExecutionMode;
}
export interface SchemaCompareGetOptionsParams { export interface SchemaCompareGetOptionsParams {
} }
@@ -680,15 +673,7 @@ export namespace SchemaCompareGenerateScriptRequest {
} }
export namespace SchemaComparePublishChangesRequest { export namespace SchemaComparePublishChangesRequest {
export const type = new RequestType<SchemaComparePublishDatabaseChangesParams, azdata.ResultStatus, void, void>('schemaCompare/publish'); export const type = new RequestType<SchemaComparePublishChangesParams, azdata.ResultStatus, void, void>('schemaCompare/publish');
}
export namespace SchemaComparePublishDatabaseChangesRequest {
export const type = new RequestType<SchemaComparePublishDatabaseChangesParams, azdata.ResultStatus, void, void>('schemaCompare/publishDatabase');
}
export namespace SchemaComparePublishProjectChangesRequest {
export const type = new RequestType<SchemaComparePublishProjectChangesParams, mssql.SchemaComparePublishProjectResult, void, void>('schemaCompare/publishProject');
} }
export namespace SchemaCompareGetDefaultOptionsRequest { export namespace SchemaCompareGetDefaultOptionsRequest {
@@ -1045,12 +1030,12 @@ export namespace GetSqlMigrationAssessmentItemsRequest {
export interface TableDesignerEditRequestParams { export interface TableDesignerEditRequestParams {
tableInfo: azdata.designers.TableInfo, tableInfo: azdata.designers.TableInfo,
tableChangeInfo: azdata.designers.DesignerEdit, tableChangeInfo: azdata.designers.DesignerEdit,
viewModel: azdata.designers.DesignerViewModel data: azdata.designers.DesignerData
} }
export interface SaveTableDesignerChangesRequestParams { export interface SaveTableDesignerChangesRequestParams {
tableInfo: azdata.designers.TableInfo, tableInfo: azdata.designers.TableInfo,
viewModel: azdata.designers.DesignerViewModel data: azdata.designers.DesignerData
} }
export namespace GetTableDesignerInfoRequest { export namespace GetTableDesignerInfoRequest {
@@ -1065,7 +1050,4 @@ export namespace SaveTableDesignerChangesRequest {
export const type = new RequestType<SaveTableDesignerChangesRequestParams, void, void, void>('tabledesigner/savechanges'); export const type = new RequestType<SaveTableDesignerChangesRequestParams, void, void, void>('tabledesigner/savechanges');
} }
export namespace DisposeTableDesignerRequest {
export const type = new RequestType<azdata.designers.TableInfo, void, void, void>('tabledesigner/dispose');
}
// ------------------------------- < Table Designer > ------------------------------------ // ------------------------------- < Table Designer > ------------------------------------

View File

@@ -1117,10 +1117,10 @@ export class TableDesignerFeature extends SqlOpsFeature<undefined> {
return Promise.reject(e); return Promise.reject(e);
} }
}; };
const processTableEdit = (tableInfo: azdata.designers.TableInfo, viewModel: azdata.designers.DesignerViewModel, tableChangeInfo: azdata.designers.DesignerEdit): Thenable<azdata.designers.DesignerEditResult> => { const processTableEdit = (tableInfo: azdata.designers.TableInfo, data: azdata.designers.DesignerData, tableChangeInfo: azdata.designers.DesignerEdit): Thenable<azdata.designers.DesignerEditResult> => {
let params: contracts.TableDesignerEditRequestParams = { let params: contracts.TableDesignerEditRequestParams = {
tableInfo: tableInfo, tableInfo: tableInfo,
viewModel: viewModel, data: data,
tableChangeInfo: tableChangeInfo tableChangeInfo: tableChangeInfo
}; };
try { try {
@@ -1132,10 +1132,10 @@ export class TableDesignerFeature extends SqlOpsFeature<undefined> {
} }
}; };
const saveTable = (tableInfo: azdata.designers.TableInfo, viewModel: azdata.designers.DesignerViewModel): Thenable<void> => { const saveTable = (tableInfo: azdata.designers.TableInfo, data: azdata.designers.DesignerData): Thenable<void> => {
let params: contracts.SaveTableDesignerChangesRequestParams = { let params: contracts.SaveTableDesignerChangesRequestParams = {
tableInfo: tableInfo, tableInfo: tableInfo,
viewModel: viewModel data: data
}; };
try { try {
return client.sendRequest(contracts.SaveTableDesignerChangesRequest.type, params); return client.sendRequest(contracts.SaveTableDesignerChangesRequest.type, params);
@@ -1146,22 +1146,11 @@ export class TableDesignerFeature extends SqlOpsFeature<undefined> {
} }
}; };
const disposeTableDesigner = (tableInfo: azdata.designers.TableInfo): Thenable<void> => {
try {
return client.sendRequest(contracts.DisposeTableDesignerRequest.type, tableInfo);
}
catch (e) {
client.logFailedRequest(contracts.DisposeTableDesignerRequest.type, e);
return Promise.reject(e);
}
};
return azdata.dataprotocol.registerTableDesignerProvider({ return azdata.dataprotocol.registerTableDesignerProvider({
providerId: client.providerId, providerId: client.providerId,
getTableDesignerInfo, getTableDesignerInfo,
processTableEdit, processTableEdit,
saveTable, saveTable
disposeTableDesigner
}); });
} }
} }

View File

@@ -122,10 +122,7 @@ export const enum SchemaDifferenceType {
export const enum SchemaCompareEndpointType { export const enum SchemaCompareEndpointType {
Database = 0, Database = 0,
Dacpac = 1, Dacpac = 1
Project = 2,
// must be kept in-sync with SchemaCompareEndpointType in SQL Tools Service
// located at \src\Microsoft.SqlTools.ServiceLayer\SchemaCompare\Contracts\SchemaCompareRequest.cs
} }
export interface SchemaCompareEndpointInfo { export interface SchemaCompareEndpointInfo {
@@ -137,10 +134,6 @@ export interface SchemaCompareEndpointInfo {
ownerUri: string; ownerUri: string;
connectionDetails: azdata.ConnectionInfo; connectionDetails: azdata.ConnectionInfo;
connectionName?: string; connectionName?: string;
projectFilePath: string;
targetScripts: string[];
folderStructure: string;
dataSchemaProvider: string;
} }
export interface SchemaCompareObjectId { export interface SchemaCompareObjectId {
@@ -314,11 +307,10 @@ export interface SchemaCompareObjectId {
} }
export interface ISchemaCompareService { export interface ISchemaCompareService {
schemaCompare(operationId: string, sourceEndpointInfo: SchemaCompareEndpointInfo, targetEndpointInfo: SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: DeploymentOptions): Thenable<SchemaCompareResult>; schemaCompare(operationId: string, sourceEndpointInfo: SchemaCompareEndpointInfo, targetEndpointInfo: SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: DeploymentOptions): Thenable<SchemaCompareResult>;
schemaCompareGenerateScript(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus>; schemaCompareGenerateScript(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus>;
schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus>; schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus>;
schemaComparePublishDatabaseChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus>;
schemaComparePublishProjectChanges(operationId: string, targetProjectPath: string, targetFolderStructure: ExtractTarget, taskExecutionMode: azdata.TaskExecutionMode): Thenable<SchemaComparePublishProjectResult>;
schemaCompareGetDefaultOptions(): Thenable<SchemaCompareOptionsResult>; schemaCompareGetDefaultOptions(): Thenable<SchemaCompareOptionsResult>;
schemaCompareIncludeExcludeNode(operationId: string, diffEntry: DiffEntry, IncludeRequest: boolean, taskExecutionMode: azdata.TaskExecutionMode): Thenable<SchemaCompareIncludeExcludeResult>; schemaCompareIncludeExcludeNode(operationId: string, diffEntry: DiffEntry, IncludeRequest: boolean, taskExecutionMode: azdata.TaskExecutionMode): Thenable<SchemaCompareIncludeExcludeResult>;
schemaCompareOpenScmp(filePath: string): Thenable<SchemaCompareOpenScmpResult>; schemaCompareOpenScmp(filePath: string): Thenable<SchemaCompareOpenScmpResult>;
@@ -336,12 +328,6 @@ export interface SchemaCompareOpenScmpResult extends azdata.ResultStatus {
excludedTargetElements: SchemaCompareObjectId[]; excludedTargetElements: SchemaCompareObjectId[];
} }
export interface SchemaComparePublishProjectResult extends azdata.ResultStatus {
changedFiles: string[];
addedFiles: string[];
deletedFiles: string[];
}
//#endregion //#endregion
//#region --- dacfx //#region --- dacfx

View File

@@ -55,31 +55,11 @@ export class SchemaCompareService implements mssql.ISchemaCompareService {
} }
public schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> { public schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
const params: contracts.SchemaComparePublishDatabaseChangesParams = { operationId: operationId, targetServerName: targetServerName, targetDatabaseName: targetDatabaseName, taskExecutionMode: taskExecutionMode }; const params: contracts.SchemaComparePublishChangesParams = { operationId: operationId, targetServerName: targetServerName, targetDatabaseName: targetDatabaseName, taskExecutionMode: taskExecutionMode };
return this.client.sendRequest(contracts.SchemaComparePublishChangesRequest.type, params).then(undefined, return this.client.sendRequest(contracts.SchemaComparePublishChangesRequest.type, params).then(
e => {
this.client.logFailedRequest(contracts.SchemaComparePublishChangesRequest.type, e); return Promise.resolve(undefined);
}
);
}
public schemaComparePublishDatabaseChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
const params: contracts.SchemaComparePublishDatabaseChangesParams = { operationId: operationId, targetServerName: targetServerName, targetDatabaseName: targetDatabaseName, taskExecutionMode: taskExecutionMode };
return this.client.sendRequest(contracts.SchemaComparePublishDatabaseChangesRequest.type, params).then(
undefined, undefined,
e => { e => {
this.client.logFailedRequest(contracts.SchemaComparePublishDatabaseChangesRequest.type, e); this.client.logFailedRequest(contracts.SchemaComparePublishChangesRequest.type, e);
return Promise.resolve(undefined);
}
);
}
public schemaComparePublishProjectChanges(operationId: string, targetProjectPath: string, targetFolderStructure: mssql.ExtractTarget, taskExecutionMode: azdata.TaskExecutionMode): Thenable<mssql.SchemaComparePublishProjectResult> {
const params: contracts.SchemaComparePublishProjectChangesParams = { operationId: operationId, targetProjectPath: targetProjectPath, targetFolderStructure: targetFolderStructure, taskExecutionMode: taskExecutionMode };
return this.client.sendRequest(contracts.SchemaComparePublishProjectChangesRequest.type, params).then(
undefined,
(e: any) => {
this.client.logFailedRequest(contracts.SchemaComparePublishProjectChangesRequest.type, e);
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
); );

View File

@@ -7,17 +7,15 @@ import { AppContext } from '../appContext';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { sqlProviderName } from '../constants'; import { sqlProviderName } from '../constants';
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
export function registerTableDesignerCommands(appContext: AppContext) { export function registerTableDesignerCommands(appContext: AppContext) {
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => { appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => {
const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true); const connectionUri = await azdata.connection.getUriForConnection(context.connectionProfile.id);
await azdata.designers.openTableDesigner(sqlProviderName, { await azdata.designers.openTableDesigner(sqlProviderName, {
server: context.connectionProfile.serverName, server: context.connectionProfile.serverName,
database: context.connectionProfile.databaseName, database: context.connectionProfile.databaseName,
isNewTable: true, isNewTable: true,
id: generateUuid(), connectionUri: connectionUri
connectionString: connectionString
}); });
})); }));
@@ -26,7 +24,6 @@ export function registerTableDesignerCommands(appContext: AppContext) {
const database = context.connectionProfile.databaseName; const database = context.connectionProfile.databaseName;
const schema = context.nodeInfo.metadata.schema; const schema = context.nodeInfo.metadata.schema;
const name = context.nodeInfo.metadata.name; const name = context.nodeInfo.metadata.name;
const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true);
const connectionUri = await azdata.connection.getUriForConnection(context.connectionProfile.id); const connectionUri = await azdata.connection.getUriForConnection(context.connectionProfile.id);
await azdata.designers.openTableDesigner(sqlProviderName, { await azdata.designers.openTableDesigner(sqlProviderName, {
server: server, server: server,
@@ -34,8 +31,9 @@ export function registerTableDesignerCommands(appContext: AppContext) {
isNewTable: false, isNewTable: false,
name: name, name: name,
schema: schema, schema: schema,
id: `${connectionUri}|${database}|${schema}|${name}`, id: `${server}|${database}|${schema}|${name}`,
connectionString: connectionString connectionUri: connectionUri
}); });
})); }));
} }

View File

@@ -1136,10 +1136,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1: json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"

View File

@@ -13,12 +13,12 @@
"activationEvents": [ "activationEvents": [
"*" "*"
], ],
"capabilities": { "capabilities": {
"virtualWorkspaces": false, "virtualWorkspaces": false,
"untrustedWorkspaces": { "untrustedWorkspaces": {
"supported": true "supported": true
} }
}, },
"contributes": { "contributes": {
"configuration": { "configuration": {
"type": "object", "type": "object",
@@ -424,10 +424,6 @@
"command": "notebook.command.addNotebook", "command": "notebook.command.addNotebook",
"when": "false" "when": "false"
}, },
{
"command": "notebook.command.addSection",
"when": "false"
},
{ {
"command": "notebook.command.addMarkdown", "command": "notebook.command.addMarkdown",
"when": "false" "when": "false"
@@ -690,50 +686,48 @@
] ]
} }
], ],
"notebook.providers": [ "notebook.providers": {
{ "provider": "jupyter",
"provider": "jupyter", "fileExtensions": [
"fileExtensions": [ "IPYNB"
".ipynb" ],
], "standardKernels": [
"standardKernels": [ {
{ "name": "pysparkkernel",
"name": "pysparkkernel", "displayName": "PySpark",
"displayName": "PySpark", "connectionProviderIds": [
"connectionProviderIds": [ "MSSQL"
"MSSQL" ],
], "blockedOnSAW": true
"blockedOnSAW": true },
}, {
{ "name": "sparkkernel",
"name": "sparkkernel", "displayName": "Spark | Scala",
"displayName": "Spark | Scala", "connectionProviderIds": [
"connectionProviderIds": [ "MSSQL"
"MSSQL" ],
], "blockedOnSAW": true
"blockedOnSAW": true },
}, {
{ "name": "sparkrkernel",
"name": "sparkrkernel", "displayName": "Spark | R",
"displayName": "Spark | R", "connectionProviderIds": [
"connectionProviderIds": [ "MSSQL"
"MSSQL" ],
], "blockedOnSAW": true
"blockedOnSAW": true },
}, {
{ "name": "python3",
"name": "python3", "displayName": "Python 3",
"displayName": "Python 3", "connectionProviderIds": []
"connectionProviderIds": [] },
}, {
{ "name": "powershell",
"name": "powershell", "displayName": "PowerShell",
"displayName": "PowerShell", "connectionProviderIds": []
"connectionProviderIds": [] }
} ]
] }
}
]
}, },
"dependencies": { "dependencies": {
"@jupyterlab/services": "^3.2.1", "@jupyterlab/services": "^3.2.1",
@@ -774,8 +768,7 @@
"vscodetestcover": "^1.1.0" "vscodetestcover": "^1.1.0"
}, },
"resolutions": { "resolutions": {
"url-parse": "^1.5.1", "url-parse": "^1.5.1"
"json-schema": "0.4.0"
}, },
"enableProposedApi": true "enableProposedApi": true
} }

View File

@@ -92,7 +92,7 @@ export class InstalledPackagesTab {
} }
], ],
data: [[]], data: [[]],
height: '500px', height: '600px',
width: '400px' width: '400px'
}).component(); }).component();
this.disposables.push(this.installedPackagesTable.onCellAction(async (rowState) => { this.disposables.push(this.installedPackagesTable.onCellAction(async (rowState) => {

View File

@@ -1171,10 +1171,10 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3, json-schema@0.4.0: json-schema@0.2.3:
version "0.4.0" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stable-stringify@^1.0.1: json-stable-stringify@^1.0.1:
version "1.0.1" version "1.0.1"

View File

@@ -2,7 +2,7 @@
"name": "profiler", "name": "profiler",
"displayName": "%displayName%", "displayName": "%displayName%",
"description": "%description%", "description": "%description%",
"version": "0.12.1", "version": "0.12.2",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -2,7 +2,7 @@
"name": "query-history", "name": "query-history",
"displayName": "%queryHistory.displayName%", "displayName": "%queryHistory.displayName%",
"description": "%queryHistory.description%", "description": "%queryHistory.description%",
"version": "0.2.0", "version": "0.2.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -1,236 +0,0 @@
# Resource Deployment Extension Developer Guide
This guide is meant to provide details on what this extension does and how other extension authors are meant to use it. If there is any missing or incorrect information please submit an [issue](https://github.com/microsoft/azuredatastudio/issues).
## Overview
This extension provides a way for other extension authors to contribute types to the Resource Deployment Wizard which allows users to create and deploy resources such as servers.
This wizard is launched by either running the `Deployment: New Deployment...` command from the command palette or by clicking the `...` on the `Connections` pane and selecting `New Deployment...`
## How to Contribute a new Type
Resource Deployment types are contributed through the `package.json` of a loaded extension. This is done by adding an `resourceDeploymentTypes` property under the `contributes` section of your `package.json`.
``` json
... // Other sections in your package.json
"contributes": {
..., // Other contributions
"resourceDeploymentTypes": [
// provided types go here
]
}
```
The rest of this guide will detail the various options and configuration available to provided types - most contributions will only need a subset of the available features.
The [sample-resource-deployment](https://github.com/microsoft/azuredatastudio/tree/main/samples/sample-resource-deployment) extension provides working examples of contributed sample resource deployment types.
## resourceDeploymentTypes Schema
The contribution must adhere to a specific schema, if there is an error in your `package.json` such as an unexpected type then this may result in errors in both your extension and the feature as a whole.
**!! THIS IS A WORK IN PROGRESS, IF YOU NEED INFORMATION ON A SPECIFIC TOPIC PLEASE OPEN AN ISSUE!**
### resourceDeploymentTypes
This is the top contribution and must be an array of [ResourceType](#resourcetype) objects.
``` json
"resourceDeploymentTypes": [
{
... // Contributed type
},
{
... // Another contributed type
}
]
```
### ResourceType
The type is defined [here](https://github.com/microsoft/azuredatastudio/blob/main/extensions/resource-deployment/src/interfaces.ts#L13).
There are a number of properties on each `ResourceType`.
`name` - The name of the type, this is not displayed to the user so should be a non-localized value and typically `-` delimited (e.g. `my-resource-type`)
`displayName` - The name of the type displayed to the user, this should be a localized string
`description` - The description of the type displayed to the user
`platforms` - The OS platforms that the type supports running on, options are `linux` (Linux distros), `darwin` (MacOS), `win32` (Windows) or`*` for all.
`icon` - The icon to display for the type - supports either single icon or separate ones for light and dark mode. The icon should be in `svg` format.
`options` - An array of [ResourceTypeOption](#resourcetypeoption) objects, allowing users to provide different sub-options for a given resource type. (e.g. the specific version of SQL Server to deploy)
`providers` - An array of [DeploymentProvider](#deploymentprovider) objects which define the wizards, dialogs or other means for a user to deploy their resource.
`agreements` - **OPTIONAL** An array of [AgreementInfo](#agreementinfo) objects which define any agreements the user must accept before proceeding with the deployment.
`displayIndex` - **OPTIONAL** A number corresponding to where the type should be displayed relative to the other types. A lower number means it will show up earlier in the list. Any types which don't specify this value will be shown last.
`okButtonText` - **OPTIONAL** The text to use for the `OK` button at the bottom of the Type Picker dialog. Default is `Select`.
`helpTexts` - **OPTIONAL** An array of strings to display to the user providing more information for the resource type (such as links to docs)
`tags` - **OPTIONAL** An array of strings that are used to indicate the category that the resource type belongs to. The usable tags are defined [here](https://github.com/microsoft/azuredatastudio/blob/main/extensions/resource-deployment/src/constants.ts#L10).
### ResourceTypeOption
**TODO**
### DeploymentProvider
#### Provider Types
There are a number of different types of providers that can be used which affect what happens when the user selects that provider. These are indicated by what fields the provider contains - the provider is checked in order of top to bottom for each property and uses the first type that it finds in the properties for that provider.
`Notebook Wizard` - A wizard is opened that can be used to prompt the user for values and display information, and then at the very end will open the specified Notebook with those values injected in. Indicated by the presence of the `notebookWizard` property.
`Dialog` - A single page dialog is opened that can be used to prompt the user for values. Indicated by the presence of the `dialog` property.
`Notebook` - The specified Notebook is opened for the user to run. Indicated by the presence of the `notebook` property.
`Download` - An installer is downloaded and ran. Indicated by the presence of the `downloadUrl` property.
`Web Page` - The specified URL is opened in the default browser for the user. Indicated by the presence of the `webPageUrl` property.
`Command` - The specified command is executed. Indicated by the presence of the `command` property.
### AgreementInfo
**TODO**
### NotebookWizard (extends [WizardInfoBase](#wizardinfobase))
See [NotebookWizardInfo](https://github.com/microsoft/azuredatastudio/blob/main/extensions/resource-deployment/src/interfaces.ts#L170) for how it's defined in code.
`notebook` - The path to the Python-based Notebook that is used as a template for the wizard.
`pages` - An array of [NotebookWizardPageInfo](#notebookwizardpageinfo) containing information for each page in the Notebook Wizard.
`codeCellInsertionPosition` - **OPTIONAL** The index of the code cell to insert the injected parameters cell. Default is 0.
### WizardInfoBase
`type` - **OPTIONAL** This is an internal type only used for BDC deployment wizards. Any other deployment providers can leave it out.
`doneAction`
`scriptAction` - **OPTIONAL**
`title`
`name` - **OPTIONAL**
`pages` - An array of the pages for this wizard. Each wizard implementation will usually have its own page type that extends [PageInfoBase](#pageinfobase).
`isSummaryPageAutoGenerated` - **OPTIONAL**
### NotebookWizardPageInfo (extends [PageInfoBase](#pageinfobase))
`description` - **OPTIONAL** The page description to display at the top of the page.
### PageInfoBase
`title` - The title to display for the page
`isSummaryPage` - **OPTIONAL** Whether this page is set as a summary page that displays a summary of the Note
`sections` - An array of [SectionInfo] objects containing the details of each section to display on this page.
### SectionInfo (extends [FieldInfoBase](#fieldinfobase))
`title` - **OPTIONAL** The title to display at the top of the section
`fields` - **OPTIONAL** An array of [FieldInfo](#fieldinfo) objects containing details for each field in this section.
`rows` - **OPTIONAL** Used for wide dialogs or wizards, the label for each field will be placed to the left of the field component.
`collapsible` - **OPTIONAL** Whether the section is collapsible or not. Default is `true`.
`collapsed` - **OPTIONAL** Whether the section starts off collapsed. Default is `false`.
`spaceBetweenFields` - **OPTIONAL** A string defining how much space should be between each field. Default is `50px`.
### FieldInfo
`subFields`
`type`
`defaultValue`
`confirmationRequired`
`confirmationLabel`
`min`
`max`
`required`
`options` - **REQUIRED** if `type` is `options`. See [Options](#options) for more information.
`placeHolder`
`description`
`labelCSSStyles`
`fontWeight`
`editable`
`enabled`
`dynamicOptions`
`isEvaluated`
`validations`
`valueProvider` - **OPTIONAL** If defined then the value for this field is retrieved using the specified [Value Provider](#value-provider).
#### Options
This defines the set of options for this field to display. There are a number of different ways to configure the set of options :
* String array (`string[]`) - A static list of values that will be shown as a dropdown. Default value selected is defined as `FieldInfo.defaultValue`.
* CategoryValue array (`azdata.CategoryValue[]`) - A static list of CategoryValue objects that will be shown as a dropdown. Each value will define a display name separate from its value - use this for values you want to display differently to the user (such as names for an Azure region).
* [OptionsInfo](#optionsinfo) - An object allowing more control over the option values.
See [sample-options](https://github.com/microsoft/azuredatastudio/blob/main/samples/sample-resource-deployment/package.json) for example implementations.
##### OptionsInfo
This object defines a set of options for a field, similar to the arrays that can be used for the [options](#options) field but with greater control over of the options. Currently there are two reasons that you would use this object over the arrays - either you want to display the options as something other than a dropdown or you wish to use an [Options Source Provider](#options-source-provider) to populate the options dynamically.
`values` - An array of either `strings` or `azdata.CategoryValue` objects. See [options](#options) for more details on each of those.
`defaultValue` - The string value of the default option to have selected
`optionsType` - How to display the options, either `radio` or `dropdown`
`source` - OPTIONAL If set defines the [Options Source Provider](#options-source-provider) to use for populating the options dynamically.
### Options Source Provider
### Value Provider
When a field specifies a value provider then it is saying that the value for that field is dynamic and will be retrieved from a value provider that is registered by an extension separately. This can be used for more complex logic such as running calculations, reading files, making web requests, etc.
See [sample-value-provider](https://github.com/microsoft/azuredatastudio/blob/main/samples/sample-resource-deployment/package.json) for an example implementation.
**NOTE** There is currently some behavior that should be known before using this :
1. The value providers are hooked up after all the components are made, so order doesn't generally matter (you don't have to define the trigger fields before the target field) when the values are on the same page.
2. If the fields are on different pages then currently the hookup logic is non-deterministic and so you may end up with trigger components not existing yet if they are on a different page which hasn't completed its initialization. **So currently having a value provider that has trigger fields on another page is not something officially supported. Contact the dev team if you need this for your scenario**
`providerId` - The string ID of this provider, this must be registered by an extension using [registerValueProvider](https://github.com/microsoft/azuredatastudio/blob/main/extensions/resource-deployment/src/typings/resource-deployment.d.ts#L47).
`triggerFields` - The field IDs (`variableName` or `label`) of the fields that - when changed - will trigger `getValue` to be called and the result set as the value of the dependent field. **NOTE** While `variableName` OR `label` is supported it is generally strongly suggested to use a `variableName` (even if you don't need that variable in the final deployment target) due to potential localization mismatches that could happen between the localized strings in the package.json and the ones used by the `valueProvider`.

View File

@@ -2,7 +2,7 @@
"name": "resource-deployment", "name": "resource-deployment",
"displayName": "%extension-displayName%", "displayName": "%extension-displayName%",
"description": "%extension-description%", "description": "%extension-description%",
"version": "0.0.1", "version": "0.0.2",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -307,7 +307,7 @@ export interface DynamicOptionsAlternates {
export interface ValueProviderInfo { export interface ValueProviderInfo {
providerId: string, providerId: string,
triggerFields: string[] triggerField: string
} }
export interface FieldInfoBase { export interface FieldInfoBase {

View File

@@ -5,10 +5,10 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import 'mocha'; import 'mocha';
import { InputValueType } from 'resource-deployment';
import * as should from 'should'; import * as should from 'should';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { InputValueType } from '../../../ui/modelViewUtils';
import { createValidation, GreaterThanOrEqualsValidation, IntegerValidation, LessThanOrEqualsValidation, RegexValidation, validateInputBoxComponent, Validation, ValidationType } from '../../../ui/validation/validations'; import { createValidation, GreaterThanOrEqualsValidation, IntegerValidation, LessThanOrEqualsValidation, RegexValidation, validateInputBoxComponent, Validation, ValidationType } from '../../../ui/validation/validations';
const inputBox = <azdata.InputBoxComponent>{ const inputBox = <azdata.InputBoxComponent>{

View File

@@ -24,19 +24,9 @@ declare module 'resource-deployment' {
getIsPassword?: (variableName: string) => boolean | Promise<boolean>; getIsPassword?: (variableName: string) => boolean | Promise<boolean>;
} }
export type InputValueType = string | number | boolean | undefined;
export interface IValueProvider { export interface IValueProvider {
/**
* The ID associated with this value provider. Fields use this ID in the package.json to indicate which provider to use to get the value for that field.
* Each ID must be globally unique - an error will be thrown if the same ID is already registered.
*/
readonly id: string, readonly id: string,
/** getValue(triggerValue: string): Promise<string>;
* Gets a calculated value based on the given input values.
* @param triggerValues A map of the trigger field names and their current values specified in the valueProvider field info
*/
getValue(triggerValues: {[key: string]: InputValueType}): Promise<InputValueType>;
} }
/** /**
@@ -48,12 +38,6 @@ declare module 'resource-deployment' {
export interface IExtension { export interface IExtension {
registerOptionsSourceProvider(provider: IOptionsSourceProvider): vscode.Disposable, registerOptionsSourceProvider(provider: IOptionsSourceProvider): vscode.Disposable,
/**
* Registers a value provider that resource deployment definitions can use to dynamically fetch the value for specified fields.
* @param provider The provider to register
* @returns A disposable is returned that will unregister the provider when is disposed - this should be used to ensure
* that the provider is unregistered when the extension is uninstalled/deactivated.
*/
registerValueProvider(provider: IValueProvider): vscode.Disposable registerValueProvider(provider: IValueProvider): vscode.Disposable
} }
} }

View File

@@ -7,7 +7,7 @@ import { azureResource } from 'azureResource';
import * as fs from 'fs'; import * as fs from 'fs';
import { EOL } from 'os'; import { EOL } from 'os';
import * as path from 'path'; import * as path from 'path';
import { InputValueType, IOptionsSourceProvider } from 'resource-deployment'; import { IOptionsSourceProvider } from 'resource-deployment';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { getDateTimeString, getErrorMessage, isUserCancelledError, throwUnless } from '../common/utils'; import { getDateTimeString, getErrorMessage, isUserCancelledError, throwUnless } from '../common/utils';
@@ -33,6 +33,7 @@ const localize = nls.loadMessageBundle();
*/ */
export type Validator = () => { valid: boolean, message: string }; export type Validator = () => { valid: boolean, message: string };
export type InputValueType = string | number | undefined;
export type InputComponent = azdata.TextComponent | azdata.InputBoxComponent | azdata.DropDownComponent | azdata.CheckBoxComponent | RadioGroupLoadingComponentBuilder; export type InputComponent = azdata.TextComponent | azdata.InputBoxComponent | azdata.DropDownComponent | azdata.CheckBoxComponent | RadioGroupLoadingComponentBuilder;
export type InputComponentInfo<T extends InputComponent> = { export type InputComponentInfo<T extends InputComponent> = {
component: T; component: T;
@@ -470,35 +471,20 @@ async function hookUpValueProviders(context: WizardPageContext): Promise<void> {
if (field.valueProvider) { if (field.valueProvider) {
const fieldKey = field.variableName || field.label; const fieldKey = field.variableName || field.label;
const fieldComponent = context.inputComponents[fieldKey]; const fieldComponent = context.inputComponents[fieldKey];
const targetComponent = context.inputComponents[field.valueProvider.triggerField];
if (!targetComponent) {
console.error(`Could not find target component ${field.valueProvider.triggerField} when hooking up value providers for ${field.label}`);
return;
}
const provider = await valueProviderService.getValueProvider(field.valueProvider.providerId); const provider = await valueProviderService.getValueProvider(field.valueProvider.providerId);
let targetComponentLabelToComponent: { [label: string]: InputComponentInfo<InputComponent>; } = {};
field.valueProvider.triggerFields.forEach((triggerField) => {
const targetComponent = context.inputComponents[triggerField];
if (!targetComponent) {
console.error(`Could not find target component '${triggerField}' when hooking up value providers for '${field.label}'`);
return;
}
targetComponentLabelToComponent[triggerField] = targetComponent;
});
// If one triggerfield changes value, update the new field value.
const updateFields = async () => { const updateFields = async () => {
let targetComponentLabelToValue: { [label: string]: InputValueType; } = {}; const targetComponentValue = await targetComponent.getValue();
for (let label in targetComponentLabelToComponent) { const newFieldValue = await provider.getValue(targetComponentValue?.toString() ?? '');
targetComponentLabelToValue[label] = await targetComponentLabelToComponent[label].getValue();
}
let newFieldValue = await provider.getValue(targetComponentLabelToValue);
fieldComponent.setValue(newFieldValue); fieldComponent.setValue(newFieldValue);
}; };
targetComponent.onValueChanged(() => {
// Set the onValueChanged behavior for each component updateFields();
for (let label in targetComponentLabelToComponent) { });
context.onNewDisposableCreated(targetComponentLabelToComponent[label].onValueChanged(() => {
updateFields();
}));
}
await updateFields(); await updateFields();
} }
})); }));
@@ -776,10 +762,7 @@ function processDropdownOptionsTypeField(context: FieldContext): azdata.DropDown
// Note we don't currently check that the value actually exists in the list - if it doesn't then it'll // Note we don't currently check that the value actually exists in the list - if it doesn't then it'll
// just default to the first one anyways // just default to the first one anyways
const initialValue = context.fieldInfo.variableName && context.initialVariableValues?.[context.fieldInfo.variableName]?.toString(); const initialValue = context.fieldInfo.variableName && context.initialVariableValues?.[context.fieldInfo.variableName]?.toString();
const optionValues = options.values; const defaultValue = initialValue || options.defaultValue;
// If we have an array of CategoryValues then find the option that matches the defaultValue specified - otherwise just use the defaultValue provided
const defaultValueOption = (optionValues && optionValues.length > 0 && typeof optionValues[0] === 'object') ? (optionValues as azdata.CategoryValue[]).find(v => v.name === options.defaultValue) : options.defaultValue;
const defaultValue = initialValue || defaultValueOption;
const dropdown = createDropdownInputInfo(context.view, { const dropdown = createDropdownInputInfo(context.view, {
values: options.values, values: options.values,
defaultValue: defaultValue, defaultValue: defaultValue,
@@ -880,18 +863,6 @@ function processReadonlyTextField(context: FieldContext, allowEvaluation: boolea
const text = context.fieldInfo.defaultValue !== undefined const text = context.fieldInfo.defaultValue !== undefined
? createLabel(context.view, { text: context.fieldInfo.defaultValue, description: '', required: false, width: context.fieldInfo.inputWidth }) ? createLabel(context.view, { text: context.fieldInfo.defaultValue, description: '', required: false, width: context.fieldInfo.inputWidth })
: undefined; : undefined;
if (text) {
// If we created the text component then add it to our list of inputs so other fields can utilize it
const onChangedEmitter = new vscode.EventEmitter<void>(); // Stub event since we don't currently support updating this when the dependent fields change
context.onNewDisposableCreated(onChangedEmitter);
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
component: text,
getValue: async (): Promise<InputValueType> => typeof text.value === 'string' ? text.value : text.value?.join(EOL),
setValue: (value: InputValueType) => text.value = value?.toString(),
onValueChanged: onChangedEmitter.event,
});
}
addLabelInputPairToContainer(context.view, context.components, label, text, context.fieldInfo); addLabelInputPairToContainer(context.view, context.components, label, text, context.fieldInfo);
return { label: label, text: text }; return { label: label, text: text };
} }

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { InputValueType } from 'resource-deployment';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { isUndefinedOrEmpty, throwUnless } from '../../common/utils'; import { isUndefinedOrEmpty, throwUnless } from '../../common/utils';
import { InputValueType } from '../modelViewUtils';
export interface ValidationResult { export interface ValidationResult {
valid: boolean; valid: boolean;

View File

@@ -2,7 +2,7 @@
"name": "schema-compare", "name": "schema-compare",
"displayName": "%displayName%", "displayName": "%displayName%",
"description": "%description%", "description": "%description%",
"version": "1.13.0", "version": "1.12.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": false, "preview": false,
"engines": { "engines": {

View File

@@ -9,7 +9,7 @@ import * as loc from '../localizedConstants';
import * as path from 'path'; import * as path from 'path';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow'; import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { TelemetryReporter, TelemetryViews } from '../telemetry'; import { TelemetryReporter, TelemetryViews } from '../telemetry';
import { getEndpointName, getRootPath, exists, getAzdataApi, getSchemaCompareEndpointString } from '../utils'; import { getEndpointName, getRootPath, exists } from '../utils';
import * as mssql from '../../../mssql'; import * as mssql from '../../../mssql';
const titleFontSize: number = 13; const titleFontSize: number = 13;
@@ -18,16 +18,13 @@ interface Deferred<T> {
resolve: (result: T | Promise<T>) => void; resolve: (result: T | Promise<T>) => void;
reject: (reason: any) => void; reject: (reason: any) => void;
} }
export class SchemaCompareDialog { export class SchemaCompareDialog {
public dialog: azdata.window.Dialog; public dialog: azdata.window.Dialog;
public dialogName: string; public dialogName: string;
private schemaCompareTab: azdata.window.DialogTab;
private sourceDacpacRadioButton: azdata.RadioButtonComponent; private sourceDacpacRadioButton: azdata.RadioButtonComponent;
private sourceDatabaseRadioButton: azdata.RadioButtonComponent; private sourceDatabaseRadioButton: azdata.RadioButtonComponent;
private sourceProjectRadioButton: azdata.RadioButtonComponent; private schemaCompareTab: azdata.window.DialogTab;
private sourceDacpacComponent: azdata.FormComponent; private sourceDacpacComponent: azdata.FormComponent;
private sourceProjectFilePathComponent: azdata.FormComponent;
private sourceTextBox: azdata.InputBoxComponent; private sourceTextBox: azdata.InputBoxComponent;
private sourceFileButton: azdata.ButtonComponent; private sourceFileButton: azdata.ButtonComponent;
private sourceServerComponent: azdata.FormComponent; private sourceServerComponent: azdata.FormComponent;
@@ -35,30 +32,22 @@ export class SchemaCompareDialog {
private sourceConnectionButton: azdata.ButtonComponent; private sourceConnectionButton: azdata.ButtonComponent;
private sourceDatabaseComponent: azdata.FormComponent; private sourceDatabaseComponent: azdata.FormComponent;
private sourceDatabaseDropdown: azdata.DropDownComponent; private sourceDatabaseDropdown: azdata.DropDownComponent;
private sourceEndpointType: mssql.SchemaCompareEndpointType;
private sourceDbEditable: string;
private sourceDacpacPath: string;
private sourceProjectFilePath: string;
private targetDacpacComponent: azdata.FormComponent; private targetDacpacComponent: azdata.FormComponent;
private targetProjectFilePathComponent: azdata.FormComponent;
private targetProjectStructureComponent: azdata.FormComponent;
private targetTextBox: azdata.InputBoxComponent; private targetTextBox: azdata.InputBoxComponent;
private targetFileButton: azdata.ButtonComponent; private targetFileButton: azdata.ButtonComponent;
private targetStructureDropdown: azdata.DropDownComponent;
private targetServerComponent: azdata.FormComponent; private targetServerComponent: azdata.FormComponent;
protected targetServerDropdown: azdata.DropDownComponent; protected targetServerDropdown: azdata.DropDownComponent;
private targetConnectionButton: azdata.ButtonComponent; private targetConnectionButton: azdata.ButtonComponent;
private targetDatabaseComponent: azdata.FormComponent; private targetDatabaseComponent: azdata.FormComponent;
private targetDatabaseDropdown: azdata.DropDownComponent; private targetDatabaseDropdown: azdata.DropDownComponent;
private targetDacpacPath: string; private formBuilder: azdata.FormBuilder;
private targetProjectFilePath: string; private sourceIsDacpac: boolean;
private targetEndpointType: mssql.SchemaCompareEndpointType; private targetIsDacpac: boolean;
private connectionId: string;
private sourceDbEditable: string;
private targetDbEditable: string; private targetDbEditable: string;
private previousSource: mssql.SchemaCompareEndpointInfo; private previousSource: mssql.SchemaCompareEndpointInfo;
private previousTarget: mssql.SchemaCompareEndpointInfo; private previousTarget: mssql.SchemaCompareEndpointInfo;
private formBuilder: azdata.FormBuilder;
private connectionId: string;
private toDispose: vscode.Disposable[] = [];
private initDialogComplete: Deferred<void>; private initDialogComplete: Deferred<void>;
private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject }); private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
@@ -70,11 +59,6 @@ export class SchemaCompareDialog {
constructor(private schemaCompareMainWindow: SchemaCompareMainWindow, private view?: azdata.ModelView, private extensionContext?: vscode.ExtensionContext) { constructor(private schemaCompareMainWindow: SchemaCompareMainWindow, private view?: azdata.ModelView, private extensionContext?: vscode.ExtensionContext) {
this.previousSource = schemaCompareMainWindow.sourceEndpointInfo; this.previousSource = schemaCompareMainWindow.sourceEndpointInfo;
this.previousTarget = schemaCompareMainWindow.targetEndpointInfo; this.previousTarget = schemaCompareMainWindow.targetEndpointInfo;
this.dialog = azdata.window.createModelViewDialog(loc.SchemaCompareLabel);
this.dialog.registerCloseValidator(async () => {
return this.validate();
});
} }
protected async initializeDialog(): Promise<void> { protected async initializeDialog(): Promise<void> {
@@ -95,17 +79,27 @@ export class SchemaCompareDialog {
this.dialog.okButton.label = loc.OkButtonText; this.dialog.okButton.label = loc.OkButtonText;
this.dialog.okButton.enabled = false; this.dialog.okButton.enabled = false;
this.toDispose.push(this.dialog.okButton.onClick(async () => await this.handleOkButtonClick())); this.dialog.okButton.onClick(async () => await this.execute());
this.dialog.cancelButton.label = loc.CancelButtonText; this.dialog.cancelButton.label = loc.CancelButtonText;
this.toDispose.push(this.dialog.cancelButton.onClick(async () => await this.cancel())); this.dialog.cancelButton.onClick(async () => await this.cancel());
azdata.window.openDialog(this.dialog); azdata.window.openDialog(this.dialog);
await this.initDialogPromise; await this.initDialogPromise;
} }
public async execute(): Promise<void> { public async execute(): Promise<void> {
if (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Database) { if (this.sourceIsDacpac) {
this.schemaCompareMainWindow.sourceEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Dacpac,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: this.sourceTextBox.value,
connectionDetails: undefined
};
} else {
const sourceServerDropdownValue = this.sourceServerDropdown.value as ConnectionDropdownValue; const sourceServerDropdownValue = this.sourceServerDropdown.value as ConnectionDropdownValue;
const ownerUri = await azdata.connection.getUriForConnection(sourceServerDropdownValue.connection.connectionId); const ownerUri = await azdata.connection.getUriForConnection(sourceServerDropdownValue.connection.connectionId);
@@ -115,45 +109,23 @@ export class SchemaCompareDialog {
serverName: sourceServerDropdownValue.name, serverName: sourceServerDropdownValue.name,
databaseName: this.sourceDatabaseDropdown.value.toString(), databaseName: this.sourceDatabaseDropdown.value.toString(),
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
targetScripts: [],
folderStructure: '',
packageFilePath: '', packageFilePath: '',
dataSchemaProvider: '',
connectionDetails: undefined, connectionDetails: undefined,
connectionName: sourceServerDropdownValue.connection.options.connectionName connectionName: sourceServerDropdownValue.connection.options.connectionName
}; };
} else if (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Dacpac) { }
this.schemaCompareMainWindow.sourceEndpointInfo = {
if (this.targetIsDacpac) {
this.schemaCompareMainWindow.targetEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Dacpac, endpointType: mssql.SchemaCompareEndpointType.Dacpac,
serverDisplayName: '', serverDisplayName: '',
serverName: '', serverName: '',
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
projectFilePath: '', packageFilePath: this.targetTextBox.value,
targetScripts: [],
folderStructure: '',
dataSchemaProvider: '',
packageFilePath: this.sourceTextBox.value,
connectionDetails: undefined connectionDetails: undefined
}; };
} else { } else {
this.schemaCompareMainWindow.sourceEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Project,
projectFilePath: this.sourceTextBox.value,
targetScripts: await this.getTargetScripts(true),
dataSchemaProvider: await this.getDsp(this.sourceTextBox.value),
folderStructure: '',
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: '',
connectionDetails: undefined
};
}
if (this.targetEndpointType === mssql.SchemaCompareEndpointType.Database) {
const targetServerDropdownValue = this.targetServerDropdown.value as ConnectionDropdownValue; const targetServerDropdownValue = this.targetServerDropdown.value as ConnectionDropdownValue;
const ownerUri = await azdata.connection.getUriForConnection(targetServerDropdownValue.connection.connectionId); const ownerUri = await azdata.connection.getUriForConnection(targetServerDropdownValue.connection.connectionId);
@@ -163,48 +135,16 @@ export class SchemaCompareDialog {
serverName: targetServerDropdownValue.name, serverName: targetServerDropdownValue.name,
databaseName: this.targetDatabaseDropdown.value.toString(), databaseName: this.targetDatabaseDropdown.value.toString(),
ownerUri: ownerUri, ownerUri: ownerUri,
projectFilePath: '',
folderStructure: '',
targetScripts: [],
packageFilePath: '', packageFilePath: '',
dataSchemaProvider: '',
connectionDetails: undefined, connectionDetails: undefined,
connectionName: targetServerDropdownValue.connection.options.connectionName connectionName: targetServerDropdownValue.connection.options.connectionName
}; };
} else if (this.targetEndpointType === mssql.SchemaCompareEndpointType.Dacpac) {
this.schemaCompareMainWindow.targetEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Dacpac,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
packageFilePath: this.targetTextBox.value,
connectionDetails: undefined
};
} else {
this.schemaCompareMainWindow.targetEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Project,
projectFilePath: this.targetTextBox.value,
folderStructure: this.targetStructureDropdown!.value as string,
targetScripts: await this.getTargetScripts(false),
dataSchemaProvider: await this.getDsp(this.targetTextBox.value),
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: '',
connectionDetails: undefined
};
} }
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareDialog, 'SchemaCompareStart') TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareDialog, 'SchemaCompareStart')
.withAdditionalProperties({ .withAdditionalProperties({
sourceEndpointType: getSchemaCompareEndpointString(this.sourceEndpointType), sourceIsDacpac: this.sourceIsDacpac.toString(),
targetEndpointType: getSchemaCompareEndpointString(this.targetEndpointType) targetIsDacpac: this.targetIsDacpac.toString()
}).send(); }).send();
// update source and target values that are displayed // update source and target values that are displayed
@@ -242,7 +182,6 @@ export class SchemaCompareDialog {
} }
protected async cancel(): Promise<void> { protected async cancel(): Promise<void> {
this.dispose();
} }
private async initializeSchemaCompareTab(): Promise<void> { private async initializeSchemaCompareTab(): Promise<void> {
@@ -251,67 +190,36 @@ export class SchemaCompareDialog {
this.view = view; this.view = view;
} }
let sourceValue = '';
if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Dacpac) {
sourceValue = this.schemaCompareMainWindow.sourceEndpointInfo.packageFilePath;
} else if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Project) {
sourceValue = this.schemaCompareMainWindow.sourceEndpointInfo.projectFilePath;
}
this.sourceTextBox = this.view.modelBuilder.inputBox().withProps({ this.sourceTextBox = this.view.modelBuilder.inputBox().withProps({
value: sourceValue, value: this.schemaCompareMainWindow.sourceEndpointInfo ? this.schemaCompareMainWindow.sourceEndpointInfo.packageFilePath : '',
width: this.textBoxWidth, width: this.textBoxWidth,
ariaLabel: loc.sourceFile ariaLabel: loc.sourceFile
}).component(); }).component();
this.sourceTextBox.onTextChanged(async (e) => { this.sourceTextBox.onTextChanged(async (e) => {
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
if (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Dacpac) {
this.sourceDacpacPath = e;
} else if (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Project) {
this.sourceProjectFilePath = e;
}
}); });
let targetValue = '';
if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Dacpac) {
targetValue = this.schemaCompareMainWindow.targetEndpointInfo.packageFilePath;
} else if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Project) {
targetValue = this.schemaCompareMainWindow.targetEndpointInfo.projectFilePath;
}
this.targetTextBox = this.view.modelBuilder.inputBox().withProps({ this.targetTextBox = this.view.modelBuilder.inputBox().withProps({
value: targetValue, value: this.schemaCompareMainWindow.targetEndpointInfo ? this.schemaCompareMainWindow.targetEndpointInfo.packageFilePath : '',
width: this.textBoxWidth, width: this.textBoxWidth,
ariaLabel: loc.targetFile ariaLabel: loc.targetFile
}).component(); }).component();
this.targetTextBox.onTextChanged(async (e) => { this.targetTextBox.onTextChanged(async () => {
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
if (this.targetEndpointType === mssql.SchemaCompareEndpointType.Dacpac) {
this.targetDacpacPath = e;
} else if (this.targetEndpointType === mssql.SchemaCompareEndpointType.Project) {
this.targetProjectFilePath = e;
}
}); });
this.sourceServerComponent = this.createSourceServerDropdown(); this.sourceServerComponent = this.createSourceServerDropdown();
this.sourceDatabaseComponent = this.createSourceDatabaseDropdown(); this.sourceDatabaseComponent = this.createSourceDatabaseDropdown();
this.targetServerComponent = this.createTargetServerDropdown(); this.targetServerComponent = this.createTargetServerDropdown();
this.targetDatabaseComponent = this.createTargetDatabaseDropdown(); this.targetDatabaseComponent = this.createTargetDatabaseDropdown();
this.sourceDacpacComponent = this.createFileBrowser(false, true, this.schemaCompareMainWindow.sourceEndpointInfo); this.sourceDacpacComponent = this.createFileBrowser(false, this.schemaCompareMainWindow.sourceEndpointInfo);
this.targetDacpacComponent = this.createFileBrowser(true, true, this.schemaCompareMainWindow.targetEndpointInfo); this.targetDacpacComponent = this.createFileBrowser(true, this.schemaCompareMainWindow.targetEndpointInfo);
this.sourceProjectFilePathComponent = this.createFileBrowser(false, false, this.schemaCompareMainWindow.sourceEndpointInfo);
this.targetProjectFilePathComponent = this.createFileBrowser(true, false, this.schemaCompareMainWindow.targetEndpointInfo);
this.targetProjectStructureComponent = this.createStructureDropdown();
let sourceRadioButtons = this.createSourceRadioButtons(); let sourceRadioButtons = this.createSourceRadioButtons();
let targetRadioButtons = this.createTargetRadioButtons(); let targetRadioButtons = this.createTargetRadioButtons();
@@ -319,37 +227,31 @@ export class SchemaCompareDialog {
let sourceComponents = []; let sourceComponents = [];
let targetComponents = []; let targetComponents = [];
// start source and target with either dacpac, database, or project selection based on what the previous value was // start source and target with either dacpac or database selection based on what the previous value was
sourceComponents = [sourceRadioButtons]; if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
sourceComponents = [
switch (this.sourceEndpointType) { sourceRadioButtons,
case mssql.SchemaCompareEndpointType.Database: this.sourceServerComponent,
sourceComponents.push( this.sourceDatabaseComponent
this.sourceServerComponent, ];
this.sourceDatabaseComponent); } else {
break; sourceComponents = [
case mssql.SchemaCompareEndpointType.Dacpac: sourceRadioButtons,
sourceComponents.push(this.sourceDacpacComponent); this.sourceDacpacComponent,
break; ];
case mssql.SchemaCompareEndpointType.Project:
sourceComponents.push(this.sourceProjectFilePathComponent);
break;
} }
targetComponents = [targetRadioButtons]; if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
targetComponents = [
switch (this.targetEndpointType) { targetRadioButtons,
case mssql.SchemaCompareEndpointType.Database: this.targetServerComponent,
targetComponents.push( this.targetDatabaseComponent
this.targetServerComponent, ];
this.targetDatabaseComponent); } else {
break; targetComponents = [
case mssql.SchemaCompareEndpointType.Dacpac: targetRadioButtons,
targetComponents.push(this.targetDacpacComponent); this.targetDacpacComponent,
break; ];
case mssql.SchemaCompareEndpointType.Project:
targetComponents.push(this.targetProjectFilePathComponent);
break;
} }
this.formBuilder = <azdata.FormBuilder>this.view.modelBuilder.formContainer() this.formBuilder = <azdata.FormBuilder>this.view.modelBuilder.formContainer()
@@ -372,26 +274,17 @@ export class SchemaCompareDialog {
let formModel = this.formBuilder.component(); let formModel = this.formBuilder.component();
await this.view.initializeModel(formModel); await this.view.initializeModel(formModel);
if (this.sourceIsDacpac) {
switch (this.sourceEndpointType) { await this.sourceDacpacRadioButton.focus();
case (mssql.SchemaCompareEndpointType.Database): } else {
await this.sourceDatabaseRadioButton.focus(); await this.sourceDatabaseRadioButton.focus();
break;
case (mssql.SchemaCompareEndpointType.Dacpac):
await this.sourceDacpacRadioButton.focus();
break;
case (mssql.SchemaCompareEndpointType.Project):
await this.sourceProjectRadioButton.focus();
break;
} }
this.initDialogComplete.resolve(); this.initDialogComplete.resolve();
}); });
} }
private createFileBrowser(isTarget: boolean, dacpac: boolean, endpoint: mssql.SchemaCompareEndpointInfo): azdata.FormComponent { private createFileBrowser(isTarget: boolean, endpoint: mssql.SchemaCompareEndpointInfo): azdata.FormComponent {
let currentTextbox = isTarget ? this.targetTextBox : this.sourceTextBox; let currentTextbox = isTarget ? this.targetTextBox : this.sourceTextBox;
if (isTarget) { if (isTarget) {
this.targetFileButton = this.view.modelBuilder.button().withProps({ this.targetFileButton = this.view.modelBuilder.button().withProps({
title: loc.selectTargetFile, title: loc.selectTargetFile,
@@ -409,9 +302,8 @@ export class SchemaCompareDialog {
} }
let currentButton = isTarget ? this.targetFileButton : this.sourceFileButton; let currentButton = isTarget ? this.targetFileButton : this.sourceFileButton;
const filter = dacpac ? 'dacpac' : 'sqlproj';
currentButton.onDidClick(async () => { currentButton.onDidClick(async (click) => {
// file browser should open where the current dacpac is or the appropriate default folder // file browser should open where the current dacpac is or the appropriate default folder
let rootPath = getRootPath(); let rootPath = getRootPath();
let defaultUri = endpoint && endpoint.packageFilePath && await exists(endpoint.packageFilePath) ? endpoint.packageFilePath : rootPath; let defaultUri = endpoint && endpoint.packageFilePath && await exists(endpoint.packageFilePath) ? endpoint.packageFilePath : rootPath;
@@ -424,7 +316,7 @@ export class SchemaCompareDialog {
defaultUri: vscode.Uri.file(defaultUri), defaultUri: vscode.Uri.file(defaultUri),
openLabel: loc.open, openLabel: loc.open,
filters: { filters: {
'Files': [filter], 'dacpac Files': ['dacpac'],
} }
} }
); );
@@ -444,22 +336,6 @@ export class SchemaCompareDialog {
}; };
} }
private createStructureDropdown(): azdata.FormComponent {
this.targetStructureDropdown = this.view.modelBuilder.dropDown().withProps({
editable: true,
fireOnTextChange: true,
ariaLabel: loc.targetStructure,
width: this.textBoxWidth,
values: [loc.file, loc.flat, loc.objectType, loc.schema, loc.schemaObjectType],
value: loc.schemaObjectType,
}).component();
return {
component: this.targetStructureDropdown,
title: loc.StructureDropdownLabel,
};
}
private createSourceRadioButtons(): azdata.FormComponent { private createSourceRadioButtons(): azdata.FormComponent {
this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton() this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton()
.withProps({ .withProps({
@@ -473,69 +349,36 @@ export class SchemaCompareDialog {
label: loc.DatabaseRadioButtonLabel label: loc.DatabaseRadioButtonLabel
}).component(); }).component();
this.sourceProjectRadioButton = this.view.modelBuilder.radioButton()
.withProps({
name: 'source',
label: loc.ProjectRadioButtonLabel
}).component();
// show dacpac file browser // show dacpac file browser
this.sourceDacpacRadioButton.onDidClick(async () => { this.sourceDacpacRadioButton.onDidClick(async () => {
this.sourceEndpointType = mssql.SchemaCompareEndpointType.Dacpac; this.sourceIsDacpac = true;
this.sourceTextBox.value = this.sourceDacpacPath;
this.formBuilder.removeFormItem(this.sourceServerComponent); this.formBuilder.removeFormItem(this.sourceServerComponent);
this.formBuilder.removeFormItem(this.sourceDatabaseComponent); this.formBuilder.removeFormItem(this.sourceDatabaseComponent);
this.formBuilder.removeFormItem(this.sourceProjectFilePathComponent);
this.formBuilder.insertFormItem(this.sourceDacpacComponent, 2, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.insertFormItem(this.sourceDacpacComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
// show server and db dropdowns // show server and db dropdowns
this.sourceDatabaseRadioButton.onDidClick(async () => { this.sourceDatabaseRadioButton.onDidClick(async () => {
this.sourceEndpointType = mssql.SchemaCompareEndpointType.Database; this.sourceIsDacpac = false;
this.formBuilder.insertFormItem(this.sourceServerComponent, 2, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.insertFormItem(this.sourceServerComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.removeFormItem(this.sourceDacpacComponent); this.formBuilder.removeFormItem(this.sourceDacpacComponent);
this.formBuilder.removeFormItem(this.sourceProjectFilePathComponent);
await this.populateServerDropdown(false); await this.populateServerDropdown(false);
}); });
// show project directory browser // if source is currently a db, show it in the server and db dropdowns
this.sourceProjectRadioButton.onDidClick(async () => { if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
this.sourceEndpointType = mssql.SchemaCompareEndpointType.Project; this.sourceDatabaseRadioButton.checked = true;
this.sourceTextBox.value = this.sourceProjectFilePath; this.sourceIsDacpac = false;
this.formBuilder.removeFormItem(this.sourceServerComponent); } else {
this.formBuilder.removeFormItem(this.sourceDatabaseComponent); this.sourceDacpacRadioButton.checked = true;
this.formBuilder.removeFormItem(this.sourceDacpacComponent); this.sourceIsDacpac = true;
this.formBuilder.insertFormItem(this.sourceProjectFilePathComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
this.sourceEndpointType = this.schemaCompareMainWindow.sourceEndpointInfo?.endpointType ?? mssql.SchemaCompareEndpointType.Database; // default to database if no specific source is passed
switch (this.sourceEndpointType) {
case mssql.SchemaCompareEndpointType.Dacpac:
this.sourceDacpacRadioButton.checked = true;
break;
case mssql.SchemaCompareEndpointType.Project:
this.sourceProjectRadioButton.checked = true;
break;
case mssql.SchemaCompareEndpointType.Database:
this.sourceDatabaseRadioButton.checked = true;
break;
} }
let radioButtons = [this.sourceDatabaseRadioButton, this.sourceDacpacRadioButton];
// TODO: re-add once database projects changes are checked in; chicken-and-egg problem (https://github.com/microsoft/azuredatastudio/pull/17738)
// if (vscode.extensions.getExtension(loc.sqlDatabaseProjectExtensionId)) {
// radioButtons.push(this.sourceProjectRadioButton);
// }
let flexRadioButtonsModel = this.view.modelBuilder.flexContainer() let flexRadioButtonsModel = this.view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' }) .withLayout({ flexFlow: 'column' })
.withItems(radioButtons) .withItems([this.sourceDacpacRadioButton, this.sourceDatabaseRadioButton])
.withProps({ ariaRole: 'radiogroup' }) .withProps({ ariaRole: 'radiogroup' })
.component(); .component();
@@ -546,85 +389,50 @@ export class SchemaCompareDialog {
} }
private createTargetRadioButtons(): azdata.FormComponent { private createTargetRadioButtons(): azdata.FormComponent {
let targetDacpacRadioButton = this.view.modelBuilder.radioButton() let dacpacRadioButton = this.view.modelBuilder.radioButton()
.withProps({ .withProps({
name: 'target', name: 'target',
label: loc.DacpacRadioButtonLabel label: loc.DacpacRadioButtonLabel
}).component(); }).component();
let targetDatabaseRadioButton = this.view.modelBuilder.radioButton() let databaseRadioButton = this.view.modelBuilder.radioButton()
.withProps({ .withProps({
name: 'target', name: 'target',
label: loc.DatabaseRadioButtonLabel label: loc.DatabaseRadioButtonLabel
}).component(); }).component();
let targetProjectRadioButton = this.view.modelBuilder.radioButton()
.withProps({
name: 'target',
label: loc.ProjectRadioButtonLabel
}).component();
// show dacpac file browser // show dacpac file browser
targetDacpacRadioButton.onDidClick(async () => { dacpacRadioButton.onDidClick(async () => {
this.targetEndpointType = mssql.SchemaCompareEndpointType.Dacpac; this.targetIsDacpac = true;
this.targetTextBox.value = this.targetDacpacPath;
this.formBuilder.removeFormItem(this.targetServerComponent); this.formBuilder.removeFormItem(this.targetServerComponent);
this.formBuilder.removeFormItem(this.targetDatabaseComponent); this.formBuilder.removeFormItem(this.targetDatabaseComponent);
this.formBuilder.removeFormItem(this.targetProjectFilePathComponent);
this.formBuilder.removeFormItem(this.targetProjectStructureComponent);
this.formBuilder.addFormItem(this.targetDacpacComponent, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.addFormItem(this.targetDacpacComponent, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
// show server and db dropdowns // show server and db dropdowns
targetDatabaseRadioButton.onDidClick(async () => { databaseRadioButton.onDidClick(async () => {
this.targetEndpointType = mssql.SchemaCompareEndpointType.Database; this.targetIsDacpac = false;
this.formBuilder.removeFormItem(this.targetDacpacComponent); this.formBuilder.removeFormItem(this.targetDacpacComponent);
this.formBuilder.removeFormItem(this.targetProjectFilePathComponent);
this.formBuilder.removeFormItem(this.targetProjectStructureComponent);
this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize });
await this.populateServerDropdown(true); await this.populateServerDropdown(true);
}); });
// show project directory browser // if target is currently a db, show it in the server and db dropdowns
targetProjectRadioButton.onDidClick(async () => { if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
this.targetEndpointType = mssql.SchemaCompareEndpointType.Project; databaseRadioButton.checked = true;
this.targetTextBox.value = this.targetProjectFilePath; this.targetIsDacpac = false;
this.formBuilder.removeFormItem(this.targetServerComponent); } else {
this.formBuilder.removeFormItem(this.targetDatabaseComponent); dacpacRadioButton.checked = true;
this.formBuilder.removeFormItem(this.targetDacpacComponent); this.targetIsDacpac = true;
this.formBuilder.addFormItem(this.targetProjectFilePathComponent, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.addFormItem(this.targetProjectStructureComponent, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
this.targetEndpointType = this.schemaCompareMainWindow.targetEndpointInfo?.endpointType ?? mssql.SchemaCompareEndpointType.Database; // default to database if no specific target is passed
switch (this.targetEndpointType) {
case mssql.SchemaCompareEndpointType.Dacpac:
targetDacpacRadioButton.checked = true;
break;
case mssql.SchemaCompareEndpointType.Project:
targetProjectRadioButton.checked = true;
break;
case mssql.SchemaCompareEndpointType.Database:
targetDatabaseRadioButton.checked = true;
break;
} }
let radioButtons = [targetDatabaseRadioButton, targetDacpacRadioButton];
// TODO: re-add once database projects changes are checked in; chicken-and-egg problem (https://github.com/microsoft/azuredatastudio/pull/17738)
// if (vscode.extensions.getExtension(loc.sqlDatabaseProjectExtensionId)) {
// radioButtons.push(targetProjectRadioButton);
// }
let flexRadioButtonsModel = this.view.modelBuilder.flexContainer() let flexRadioButtonsModel = this.view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' }) .withLayout({ flexFlow: 'column' })
.withItems(radioButtons) .withItems([dacpacRadioButton, databaseRadioButton]
)
.withProps({ ariaRole: 'radiogroup' }) .withProps({ ariaRole: 'radiogroup' })
.component(); .component();
@@ -635,83 +443,18 @@ export class SchemaCompareDialog {
} }
private async shouldEnableOkayButton(): Promise<boolean> { private async shouldEnableOkayButton(): Promise<boolean> {
let sourcefilled = (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Dacpac && await this.existsDacpac(this.sourceTextBox.value)) let sourcefilled = (this.sourceIsDacpac && await this.existsDacpac(this.sourceTextBox.value))
|| (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Project && this.existsProjectFile(this.sourceTextBox.value)) || (!this.sourceIsDacpac && !isNullOrUndefined(this.sourceDatabaseDropdown.value) && this.sourceDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.sourceDbEditable)) !== -1);
|| (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Database && !isNullOrUndefined(this.sourceDatabaseDropdown.value) && this.sourceDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.sourceDbEditable)) !== -1); let targetfilled = (this.targetIsDacpac && await this.existsDacpac(this.targetTextBox.value))
let targetfilled = (this.targetEndpointType === mssql.SchemaCompareEndpointType.Dacpac && await this.existsDacpac(this.targetTextBox.value)) || (!this.targetIsDacpac && !isNullOrUndefined(this.targetDatabaseDropdown.value) && this.targetDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.targetDbEditable)) !== -1);
|| (this.targetEndpointType === mssql.SchemaCompareEndpointType.Project && this.existsProjectFile(this.targetTextBox.value))
|| (this.targetEndpointType === mssql.SchemaCompareEndpointType.Database && !isNullOrUndefined(this.targetDatabaseDropdown.value) && this.targetDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.targetDbEditable)) !== -1);
return sourcefilled && targetfilled; return sourcefilled && targetfilled;
} }
public async handleOkButtonClick(): Promise<void> {
await this.execute();
this.dispose();
}
protected showErrorMessage(message: string): void {
this.dialog.message = {
text: message,
level: getAzdataApi()!.window.MessageLevel.Error
};
}
async validate(): Promise<boolean> {
try {
// check project extension is installed
if (!vscode.extensions.getExtension(loc.sqlDatabaseProjectExtensionId) &&
(this.sourceEndpointType === mssql.SchemaCompareEndpointType.Project ||
this.targetEndpointType === mssql.SchemaCompareEndpointType.Project)) {
this.showErrorMessage(loc.noProjectExtension);
return false;
}
// check Database Schema Providers are set and valid
if (this.sourceEndpointType === mssql.SchemaCompareEndpointType.Project) {
try {
await this.getDsp(this.sourceTextBox.value);
} catch (err) {
this.showErrorMessage(loc.dspErrorSource);
}
}
if (this.targetEndpointType === mssql.SchemaCompareEndpointType.Project) {
try {
await this.getDsp(this.targetTextBox.value);
} catch (err) {
this.showErrorMessage(loc.dspErrorTarget);
}
}
return true;
} catch (e) {
this.showErrorMessage(e?.message ? e.message : e);
return false;
}
}
private dispose(): void {
this.toDispose.forEach(disposable => disposable.dispose());
}
private async existsDacpac(filename: string): Promise<boolean> { private async existsDacpac(filename: string): Promise<boolean> {
return !isNullOrUndefined(filename) && await exists(filename) && (filename.toLocaleLowerCase().endsWith('.dacpac')); return !isNullOrUndefined(filename) && await exists(filename) && (filename.toLocaleLowerCase().endsWith('.dacpac'));
} }
private async existsProjectFile(filename: string): Promise<boolean> {
return !isNullOrUndefined(filename) && await exists(filename) && (filename.toLocaleLowerCase().endsWith('.sqlproj'));
}
private async getTargetScripts(source: boolean): Promise<string[]> {
const projectFilePath = source ? this.sourceTextBox.value : this.targetTextBox.value;
return await vscode.commands.executeCommand(loc.sqlDatabaseProjectsGetTargetScripts, projectFilePath);
}
private async getDsp(projectFilePath: string): Promise<string> {
return await vscode.commands.executeCommand(loc.sqlDatabaseProjectsGetDsp, projectFilePath);
}
protected createSourceServerDropdown(): azdata.FormComponent { protected createSourceServerDropdown(): azdata.FormComponent {
this.sourceServerDropdown = this.view.modelBuilder.dropDown().withProps( this.sourceServerDropdown = this.view.modelBuilder.dropDown().withProps(
{ {
@@ -781,7 +524,9 @@ export class SchemaCompareDialog {
width: this.textBoxWidth width: this.textBoxWidth
} }
).component(); ).component();
this.targetConnectionButton = this.createConnectionButton(true); this.targetConnectionButton = this.createConnectionButton(true);
this.targetServerDropdown.onValueChanged(async (value) => { this.targetServerDropdown.onValueChanged(async (value) => {
if (value.selected && this.targetServerDropdown.values.findIndex(x => this.matchesValue(x, value.selected)) === -1) { if (value.selected && this.targetServerDropdown.values.findIndex(x => this.matchesValue(x, value.selected)) === -1) {
await this.targetDatabaseDropdown.updateProperties({ await this.targetDatabaseDropdown.updateProperties({
@@ -794,8 +539,10 @@ export class SchemaCompareDialog {
await this.populateDatabaseDropdown((this.targetServerDropdown.value as ConnectionDropdownValue).connection, true); await this.populateDatabaseDropdown((this.targetServerDropdown.value as ConnectionDropdownValue).connection, true);
} }
}); });
// don't await so that dialog loading won't be blocked. Dropdown will show loading indicator until it is populated // don't await so that dialog loading won't be blocked. Dropdown will show loading indicator until it is populated
this.populateServerDropdown(true); this.populateServerDropdown(true);
return { return {
component: this.targetServerDropdown, component: this.targetServerDropdown,
title: loc.ServerDropdownLabel, title: loc.ServerDropdownLabel,

View File

@@ -7,7 +7,7 @@ import * as vscode from 'vscode';
import { SchemaCompareMainWindow } from './schemaCompareMainWindow'; import { SchemaCompareMainWindow } from './schemaCompareMainWindow';
export async function activate(extensionContext: vscode.ExtensionContext): Promise<void> { export async function activate(extensionContext: vscode.ExtensionContext): Promise<void> {
vscode.commands.registerCommand('schemaCompare.start', async (sourceContext: any, targetContext: any = undefined, comparisonResult: any = undefined) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).start(sourceContext, targetContext, comparisonResult); }); vscode.commands.registerCommand('schemaCompare.start', async (context: any) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).start(context); });
} }
export function deactivate(): void { export function deactivate(): void {

View File

@@ -14,11 +14,9 @@ export const TargetTitle: string = localize('schemaCompareDialog.TargetTitle', "
export const FileTextBoxLabel: string = localize('schemaCompareDialog.fileTextBoxLabel', "File"); export const FileTextBoxLabel: string = localize('schemaCompareDialog.fileTextBoxLabel', "File");
export const DacpacRadioButtonLabel: string = localize('schemaCompare.dacpacRadioButtonLabel', "Data-tier Application File (.dacpac)"); export const DacpacRadioButtonLabel: string = localize('schemaCompare.dacpacRadioButtonLabel', "Data-tier Application File (.dacpac)");
export const DatabaseRadioButtonLabel: string = localize('schemaCompare.databaseButtonLabel', "Database"); export const DatabaseRadioButtonLabel: string = localize('schemaCompare.databaseButtonLabel', "Database");
export const ProjectRadioButtonLabel: string = localize('schemaCompare.projectButtonLabel', "Database Project");
export const RadioButtonsLabel: string = localize('schemaCompare.radioButtonsLabel', "Type"); export const RadioButtonsLabel: string = localize('schemaCompare.radioButtonsLabel', "Type");
export const ServerDropdownLabel: string = localize('schemaCompareDialog.serverDropdownTitle', "Server"); export const ServerDropdownLabel: string = localize('schemaCompareDialog.serverDropdownTitle', "Server");
export const DatabaseDropdownLabel: string = localize('schemaCompareDialog.databaseDropdownTitle', "Database"); export const DatabaseDropdownLabel: string = localize('schemaCompareDialog.databaseDropdownTitle', "Database");
export const StructureDropdownLabel: string = localize('schemaCompareDialog.structureDropdownLabel', "Folder Structure");
export const SchemaCompareLabel: string = localize('schemaCompare.dialogTitle', "Schema Compare"); export const SchemaCompareLabel: string = localize('schemaCompare.dialogTitle', "Schema Compare");
export const differentSourceMessage: string = localize('schemaCompareDialog.differentSourceMessage', "A different source schema has been selected. Compare to see the comparison?"); export const differentSourceMessage: string = localize('schemaCompareDialog.differentSourceMessage', "A different source schema has been selected. Compare to see the comparison?");
export const differentTargetMessage: string = localize('schemaCompareDialog.differentTargetMessage', "A different target schema has been selected. Compare to see the comparison?"); export const differentTargetMessage: string = localize('schemaCompareDialog.differentTargetMessage', "A different target schema has been selected. Compare to see the comparison?");
@@ -33,12 +31,6 @@ export const sourceServer: string = localize('schemaCompareDialog.sourceServerDr
export const targetServer: string = localize('schemaCompareDialog.targetServerDropdown', "Target Server"); export const targetServer: string = localize('schemaCompareDialog.targetServerDropdown', "Target Server");
export const defaultText: string = localize('schemaCompareDialog.defaultUser', "default"); export const defaultText: string = localize('schemaCompareDialog.defaultUser', "default");
export const open: string = localize('schemaCompare.openFile', "Open"); export const open: string = localize('schemaCompare.openFile', "Open");
export const targetStructure = localize('targetStructure', "Target Folder Structure");
export const file = localize('file', "File");
export const flat = localize('flat', "Flat");
export const objectType = localize('objectType', "Object Type");
export const schema = localize('schema', "Schema");
export const schemaObjectType = localize('schemaObjectType', "Schema/Object Type");
export const selectSourceFile: string = localize('schemaCompare.selectSourceFile', "Select source file"); export const selectSourceFile: string = localize('schemaCompare.selectSourceFile', "Select source file");
export const selectTargetFile: string = localize('schemaCompare.selectTargetFile', "Select target file"); export const selectTargetFile: string = localize('schemaCompare.selectTargetFile', "Select target file");
export const ResetButtonText: string = localize('SchemaCompareOptionsDialog.Reset', "Reset"); export const ResetButtonText: string = localize('SchemaCompareOptionsDialog.Reset', "Reset");
@@ -69,7 +61,7 @@ export const include: string = localize('schemaCompare.includeColumnName', "Incl
export const action: string = localize('schemaCompare.actionColumn', "Action"); export const action: string = localize('schemaCompare.actionColumn', "Action");
export const targetName: string = localize('schemaCompare.targetNameColumn', "Target Name"); export const targetName: string = localize('schemaCompare.targetNameColumn', "Target Name");
export const generateScriptDisabled: string = localize('schemaCompare.generateScriptButtonDisabledTitle', "Generate script is enabled when the target is a database"); export const generateScriptDisabled: string = localize('schemaCompare.generateScriptButtonDisabledTitle', "Generate script is enabled when the target is a database");
export const applyDisabled: string = localize('schemaCompare.applyButtonDisabledTitle', "Apply is enabled when the target is a database or database project"); export const applyDisabled: string = localize('schemaCompare.applyButtonDisabledTitle', "Apply is enabled when the target is a database");
export function cannotExcludeMessageDependent(diffEntryName: string, firstDependentName: string): string { return localize('schemaCompare.cannotExcludeMessageWithDependent', "Cannot exclude {0}. Included dependents exist, such as {1}", diffEntryName, firstDependentName); } export function cannotExcludeMessageDependent(diffEntryName: string, firstDependentName: string): string { return localize('schemaCompare.cannotExcludeMessageWithDependent', "Cannot exclude {0}. Included dependents exist, such as {1}", diffEntryName, firstDependentName); }
export function cannotIncludeMessageDependent(diffEntryName: string, firstDependentName: string): string { return localize('schemaCompare.cannotIncludeMessageWithDependent', "Cannot include {0}. Excluded dependents exist, such as {1}", diffEntryName, firstDependentName); } export function cannotIncludeMessageDependent(diffEntryName: string, firstDependentName: string): string { return localize('schemaCompare.cannotIncludeMessageWithDependent', "Cannot include {0}. Excluded dependents exist, such as {1}", diffEntryName, firstDependentName); }
export function cannotExcludeMessage(diffEntryName: string): string { return localize('schemaCompare.cannotExcludeMessage', "Cannot exclude {0}. Included dependents exist", diffEntryName); } export function cannotExcludeMessage(diffEntryName: string): string { return localize('schemaCompare.cannotExcludeMessage', "Cannot exclude {0}. Included dependents exist", diffEntryName); }
@@ -326,20 +318,3 @@ export function cancelErrorMessage(errorMessage: string): string { return locali
export function generateScriptErrorMessage(errorMessage: string): string { return localize('schemaCompare.generateScriptErrorMessage', "Generate script failed: '{0}'", (errorMessage) ? errorMessage : 'Unknown'); } export function generateScriptErrorMessage(errorMessage: string): string { return localize('schemaCompare.generateScriptErrorMessage', "Generate script failed: '{0}'", (errorMessage) ? errorMessage : 'Unknown'); }
export function applyErrorMessage(errorMessage: string): string { return localize('schemaCompare.updateErrorMessage', "Schema Compare Apply failed '{0}'", errorMessage ? errorMessage : 'Unknown'); } export function applyErrorMessage(errorMessage: string): string { return localize('schemaCompare.updateErrorMessage', "Schema Compare Apply failed '{0}'", errorMessage ? errorMessage : 'Unknown'); }
export function openScmpErrorMessage(errorMessage: string): string { return localize('schemaCompare.openScmpErrorMessage', "Open scmp failed: '{0}'", (errorMessage) ? errorMessage : 'Unknown'); } export function openScmpErrorMessage(errorMessage: string): string { return localize('schemaCompare.openScmpErrorMessage', "Open scmp failed: '{0}'", (errorMessage) ? errorMessage : 'Unknown'); }
export const applyError: string = localize('schemaCompare.applyError', "There was an error updating the project");
export const dspErrorSource: string = localize('schemaCompareDialog.dspErrorSource', "The source .sqlproj file does not specify a database schema component");
export const dspErrorTarget: string = localize('schemaCompareDialog.dspErrorTarget', "The target .sqlproj file does not specify a database schema component");
export const noProjectExtension: string = localize('schemaCompareDialog.noProjectExtension', "The sql-database-projects extension is required to perform schema comparison with database projects");
export const noProjectExtensionApply: string = localize('schemaCompareDialog.noProjectExtensionApply', "The sql-database-projects extension is required to apply changes to a project");
// Information messages
export const applySuccess: string = localize('schemaCompare.applySuccess', "Project was successfully updated");
// Extensions
export const sqlDatabaseProjectExtensionId: string = 'microsoft.sql-database-projects';
// Commands
export const sqlDatabaseProjectsGetTargetScripts: string = 'sqlDatabaseProjects.schemaCompareGetTargetScripts';
export const sqlDatabaseProjectsGetDsp: string = 'sqlDatabaseProjects.schemaCompareGetDsp';
export const sqlDatabaseProjectsPublishChanges: string = 'sqlDatabaseProjects.schemaComparePublishProjectChanges';
export const sqlDatabaseProjectsShowProjectsView: string = 'sqlDatabaseProjects.schemaCompareShowProjectsView';

View File

@@ -11,7 +11,7 @@ import * as mssql from '../../mssql';
import * as loc from './localizedConstants'; import * as loc from './localizedConstants';
import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog'; import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog';
import { TelemetryReporter, TelemetryViews } from './telemetry'; import { TelemetryReporter, TelemetryViews } from './telemetry';
import { getTelemetryErrorType, getEndpointName, verifyConnectionAndGetOwnerUri, getRootPath, getSchemaCompareEndpointString } from './utils'; import { getTelemetryErrorType, getEndpointName, verifyConnectionAndGetOwnerUri, getRootPath } from './utils';
import { SchemaCompareDialog } from './dialogs/schemaCompareDialog'; import { SchemaCompareDialog } from './dialogs/schemaCompareDialog';
import { isNullOrUndefined } from 'util'; import { isNullOrUndefined } from 'util';
@@ -81,33 +81,14 @@ export class SchemaCompareMainWindow {
this.editor = azdata.workspace.createModelViewEditor(loc.SchemaCompareLabel, { retainContextWhenHidden: true, supportsSave: true, resourceName: schemaCompareResourceName }, 'SchemaCompareEditor'); this.editor = azdata.workspace.createModelViewEditor(loc.SchemaCompareLabel, { retainContextWhenHidden: true, supportsSave: true, resourceName: schemaCompareResourceName }, 'SchemaCompareEditor');
} }
// schema compare can get started with four contexts for the source: // schema compare can get started with three contexts for the source:
// 1. undefined // 1. undefined
// 2. connection profile // 2. connection profile
// 3. dacpac // 3. dacpac
// 4. project public async start(context: any): Promise<void> {
public async start(sourceContext: any, targetContext: mssql.SchemaCompareEndpointInfo = undefined, comparisonResult: mssql.SchemaCompareResult = undefined): Promise<void> { // if schema compare was launched from a db, set that as the source
const targetIsSetAsProject: boolean = targetContext && targetContext.endpointType === mssql.SchemaCompareEndpointType.Project; let profile = context ? <azdata.IConnectionProfile>context.connectionProfile : undefined;
let sourceDacpac = context as string;
// if schema compare was launched from a db or a connection profile, set that as the source
let profile: azdata.IConnectionProfile;
if (targetIsSetAsProject) {
profile = sourceContext;
this.targetEndpointInfo = targetContext;
} else {
profile = sourceContext ? <azdata.IConnectionProfile>sourceContext.connectionProfile : undefined;
}
let sourceDacpac = undefined;
let sourceProject = undefined;
if (!profile && sourceContext as string && (sourceContext as string).endsWith('.dacpac')) {
sourceDacpac = sourceContext as string;
} else if (!profile) {
sourceProject = sourceContext as string;
}
if (profile) { if (profile) {
let ownerUri = await azdata.connection.getUriForConnection((profile.id)); let ownerUri = await azdata.connection.getUriForConnection((profile.id));
let usr = profile.userName; let usr = profile.userName;
@@ -123,11 +104,7 @@ export class SchemaCompareMainWindow {
ownerUri: ownerUri, ownerUri: ownerUri,
packageFilePath: '', packageFilePath: '',
connectionDetails: undefined, connectionDetails: undefined,
connectionName: profile.connectionName, connectionName: profile.connectionName
projectFilePath: '',
targetScripts: [],
dataSchemaProvider: '',
folderStructure: ''
}; };
} else if (sourceDacpac) { } else if (sourceDacpac) {
this.sourceEndpointInfo = { this.sourceEndpointInfo = {
@@ -137,25 +114,7 @@ export class SchemaCompareMainWindow {
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
packageFilePath: sourceDacpac, packageFilePath: sourceDacpac,
connectionDetails: undefined, connectionDetails: undefined
projectFilePath: '',
targetScripts: [],
dataSchemaProvider: '',
folderStructure: ''
};
} else if (sourceProject) {
this.sourceEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Project,
packageFilePath: '',
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
connectionDetails: undefined,
projectFilePath: sourceProject,
targetScripts: [],
dataSchemaProvider: undefined,
folderStructure: ''
}; };
} }
@@ -164,10 +123,6 @@ export class SchemaCompareMainWindow {
this.registerContent(), this.registerContent(),
this.editor.openEditor() this.editor.openEditor()
]); ]);
if (targetIsSetAsProject) {
await this.execute(comparisonResult);
}
} }
private async registerContent(): Promise<void> { private async registerContent(): Promise<void> {
@@ -207,8 +162,7 @@ export class SchemaCompareMainWindow {
this.createSourceAndTargetButtons(); this.createSourceAndTargetButtons();
this.sourceName = getEndpointName(this.sourceEndpointInfo); this.sourceName = getEndpointName(this.sourceEndpointInfo);
this.targetName = getEndpointName(this.targetEndpointInfo); this.targetName = ' ';
this.sourceNameComponent = this.view.modelBuilder.inputBox().withProps({ this.sourceNameComponent = this.view.modelBuilder.inputBox().withProps({
value: this.sourceName, value: this.sourceName,
title: this.sourceName, title: this.sourceName,
@@ -321,44 +275,34 @@ export class SchemaCompareMainWindow {
this.deploymentOptions = deploymentOptions; this.deploymentOptions = deploymentOptions;
} }
public async execute(comparisonResult: mssql.SchemaCompareCompletionResult = undefined) { public async execute() {
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonStarted');
const service = await this.getService(); const service = await this.getService();
if (comparisonResult) { if (!this.operationId) {
this.operationId = comparisonResult.operationId; // create once per page
this.comparisonResult = comparisonResult; this.operationId = generateGuid();
this.flexModel.removeItem(this.startText);
} else {
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonStarted');
if (!this.operationId) {
// create once per page
this.operationId = generateGuid();
}
this.comparisonResult = await service.schemaCompare(this.operationId, this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions);
if (!this.comparisonResult || !this.comparisonResult.success) {
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFailed', undefined, getTelemetryErrorType(this.comparisonResult?.errorMessage))
.withAdditionalProperties({
operationId: this.comparisonResult.operationId
}).send();
vscode.window.showErrorMessage(loc.compareErrorMessage(this.comparisonResult?.errorMessage));
// reset state so a new comparison can be made
this.resetWindow();
return;
}
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFinished')
.withAdditionalProperties({
'endTime': Date.now().toString(),
'operationId': this.comparisonResult.operationId
}).send();
} }
this.comparisonResult = await service.schemaCompare(this.operationId, this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions);
if (!this.comparisonResult || !this.comparisonResult.success) {
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFailed', undefined, getTelemetryErrorType(this.comparisonResult?.errorMessage))
.withAdditionalProperties({
operationId: this.comparisonResult.operationId
}).send();
vscode.window.showErrorMessage(loc.compareErrorMessage(this.comparisonResult?.errorMessage));
// reset state so a new comparison can be made
this.resetWindow();
return;
}
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFinished')
.withAdditionalProperties({
'endTime': Date.now().toString(),
'operationId': this.comparisonResult.operationId
}).send();
let data = this.getAllDifferences(this.comparisonResult.differences); let data = this.getAllDifferences(this.comparisonResult.differences);
this.differencesTable.updateProperties({ this.differencesTable.updateProperties({
@@ -419,15 +363,9 @@ export class SchemaCompareMainWindow {
// only enable generate script button if the target is a db // only enable generate script button if the target is a db
if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
this.generateScriptButton.enabled = true; this.generateScriptButton.enabled = true;
} else {
this.generateScriptButton.title = loc.generateScriptDisabled;
}
// only enable apply button if the target is a db or a project
if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database ||
this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Project) {
this.applyButton.enabled = true; this.applyButton.enabled = true;
} else { } else {
this.generateScriptButton.title = loc.generateScriptDisabled;
this.applyButton.title = loc.applyDisabled; this.applyButton.title = loc.applyDisabled;
} }
} else { } else {
@@ -824,6 +762,7 @@ export class SchemaCompareMainWindow {
} }
public async publishChanges(): Promise<void> { public async publishChanges(): Promise<void> {
// need only yes button - since the modal dialog has a default cancel // need only yes button - since the modal dialog has a default cancel
const yesString = loc.YesButtonText; const yesString = loc.YesButtonText;
await vscode.window.showWarningMessage(loc.applyConfirmation, { modal: true }, yesString).then(async (result) => { await vscode.window.showWarningMessage(loc.applyConfirmation, { modal: true }, yesString).then(async (result) => {
@@ -837,26 +776,14 @@ export class SchemaCompareMainWindow {
// disable apply and generate script buttons because the results are no longer valid after applying the changes // disable apply and generate script buttons because the results are no longer valid after applying the changes
this.setButtonsForRecompare(); this.setButtonsForRecompare();
const service: mssql.ISchemaCompareService = await this.getService(); const service = await this.getService();
let result: azdata.ResultStatus | undefined = undefined; const result = await service.schemaComparePublishChanges(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.execute);
switch (this.targetEndpointInfo.endpointType) {
case mssql.SchemaCompareEndpointType.Database:
result = await service.schemaComparePublishDatabaseChanges(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.execute);
break;
case mssql.SchemaCompareEndpointType.Project: // Project apply needs sql-database-projects updates in (circular dependency; coming next) // TODO: re-add this and show project logic below
case mssql.SchemaCompareEndpointType.Dacpac: // Dacpac is an invalid publish target
default:
throw new Error(`Unsupported SchemaCompareEndpointType: ${getSchemaCompareEndpointString(this.targetEndpointInfo.endpointType)}`);
}
if (!result || !result.success) { if (!result || !result.success) {
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyFailed', undefined, getTelemetryErrorType(result.errorMessage))
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyFailed', undefined, getTelemetryErrorType(result?.errorMessage))
.withAdditionalProperties({ .withAdditionalProperties({
'operationId': this.comparisonResult.operationId 'operationId': this.comparisonResult.operationId
}).send(); }).send();
vscode.window.showErrorMessage(loc.applyErrorMessage(result?.errorMessage)); vscode.window.showErrorMessage(loc.applyErrorMessage(result.errorMessage));
// reenable generate script and apply buttons if apply failed // reenable generate script and apply buttons if apply failed
this.generateScriptButton.enabled = true; this.generateScriptButton.enabled = true;
@@ -864,7 +791,6 @@ export class SchemaCompareMainWindow {
this.applyButton.enabled = true; this.applyButton.enabled = true;
this.applyButton.title = loc.applyEnabledMessage; this.applyButton.title = loc.applyEnabledMessage;
} }
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyEnded') TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyEnded')
.withAdditionalProperties({ .withAdditionalProperties({
'endTime': Date.now().toString(), 'endTime': Date.now().toString(),
@@ -1156,15 +1082,11 @@ export class SchemaCompareMainWindow {
} }
private setButtonStatesForNoChanges(enableButtons: boolean): void { private setButtonStatesForNoChanges(enableButtons: boolean): void {
// generate script and apply can only be enabled if the target is a database or project // generate script and apply can only be enabled if the target is a database
if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database ||
this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Project) {
this.applyButton.enabled = enableButtons;
this.applyButton.title = enableButtons ? loc.applyEnabledMessage : loc.applyNoChangesMessage;
}
if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
this.applyButton.enabled = enableButtons;
this.generateScriptButton.enabled = enableButtons; this.generateScriptButton.enabled = enableButtons;
this.applyButton.title = enableButtons ? loc.applyEnabledMessage : loc.applyNoChangesMessage;
this.generateScriptButton.title = enableButtons ? loc.generateScriptEnabledMessage : loc.generateScriptNoChangesMessage; this.generateScriptButton.title = enableButtons ? loc.generateScriptEnabledMessage : loc.generateScriptNoChangesMessage;
} }
} }

View File

@@ -110,7 +110,7 @@ describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
it('Should show error if publish changes fails', async function (): Promise<void> { it('Should show error if publish changes fails', async function (): Promise<void> {
let service = createServiceMock(); let service = createServiceMock();
service.setup(x => x.schemaComparePublishDatabaseChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
success: false, success: false,
errorMessage: 'error1' errorMessage: 'error1'
})); }));
@@ -121,7 +121,7 @@ describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
await schemaCompareResult.start(undefined); await schemaCompareResult.start(undefined);
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource); schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
schemaCompareResult.targetEndpointInfo = setDatabaseEndpointInfo(); schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
await schemaCompareResult.execute(); await schemaCompareResult.execute();
await schemaCompareResult.publishChanges(); await schemaCompareResult.publishChanges();
@@ -131,7 +131,7 @@ describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
it('Should show not error if publish changes succeed', async function (): Promise<void> { it('Should show not error if publish changes succeed', async function (): Promise<void> {
let service = createServiceMock(); let service = createServiceMock();
service.setup(x => x.schemaComparePublishDatabaseChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
success: true, success: true,
errorMessage: '' errorMessage: ''
})); }));
@@ -140,7 +140,7 @@ describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
await schemaCompareResult.start(undefined); await schemaCompareResult.start(undefined);
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource); schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
schemaCompareResult.targetEndpointInfo = setDatabaseEndpointInfo(); schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
await schemaCompareResult.execute(); await schemaCompareResult.execute();
await schemaCompareResult.publishChanges(); await schemaCompareResult.publishChanges();
should(showErrorMessageSpy.notCalled).be.true(); should(showErrorMessageSpy.notCalled).be.true();
@@ -343,7 +343,7 @@ describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
it('Should not show error if user does not want to publish', async function (): Promise<void> { it('Should not show error if user does not want to publish', async function (): Promise<void> {
let service = createServiceMock(); let service = createServiceMock();
service.setup(x => x.schemaComparePublishDatabaseChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
success: true, success: true,
errorMessage: '' errorMessage: ''
})); }));

View File

@@ -24,14 +24,6 @@ export class SchemaCompareTestService implements mssql.ISchemaCompareService {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
schemaComparePublishDatabaseChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
throw new Error('Method not implemented.');
}
schemaComparePublishProjectChanges(operationId: string, targetProjectPath: string, targetFolderStructure: mssql.ExtractTarget, taskExecutionMode: azdata.TaskExecutionMode): Thenable<mssql.SchemaComparePublishProjectResult> {
throw new Error('Method not implemented.');
}
schemaCompareGetDefaultOptions(): Thenable<mssql.SchemaCompareOptionsResult> { schemaCompareGetDefaultOptions(): Thenable<mssql.SchemaCompareOptionsResult> {
let result: mssql.SchemaCompareOptionsResult = { let result: mssql.SchemaCompareOptionsResult = {
defaultDeploymentOptions: undefined, defaultDeploymentOptions: undefined,
@@ -50,6 +42,7 @@ export class SchemaCompareTestService implements mssql.ISchemaCompareService {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
schemaCompareSaveScmp(sourceEndpointInfo: mssql.SchemaCompareEndpointInfo, targetEndpointInfo: mssql.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: mssql.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: mssql.SchemaCompareObjectId[], excludedTargetObjects: mssql.SchemaCompareObjectId[]): Thenable<azdata.ResultStatus> { schemaCompareSaveScmp(sourceEndpointInfo: mssql.SchemaCompareEndpointInfo, targetEndpointInfo: mssql.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: mssql.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: mssql.SchemaCompareObjectId[], excludedTargetObjects: mssql.SchemaCompareObjectId[]): Thenable<azdata.ResultStatus> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }

View File

@@ -94,11 +94,7 @@ export const mockDacpacEndpoint: mssql.SchemaCompareEndpointInfo = {
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
packageFilePath: mockFilePath, packageFilePath: mockFilePath,
connectionDetails: undefined, connectionDetails: undefined
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
}; };
export const mockDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { export const mockDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {
@@ -108,11 +104,7 @@ export const mockDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {
databaseName: '', databaseName: '',
ownerUri: '', ownerUri: '',
packageFilePath: '', packageFilePath: '',
connectionDetails: undefined, connectionDetails: undefined
projectFilePath: '',
folderStructure: '',
targetScripts: [],
dataSchemaProvider: '',
}; };
export async function shouldThrowSpecificError(block: Function, expectedMessage: string, details?: string) { export async function shouldThrowSpecificError(block: Function, expectedMessage: string, details?: string) {

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import type * as azdataType from 'azdata'; // eslint-disable-line no-duplicate-imports
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as mssql from '../../mssql'; import * as mssql from '../../mssql';
import * as os from 'os'; import * as os from 'os';
@@ -40,19 +39,6 @@ export function getTelemetryErrorType(msg: string): string {
} }
} }
export function getSchemaCompareEndpointString(endpointType: mssql.SchemaCompareEndpointType): string {
switch (endpointType) {
case mssql.SchemaCompareEndpointType.Database:
return 'Database';
case mssql.SchemaCompareEndpointType.Dacpac:
return 'Dacpac';
case mssql.SchemaCompareEndpointType.Project:
return 'Project';
default:
return `Unknown: ${endpointType}`;
}
}
/** /**
* Return the appropriate endpoint name depending on if the endpoint is a dacpac or a database * Return the appropriate endpoint name depending on if the endpoint is a dacpac or a database
* @param endpoint endpoint to get the name of * @param endpoint endpoint to get the name of
@@ -78,11 +64,8 @@ export function getEndpointName(endpoint: mssql.SchemaCompareEndpointInfo): stri
return ' '; return ' ';
} }
} else if (endpoint.endpointType === mssql.SchemaCompareEndpointType.Dacpac) {
return endpoint.packageFilePath;
} else { } else {
return endpoint.projectFilePath; return endpoint.packageFilePath;
} }
} }
@@ -161,24 +144,3 @@ export async function exists(path: string): Promise<boolean> {
return false; return false;
} }
} }
// Try to load the azdata API - but gracefully handle the failure in case we're running
// in a context where the API doesn't exist (such as VS Code)
let azdataApi: typeof azdataType | undefined = undefined;
try {
azdataApi = require('azdata');
if (!azdataApi?.version) {
// webpacking makes the require return an empty object instead of throwing an error so make sure we clear the var
azdataApi = undefined;
}
} catch {
// no-op
}
/**
* Gets the azdata API if it's available in the context this extension is running in.
* @returns The azdata API if it's available
*/
export function getAzdataApi(): typeof azdataType | undefined {
return azdataApi;
}

View File

@@ -2,7 +2,7 @@
"name": "server-report", "name": "server-report",
"displayName": "Server Reports", "displayName": "Server Reports",
"description": "Server Reports", "description": "Server Reports",
"version": "0.2.4", "version": "0.2.5",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"engines": { "engines": {

View File

@@ -2,7 +2,7 @@
"name": "sql-assessment", "name": "sql-assessment",
"displayName": "%displayName%", "displayName": "%displayName%",
"description": "%description%", "description": "%description%",
"version": "0.6.1", "version": "0.6.2",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",

View File

@@ -4,11 +4,14 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
// This task is meant for running the VS Code version of the extension. See VSCODE_DEVELOPMENT.md for more information // Note for debugging the VS Code version of the extension, currently you will need to modify
// the package.json and manually copy over the values from package.vscode.json into package.json
// (otherwise you'll get errors since other extensions depend on an extension with the name
// data-workspace-vscode, not data-workspace)
{ {
"type": "extensionHost", "type": "extensionHost",
"request": "launch", "request": "launch",
"name": "Launch Extension in VS Code", "name": "Launch Extension",
"runtimeExecutable": "${execPath}", "runtimeExecutable": "${execPath}",
"args": [ "args": [
"--extensionDevelopmentPath=${workspaceFolder}" "--extensionDevelopmentPath=${workspaceFolder}"
@@ -18,4 +21,4 @@
] ]
} }
] ]
} }

View File

@@ -1,17 +1,9 @@
# Microsoft SQL Server Database Projects for Azure Data Studio and VS Code # Microsoft SQL Server Database Projects for Azure Data Studio and VS Code
## Overview Microsoft SQL Server Database Projects for Azure Data Studio and VS Code includes:
Microsoft SQL Server Database Projects for Azure Data Studio and VS Code provides a way to design, edit, and publish schemas for SQL databases from a source controlled project.
### VS Code
This extension is bundled into the `SQL Server (MSSQL)` extension for VS Code and will be installed automatically when that extension is updated or installed.
### Azure Data Studio
This extension is provided as a separate extension in the marketplace.
## Database Projects
The Database Projects extension provides a way to design, edit, and publish schemas for SQL databases from a source controlled project.
Please report issues and feature requests [here.](https://github.com/microsoft/azuredatastudio/issues) Please report issues and feature requests [here.](https://github.com/microsoft/azuredatastudio/issues)
@@ -19,8 +11,7 @@ Please report issues and feature requests [here.](https://github.com/microsoft/a
* Create a new database project by going to the **Projects** viewlet or by searching **Projects: New** in the command palette. * Create a new database project by going to the **Projects** viewlet or by searching **Projects: New** in the command palette.
* Existing database projects can be opened by going to the **Projects** viewlet or by searching **Projects: Open Existing** in the command palette. * Existing database projects can be opened by going to the **Projects** viewlet or by searching **Projects: Open Existing** in the command palette.
* Start from an existing database by using the **Create Project from Database** from the command palette or database context menu. * Start from an existing database by using **Create Project From Database** from the command palette or database context menu.
* Start from an OpenAPI/Swagger spec by using the **Generate SQL Project from OpenAPI/Swagger spec** command.
## Code of Conduct ## Code of Conduct

View File

@@ -1,15 +0,0 @@
# VS Code Extension Development
For working on the VS Code version of the package follow these steps for local development/testing.
1. Copy the values from [package.vscode.json](./package.vscode.json) into [package.json](./package.json) (overwriting the properties with the same name there)
2. Delete the following properties (this includes their arrays of values as well) from the `contributes/menus` property in the [package.json](./package.json)
* `objectExplorer/item/context`
* `dataExplorer/context`
* `dashboard/toolbar`
3. Compile Azure Data Studio as normal and wait for it to finish
4. Run `code <PathToAzureDataStudioSource>/extensions/sql-database-projects` from the command line to open a new VS Code instance at the `sql-database-projects` folder
5. Run the `Launch Extension in VS Code` launch target from the `Run and Debug` view
6. This should launch an `Extension Development Host` version of VS Code that is running the extension from sources.
If you have the compilation running as watch then once you make changes you can just reload the window to pick up the latest changes being made.

View File

@@ -1,8 +1,8 @@
{ {
"name": "sql-database-projects", "name": "sql-database-projects",
"displayName": "SQL Database Projects", "displayName": "SQL Database Projects",
"description": "Enables users to develop and publish database schemas for MSSQL Databases", "description": "Allows users to develop and publish database schemas for MSSQL Databases",
"version": "0.14.0", "version": "0.13.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"engines": { "engines": {
@@ -17,7 +17,6 @@
"onCommand:sqlDatabaseProjects.open", "onCommand:sqlDatabaseProjects.open",
"onCommand:sqlDatabaseProjects.createProjectFromDatabase", "onCommand:sqlDatabaseProjects.createProjectFromDatabase",
"onCommand:sqlDatabaseProjects.generateProjectFromOpenApiSpec", "onCommand:sqlDatabaseProjects.generateProjectFromOpenApiSpec",
"onCommand:sqlDatabaseProjects.addSqlBinding",
"workspaceContains:**/*.sqlproj", "workspaceContains:**/*.sqlproj",
"onView:dataworkspace.views.main" "onView:dataworkspace.views.main"
], ],
@@ -44,14 +43,18 @@
{ {
"title": "%sqlDatabaseProjects.Settings%", "title": "%sqlDatabaseProjects.Settings%",
"properties": { "properties": {
"sqlDatabaseProjects.dotnetSDK Location": { "sqlDatabaseProjects.netCoreSDKLocation": {
"type": "string", "type": "string",
"description": "%sqlDatabaseProjects.dotnetInstallLocation%" "description": "%sqlDatabaseProjects.netCoreInstallLocation%"
}, },
"sqlDatabaseProjects.netCoreDoNotAsk": { "sqlDatabaseProjects.netCoreDoNotAsk": {
"type": "boolean", "type": "boolean",
"description": "%sqlDatabaseProjects.netCoreDoNotAsk%" "description": "%sqlDatabaseProjects.netCoreDoNotAsk%"
}, },
"sqlDatabaseProjects.netCoreDowngradeDoNotShow": {
"type": "boolean",
"description": "%sqlDatabaseProjects.netCoreDowngradeDoNotShow%"
},
"sqlDatabaseProjects.nodejsDoNotAsk": { "sqlDatabaseProjects.nodejsDoNotAsk": {
"type": "boolean", "type": "boolean",
"description": "%sqlDatabaseProjects.nodejsDoNotAsk%" "description": "%sqlDatabaseProjects.nodejsDoNotAsk%"
@@ -165,11 +168,6 @@
"title": "%sqlDatabaseProjects.editProjectFile%", "title": "%sqlDatabaseProjects.editProjectFile%",
"category": "%sqlDatabaseProjects.displayName%" "category": "%sqlDatabaseProjects.displayName%"
}, },
{
"command": "sqlDatabaseProjects.addSqlBinding",
"title": "%sqlDatabaseProjects.addSqlBinding%",
"category": "MS SQL"
},
{ {
"command": "sqlDatabaseProjects.changeTargetPlatform", "command": "sqlDatabaseProjects.changeTargetPlatform",
"title": "%sqlDatabaseProjects.changeTargetPlatform%", "title": "%sqlDatabaseProjects.changeTargetPlatform%",
@@ -270,10 +268,6 @@
"command": "sqlDatabaseProjects.editProjectFile", "command": "sqlDatabaseProjects.editProjectFile",
"when": "false" "when": "false"
}, },
{
"command": "sqlDatabaseProjects.addSqlBinding",
"when": "editorLangId == csharp && !azdataAvailable && resourceScheme != untitled"
},
{ {
"command": "sqlDatabaseProjects.exclude", "command": "sqlDatabaseProjects.exclude",
"when": "false" "when": "false"

View File

@@ -33,11 +33,12 @@
"sqlDatabaseProjects.generateProjectFromOpenApiSpec": "Generate SQL Project from OpenAPI/Swagger spec", "sqlDatabaseProjects.generateProjectFromOpenApiSpec": "Generate SQL Project from OpenAPI/Swagger spec",
"sqlDatabaseProjects.Settings": "Database Projects", "sqlDatabaseProjects.Settings": "Database Projects",
"sqlDatabaseProjects.dotnetInstallLocation": "Full path to .NET SDK on the machine.", "sqlDatabaseProjects.netCoreInstallLocation": "Full path to .NET Core SDK on the machine.",
"sqlDatabaseProjects.netCoreDoNotAsk": "Whether to prompt the user to install .NET Core when not detected.", "sqlDatabaseProjects.netCoreDoNotAsk": "Whether to prompt the user to install .NET Core when not detected.",
"sqlDatabaseProjects.netCoreDowngradeDoNotShow": "Whether to prompt the user to set .NET SDK version when a newer unsupported version is detected.",
"sqlDatabaseProjects.nodejsDoNotAsk": "Whether to prompt the user to install Node.js when not detected.", "sqlDatabaseProjects.nodejsDoNotAsk": "Whether to prompt the user to install Node.js when not detected.",
"sqlDatabaseProjects.autorestSqlVersion": "Which version of Autorest.Sql to use from NPM. Latest will be used if not set.", "sqlDatabaseProjects.autorestSqlVersion": "Which version of Autorest.Sql to use from NPM. Latest will be used if not set.",
"sqlDatabaseProjects.welcome": "No database projects currently open.\n[New Project](command:sqlDatabaseProjects.new)\n[Open Project](command:sqlDatabaseProjects.open)\n[Create Project From Database](command:sqlDatabaseProjects.importDatabase)", "sqlDatabaseProjects.welcome": "No database projects currently open.\n[New Project](command:sqlDatabaseProjects.new)\n[Open Project](command:sqlDatabaseProjects.open)\n[Create Project From Database](command:sqlDatabaseProjects.importDatabase)",
"sqlDatabaseProjects.addSqlBinding":"Add SQL Binding (preview)" "sqlDatabaseProjects.addSqlBinding":"Add SQL Binding"
} }

View File

@@ -21,7 +21,6 @@ export const msdb = 'msdb';
export const msdbDacpac = 'msdb.dacpac'; export const msdbDacpac = 'msdb.dacpac';
export const MicrosoftDatatoolsSchemaSqlSql = 'Microsoft.Data.Tools.Schema.Sql.Sql'; export const MicrosoftDatatoolsSchemaSqlSql = 'Microsoft.Data.Tools.Schema.Sql.Sql';
export const databaseSchemaProvider = 'DatabaseSchemaProvider'; export const databaseSchemaProvider = 'DatabaseSchemaProvider';
export const sqlProjectSdk = 'Microsoft.Build.Sql';
// Project Provider // Project Provider
export const emptySqlDatabaseProjectTypeId = 'EmptySqlDbProj'; export const emptySqlDatabaseProjectTypeId = 'EmptySqlDbProj';
@@ -70,7 +69,6 @@ export const dataSourcesNodeName = localize('dataSourcesNodeName', "Data Sources
export const databaseReferencesNodeName = localize('databaseReferencesNodeName', "Database References"); export const databaseReferencesNodeName = localize('databaseReferencesNodeName', "Database References");
export const sqlConnectionStringFriendly = localize('sqlConnectionStringFriendly', "SQL connection string"); export const sqlConnectionStringFriendly = localize('sqlConnectionStringFriendly', "SQL connection string");
export const yesString = localize('yesString', "Yes"); export const yesString = localize('yesString', "Yes");
export const openEulaString = localize('openEulaString', "Open License Agreement");
export const noString = localize('noString', "No"); export const noString = localize('noString', "No");
export const noStringDefault = localize('noStringDefault', "No (default)"); export const noStringDefault = localize('noStringDefault', "No (default)");
export const okString = localize('okString', "Ok"); export const okString = localize('okString', "Ok");
@@ -106,7 +104,7 @@ export const dataSourceDropdownTitle = localize('dataSourceDropdownTitle', "Data
export const noDataSourcesText = localize('noDataSourcesText', "No data sources in this project"); export const noDataSourcesText = localize('noDataSourcesText', "No data sources in this project");
export const loadProfilePlaceholderText = localize('loadProfilePlaceholderText', "Load profile..."); export const loadProfilePlaceholderText = localize('loadProfilePlaceholderText', "Load profile...");
export const profileReadError = (err: any) => localize('profileReadError', "Error loading the publish profile. {0}", utils.getErrorMessage(err)); export const profileReadError = (err: any) => localize('profileReadError', "Error loading the publish profile. {0}", utils.getErrorMessage(err));
export const sqlCmdVariables = localize('sqlCmdTableLabel', "SQLCMD Variables"); export const sqlCmdTableLabel = localize('sqlCmdTableLabel', "SQLCMD Variables");
export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Name"); export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Name");
export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value"); export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value");
export const loadSqlCmdVarsButtonTitle = localize('reloadValuesFromProjectButtonTitle', "Reload values from project"); export const loadSqlCmdVarsButtonTitle = localize('reloadValuesFromProjectButtonTitle', "Reload values from project");
@@ -134,11 +132,6 @@ export const selectPublishOption = localize('selectPublishOption', "Select where
export const publishToExistingServer = localize('publishToExistingServer', "Publish to existing server"); export const publishToExistingServer = localize('publishToExistingServer', "Publish to existing server");
export const publishToDockerContainer = localize('publishToDockerContainer', "Publish to new server in a container"); export const publishToDockerContainer = localize('publishToDockerContainer', "Publish to new server in a container");
export const enterPortNumber = localize('enterPortNumber', "Enter SQL server port number or press enter to use the default value"); export const enterPortNumber = localize('enterPortNumber', "Enter SQL server port number or press enter to use the default value");
export const serverPortNumber = localize('serverPortNumber', "SQL server port number");
export const serverPassword = localize('serverPassword', "SQL Server admin password");
export const confirmServerPassword = localize('confirmServerPassword', "Confirm SQL Server admin password");
export const baseDockerImage = localize('baseDockerImage', "Base SQL Server Docker image");
export const publishTo = localize('publishTo', "Publish Target");
export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name"); export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name");
export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template"); export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template");
export const enterPassword = localize('enterPassword', "Enter SQL Server admin password"); export const enterPassword = localize('enterPassword', "Enter SQL Server admin password");
@@ -150,14 +143,6 @@ export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be
export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty"); export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty");
export const dockerImageLabelPrefix = 'source=sqldbproject'; export const dockerImageLabelPrefix = 'source=sqldbproject';
export const dockerImageNamePrefix = 'sqldbproject'; export const dockerImageNamePrefix = 'sqldbproject';
//
export const eulaAgreementTemplate = localize({ key: 'eulaAgreementTemplate', comment: ['The placeholders are contents of the line and should not be translated.'] }, "I accept the {0}.");
export function eulaAgreementText(name: string) { return localize({ key: 'eulaAgreementText', comment: ['The placeholders are contents of the line and should not be translated.'] }, "I accept the {0}.", name); }
export const eulaAgreementTitle = localize('eulaAgreementTitle', "Microsoft SQL Server License Agreement");
export const edgeEulaAgreementTitle = localize('edgeEulaAgreementTitle', "Microsoft Azure SQL Edge License Agreement");
export const sqlServerEulaLink = 'https://go.microsoft.com/fwlink/?linkid=857698';
export const sqlServerEdgeEulaLink = 'https://go.microsoft.com/fwlink/?linkid=2139274';
export const connectionNamePrefix = 'SQLDbProject'; export const connectionNamePrefix = 'SQLDbProject';
export const sqlServerDockerRegistry = 'mcr.microsoft.com'; export const sqlServerDockerRegistry = 'mcr.microsoft.com';
export const sqlServerDockerRepository = 'mssql/server'; export const sqlServerDockerRepository = 'mssql/server';
@@ -167,8 +152,6 @@ export const mssqlFolderName = '.mssql';
export const dockerFileName = 'Dockerfile'; export const dockerFileName = 'Dockerfile';
export const startCommandName = 'start.sh'; export const startCommandName = 'start.sh';
export const defaultPortNumber = '1433'; export const defaultPortNumber = '1433';
export const defaultLocalServerName = 'localhost';
export const defaultLocalServerAdminName = 'sa';
export const defaultConnectionStringEnvVarName = 'SQLConnectionString'; export const defaultConnectionStringEnvVarName = 'SQLConnectionString';
export const defaultConnectionStringTemplate = 'Data Source=@@SERVER@@,@@PORT@@;Initial Catalog=@@DATABASE@@;User id=@@USER@@;Password=@@SA_PASSWORD@@;'; export const defaultConnectionStringTemplate = 'Data Source=@@SERVER@@,@@PORT@@;Initial Catalog=@@DATABASE@@;User id=@@USER@@;Password=@@SA_PASSWORD@@;';
export const azureFunctionLocalSettingsFileName = 'local.settings.json'; export const azureFunctionLocalSettingsFileName = 'local.settings.json';
@@ -179,8 +162,6 @@ export const deployDbTaskName = localize('deployDbTaskName', "Deploying SQL Db P
export const publishProjectSucceed = localize('publishProjectSucceed', "Database project published successfully"); export const publishProjectSucceed = localize('publishProjectSucceed', "Database project published successfully");
export const publishingProjectMessage = localize('publishingProjectMessage', "Publishing project in a container..."); export const publishingProjectMessage = localize('publishingProjectMessage', "Publishing project in a container...");
export const cleaningDockerImagesMessage = localize('cleaningDockerImagesMessage', "Cleaning existing deployments..."); export const cleaningDockerImagesMessage = localize('cleaningDockerImagesMessage', "Cleaning existing deployments...");
export const dockerImageMessage = localize('dockerImageMessage', "Docker Image:");
export const dockerImageEulaMessage = localize('dockerImageEulaMessage', "License Agreement:");
export const creatingDeploymentSettingsMessage = localize('creatingDeploymentSettingsMessage', "Creating deployment settings ..."); export const creatingDeploymentSettingsMessage = localize('creatingDeploymentSettingsMessage', "Creating deployment settings ...");
export const runningDockerMessage = localize('runningDockerMessage', "Building and running the docker container ..."); export const runningDockerMessage = localize('runningDockerMessage', "Building and running the docker container ...");
export function dockerNotRunningError(error: string) { return localize('dockerNotRunningError', "Failed to verify docker. Please make sure docker is installed and running. Error: '{0}'", error || ''); } export function dockerNotRunningError(error: string) { return localize('dockerNotRunningError', "Failed to verify docker. Please make sure docker is installed and running. Error: '{0}'", error || ''); }
@@ -246,7 +227,8 @@ export const browseButtonText = localize('browseButtonText', "Browse folder");
export const selectFolderStructure = localize('selectFolderStructure', "Select folder structure"); export const selectFolderStructure = localize('selectFolderStructure', "Select folder structure");
export const folderStructureLabel = localize('folderStructureLabel', "Folder structure"); export const folderStructureLabel = localize('folderStructureLabel', "Folder structure");
export const WorkspaceFileExtension = '.code-workspace'; export const WorkspaceFileExtension = '.code-workspace';
export const browseEllipsisWithIcon = `$(folder) ${localize('browseEllipsis', "Browse...")}`; export const browseEllipsis = localize('browseEllipsis', "Browse...");
export const browseEllipsisWithIcon = `$(folder) ${browseEllipsis}`;
export const selectProjectLocation = localize('selectProjectLocation', "Select project location"); export const selectProjectLocation = localize('selectProjectLocation', "Select project location");
export const ProjectParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.projectParentDirectoryNotExistError', "The selected project location '{0}' does not exist or is not a directory.", location); }; export const ProjectParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.projectParentDirectoryNotExistError', "The selected project location '{0}' does not exist or is not a directory.", location); };
export const ProjectDirectoryAlreadyExistError = (projectName: string, location: string): string => { return localize('dataworkspace.projectDirectoryAlreadyExistError', "There is already a directory named '{0}' in the selected location: '{1}'.", projectName, location); }; export const ProjectDirectoryAlreadyExistError = (projectName: string, location: string): string => { return localize('dataworkspace.projectDirectoryAlreadyExistError', "There is already a directory named '{0}' in the selected location: '{1}'.", projectName, location); };
@@ -264,8 +246,8 @@ export const invalidSqlConnectionString = localize('invalidSqlConnectionString',
export const extractTargetRequired = localize('extractTargetRequired', "Target information for extract is required to create database project."); export const extractTargetRequired = localize('extractTargetRequired', "Target information for extract is required to create database project.");
export const schemaCompareNotInstalled = localize('schemaCompareNotInstalled', "Schema compare extension installation is required to run schema compare"); export const schemaCompareNotInstalled = localize('schemaCompareNotInstalled', "Schema compare extension installation is required to run schema compare");
export const buildFailedCannotStartSchemaCompare = localize('buildFailedCannotStartSchemaCompare', "Schema compare could not start because build failed"); export const buildFailedCannotStartSchemaCompare = localize('buildFailedCannotStartSchemaCompare', "Schema compare could not start because build failed");
export function updateProjectForRoundTrip(projectName: string) { return localize('updateProjectForRoundTrip', "The targets, references, and system database references need to be updated to build the project '{0}'. If the project was created in SSDT, it will continue to work in both tools. Do you want to update the project?", projectName); } export const updateProjectForRoundTrip = localize('updateProjectForRoundTrip', "The targets, references, and system database references need to be updated to build this project. If the project is created in SSDT, it will continue to work in both tools. Do you want to update the project?");
export function updateProjectDatabaseReferencesForRoundTrip(projectName: string) { return localize('updateProjectDatabaseReferencesForRoundTrip', "The system database references need to be updated to build the project '{0}'. If the project was created in SSDT, it will continue to work in both tools. Do you want to update the project?", projectName); } export const updateProjectDatabaseReferencesForRoundTrip = localize('updateProjectDatabaseReferencesForRoundTrip', "The system database references need to be updated to build this project. If the project is created in SSDT, it will continue to work in both tools. Do you want to update the project?");
export const databaseReferenceTypeRequired = localize('databaseReferenceTypeRequired', "Database reference type is required for adding a reference to a database"); export const databaseReferenceTypeRequired = localize('databaseReferenceTypeRequired', "Database reference type is required for adding a reference to a database");
export const systemDatabaseReferenceRequired = localize('systemDatabaseReferenceRequired', "System database selection is required for adding a reference to a system database"); export const systemDatabaseReferenceRequired = localize('systemDatabaseReferenceRequired', "System database selection is required for adding a reference to a system database");
export const dacpacFileLocationRequired = localize('dacpacFileLocationRequired', "Dacpac file location is required for adding a reference to a database"); export const dacpacFileLocationRequired = localize('dacpacFileLocationRequired', "Dacpac file location is required for adding a reference to a database");
@@ -304,7 +286,7 @@ export function unableToFindSqlCmdVariable(variableName: string) { return locali
export function unableToFindDatabaseReference(reference: string) { return localize('unableToFindReference', "Unable to find database reference {0}", reference); } export function unableToFindDatabaseReference(reference: string) { return localize('unableToFindReference', "Unable to find database reference {0}", reference); }
export function invalidGuid(guid: string) { return localize('invalidGuid', "Specified GUID is invalid: {0}", guid); } export function invalidGuid(guid: string) { return localize('invalidGuid', "Specified GUID is invalid: {0}", guid); }
export function invalidTargetPlatform(targetPlatform: string, supportedTargetPlatforms: string[]) { return localize('invalidTargetPlatform', "Invalid target platform: {0}. Supported target platforms: {1}", targetPlatform, supportedTargetPlatforms.toString()); } export function invalidTargetPlatform(targetPlatform: string, supportedTargetPlatforms: string[]) { return localize('invalidTargetPlatform', "Invalid target platform: {0}. Supported target platforms: {1}", targetPlatform, supportedTargetPlatforms.toString()); }
export function errorReadingProject(section: string, path: string) { return localize('errorReadingProjectGuid', "Error trying to read {0} of project '{1}'", section, path); }
// Action types // Action types
export const deleteAction = localize('deleteAction', 'Delete'); export const deleteAction = localize('deleteAction', 'Delete');
@@ -330,21 +312,22 @@ export const postDeployScriptFriendlyName = localize('postDeployScriptFriendlyNa
// Build // Build
export const DotnetInstallationConfirmation: string = localize('sqlDatabaseProjects.DotnetInstallationConfirmation', "The .NET SDK cannot be located. Project build will not work. Please install .NET Core SDK version 3.1 or higher or update the .NET SDK location in settings if already installed."); export const NetCoreInstallationConfirmation: string = localize('sqlDatabaseProjects.NetCoreInstallationConfirmation', "The .NET Core SDK cannot be located. Project build will not work. Please install .NET Core SDK version 3.1 or update the .NET Core SDK location in settings if already installed.");
export function NetCoreSupportedVersionInstallationConfirmation(installedVersion: string) { return localize('sqlDatabaseProjects.NetCoreSupportedVersionInstallationConfirmation', "Currently installed .NET Core SDK version is {0}, which is not supported. Project build will not work. Please install .NET Core SDK version 3.1 or higher or update the .NET SDK supported version location in settings if already installed.", installedVersion); } export function NetCoreSupportedVersionInstallationConfirmation(installedVersion: string) { return localize('sqlDatabaseProjects.NetCoreSupportedVersionInstallationConfirmation', "Currently installed .NET Core SDK version is {0}, which is not supported. Project build will not work. Please install .NET Core SDK version 3.1 or update the .NET Core SDK supported version location in settings if already installed.", installedVersion); }
export const UpdateDotnetLocation: string = localize('sqlDatabaseProjects.UpdateDotnetLocation', "Update Location"); export function NetCoreVersionDowngradeConfirmation(installedVersion: string) { return localize('sqlDatabaseProjects.NetCoreVersionDowngradeConfirmation', "Installed .NET SDK version {0} is newer than the currently supported versions. Project build will not work. Please install .NET Core SDK version 3.1 and include a global.json in the project folder specifying the SDK version to use. [More Information](https://docs.microsoft.com/dotnet/core/versions/selection)", installedVersion); }
export const UpdateNetCoreLocation: string = localize('sqlDatabaseProjects.UpdateNetCoreLocation', "Update Location");
export const projectsOutputChannel = localize('sqlDatabaseProjects.outputChannel', "Database Projects"); export const projectsOutputChannel = localize('sqlDatabaseProjects.outputChannel', "Database Projects");
// Prompt buttons // Prompt buttons
export const Install: string = localize('sqlDatabaseProjects.Install', "Install"); export const Install: string = localize('sqlDatabaseProjects.Install', "Install");
export const DoNotAskAgain: string = localize('sqlDatabaseProjects.doNotAskAgain', "Don't Ask Again"); export const DoNotAskAgain: string = localize('sqlDatabaseProjects.doNotAskAgain', "Don't Ask Again");
export const DoNotShowAgain: string = localize('sqlDatabaseProjects.doNotShowAgain', "Don't Show Again");
// SqlProj file XML names // SqlProj file XML names
export const ItemGroup = 'ItemGroup'; export const ItemGroup = 'ItemGroup';
export const Build = 'Build'; export const Build = 'Build';
export const Folder = 'Folder'; export const Folder = 'Folder';
export const Include = 'Include'; export const Include = 'Include';
export const Remove = 'Remove';
export const Import = 'Import'; export const Import = 'Import';
export const Project = 'Project'; export const Project = 'Project';
export const Condition = 'Condition'; export const Condition = 'Condition';
@@ -378,17 +361,6 @@ export const Private = 'Private';
export const ProjectGuid = 'ProjectGuid'; export const ProjectGuid = 'ProjectGuid';
export const Type = 'Type'; export const Type = 'Type';
export const ExternalStreamingJob: string = 'ExternalStreamingJob'; export const ExternalStreamingJob: string = 'ExternalStreamingJob';
export const Sdk: string = 'Sdk';
export const BuildElements = localize('buildElements', "Build Elements");
export const FolderElements = localize('folderElements', "Folder Elements");
export const PreDeployElements = localize('preDeployElements', "PreDeploy Elements");
export const PostDeployElements = localize('postDeployElements', "PostDeploy Elements");
export const NoneElements = localize('noneElements', "None Elements");
export const ImportElements = localize('importElements', "Import Elements");
export const ProjectReferenceNameElement = localize('projectReferenceNameElement', "Project reference name element");
export const ProjectReferenceElement = localize('projectReferenceElement', "Project reference");
export const DacpacReferenceElement = localize('dacpacReferenceElement', "Dacpac reference");
/** Name of the property item in the project file that defines default database collation. */ /** Name of the property item in the project file that defines default database collation. */
export const DefaultCollationProperty = 'DefaultCollation'; export const DefaultCollationProperty = 'DefaultCollation';
@@ -451,12 +423,9 @@ export enum DatabaseProjectItemType {
// AutoRest // AutoRest
export const autorestPostDeploymentScriptName = 'PostDeploymentScript.sql'; export const autorestPostDeploymentScriptName = 'PostDeploymentScript.sql';
export const nodeButNotAutorestFound = localize('nodeButNotAutorestFound', "Autorest tool not found in system path, but found Node.js. Prompting user for how to proceed. Execute 'npm install autorest -g' to install permanently and avoid this message."); export const nodeButNotAutorestFound = localize('nodeButNotAutorestFound', "Autorest tool not found in system path, but found Node.js. Running via npx. Please execute 'npm install autorest -g' to install permanently.");
export const nodeNotFound = localize('nodeNotFound', "Neither Autorest nor Node.js (npx) found in system path. Please install Node.js for Autorest generation to work."); export const nodeNotFound = localize('nodeNotFound', "Neither Autorest nor Node.js (npx) found in system path. Please install Node.js for Autorest generation to work.");
export const nodeButNotAutorestFoundPrompt = localize('nodeButNotAutorestFoundPrompt', "Autorest is not installed. To proceed, choose whether to run Autorest from a temporary location via 'npx' or install Autorest globally then run."); export const nodeButNotAutorestFoundPrompt = localize('nodeButNotAutorestFoundPrompt', "Autorest is not installed. To proceed, choose whether to run Autorest from a temporary location via 'npx' or install Autorest globally then run.");
export const userSelectionInstallGlobally = localize('userSelectionInstallGlobally', "User selected to install autorest gloablly. Installing now...");
export const userSelectionRunNpx = localize('userSelectionRunNpx', "User selected to run via npx.");
export const userSelectionCancelled = localize('userSelectionCancelled', "User has cancelled selection for how to run autorest.");
export const installGlobally = localize('installGlobally', "Install globally"); export const installGlobally = localize('installGlobally', "Install globally");
export const runViaNpx = localize('runViaNpx', "Run via npx"); export const runViaNpx = localize('runViaNpx', "Run via npx");
@@ -524,7 +493,6 @@ export const noAzureFunctionsProjectsInWorkspace = localize('noAzureFunctionsPro
export const addPackage = localize('addPackage', "Add Package"); export const addPackage = localize('addPackage', "Add Package");
export const createNewLocalAppSetting = localize('createNewLocalAppSetting', 'Create new local app setting'); export const createNewLocalAppSetting = localize('createNewLocalAppSetting', 'Create new local app setting');
export const createNewLocalAppSettingWithIcon = `$(add) ${createNewLocalAppSetting}`; export const createNewLocalAppSettingWithIcon = `$(add) ${createNewLocalAppSetting}`;
export const sqlConnectionStringSetting = 'SqlConnectionString';
export const valueMustNotBeEmpty = localize('valueMustNotBeEmpty', "Value must not be empty"); export const valueMustNotBeEmpty = localize('valueMustNotBeEmpty', "Value must not be empty");
export const enterConnectionStringSettingName = localize('enterConnectionStringSettingName', "Enter connection string setting name"); export const enterConnectionStringSettingName = localize('enterConnectionStringSettingName', "Enter connection string setting name");
export const enterConnectionString = localize('enterConnectionString', "Enter connection string"); export const enterConnectionString = localize('enterConnectionString', "Enter connection string");
@@ -535,4 +503,3 @@ export function failedToParse(errorMessage: string) { return localize('failedToP
export function jsonParseError(error: string, line: number, column: number) { return localize('jsonParseError', '{0} near line "{1}", column "{2}"', error, line, column); } export function jsonParseError(error: string, line: number, column: number) { return localize('jsonParseError', '{0} near line "{1}", column "{2}"', error, line, column); }
export const moreInformation = localize('moreInformation', "More Information"); export const moreInformation = localize('moreInformation', "More Information");
export const addPackageReferenceMessage = localize('addPackageReferenceMessage', 'To use SQL bindings, ensure your Azure Functions project has a reference to {0}', sqlExtensionPackageName); export const addPackageReferenceMessage = localize('addPackageReferenceMessage', 'To use SQL bindings, ensure your Azure Functions project has a reference to {0}', sqlExtensionPackageName);
export const addSqlBindingPackageError = localize('addSqlBindingPackageError', 'Error adding Sql Binding extension package to project');

View File

@@ -6,20 +6,7 @@
/** /**
* Deferred promise * Deferred promise
*/ */
export class Deferred<T = void> { export interface Deferred<T> {
promise: Promise<T>; resolve: (result: T | Promise<T>) => void;
resolve!: (value: T | PromiseLike<T>) => void; reject: (reason: any) => void;
reject!: (reason?: any) => void;
constructor() {
this.promise = new Promise<T>((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult> {
return this.promise.then(onfulfilled, onrejected);
}
} }

View File

@@ -12,6 +12,7 @@ import * as glob from 'fast-glob';
import * as dataworkspace from 'dataworkspace'; import * as dataworkspace from 'dataworkspace';
import * as mssql from '../../../mssql'; import * as mssql from '../../../mssql';
import * as vscodeMssql from 'vscode-mssql'; import * as vscodeMssql from 'vscode-mssql';
import * as childProcess from 'child_process';
import * as fse from 'fs-extra'; import * as fse from 'fs-extra';
import * as which from 'which'; import * as which from 'which';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
@@ -155,24 +156,20 @@ export function convertSlashesForSqlProj(filePath: string): string {
/** /**
* Read SQLCMD variables from xmlDoc and return them * Read SQLCMD variables from xmlDoc and return them
* @param xmlDoc xml doc to read SQLCMD variables from. Format must be the same that sqlproj and publish profiles use * @param xmlDoc xml doc to read SQLCMD variables from. Format must be the same that sqlproj and publish profiles use
* @param publishProfile true if reading from publish profile
*/ */
export function readSqlCmdVariables(xmlDoc: Document, publishProfile: boolean): Record<string, string> { export function readSqlCmdVariables(xmlDoc: any): Record<string, string> {
let sqlCmdVariables: Record<string, string> = {}; let sqlCmdVariables: Record<string, string> = {};
for (let i = 0; i < xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)?.length; i++) { for (let i = 0; i < xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)?.length; i++) {
const sqlCmdVar = xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)[i]; const sqlCmdVar = xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)[i];
const varName = sqlCmdVar.getAttribute(constants.Include)!; const varName = sqlCmdVar.getAttribute(constants.Include);
// Publish profiles only support Value, so don't use DefaultValue even if it's there if (sqlCmdVar.getElementsByTagName(constants.DefaultValue)[0] !== undefined) {
// SSDT uses the Value (like <Value>$(SqlCmdVar__1)</Value>) where there
// are local variable values you can set in VS in the properties. Since we don't support that in ADS, only DefaultValue is supported for sqlproj.
if (!publishProfile && sqlCmdVar.getElementsByTagName(constants.DefaultValue)[0] !== undefined) {
// project file path // project file path
sqlCmdVariables[varName] = sqlCmdVar.getElementsByTagName(constants.DefaultValue)[0].childNodes[0].nodeValue!; sqlCmdVariables[varName] = sqlCmdVar.getElementsByTagName(constants.DefaultValue)[0].childNodes[0].nodeValue;
} }
else { else {
// profile path // profile path
sqlCmdVariables[varName] = sqlCmdVar.getElementsByTagName(constants.Value)[0].childNodes[0].nodeValue!; sqlCmdVariables[varName] = sqlCmdVar.getElementsByTagName(constants.Value)[0].childNodes[0].nodeValue;
} }
} }
@@ -425,6 +422,53 @@ export async function createFolderIfNotExist(folderPath: string): Promise<void>
} }
} }
export async function executeCommand(cmd: string, outputChannel: vscode.OutputChannel, sensitiveData: string[] = [], timeout: number = 5 * 60 * 1000): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (outputChannel) {
let cmdOutputMessage = cmd;
sensitiveData.forEach(element => {
cmdOutputMessage = cmdOutputMessage.replace(element, '***');
});
outputChannel.appendLine(` > ${cmdOutputMessage}`);
}
let child = childProcess.exec(cmd, {
timeout: timeout
}, (err, stdout) => {
if (err) {
// removing sensitive data from the exception
sensitiveData.forEach(element => {
err.cmd = err.cmd?.replace(element, '***');
err.message = err.message?.replace(element, '***');
});
reject(err);
} else {
resolve(stdout);
}
});
// Add listeners to print stdout and stderr if an output channel was provided
if (child?.stdout) {
child.stdout.on('data', data => { outputDataChunk(outputChannel, data, ' stdout: '); });
}
if (child?.stderr) {
child.stderr.on('data', data => { outputDataChunk(outputChannel, data, ' stderr: '); });
}
});
}
export function outputDataChunk(outputChannel: vscode.OutputChannel, data: string | Buffer, header: string): void {
data.toString().split(/\r?\n/)
.forEach(line => {
if (outputChannel) {
outputChannel.appendLine(header + line);
}
});
}
export async function retry<T>( export async function retry<T>(
name: string, name: string,
attempt: () => Promise<T>, attempt: () => Promise<T>,
@@ -529,52 +573,3 @@ export async function showInfoMessageWithOutputChannel(message: string, outputCh
} }
} }
/**
* Returns the results of the glob pattern
* @param pattern Glob pattern to search for
*/
export async function globWithPattern(pattern: string): Promise<string[]> {
const forwardSlashPattern = pattern.replace(/\\/g, '/');
return await glob(forwardSlashPattern);
}
/**
* Recursively gets all the sql files at any depth in a folder
* @param folderPath
* @param ignoreBinObj ignore sql files in bin and obj folders
*/
export async function getSqlFilesInFolder(folderPath: string, ignoreBinObj?: boolean): Promise<string[]> {
// path needs to use forward slashes for glob to work
folderPath = folderPath.replace(/\\/g, '/');
const sqlFilter = path.posix.join(folderPath, '**', '*.sql');
if (ignoreBinObj) {
// don't add files in bin and obj folders
const binIgnore = path.posix.join(folderPath, 'bin', '**', '*.sql');
const objIgnore = path.posix.join(folderPath, 'obj', '**', '*.sql');
return await glob(sqlFilter, { ignore: [binIgnore, objIgnore] });
} else {
return await glob(sqlFilter);
}
}
/**
* Recursively gets all the folders at any depth in the given folder
* @param folderPath
* @param ignoreBinObj ignore bin and obj folders
*/
export async function getFoldersInFolder(folderPath: string, ignoreBinObj?: boolean): Promise<string[]> {
// path needs to use forward slashes for glob to work
const escapedPath = glob.escapePath(folderPath.replace(/\\/g, '/'));
const folderFilter = path.posix.join(escapedPath, '/**');
if (ignoreBinObj) {
// don't add bin and obj folders
const binIgnore = path.posix.join(escapedPath, 'bin');
const objIgnore = path.posix.join(escapedPath, 'obj');
return await glob(folderFilter, { onlyDirectories: true, ignore: [binIgnore, objIgnore] });
} else {
return await glob(folderFilter, { onlyDirectories: true });
}
}

View File

@@ -10,7 +10,7 @@ import * as templates from '../templates/templates';
import * as path from 'path'; import * as path from 'path';
import { ProjectsController } from './projectController'; import { ProjectsController } from './projectController';
import { DBProjectConfigurationKey, DotnetInstallLocationKey, NetCoreInstallLocationKey, NetCoreTool } from '../tools/netcoreTool'; import { NetCoreTool } from '../tools/netcoreTool';
import { IconPathHelper } from '../common/iconHelper'; import { IconPathHelper } from '../common/iconHelper';
import { WorkspaceTreeItem } from 'dataworkspace'; import { WorkspaceTreeItem } from 'dataworkspace';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
@@ -45,13 +45,6 @@ export default class MainController implements vscode.Disposable {
} }
public async activate(): Promise<SqlDatabaseProjectProvider> { public async activate(): Promise<SqlDatabaseProjectProvider> {
// upgrade path from former netCoreSDKLocation setting to dotnetSDK Location setting
// copy old setting's value to new setting
const oldNetCoreInstallSetting = vscode.workspace.getConfiguration(DBProjectConfigurationKey)[NetCoreInstallLocationKey];
if (oldNetCoreInstallSetting && !vscode.workspace.getConfiguration(DBProjectConfigurationKey)[DotnetInstallLocationKey]) {
await vscode.workspace.getConfiguration(DBProjectConfigurationKey).update(DotnetInstallLocationKey, oldNetCoreInstallSetting, true);
}
await this.initializeDatabaseProjects(); await this.initializeDatabaseProjects();
return new SqlDatabaseProjectProvider(this.projectsController); return new SqlDatabaseProjectProvider(this.projectsController);
} }
@@ -61,7 +54,7 @@ export default class MainController implements vscode.Disposable {
vscode.commands.registerCommand('sqlDatabaseProjects.properties', async (node: WorkspaceTreeItem) => { return vscode.window.showErrorMessage(`Properties not yet implemented: ${node.element.uri.path}`); }); // TODO vscode.commands.registerCommand('sqlDatabaseProjects.properties', async (node: WorkspaceTreeItem) => { return vscode.window.showErrorMessage(`Properties not yet implemented: ${node.element.uri.path}`); }); // TODO
vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { return this.projectsController.buildProject(node); }); vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { return this.projectsController.buildProject(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { return this.projectsController.publishProject(node); }); vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { this.projectsController.publishProject(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { return this.projectsController.schemaCompare(node); }); vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { return this.projectsController.schemaCompare(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { return this.projectsController.createProjectFromDatabase(context); }); vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { return this.projectsController.createProjectFromDatabase(context); });
vscode.commands.registerCommand('sqlDatabaseProjects.generateProjectFromOpenApiSpec', async () => { return this.projectsController.generateProjectFromOpenApiSpec(); }); vscode.commands.registerCommand('sqlDatabaseProjects.generateProjectFromOpenApiSpec', async () => { return this.projectsController.generateProjectFromOpenApiSpec(); });
@@ -89,6 +82,9 @@ export default class MainController implements vscode.Disposable {
IconPathHelper.setExtensionContext(this.extensionContext); IconPathHelper.setExtensionContext(this.extensionContext);
await templates.loadTemplates(path.join(this.context.extensionPath, 'resources', 'templates')); await templates.loadTemplates(path.join(this.context.extensionPath, 'resources', 'templates'));
// ensure .net core is installed
await this.netcoreTool.findOrInstallNetCore();
} }
public dispose(): void { public dispose(): void {

View File

@@ -17,7 +17,7 @@ import type * as mssqlVscode from 'vscode-mssql';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog'; import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
import { Project, reservedProjectFolders } from '../models/project'; import { Project, reservedProjectFolders, FileProjectEntry, SqlProjectReferenceProjectEntry, IDatabaseReferenceProjectEntry } from '../models/project';
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider'; import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem'; import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
import { IDeploySettings } from '../models/IDeploySettings'; import { IDeploySettings } from '../models/IDeploySettings';
@@ -35,15 +35,13 @@ import { CreateProjectFromDatabaseDialog } from '../dialogs/createProjectFromDat
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { IconPathHelper } from '../common/iconHelper'; import { IconPathHelper } from '../common/iconHelper';
import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData'; import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData';
import { getPublishDatabaseSettings, launchPublishTargetOption } from '../dialogs/publishDatabaseQuickpick'; import { launchPublishDatabaseQuickpick } from '../dialogs/publishDatabaseQuickpick';
import { launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick'; import { launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick';
import { DeployService } from '../models/deploy/deployService'; import { DeployService } from '../models/deploy/deployService';
import { SqlTargetPlatform } from 'sqldbproj'; import { SqlTargetPlatform } from 'sqldbproj';
import { AutorestHelper } from '../tools/autorestHelper'; import { AutorestHelper } from '../tools/autorestHelper';
import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick'; import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick';
import { addDatabaseReferenceQuickpick } from '../dialogs/addDatabaseReferenceQuickpick'; import { addDatabaseReferenceQuickpick } from '../dialogs/addDatabaseReferenceQuickpick';
import { IDeployProfile } from '../models/deploy/deployProfile';
import { FileProjectEntry, IDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/projectEntry';
const maxTableLength = 10; const maxTableLength = 10;
@@ -224,7 +222,7 @@ export class ProjectsController {
const options: ShellCommandOptions = { const options: ShellCommandOptions = {
commandTitle: 'Build', commandTitle: 'Build',
workingDirectory: project.projectFolderPath, workingDirectory: project.projectFolderPath,
argument: this.buildHelper.constructBuildArguments(project.projectFilePath, this.buildHelper.extensionBuildDirPath, project.isSdkStyleProject) argument: this.buildHelper.constructBuildArguments(project.projectFilePath, this.buildHelper.extensionBuildDirPath)
}; };
try { try {
@@ -253,8 +251,7 @@ export class ProjectsController {
const message = utils.getErrorMessage(err); const message = utils.getErrorMessage(err);
if (err instanceof DotNetError) { if (err instanceof DotNetError) {
// DotNetErrors already get shown by the netCoreTool so just show this one in the console void vscode.window.showErrorMessage(message);
console.error(message);
} else { } else {
void vscode.window.showErrorMessage(constants.projBuildFailed(message)); void vscode.window.showErrorMessage(constants.projBuildFailed(message));
} }
@@ -266,9 +263,10 @@ export class ProjectsController {
* Publishes a project to docker container * Publishes a project to docker container
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project * @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
*/ */
public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: IDeployProfile): Promise<void> { public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
const project: Project = this.getProjectFromContext(context); const project: Project = this.getProjectFromContext(context);
try { try {
let deployProfile = await launchPublishToDockerContainerQuickpick(project);
if (deployProfile && deployProfile.deploySettings) { if (deployProfile && deployProfile.deploySettings) {
let connectionUri: string | undefined; let connectionUri: string | undefined;
if (deployProfile.localDbSetting) { if (deployProfile.localDbSetting) {
@@ -302,60 +300,28 @@ export class ProjectsController {
* Builds and publishes a project * Builds and publishes a project
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project * @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
*/ */
public async publishProject(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void>; public publishProject(treeNode: dataworkspace.WorkspaceTreeItem): PublishDatabaseDialog;
/** /**
* Builds and publishes a project * Builds and publishes a project
* @param project Project to be built and published * @param project Project to be built and published
*/ */
public async publishProject(project: Project): Promise<void>; public publishProject(project: Project): PublishDatabaseDialog;
public async publishProject(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> { public publishProject(context: Project | dataworkspace.WorkspaceTreeItem): PublishDatabaseDialog | undefined {
const project: Project = this.getProjectFromContext(context); const project: Project = this.getProjectFromContext(context);
if (utils.getAzdataApi()) { if (utils.getAzdataApi()) {
let publishDatabaseDialog = this.getPublishDialog(project); let publishDatabaseDialog = this.getPublishDialog(project);
publishDatabaseDialog.publish = async (proj, prof) => this.publishOrScriptProject(proj, prof, true); publishDatabaseDialog.publish = async (proj, prof) => this.publishOrScriptProject(proj, prof, true);
publishDatabaseDialog.publishToContainer = async (proj, prof) => this.publishToDockerContainer(proj, prof);
publishDatabaseDialog.generateScript = async (proj, prof) => this.publishOrScriptProject(proj, prof, false); publishDatabaseDialog.generateScript = async (proj, prof) => this.publishOrScriptProject(proj, prof, false);
publishDatabaseDialog.readPublishProfile = async (profileUri) => readPublishProfile(profileUri); publishDatabaseDialog.readPublishProfile = async (profileUri) => readPublishProfile(profileUri);
publishDatabaseDialog.openDialog(); publishDatabaseDialog.openDialog();
return publishDatabaseDialog.waitForClose(); return publishDatabaseDialog;
} else { } else {
void this.publishDatabase(project); void launchPublishDatabaseQuickpick(project, this);
}
}
/**
* Create flow for Publishing a database using only VS Code-native APIs such as QuickPick
*/
private async publishDatabase(project: Project): Promise<void> {
const publishTarget = await launchPublishTargetOption();
// Return when user hits escape
if (!publishTarget) {
return undefined; return undefined;
} }
if (publishTarget === constants.publishToDockerContainer) {
const deployProfile = await launchPublishToDockerContainerQuickpick(project);
if (deployProfile?.deploySettings) {
await this.publishToDockerContainer(project, deployProfile);
}
} else {
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project);
if (settings) {
// 5. Select action to take
const action = await vscode.window.showQuickPick(
[constants.generateScriptButtonText, constants.publish],
{ title: constants.chooseAction, ignoreFocusOut: true });
if (!action) {
return;
}
await this.publishOrScriptProject(project, settings, action === constants.publish);
}
}
} }
/** /**
@@ -868,7 +834,7 @@ export class ProjectsController {
public async selectAutorestSpecFile(): Promise<string | undefined> { public async selectAutorestSpecFile(): Promise<string | undefined> {
let quickpickSelection = await vscode.window.showQuickPick( let quickpickSelection = await vscode.window.showQuickPick(
[constants.browseEllipsisWithIcon], [constants.browseEllipsis],
{ title: constants.selectSpecFile, ignoreFocusOut: true }); { title: constants.selectSpecFile, ignoreFocusOut: true });
if (!quickpickSelection) { if (!quickpickSelection) {
return; return;
@@ -1091,6 +1057,25 @@ export class ProjectsController {
return new AddDatabaseReferenceDialog(project); return new AddDatabaseReferenceDialog(project);
} }
public async updateProjectForRoundTrip(project: Project) {
if (project.importedTargets.includes(constants.NetCoreTargets) && !project.containsSSDTOnlySystemDatabaseReferences()) {
return;
}
if (!project.importedTargets.includes(constants.NetCoreTargets)) {
const result = await vscode.window.showWarningMessage(constants.updateProjectForRoundTrip, constants.yesString, constants.noString);
if (result === constants.yesString) {
await project.updateProjectForRoundTrip();
await project.updateSystemDatabaseReferencesInProjFile();
}
} else if (project.containsSSDTOnlySystemDatabaseReferences()) {
const result = await vscode.window.showWarningMessage(constants.updateProjectDatabaseReferencesForRoundTrip, constants.yesString, constants.noString);
if (result === constants.yesString) {
await project.updateSystemDatabaseReferencesInProjFile();
}
}
}
private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise<void> { private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise<void> {
if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') { if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') {
return; return;

View File

@@ -9,13 +9,12 @@ import * as path from 'path';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
import * as utils from '../common/utils'; import * as utils from '../common/utils';
import { Project } from '../models/project'; import { Project, SystemDatabase } from '../models/project';
import { cssStyles } from '../common/uiConstants'; import { cssStyles } from '../common/uiConstants';
import { IconPathHelper } from '../common/iconHelper'; import { IconPathHelper } from '../common/iconHelper';
import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectReferenceSettings } from '../models/IDatabaseReferenceSettings'; import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectReferenceSettings } from '../models/IDatabaseReferenceSettings';
import { Deferred } from '../common/promise'; import { Deferred } from '../common/promise';
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { SystemDatabase } from '../models/projectEntry';
export enum ReferenceType { export enum ReferenceType {
project, project,
@@ -47,7 +46,8 @@ export class AddDatabaseReferenceDialog {
public currentReferenceType: ReferenceType | undefined; public currentReferenceType: ReferenceType | undefined;
private toDispose: vscode.Disposable[] = []; private toDispose: vscode.Disposable[] = [];
private initDialogComplete: Deferred = new Deferred(); private initDialogComplete: Deferred<void> | undefined;
private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
public addReference: ((proj: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings) => any) | undefined; public addReference: ((proj: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings) => any) | undefined;
@@ -86,7 +86,7 @@ export class AddDatabaseReferenceDialog {
this.dialog.cancelButton.label = constants.cancelButtonText; this.dialog.cancelButton.label = constants.cancelButtonText;
utils.getAzdataApi()!.window.openDialog(this.dialog); utils.getAzdataApi()!.window.openDialog(this.dialog);
await this.initDialogComplete.promise; await this.initDialogPromise;
} }
private dispose(): void { private dispose(): void {
@@ -144,7 +144,7 @@ export class AddDatabaseReferenceDialog {
await this.systemDatabaseRadioButton?.focus(); await this.systemDatabaseRadioButton?.focus();
} }
this.initDialogComplete.resolve(); this.initDialogComplete?.resolve();
}); });
} }

View File

@@ -118,7 +118,6 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined,
} }
existingSettings.unshift({ label: constants.createNewLocalAppSettingWithIcon, isCreateNew: true }); existingSettings.unshift({ label: constants.createNewLocalAppSettingWithIcon, isCreateNew: true });
let sqlConnectionStringSettingExists = existingSettings.find(s => s.label === constants.sqlConnectionStringSetting);
while (!connectionStringSettingName) { while (!connectionStringSettingName) {
const selectedSetting = await vscode.window.showQuickPick(existingSettings, { const selectedSetting = await vscode.window.showQuickPick(existingSettings, {
@@ -136,7 +135,6 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined,
{ {
title: constants.enterConnectionStringSettingName, title: constants.enterConnectionStringSettingName,
ignoreFocusOut: true, ignoreFocusOut: true,
value: sqlConnectionStringSettingExists ? '' : constants.sqlConnectionStringSetting,
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty validateInput: input => input ? undefined : constants.nameMustNotBeEmpty
} }
) ?? ''; ) ?? '';
@@ -150,7 +148,6 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined,
{ {
title: constants.enterConnectionString, title: constants.enterConnectionString,
ignoreFocusOut: true, ignoreFocusOut: true,
value: 'Server=localhost;Initial Catalog={db_name};User ID=sa;Password={your_password};Persist Security Info=False',
validateInput: input => input ? undefined : constants.valueMustNotBeEmpty validateInput: input => input ? undefined : constants.valueMustNotBeEmpty
} }
) ?? ''; ) ?? '';
@@ -212,3 +209,4 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined,
// 6. Add sql extension package reference to project. If the reference is already there, it doesn't get added again // 6. Add sql extension package reference to project. If the reference is already there, it doesn't get added again
await packageHelper.addPackageToAFProjectContainingFile(uri, constants.sqlExtensionPackageName); await packageHelper.addPackageToAFProjectContainingFile(uri, constants.sqlExtensionPackageName);
} }

View File

@@ -29,7 +29,8 @@ export class CreateProjectFromDatabaseDialog {
private formBuilder: azdataType.FormBuilder | undefined; private formBuilder: azdataType.FormBuilder | undefined;
private connectionId: string | undefined; private connectionId: string | undefined;
private toDispose: vscode.Disposable[] = []; private toDispose: vscode.Disposable[] = [];
private initDialogComplete: Deferred = new Deferred(); private initDialogComplete!: Deferred<void>;
private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
public createProjectFromDatabaseCallback: ((model: ImportDataModel) => any) | undefined; public createProjectFromDatabaseCallback: ((model: ImportDataModel) => any) | undefined;
@@ -50,7 +51,7 @@ export class CreateProjectFromDatabaseDialog {
this.dialog.cancelButton.label = constants.cancelButtonText; this.dialog.cancelButton.label = constants.cancelButtonText;
getAzdataApi()!.window.openDialog(this.dialog); getAzdataApi()!.window.openDialog(this.dialog);
await this.initDialogComplete.promise; await this.initDialogPromise;
if (this.profile) { if (this.profile) {
await this.updateConnectionComponents(getConnectionName(this.profile), this.profile.id, this.profile.databaseName!); await this.updateConnectionComponents(getConnectionName(this.profile), this.profile.id, this.profile.databaseName!);

View File

@@ -6,7 +6,6 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
import * as utils from '../common/utils'; import * as utils from '../common/utils';
import * as uiUtils from './utils';
import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile'; import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile';
import { Project } from '../models/project'; import { Project } from '../models/project';
import { getPublishDatabaseSettings } from './publishDatabaseQuickpick'; import { getPublishDatabaseSettings } from './publishDatabaseQuickpick';
@@ -70,50 +69,6 @@ export async function launchDeployAppIntegrationQuickpick(project: Project): Pro
}; };
} }
async function launchEulaQuickPick(baseImage: string): Promise<boolean> {
let eulaAccepted: boolean = false;
const baseImages = uiUtils.getDockerBaseImages();
const imageInfo = baseImages.find(x => x.name === baseImage);
const agreementInfo = imageInfo?.agreementInfo;
if (agreementInfo) {
const openEulaButton: vscode.QuickInputButton = {
iconPath: new vscode.ThemeIcon('link-external'),
tooltip: constants.openEulaString
};
const quickPick = vscode.window.createQuickPick();
quickPick.items = [{ label: constants.yesString },
{ label: constants.noString }];
quickPick.title = uiUtils.getAgreementDisplayText(agreementInfo);
quickPick.ignoreFocusOut = true;
quickPick.buttons = [openEulaButton];
const disposables: vscode.Disposable[] = [];
try {
const eulaAcceptedPromise = new Promise<boolean>((resolve) => {
disposables.push(
quickPick.onDidHide(() => {
resolve(false);
}),
quickPick.onDidTriggerButton(async () => {
await vscode.env.openExternal(vscode.Uri.parse(agreementInfo.link.url));
}),
quickPick.onDidChangeSelection((item) => {
resolve(item[0].label === constants.yesString);
}));
});
quickPick.show();
eulaAccepted = await eulaAcceptedPromise;
quickPick.hide();
}
finally {
disposables.forEach(d => d.dispose());
}
return eulaAccepted;
}
return false;
}
/** /**
* Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick * Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick
*/ */
@@ -164,9 +119,12 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
return undefined; return undefined;
} }
const baseImages = uiUtils.getDockerBaseImages();
const baseImage = await vscode.window.showQuickPick( const baseImage = await vscode.window.showQuickPick(
baseImages.map(x => x.name), [
`${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2017-latest`,
`${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2019-latest`,
`${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}:latest`
],
{ title: constants.selectBaseImage, ignoreFocusOut: true }); { title: constants.selectBaseImage, ignoreFocusOut: true });
// Return when user hits escape // Return when user hits escape
@@ -174,21 +132,13 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
return undefined; return undefined;
} }
const eulaAccepted = await launchEulaQuickPick(baseImage);
if (!eulaAccepted) {
return undefined;
}
const imageInfo = baseImages.find(x => x.name === baseImage);
localDbSetting = { localDbSetting = {
serverName: constants.defaultLocalServerName, serverName: 'localhost',
userName: constants.defaultLocalServerAdminName, userName: 'sa',
dbName: project.projectFileName, dbName: project.projectFileName,
password: password, password: password,
port: +portNumber, port: +portNumber,
dockerBaseImage: baseImage, dockerBaseImage: baseImage
dockerBaseImageEula: imageInfo?.agreementInfo?.link?.url || ''
}; };
let deploySettings = await getPublishDatabaseSettings(project, false); let deploySettings = await getPublishDatabaseSettings(project, false);

View File

@@ -14,10 +14,8 @@ import { IDeploySettings } from '../models/IDeploySettings';
import { DeploymentOptions } from '../../../mssql/src/mssql'; import { DeploymentOptions } from '../../../mssql/src/mssql';
import { IconPathHelper } from '../common/iconHelper'; import { IconPathHelper } from '../common/iconHelper';
import { cssStyles } from '../common/uiConstants'; import { cssStyles } from '../common/uiConstants';
import { getAgreementDisplayText, getConnectionName, getDockerBaseImages } from './utils'; import { getConnectionName } from './utils';
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { IDeployProfile } from '../models/deploy/deployProfile';
import { Deferred } from '../common/promise';
interface DataSourceDropdownValue extends azdataType.CategoryValue { interface DataSourceDropdownValue extends azdataType.CategoryValue {
dataSource: SqlConnectionDataSource; dataSource: SqlConnectionDataSource;
@@ -31,25 +29,14 @@ export class PublishDatabaseDialog {
private dataSourcesFormComponent: azdataType.FormComponent | undefined; private dataSourcesFormComponent: azdataType.FormComponent | undefined;
private dataSourcesDropDown: azdataType.DropDownComponent | undefined; private dataSourcesDropDown: azdataType.DropDownComponent | undefined;
private targetDatabaseDropDown: azdataType.DropDownComponent | undefined; private targetDatabaseDropDown: azdataType.DropDownComponent | undefined;
private targetDatabaseTextBox: azdataType.TextComponent | undefined;
private connectionsRadioButton: azdataType.RadioButtonComponent | undefined; private connectionsRadioButton: azdataType.RadioButtonComponent | undefined;
private existingServerRadioButton: azdataType.RadioButtonComponent | undefined;
private dockerServerRadioButton: azdataType.RadioButtonComponent | undefined;
private eulaCheckBox: azdataType.CheckBoxComponent | undefined;
private dataSourcesRadioButton: azdataType.RadioButtonComponent | undefined; private dataSourcesRadioButton: azdataType.RadioButtonComponent | undefined;
private sqlCmdVariablesTable: azdataType.DeclarativeTableComponent | undefined; private sqlCmdVariablesTable: azdataType.DeclarativeTableComponent | undefined;
private sqlCmdVariablesFormComponentGroup: azdataType.FormComponentGroup | undefined; private sqlCmdVariablesFormComponentGroup: azdataType.FormComponentGroup | undefined;
private loadSqlCmdVarsButton: azdataType.ButtonComponent | undefined; private loadSqlCmdVarsButton: azdataType.ButtonComponent | undefined;
private loadProfileTextBox: azdataType.InputBoxComponent | undefined; private loadProfileTextBox: azdataType.InputBoxComponent | undefined;
private formBuilder: azdataType.FormBuilder | undefined; private formBuilder: azdataType.FormBuilder | undefined;
private connectionRow: azdataType.FlexContainer | undefined;
private databaseRow: azdataType.FlexContainer | undefined;
private localDbSection: azdataType.FlexContainer | undefined;
private baseDockerImageDropDown: azdataType.DropDownComponent | undefined;
private serverAdminPasswordTextBox: azdataType.InputBoxComponent | undefined;
private serverConfigAdminPasswordTextBox: azdataType.InputBoxComponent | undefined;
private serverPortTextBox: azdataType.InputBoxComponent | undefined;
private existingServerSelected: boolean = true;
private connectionId: string | undefined; private connectionId: string | undefined;
private connectionIsDataSource: boolean | undefined; private connectionIsDataSource: boolean | undefined;
private sqlCmdVars: Record<string, string> | undefined; private sqlCmdVars: Record<string, string> | undefined;
@@ -57,18 +44,14 @@ export class PublishDatabaseDialog {
private profileUsed: boolean = false; private profileUsed: boolean = false;
private serverName: string | undefined; private serverName: string | undefined;
private completionPromise: Deferred = new Deferred();
private toDispose: vscode.Disposable[] = []; private toDispose: vscode.Disposable[] = [];
public publish: ((proj: Project, profile: IDeploySettings) => any) | undefined; public publish: ((proj: Project, profile: IDeploySettings) => any) | undefined;
public publishToContainer: ((proj: Project, profile: IDeployProfile) => any) | undefined;
public generateScript: ((proj: Project, profile: IDeploySettings) => any) | undefined; public generateScript: ((proj: Project, profile: IDeploySettings) => any) | undefined;
public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined; public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined;
constructor(private project: Project) { constructor(private project: Project) {
this.dialog = utils.getAzdataApi()!.window.createModelViewDialog(constants.publishDialogName, 'sqlProjectPublishDialog'); this.dialog = utils.getAzdataApi()!.window.createModelViewDialog(constants.publishDialogName, 'sqlProjectPublishDialog');
this.toDispose.push(this.dialog.onClosed(_ => this.completionPromise.resolve()));
this.publishTab = utils.getAzdataApi()!.window.createTab(constants.publishDialogName); this.publishTab = utils.getAzdataApi()!.window.createTab(constants.publishDialogName);
} }
@@ -90,15 +73,6 @@ export class PublishDatabaseDialog {
utils.getAzdataApi()!.window.openDialog(this.dialog); utils.getAzdataApi()!.window.openDialog(this.dialog);
} }
public set publishToExistingServer(v: boolean) {
this.existingServerSelected = v;
}
public waitForClose(): Promise<void> {
return this.completionPromise.promise;
}
private dispose(): void { private dispose(): void {
this.toDispose.forEach(disposable => disposable.dispose()); this.toDispose.forEach(disposable => disposable.dispose());
} }
@@ -110,10 +84,8 @@ export class PublishDatabaseDialog {
private initializePublishTab(): void { private initializePublishTab(): void {
this.publishTab.registerContent(async view => { this.publishTab.registerContent(async view => {
const flexRadioButtonsModel = this.createPublishTypeRadioButtons(view);
// TODO : enable using this when data source creation is enabled // TODO : enable using this when data source creation is enabled
this.createRadioButtons(view); this.createRadioButtons(view);
this.createLocalDbInfoRow(view);
this.dataSourcesFormComponent = this.createDataSourcesFormComponent(view); this.dataSourcesFormComponent = this.createDataSourcesFormComponent(view);
@@ -131,15 +103,15 @@ export class PublishDatabaseDialog {
component: <azdataType.DeclarativeTableComponent>this.sqlCmdVariablesTable component: <azdataType.DeclarativeTableComponent>this.sqlCmdVariablesTable
} }
], ],
title: constants.sqlCmdVariables title: constants.sqlCmdTableLabel
}; };
const profileRow = this.createProfileRow(view); const profileRow = this.createProfileRow(view);
this.connectionRow = this.createConnectionRow(view); const connectionRow = this.createConnectionRow(view);
this.databaseRow = this.createDatabaseRow(view); const databaseRow = this.createDatabaseRow(view);
const horizontalFormSection = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component(); const horizontalFormSection = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
horizontalFormSection.addItems([profileRow, this.databaseRow]); horizontalFormSection.addItems([profileRow, connectionRow, databaseRow]);
this.formBuilder = <azdataType.FormBuilder>view.modelBuilder.formContainer() this.formBuilder = <azdataType.FormBuilder>view.modelBuilder.formContainer()
@@ -147,14 +119,6 @@ export class PublishDatabaseDialog {
{ {
title: '', title: '',
components: [ components: [
{
component: flexRadioButtonsModel,
title: ''
},
{
component: this.connectionRow,
title: ''
},
{ {
component: horizontalFormSection, component: horizontalFormSection,
title: '' title: ''
@@ -218,45 +182,17 @@ export class PublishDatabaseDialog {
} }
public async publishClick(): Promise<void> { public async publishClick(): Promise<void> {
if (this.existingServerSelected) { const settings: IDeploySettings = {
const settings: IDeploySettings = { databaseName: this.getTargetDatabaseName(),
databaseName: this.targetDatabaseName, serverName: this.getServerName(),
serverName: this.getServerName(), connectionUri: await this.getConnectionUri(),
connectionUri: await this.getConnectionUri(), sqlCmdVariables: this.getSqlCmdVariablesForPublish(),
sqlCmdVariables: this.getSqlCmdVariablesForPublish(), deploymentOptions: await this.getDeploymentOptions(),
deploymentOptions: await this.getDeploymentOptions(), profileUsed: this.profileUsed
profileUsed: this.profileUsed };
};
utils.getAzdataApi()!.window.closeDialog(this.dialog); utils.getAzdataApi()!.window.closeDialog(this.dialog);
await this.publish!(this.project, settings); await this.publish!(this.project, settings);
} else {
const dockerBaseImage = this.getBaseDockerImageName();
const baseImages = getDockerBaseImages();
const imageInfo = baseImages.find(x => x.name === dockerBaseImage);
const settings: IDeployProfile = {
localDbSetting: {
dbName: this.targetDatabaseName,
dockerBaseImage: dockerBaseImage,
dockerBaseImageEula: imageInfo?.agreementInfo?.link?.url || '',
password: this.serverAdminPasswordTextBox?.value || '',
port: +(this.serverPortTextBox?.value || constants.defaultPortNumber),
serverName: constants.defaultLocalServerName,
userName: constants.defaultLocalServerAdminName
},
deploySettings: {
databaseName: this.targetDatabaseName,
serverName: constants.defaultLocalServerName,
connectionUri: '',
sqlCmdVariables: this.getSqlCmdVariablesForPublish(),
deploymentOptions: await this.getDeploymentOptions(),
profileUsed: this.profileUsed
}
};
utils.getAzdataApi()!.window.closeDialog(this.dialog);
await this.publishToContainer!(this.project, settings);
}
this.dispose(); this.dispose();
} }
@@ -266,7 +202,7 @@ export class PublishDatabaseDialog {
const sqlCmdVars = this.getSqlCmdVariablesForPublish(); const sqlCmdVars = this.getSqlCmdVariablesForPublish();
const settings: IDeploySettings = { const settings: IDeploySettings = {
databaseName: this.targetDatabaseName, databaseName: this.getTargetDatabaseName(),
serverName: this.getServerName(), serverName: this.getServerName(),
connectionUri: await this.getConnectionUri(), connectionUri: await this.getConnectionUri(),
sqlCmdVariables: sqlCmdVars, sqlCmdVariables: sqlCmdVars,
@@ -298,26 +234,8 @@ export class PublishDatabaseDialog {
return sqlCmdVariables; return sqlCmdVariables;
} }
public get targetDatabaseName(): string { public getTargetDatabaseName(): string {
if (this.existingServerSelected) { return <string>this.targetDatabaseDropDown?.value ?? '';
return <string>this.targetDatabaseDropDown?.value ?? '';
} else {
return <string>this.targetDatabaseTextBox?.value || '';
}
}
public set targetDatabaseName(value: string) {
(<azdataType.DropDownComponent>this.targetDatabaseDropDown).values = [];
this.targetDatabaseDropDown!.values?.push(<any>value);
this.targetDatabaseDropDown!.value = value;
if (this.targetDatabaseTextBox) {
this.targetDatabaseTextBox!.value = value;
}
}
public getBaseDockerImageName(): string {
return <string>this.baseDockerImageDropDown?.value ?? '';
} }
public getDefaultDatabaseName(): string { public getDefaultDatabaseName(): string {
@@ -368,79 +286,6 @@ export class PublishDatabaseDialog {
return flexRadioButtonsModel; return flexRadioButtonsModel;
} }
private createPublishTypeRadioButtons(view: azdataType.ModelView): azdataType.Component {
const publishToLabel = view.modelBuilder.text().withProps({
value: constants.publishTo,
width: cssStyles.publishDialogLabelWidth
}).component();
this.existingServerRadioButton = view.modelBuilder.radioButton()
.withProps({
name: 'publishType',
label: constants.publishToExistingServer
}).component();
this.existingServerRadioButton.checked = true;
this.existingServerRadioButton.onDidChangeCheckedState((checked) => {
this.onPublishTypeChange(checked, view);
});
this.dockerServerRadioButton = view.modelBuilder.radioButton()
.withProps({
name: 'publishType',
label: constants.publishToDockerContainer
}).component();
this.dockerServerRadioButton.onDidChangeCheckedState((checked) => {
this.onPublishTypeChange(!checked, view);
});
const radioButtonContainer = view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' })
.withItems([this.existingServerRadioButton, this.dockerServerRadioButton])
.withProps({ ariaRole: 'radiogroup' })
.component();
let flexRadioButtonsModel: azdataType.FlexContainer = view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'row', alignItems: 'baseline' })
.withItems([publishToLabel, radioButtonContainer], { CSSStyles: { flex: '0 0 auto', 'margin-right': '10px' } })
.component();
return flexRadioButtonsModel;
}
private onPublishTypeChange(existingServer: boolean, view: azdataType.ModelView) {
this.existingServerSelected = existingServer;
this.createDatabaseRow(view);
this.tryEnableGenerateScriptAndOkButtons();
if (existingServer) {
if (this.connectionRow) {
this.formBuilder!.insertFormItem({
title: '',
component: this.connectionRow
}, 2);
}
if (this.localDbSection) {
this.formBuilder!.removeFormItem({
title: '',
component: this.localDbSection
});
}
} else {
if (this.connectionRow) {
this.formBuilder!.removeFormItem({
title: '',
component: this.connectionRow
});
}
if (this.localDbSection) {
this.formBuilder!.insertFormItem({
title: '',
component: this.localDbSection
}, 2);
}
}
}
private createTargetConnectionComponent(view: azdataType.ModelView): azdataType.InputBoxComponent { private createTargetConnectionComponent(view: azdataType.ModelView): azdataType.InputBoxComponent {
this.targetConnectionTextBox = view.modelBuilder.inputBox().withProps({ this.targetConnectionTextBox = view.modelBuilder.inputBox().withProps({
value: '', value: '',
@@ -540,159 +385,37 @@ export class PublishDatabaseDialog {
return connectionRow; return connectionRow;
} }
private createLocalDbInfoRow(view: azdataType.ModelView): azdataType.FlexContainer {
this.serverPortTextBox = view.modelBuilder.inputBox().withProps({
value: constants.defaultPortNumber,
ariaLabel: constants.serverPortNumber,
placeHolder: constants.serverPortNumber,
width: cssStyles.publishDialogTextboxWidth,
enabled: true,
inputType: 'number',
validationErrorMessage: constants.portMustBeNumber
}).withValidation(component => utils.validateSqlServerPortNumber(component.value)).component();
this.serverPortTextBox.onTextChanged(() => {
this.tryEnableGenerateScriptAndOkButtons();
});
const serverPortRow = this.createFormRow(view, constants.serverPortNumber, this.serverPortTextBox);
this.serverAdminPasswordTextBox = view.modelBuilder.inputBox().withProps({
value: '',
ariaLabel: constants.serverPassword,
placeHolder: constants.serverPassword,
width: cssStyles.publishDialogTextboxWidth,
enabled: true,
inputType: 'password',
validationErrorMessage: constants.invalidSQLPasswordMessage
}).withValidation(component => !utils.isEmptyString(component.value) && utils.isValidSQLPassword(component.value || '')).component();
const serverPasswordRow = this.createFormRow(view, constants.serverPassword, this.serverAdminPasswordTextBox);
this.serverConfigAdminPasswordTextBox = view.modelBuilder.inputBox().withProps({
value: '',
ariaLabel: constants.confirmServerPassword,
placeHolder: constants.confirmServerPassword,
width: cssStyles.publishDialogTextboxWidth,
enabled: true,
inputType: 'password',
validationErrorMessage: constants.passwordNotMatch
}).withValidation(component => component.value === this.serverAdminPasswordTextBox?.value).component();
this.serverAdminPasswordTextBox.onTextChanged(() => {
this.tryEnableGenerateScriptAndOkButtons();
if (this.serverConfigAdminPasswordTextBox) {
this.serverConfigAdminPasswordTextBox.value = '';
}
});
this.serverConfigAdminPasswordTextBox.onTextChanged(() => {
this.tryEnableGenerateScriptAndOkButtons();
});
const serverConfirmPasswordRow = this.createFormRow(view, constants.confirmServerPassword, this.serverConfigAdminPasswordTextBox);
const baseImages = getDockerBaseImages();
this.baseDockerImageDropDown = view.modelBuilder.dropDown().withProps({
values: baseImages.map(x => x.name),
ariaLabel: constants.baseDockerImage,
width: cssStyles.publishDialogTextboxWidth,
enabled: true
}).component();
const agreementInfo = baseImages[0].agreementInfo;
const dropDownRow = this.createFormRow(view, constants.baseDockerImage, this.baseDockerImageDropDown);
this.eulaCheckBox = view.modelBuilder.checkBox().withProps({
ariaLabel: getAgreementDisplayText(agreementInfo),
required: true
}).component();
this.eulaCheckBox.onChanged(() => {
this.tryEnableGenerateScriptAndOkButtons();
});
const eulaRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
this.localDbSection = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
this.localDbSection.addItems([serverPortRow, serverPasswordRow, serverConfirmPasswordRow, dropDownRow, eulaRow]);
this.baseDockerImageDropDown.onValueChanged(() => {
if (this.eulaCheckBox) {
this.eulaCheckBox.checked = false;
}
const baseImage = getDockerBaseImages().find(x => x.name === this.baseDockerImageDropDown?.value);
if (baseImage?.agreementInfo.link) {
const text = view.modelBuilder.text().withProps({
value: constants.eulaAgreementTemplate,
links: [baseImage.agreementInfo.link],
requiredIndicator: true
}).component();
if (eulaRow && this.eulaCheckBox) {
eulaRow?.clearItems();
eulaRow?.addItems([this.eulaCheckBox, text], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } });
}
}
});
return this.localDbSection;
}
private createFormRow(view: azdataType.ModelView, label: string, component: azdataType.Component): azdataType.FlexContainer {
const labelComponent = view.modelBuilder.text().withProps({
value: label,
requiredIndicator: true,
width: cssStyles.publishDialogLabelWidth
}).component();
return view.modelBuilder.flexContainer().withItems([labelComponent, component], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
}
private createDatabaseRow(view: azdataType.ModelView): azdataType.FlexContainer { private createDatabaseRow(view: azdataType.ModelView): azdataType.FlexContainer {
let databaseComponent: azdataType.Component | undefined; this.targetDatabaseDropDown = view.modelBuilder.dropDown().withProps({
values: [this.getDefaultDatabaseName()],
value: this.getDefaultDatabaseName(),
ariaLabel: constants.databaseNameLabel,
required: true,
width: cssStyles.publishDialogTextboxWidth,
editable: true,
fireOnTextChange: true
}).component();
if (!this.existingServerSelected) { this.targetDatabaseDropDown.onValueChanged(() => {
if (this.targetDatabaseTextBox === undefined) { this.tryEnableGenerateScriptAndOkButtons();
this.targetDatabaseTextBox = view.modelBuilder.inputBox().withProps({ });
ariaLabel: constants.databaseNameLabel,
required: true,
width: cssStyles.publishDialogTextboxWidth,
value: this.getDefaultDatabaseName()
}).component();
}
databaseComponent = this.targetDatabaseTextBox;
} else {
if (this.targetDatabaseDropDown === undefined) {
this.targetDatabaseDropDown = view.modelBuilder.dropDown().withProps({
values: [this.getDefaultDatabaseName()],
value: this.getDefaultDatabaseName(),
ariaLabel: constants.databaseNameLabel,
required: true,
width: cssStyles.publishDialogTextboxWidth,
editable: true,
fireOnTextChange: true
}).component();
this.targetDatabaseDropDown.onValueChanged(() => {
this.tryEnableGenerateScriptAndOkButtons();
});
}
databaseComponent = this.targetDatabaseDropDown;
}
const databaseLabel = view.modelBuilder.text().withProps({ const databaseLabel = view.modelBuilder.text().withProps({
value: constants.databaseNameLabel, value: constants.databaseNameLabel,
requiredIndicator: true, requiredIndicator: true,
width: cssStyles.publishDialogLabelWidth width: cssStyles.publishDialogLabelWidth
}).component(); }).component();
const itemLayout = { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } };
if (this.databaseRow === undefined) { const databaseRow = view.modelBuilder.flexContainer().withItems([databaseLabel, <azdataType.DropDownComponent>this.targetDatabaseDropDown], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
this.databaseRow = view.modelBuilder.flexContainer().withItems([databaseLabel, <azdataType.Component>databaseComponent], itemLayout).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
} else { return databaseRow;
this.databaseRow.clearItems();
this.databaseRow.addItems([databaseLabel, <azdataType.Component>databaseComponent], itemLayout);
}
return this.databaseRow;
} }
private createSqlCmdTable(view: azdataType.ModelView): azdataType.DeclarativeTableComponent { private createSqlCmdTable(view: azdataType.ModelView): azdataType.DeclarativeTableComponent {
this.sqlCmdVars = { ...this.project.sqlCmdVariables }; this.sqlCmdVars = { ...this.project.sqlCmdVariables };
const table = view.modelBuilder.declarativeTable().withProps({ const table = view.modelBuilder.declarativeTable().withProps({
ariaLabel: constants.sqlCmdVariables, ariaLabel: constants.sqlCmdTableLabel,
dataValues: this.convertSqlCmdVarsToTableFormat(this.sqlCmdVars), dataValues: this.convertSqlCmdVarsToTableFormat(this.sqlCmdVars),
columns: [ columns: [
{ {
@@ -812,14 +535,15 @@ export class PublishDatabaseDialog {
if (this.readPublishProfile) { if (this.readPublishProfile) {
const result = await this.readPublishProfile(fileUris[0]); const result = await this.readPublishProfile(fileUris[0]);
// clear out old database dropdown values. They'll get populated later if there was a connection specified in the profile // clear out old database dropdown values. They'll get populated later if there was a connection specified in the profile
this.targetDatabaseName = ''; (<azdataType.DropDownComponent>this.targetDatabaseDropDown).values = [];
this.connectionId = result.connectionId; this.connectionId = result.connectionId;
this.serverName = result.serverName; this.serverName = result.serverName;
await this.updateConnectionComponents(result.connection, <string>this.connectionId); await this.updateConnectionComponents(result.connection, <string>this.connectionId);
if (result.databaseName) { if (result.databaseName) {
this.targetDatabaseName = result.databaseName; this.targetDatabaseDropDown!.values?.push(result.databaseName);
this.targetDatabaseDropDown!.value = result.databaseName;
} }
if (Object.keys(result.sqlCmdVariables).length) { if (Object.keys(result.sqlCmdVariables).length) {
@@ -863,26 +587,15 @@ export class PublishDatabaseDialog {
// only enable Generate Script and Ok buttons if all fields are filled // only enable Generate Script and Ok buttons if all fields are filled
private tryEnableGenerateScriptAndOkButtons(): void { private tryEnableGenerateScriptAndOkButtons(): void {
let publishEnabled: boolean = false; if ((this.targetConnectionTextBox!.value && this.targetDatabaseDropDown!.value
let generateScriptEnabled: boolean = false; || this.connectionIsDataSource && this.targetDatabaseDropDown!.value)
&& this.allSqlCmdVariablesFilled()) {
if (this.existingServerRadioButton?.checked) { this.dialog.okButton.enabled = true;
if ((this.targetConnectionTextBox!.value && this.targetDatabaseDropDown!.value this.dialog.customButtons[0].enabled = true;
|| this.connectionIsDataSource && this.targetDatabaseDropDown!.value) } else {
&& this.allSqlCmdVariablesFilled()) { this.dialog.okButton.enabled = false;
publishEnabled = true; this.dialog.customButtons[0].enabled = false;
generateScriptEnabled = true;
}
} else if (utils.validateSqlServerPortNumber(this.serverPortTextBox?.value) &&
!utils.isEmptyString(this.serverAdminPasswordTextBox?.value) &&
utils.isValidSQLPassword(this.serverAdminPasswordTextBox?.value || '', constants.defaultLocalServerAdminName) &&
this.serverAdminPasswordTextBox?.value === this.serverConfigAdminPasswordTextBox?.value
&& this.eulaCheckBox?.checked) {
publishEnabled = true; // only publish is supported for container
} }
this.dialog.okButton.enabled = publishEnabled;
this.dialog.customButtons[0].enabled = generateScriptEnabled;
} }
private allSqlCmdVariablesFilled(): boolean { private allSqlCmdVariablesFilled(): boolean {

Some files were not shown because too many files have changed in this diff Show More