Compare commits

...

88 Commits
1.46.0 ... main

Author SHA1 Message Date
f1467cdd72 Improves "save as Excel" functionality (#24653) 2023-10-11 19:50:22 -07:00
Cheena Malhotra
aaa9c4a744 Pass Http proxy URL and strict SSL flag to backend STS (#24550) 2023-10-11 19:50:07 -07:00
Cheena Malhotra
989193645c Bump STS version to 4.10.0.17 (#24658) 2023-10-11 19:49:49 -07:00
Alex Ma
5e04523635 [Loc] xlf update 10-11-2023 (#24657) 2023-10-11 17:04:11 -07:00
Siyang Yao
eb3598f1a7 fix bugs (#24654)
Co-authored-by: Siyang Yao <siyao@microsoft.com>
2023-10-11 14:53:49 -07:00
Alex Ma
52bbb60def Add tooltips with advanced options on hover for editor tabs (#24486)
* Added WIP table designer input change

* added test details to tableDesigner

* added connection name to details

* wip restoration of nonDefaultOptions

* added Verbosity todo for getTitle

* added updated info

* added fix for mainController

* fixed assignment

* added update to description

* restore title parts to old names

* added clarifying message

* added title to dashboard and profilerinput

* added advanced titles for edit data and query editor input

* added changes based on feedback

* added additional description

* Added some changes to tableDesigner input

* fixed comments

* removed erroneous import

* added updated titles and tooltips

* added small corrections

* added profiler XEL title feature

* added session name to profiler input tooltip

* added small tooltip rework

* remove unavailable session name

* added update to config.json
2023-10-11 14:27:25 -07:00
Cheena Malhotra
ab0ea5db62 Fix clear pooled connection title (#24650) 2023-10-11 13:52:26 -07:00
Siyang Yao
ff042613d1 Revert "add schema migration (#24594)" (#24652)
This reverts commit f70ff23ca5.
2023-10-11 12:25:37 -07:00
Siyang Yao
f70ff23ca5 add schema migration (#24594)
* add schema migration

* fix table selection issue

* fix table validation

* data only wont show schema info grids

* address comments

* update schema migration helper banner

* fix undefined

* refactor

* endedOn is - when not started

* fix toString

* refactor

* auto referesh dashboardtab and migrationtab

* add migration type in dashboard

* fix saving issue in page 0 and page 1

* fix compile issue

* fix save and close in page 3

* refactor

* fix save

* fix save

* fix save

* dont load location twice

* fix target type undefined issue

* set MI as default

* fix cannot load in step 3

* integrate assessment with schema

---------

Co-authored-by: Siyang Yao <siyao@microsoft.com>
2023-10-10 22:14:52 -07:00
Karl Burtram
32fa73f524 Update distro commit to 37199be719d05d53f4eaa7d96018e579021fe3b0 (#24647) 2023-10-10 20:56:39 -07:00
Alex Ma
d3dd7d812f [Loc] removed noQueryRunnerForUri (#24648) 2023-10-10 17:20:34 -07:00
erpett
8b3ef369af changelog for 1.46.1 (#24575) 2023-10-10 15:20:19 -07:00
Cheena Malhotra
f25b0530b9 Use python 3.11 (#24646) 2023-10-10 15:18:19 -07:00
Alex Ma
e1694e5a30 [Loc] update to xlfs 10-9-2023 (#24626) 2023-10-10 10:44:10 -07:00
Christopher Suh
587d31ab2c Transfer URI Correctly (#24614)
* transfer uri regardless of queryrunner presence

* throw error if new URI already exists

* bump sts version
2023-10-10 10:12:33 -07:00
Christopher Suh
62959d565c update commit hash for AGC merge (#24622) 2023-10-09 14:05:50 -07:00
Cory Rivera
63a78e62aa Handle some server properties not being supported for certain SQL versions (#24587)
* Co-authored-by: Benjin Dubishar <benjind@microsoft.com>
2023-10-09 13:28:08 -07:00
Sai Avishkar Sreerama
a3041f25b2 Fix to Disable Apply button for Query Store tab when no changes are made (#24573)
* fix to Disable Apply button for Query Store tab when no changes are made

* typo

* wrong name is displying in query store section
2023-10-09 13:01:48 -05:00
Christopher Suh
05b6593f58 Create a custom Air-Gapped Cloud Build (#24595)
* initial commit with new build step for agc

* add mixin agc step

* add commit hash
2023-10-05 10:26:41 -07:00
Ram Uday Kumar
8f232ae3e8 Premium SSD v2 disks in SQL VM recommendations (#24556)
* Premium SSD v2 disks in SQL VM recommendations

* Resolving review comments.
2023-10-04 16:57:44 +05:30
Christopher Suh
186f8d3771 Change HTTP request to axios (#24549)
* change request to axios

* fix typo

* remove httpClient

* fix build

* change azurenetworkresponse to axiosresponse
2023-10-03 19:04:10 -07:00
Barbara Valdez
c641865891 Use vertical tabs in server and database properties (#24521)
* use vertical tabs

* remove always show tabs option

* remove extra comma
2023-10-03 13:15:50 -07:00
Sai Avishkar Sreerama
5ed263ecd2 fixing double scroll bar issue on DSC tab (#24560) 2023-10-03 11:40:55 -05:00
CSIGS@microsoft.com
cc148930c7 Juno: check in to lego/hb_04604851-bac4-4681-9f74-73de611d6e48_20230930153756674. (#24553) 2023-10-02 10:57:32 -07:00
Sakshi Sharma
8a6f61c78d Fix column resize issue in profiler (#24547)
* Fix column resize issue in profiler

* Update property name

* Use top instead of paddingTop

* Fix error
2023-10-02 10:21:27 -07:00
Sai Avishkar Sreerama
549464dab1 Adding fiilegroup name label to the input box and auto focus of newly added row (#24536)
* adds nameupdate textbox

* fixed rows table remove button

* input value update on row selection

* using display prop instead of visible css property

* select newly added cell automatically

* sets remove button to next row after deleting a row
2023-10-02 12:11:57 -05:00
Karl Burtram
405122daeb Bump Electron to 22.3.15 (#24554) 2023-10-01 13:48:00 -07:00
Christopher Suh
86d0779c87 fix dashboard opening server vs database view (#24546) 2023-09-29 14:40:47 -07:00
Kim Santiago
cc84a5e709 make form container info have tooltip role (#24545) 2023-09-29 10:34:23 -10:00
dependabot[bot]
b54d12b2be Bump get-func-name from 2.0.0 to 2.0.2 in /test/monaco (#24527)
Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2.
- [Release notes](https://github.com/chaijs/get-func-name/releases)
- [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2)

---
updated-dependencies:
- dependency-name: get-func-name
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kim Santiago <kisantia@microsoft.com>
2023-09-29 10:12:18 -10:00
Cory Rivera
b07fee5a5f Move New Login dialog's advanced options into the general section (#24538) 2023-09-29 10:46:40 -07:00
Kim Santiago
883d5714cc Delete compilation.tar.gz after it's been extracted (#24539)
* try deleting compilation downput after it's been extracted

* consolidate into same step as extraction

* Update build/azure-pipelines/linux/sql-product-build-linux.yml

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
2023-09-29 07:39:17 -10:00
Cory Rivera
94cdaf9d57 Change Cancel button label to Back for inner dialogs. (#24537) 2023-09-28 18:02:25 -07:00
Cheena Malhotra
731dc6318f Update Azure core packages and additional error handling (#24500) 2023-09-28 15:53:49 -07:00
CSIGS@microsoft.com
25cdb558a7 Juno: check in to lego/hb_04604851-bac4-4681-9f74-73de611d6e48_20230928154102864. (#24534) 2023-09-28 13:25:46 -07:00
Charles Gagnon
696cdc3200 Fix regex replace (#24525) 2023-09-27 22:22:57 -07:00
Cory Rivera
c5e8ecd24b Add additional telemetry for basic admin operations (#24526) 2023-09-27 16:32:19 -07:00
Cory Rivera
12da714803 Redirect vscode New Jupyter Notebook command (#24520) 2023-09-27 13:25:49 -07:00
Cory Rivera
131c288ab4 Enable Rename Database for on-prem servers. Use common method for getting OE node info. (#24517) 2023-09-27 11:21:07 -07:00
Karl Burtram
646b001160 Feat/bumpelectron22324 (#24497)
* Bump Electron to 22.3.24

* Bump distro

* Bump to release version in main.ts

* revert bump in this branch

* Bump to distro to fix conflict

* bump to releaseVersion in main

* changed distro to one in branch

* Revert "changed distro to one in branch"

This reverts commit 60213995a1fd2b9b548790c090c5a57ea363d278.

* Revert "Bump to distro to fix conflict"

This reverts commit e5119783f835a70fb56d52b8bc2919a311607f6c.

* Bump to distro (new)

---------

Co-authored-by: Alex Ma <alma1@microsoft.com>
2023-09-27 10:21:00 -07:00
Kim Santiago
9a1d823c69 fixing a couple codeql warnings about incomplete string replacement (#24518) 2023-09-27 06:42:47 -10:00
Alex Ma
efcf52f62c [Loc] fix for package.nls.json and xlf update (#24522) 2023-09-26 17:56:20 -07:00
Cheena Malhotra
dce130c5af Update application name to Azure Data Studio (#24510) 2023-09-26 10:15:32 -07:00
Cheena Malhotra
306eb42ae7 Use non-floating integers with max limits in settings (#24511) 2023-09-25 18:10:05 -07:00
Kim Santiago
a612781638 Remove sql edge container option from sql projects publish (#24499)
* remove sql edge container option from sql projects publish

* undo testing change

* remove base image dropdown from publish dialog
2023-09-25 06:34:56 -10:00
Alex Ma
a1f7bddb3a [Loc] update to langpacks for 9-22-2023 (#24505) 2023-09-22 17:03:12 -07:00
Cory Rivera
f7f5ee780a Use sync callback to stop Jupyter server when ADS process exits (#24501) 2023-09-22 08:50:05 -07:00
Kim Santiago
b79381d88e vbump schema compare and sql projects after release (#24498) 2023-09-21 13:30:31 -10:00
Sakshi Sharma
711db9cadc Adding CodeQL in Windows pipeline for product build (#24496)
* Add CodeQL to product build pipeline

* Fix parsing error

* Remove variable

* Remove variables and add to pipeline

* Add CodeQL Finalize step
2023-09-21 14:51:22 -07:00
dependabot[bot]
75deb08a2c Bump graphql from 16.6.0 to 16.8.1 in /extensions/github (#24495)
Bumps [graphql](https://github.com/graphql/graphql-js) from 16.6.0 to 16.8.1.
- [Release notes](https://github.com/graphql/graphql-js/releases)
- [Commits](https://github.com/graphql/graphql-js/compare/v16.6.0...v16.8.1)

---
updated-dependencies:
- dependency-name: graphql
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 14:24:26 -07:00
Kim Santiago
ba3d16b63b fix hyperlink in infoBox not following theming (#24488) 2023-09-21 11:19:48 -10:00
Cory Rivera
64337310ae Remove redundant usage of object URNs in database commands (#24485) 2023-09-21 11:38:44 -07:00
Cory Rivera
e5e535475a Refactor notebook dependency lists. Enable Manage Packages from command palette. (#24484) 2023-09-21 10:43:41 -07:00
erpett
a63463e35b Changelog for 1.46 (#24482)
* Changelog for 1.46

* adding missing link
2023-09-20 14:48:57 -07:00
CSIGS@microsoft.com
131b818450 Juno: check in to lego/hb_04604851-bac4-4681-9f74-73de611d6e48_20230920154128463. (#24479) 2023-09-20 10:10:02 -07:00
Charles Gagnon
b0ff2ef08e Require jupyter notebook >= 6.5.6 (#24466)
* Require jupyter notebook >= 6.5.6

* remove traitlets & pin version
2023-09-19 11:17:08 -07:00
Ram Uday Kumar
ebc7ef5a43 Azure SQL MI supports maximum 100 DB per instance. (#24465)
* Azure SQL MI supports maximum 100 DB per instance.

* Error to dialog message

* resolving review comments.

* build fix (Compile & Hygiene)
2023-09-19 22:07:24 +05:30
Steven Marturano
0bd0e14f71 SQL Migration (TDE) - Improved migration info text (#24463)
* Improved migration info text

* Added constant in strings.ts

* Fixed localization key
2023-09-19 10:56:40 -04:00
Cheena Malhotra
abf11c36af Support select execution on History Table (#24464) 2023-09-18 23:10:23 -07:00
Christopher Suh
86b3eaee5a Remove deprecated azure graph endpoints (#24460)
* remove deprecated azure graph endpoints

* cleanup enums

* cleanup ProviderSettingsJson: remove graphResource

* change enums back
2023-09-18 15:01:24 -07:00
dependabot[bot]
f938b436b6 Bump actions/checkout from 3 to 4 (#24363)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 12:00:57 -07:00
Alex Ma
0d13bc4ed8 [Loc] update to XLFs for 9-16-2023 (#24457) 2023-09-18 09:27:04 -07:00
Ritik Kumar
fda050e667 added arialabel for SqlMigration Service Name InputBox (#24286) 2023-09-18 11:37:00 +05:30
Steven Marturano
a73929e5e7 Added validations to configure dialog (#24418)
* Added validations to configure dialog

* Improved validations messages text

* Addressed PR feedback

* Addressed PR feedback

* Fixed build issue

* Version bump

* Changed to single quotes
2023-09-15 18:19:04 -04:00
Sai Avishkar Sreerama
9c5ec7dcbc Filegroup Memory optimized Add button should be disabled when have one filegroup #24309 (#24446) 2023-09-15 16:19:44 -05:00
Barbara Valdez
600f59eae6 Fix enable/disable script button behavior (#24437) 2023-09-15 12:43:50 -07:00
Charles Gagnon
7e39174f63 Add log message when falling back to default kernel (#24447) 2023-09-15 11:58:22 -07:00
Lucy Zhang
e0592c10d9 Pin traitlets package to v5.9.0 (#24444)
* pin traitlets pkg to v5.9.0

* add links to github issue
2023-09-15 11:12:26 -07:00
Lucy Zhang
e6e6085d0d pin ipykernel to v5.5.5 (#24429) 2023-09-14 13:29:32 -07:00
Christopher Suh
0513282081 fix yarn.lock files so ^3.0.4 points to 3.1.2 (#24425) 2023-09-14 12:34:02 -07:00
Cheena Malhotra
b1bc59095b Prompt to refresh account on error AADSTS700082 (#24423) 2023-09-14 12:18:45 -07:00
dependabot[bot]
b6a67cfde7 Bump coverallsapp/github-action from 2.2.1 to 2.2.3 (#24362)
Bumps [coverallsapp/github-action](https://github.com/coverallsapp/github-action) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/coverallsapp/github-action/releases)
- [Commits](https://github.com/coverallsapp/github-action/compare/v2.2.1...v2.2.3)

---
updated-dependencies:
- dependency-name: coverallsapp/github-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 12:08:59 -07:00
Alex Ma
a7b64c347a added WIP fix to new row revert (#24422) 2023-09-14 11:37:18 -07:00
Sai Avishkar Sreerama
183c743537 max file size input field has wierd enable/disable behavior #24322 (#24407) 2023-09-14 13:13:22 -05:00
Charles Gagnon
e1f142b619 Fix README extension list link (#24424) 2023-09-14 10:45:47 -07:00
Alex Ma
523dd8ad4b Langpack Source update with fix for hashed strings (#24400)
* Initial update to german vscode

* more cleanup for vscode git german.

* added working alias replacer, need to add all string entities

* added aliased bundle strings

* added extension files, need to update package and readme

* added update to changelog, and restored vscode extensions

* added comments
2023-09-14 10:10:49 -07:00
Benjin Dubishar
d9b5d71148 Adding Chart component (#24357)
* added doughnut chart component

* Changing chart to doughnutChart

* reverting to genreic chart component

* adding more chart supoort

* fix minor errors

* resolve some PR comments

* native chartjs, keyboard navigation and chart options

* fix build errors

* fix chart.js/auto error

* resolve PR comments

* modify chartdataset API

* Refactoring (#24327)

* working - displaying chart data with convert

* working - introduced typed properties

* working, added BarChartConfiguration to type param

* removed ChartProperties type param

* Adding doughnut support

* Correcting number vs. point issue

* including the right changes this time

* commenting out no-longer-used labels prop

* remove hardcoded canvasID, enabled Scatterplot config

* Moved graph testing to sample extension

* Reorganizing types; adding test back to assessment dialog

* Adding example for bubble chart

* Polar area working

* cleanup

* adding draw when options isn't set

* Moving chart example configs to other file

* some cleanup

* added some docstrings

* add multiple datasets to test scatter plot

* update scatter plot example in sample

* Adding height/width support

* swapping to `as` cast

* title working

* Settling chart title and legend display

* Adding comments

* updating data working

* Updating samples

* Typo in comment

* Reverting changes made for development

* Elaborating on color in docstrings

* Separating Data and Options in component payloads

* Removing chartId as an exposed property

* Changing chartType property to TChartType

* Fleshing out types file comments

* fixing scoping of chart component properties; renaming chart canvas ID prop

* correct internal chart options typing

* removing commented-out code

* removing unused ChartClickEvent type until data selection eventing is implemented

* renaming function

* deleted commented-out code

* Adding options setters that went missing after splitting Config to Data + Options

* adding type predicates for data conversion

* Adding back type setting (dropped when chart type conversion moved)

* Narrowing type for 'type'

* Fixing typos in docstring

---------

Co-authored-by: Deepak Saini <deepaksaini@microsoft.com>
Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
Co-authored-by: Aasim Khan <aaskhan@microsoft.com>
Co-authored-by: Deepak Saini <deepak.saini1996@gmail.com>
2023-09-13 20:11:09 -07:00
Barbara Valdez
f7ac504a6c enable server and db properties (#24406) 2023-09-13 16:15:26 -07:00
Cory Rivera
51ea238b49 Add comments for openFileBrowser (#24413) 2023-09-13 16:12:45 -07:00
CSIGS@microsoft.com
c3b8c97b9d Juno: check in to lego/hb_04604851-bac4-4681-9f74-73de611d6e48_20230912153919267. (#24382) 2023-09-13 14:19:07 -07:00
Cory Rivera
08ded51e75 Use remote file dialog for database and server properties dialogs (#24390) 2023-09-13 10:49:10 -07:00
Alan Ren
4f155423dc handle error scenarios for validity check (#24393) 2023-09-13 09:40:50 -07:00
Aasim Khan
df481311ed Adding new database inline icon (#24375) 2023-09-13 09:33:00 -07:00
Cheena Malhotra
7e401bfa1a Azure Active Directory (Azure AD) is becoming Microsoft Entra ID (#24385) 2023-09-12 13:41:04 -07:00
Sai Avishkar Sreerama
96c4257d25 Database properties options fixes (#24361)
* fix for File size input in DB properties can be decremented into the negative #24307

* Some DB Scoped Config options are sentence cased #24196

* cannot add a file with filestream data filegroup type #24359

* DB Scoped Secondary values aren't updated when hidden #24197

* DB Scoped Config shows secondary values for non-secondary options #24192

* Query store capture policy section is enabling on non-custom capture mode #24371

* queryStore WaitStatistics options should be a dropdown #24372
2023-09-12 11:20:26 -05:00
Sai Avishkar Sreerama
75c59f8b41 STS vbump to 4.10.0.1 (#24380) 2023-09-12 11:20:08 -05:00
Barbara Valdez
41e7569fde More server properties fixes (#24366)
* fix locks min value

* disable login auditing in linux

* disable some properties from advanced tab
2023-09-11 12:53:25 -07:00
erpett
89e41572a8 updating release version in main post release branch split (#24374) 2023-09-11 10:54:47 -07:00
921 changed files with 200233 additions and 170538 deletions

View File

@@ -23,7 +23,7 @@ Needs Logs:
# actions for Needs Logs - Azure label
Needs Logs - Azure:
comment: |
We need more info to debug your Azure Active Directory issue. If you could attach your logs to the issue (ensure no private data is in them), it would help us fix the issue much faster.
We need more info to debug your Microsoft Entra ID issue. If you could attach your logs to the issue (ensure no private data is in them), it would help us fix the issue much faster.
- In the settings menu, find the setting titled `Azure: Logging Level` and select the `Verbose` option
- Restart Azure Data Studio

View File

@@ -8,7 +8,7 @@ jobs:
if: github.event.ref == '1.999.0'
steps:
- name: Checkout Actions
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: "microsoft/vscode-github-triage-actions"
ref: stable

View File

@@ -17,7 +17,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
# TODO: rename azure-pipelines/linux/xvfb.init to github-actions
- name: Setup Build Environment
@@ -78,7 +78,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
@@ -146,7 +146,7 @@ jobs:
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# steps:
# - uses: actions/checkout@v3
# - uses: actions/checkout@v4
# - uses: actions/setup-node@v3
# with:

View File

@@ -21,7 +21,7 @@ jobs:
CHILD_CONCURRENCY: "1"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
@@ -90,7 +90,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
# TODO: rename azure-pipelines/linux/xvfb.init to github-actions
- name: Setup Build Environment
@@ -152,7 +152,7 @@ jobs:
- name: Combine code coverage files
run: node test/combineCoverage
- name: Upload Code Coverage
uses: coverallsapp/github-action@v2.2.1
uses: coverallsapp/github-action@v2.2.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "test/coverage/lcov.info"
@@ -173,7 +173,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
@@ -236,7 +236,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:

View File

@@ -8,7 +8,7 @@ jobs:
name: Process Label Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Process Label Action
uses: hramos/label-actions@v2
with:

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: 'microsoft/azuredatastudio'
ref: main

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- uses: 'actions/setup-node@v3'
with:

View File

@@ -1,4 +1,4 @@
disturl "https://electronjs.org/headers"
target "22.3.14"
target "22.3.25"
runtime "electron"
build_from_source "true"

View File

@@ -1,5 +1,88 @@
# Change Log
## September 2023 (Hotfix 1)
Azure Data Studio 1.46.1 is the latest general availability (GA) release.
- Release number: 1.46.1
- Release date: October 3, 2023
### Bug fixes in 1.46.1
| New Item | Details |
| --- | --- |
| Security | Update to Electron v22.3.25 with patch for [CVE-2023-5217](https://github.com/advisories/GHSA-qqvq-6xgj-jw8g) |
For details about the issue addressed in the September 2023 hotfix release, visit the [September 2023 Hotfix Release on GitHub](https://github.com/microsoft/azuredatastudio/milestone/106?closed=1).
For a list of the current known issues, visit the [issues list on GitHub](https://github.com/microsoft/azuredatastudio/issues?q=is%3Aissue).
## September 2023
Azure Data Studio 1.46.0 is the latest general availability (GA) release.
- Release number: 1.46.0
- Release date: September 20, 2023
### What's new in 1.46.0
| New Item | Details |
| --- | --- |
| Attach/Detach Database | Introduced support for attaching and detaching databases (Preview) |
| Connection | Introduced support for custom cloud providers, see ([Azure Data Studio - Azure Connectivity](https://learn.microsoft.com/sql/azure-data-studio/azure-connectivity?#configuring-custom-cloud-endpoints)) for configuration information |
| Connection | Enabled Connection Pooling as default behavior |
| Connection | Introduced command `SQL Server: Clear Pooled Connections` to clear inactive pooled connections |
| Database Properties | Introduced support for viewing database properties (Preview) |
| General | Added support for Server and Database properties (Preview) |
| Result Set | Updated copy notification to automatically close after three (3) seconds, and included an option to disable notifications |
| Result Set | Added a prompt to open the file location after saving result to Excel |
| Profiler Extension | Introduced a progress dialog when opening an XEL file |
| Server Properties | Introduced support for viewing server properties (Preview) |
| SQL Database Projects Extension | Released version 1.3.1 |
| SQL Database Projects Extension | Added support for "Azure Synapse Serverless SQL Pool” target platform |
| SQL Database Projects Extension | Added support for “Synapse Data Warehouse in Microsoft Fabric” target platform |
| SQL Database Projects Extension | Updated to Microsoft.Build.Sql SDK version to 0.1.12-preview |
### Bug fixes in 1.46.0
| New Item | Details |
| --- | --- |
| Accessibility | Improved screen reader prompts for SQL Database Projects extension, Database Migration Assessment for Oracle extension, SQL Agent extension, and when installing a new extension |
| Accessibility | Addressed issues with install button tool tip, new connection button, and new server group buttons |
| Accessibility | Fixed color contrast for creating connections and notebooks, running queries, and deploying a server |
| Connection | Added refresh prompt for Azure accounts when error AADSTS700082 occurs |
| Connection | Introduced notification when a duplicate connection exists upon dragging a connection to a different group |
| Connection | Fixed issue to prevent Dashboard server name from being replaced with profile name |
| Connection | Added retry logic to wait for resume when establishing connection to a serverless Azure database |
| Connection | Fixed issue where tab color did not align with server group color |
| Connection | Updated Cluster Server connection property to have the correct Boolean value for Cosmos DB |
| Connection | Fixed issue with advanced connection options not correctly transferred to change password dialog |
| Connection | Addressed incorrect label for first connection in the Recent connections list |
| Connection | Improved account selection experience after enabling cloud settings |
| General | Fixed issue with incorrect cell colors when editing data |
| General | Addressed problem with invalid data for a column's data type when editing data |
| General | Re-enabled full screen toggle behavior for the F11 key binding |
| Notebooks | Addressed issue where kernel failed to change correctly when switching to Python |
| Query Editor | Fixed Intellisense refresh behavior |
| Query Editor | Improved query execution performance |
| Query Editor | Improved read performance for large data sets |
| Query Editor | Addressed issue where selecting Cancel would not immediately cancel a query that was executing |
| Query Editor | Resolved problem of queries hanging when executing against Synapse Dedicated Pool |
| Query Plan Viewer | Fixed issue where missing index definition recommendation included incorrect column |
| Query Plan Viewer | Addressed issue with query plan XML having the incorrect format |
| Result Set | Corrected XML formatting when opening a column from the result set |
| Result Set | Fixed issue where copying results to clipboard did not work |
| Schema Compare | Added support to automatically resize the split view when the window changes size |
| Schema Compare | Addressed error “StartIndex cannot be less than zero” which occurred when applying change using Schema Compare |
| Schema Compare | Display 'Yes' button to re-compare after changing options in Schema Compare |
| SQL Database Projects | Fixed issue where databases were not populated if a project was created from the server instead of a database |
| SQL Database Projects | Addressed error 'Could not run the "SqlModelResolutionTask" task because MSBuild could not create or connect to a task host with runtime "NET" and architecture "arm64"' resulting in build failure on arm64 with SDK-style and legacy style projects |
| Welcome Page | Improved display of Install button under the extension list on Welcome Page |
For a full list of bug fixes addressed for the September 2023 hotfix release, visit the [September 2023 Release on GitHub](https://github.com/microsoft/azuredatastudio/milestone/102?closed=1).
For a list of the current known issues, visit the [issues list on GitHub](https://github.com/microsoft/azuredatastudio/issues?q=is%3Aissue).
## July 2023 (Hotfix)
Azure Data Studio 1.45.1 is the latest general availability (GA) release.
@@ -27,8 +110,6 @@ For a full list of bug fixes addressed for the July 2023 hotfix release, visit t
| --- | --- | --- |
| Installation | Azure Data Studio installation fails on RHEL 8 | Use RHEL 9, or manually install glibc-2.29 and add it to the Library Path and then re-install ADS |
For a list of the current known issues, visit the [issues list on GitHub](https://github.com/microsoft/azuredatastudio/issues?q=is%3Aissue).
## July 2023
Azure Data Studio 1.45.0 is the latest general availability (GA) release.

View File

@@ -4,7 +4,7 @@
[![Build Status](https://dev.azure.com/ms/azuredatastudio/_apis/build/status/AzureDataStudio-Localization-CI?branchName=main)](https://dev.azure.com/ms/azuredatastudio/_build/latest?definitionId=453&branchName=main)
[![Twitter Follow](https://img.shields.io/twitter/follow/azuredatastudio?style=social)](https://twitter.com/azuredatastudio)
Azure Data Studio is a data management and development tool with connectivity to popular cloud and on-premises databases. Azure Data Studio supports Windows, macOS, and Linux, with immediate capability to connect to Azure SQL and SQL Server. Browse the [extension library](wiki/List-of-Extensions) for additional database support options including MySQL, PostgreSQL, and MongoDB.
Azure Data Studio is a data management and development tool with connectivity to popular cloud and on-premises databases. Azure Data Studio supports Windows, macOS, and Linux, with immediate capability to connect to Azure SQL and SQL Server. Browse the [extension library](https://github.com/microsoft/azuredatastudio/wiki/List-of-Extensions) for additional database support options including MySQL, PostgreSQL, and MongoDB.
## **Download the latest Azure Data Studio release**

View File

@@ -1,16 +1,19 @@
{
"codebaseName": "devdiv_vscode-client",
"codebaseName": "Azure Data Studio",
"ppe": false,
"notificationAliases": [
"sbatten@microsoft.com"
"kvhdir@microsoft.com",
"sakshis@microsoft.com"
],
"codebaseAdmins": [
"REDMOND\\stbatt",
"REDMOND\\monacotools"
"REDMOND\\karlb",
"REDMOND\\chgagnon",
"REDMOND\\kisantia",
"REDMOND\\sakshis"
],
"instanceUrl": "https://devdiv.visualstudio.com/defaultcollection",
"projectName": "DevDiv",
"areaPath": "DevDiv\\VS Code (compliance tracking only)\\Visual Studio Code Client",
"instanceUrl": "https://msdata.visualstudio.com",
"projectName": "Database Systems",
"areaPath": "Database Systems\\SQL Tools\\Azure Data Studio",
"notifyAlways": true,
"template": "TFSDEVDIV",
"tools": [

View File

@@ -25,6 +25,8 @@ steps:
- script: |
set -e
tar -xzf $(Pipeline.Workspace)/compilation.tar.gz
# delete tar.gz after it's been extracted to clear up the space
rm $(Pipeline.Workspace)/compilation.tar.gz
displayName: Extract compilation output
- script: |

View File

@@ -9,7 +9,7 @@ steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.x'
versionSpec: '3.11.x'
addToPath: true
- task: AzureKeyVault@1
@@ -41,12 +41,23 @@ steps:
exec { git config --global https.postBuffer 524288000 }
displayName: Prepare tooling
- task: CodeQL3000Init@0
displayName: CodeQL Initialize
condition: eq(variables['Codeql.enabled'], 'True')
- powershell: |
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge $(node -p "require('./package.json').distro")
displayName: Merge distro
- powershell: |
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge ab87de2203e5a9d8377a74725dc6e2258de6da79
condition: eq(variables['VSCODE_QUALITY'], 'agc')
displayName: Merge AGC endpoints
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
@@ -135,6 +146,19 @@ steps:
displayName: Install SAW Extensions
condition: and(succeeded(), eq(variables['VSCODE_QUALITY'], 'saw'), ne(variables['VSCODE_ARCH'], 'arm64'))
- powershell: |
# Install AGC specific extensions
$ErrorActionPreference = "Stop"
$tempFilePath = (New-TemporaryFile).FullName
$zipFilePath = $tempFilePath + ".zip"
$extensionUri = "$(agc-extensions-uri)"
$adsExtensionPath = "$(agent.builddirectory)\azuredatastudio-win32-x64\resources\app\extensions"
Invoke-WebRequest -Uri $extensionUri -OutFile $tempFilePath
Move-Item $tempFilePath $zipFilePath
Expand-Archive $zipFilePath -DestinationPath $adsExtensionPath
displayName: Install AGC Extensions
condition: and(succeeded(), eq(variables['VSCODE_QUALITY'], 'agc'), ne(variables['VSCODE_ARCH'], 'arm64'))
# - powershell: | @anthonydresser unit tests timeout never existing the node process
# . build/azure-pipelines/win32/exec.ps1
# $ErrorActionPreference = "Stop"
@@ -344,6 +368,10 @@ steps:
continueOnError: true
condition: and(succeededOrFailed(), eq(variables['RUN_UNSTABLE_TESTS'], 'true'))
- task: CodeQL3000Finalize@0
displayName: CodeQL Finalize
condition: eq(variables['Codeql.enabled'], 'True')
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection'
inputs:

File diff suppressed because one or more lines are too long

View File

@@ -92,21 +92,24 @@ async function main(buildDir?: string): Promise<void> {
'-insert',
'NSAppleEventsUsageDescription',
'-string',
'An application in Visual Studio Code wants to use AppleScript.',
// ${{SQL CARBON EDIT}} Update application name to Azure Data Studio
'An application in Azure Data Studio wants to use AppleScript.',
`${infoPlistPath}`
]);
await spawn('plutil', [
'-replace',
'NSMicrophoneUsageDescription',
'-string',
'An application in Visual Studio Code wants to use the Microphone.',
// ${{SQL CARBON EDIT}} Update application name to Azure Data Studio
'An application in Azure Data Studio wants to use the Microphone.',
`${infoPlistPath}`
]);
await spawn('plutil', [
'-replace',
'NSCameraUsageDescription',
'-string',
'An application in Visual Studio Code wants to use the Camera.',
// ${{SQL CARBON EDIT}} Update application name to Azure Data Studio
'An application in Azure Data Studio wants to use the Camera.',
`${infoPlistPath}`
]);
}

File diff suppressed because one or more lines are too long

View File

@@ -16,6 +16,7 @@ import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors';
import * as iconv from '@vscode/iconv-lite-umd';
import { l10nJsonFormat, getL10nXlf, l10nJsonDetails, getL10nFilesFromXlf, getL10nJson } from '@vscode/l10n-dev';
import { aliasStrings } from './vscodeLocStringAlias'; // {{SQL CARBON EDIT}} - Needed to store aliased strings.
function log(message: any, ...rest: any[]): void {
fancyLog(ansiColors.green('[i18n]'), message, ...rest);
@@ -904,6 +905,28 @@ export function createI18nFile(name: string, messages: any): File { // {{SQL CAR
'Do not edit this file. It is machine generated.'
];
for (const key of Object.keys(messages)) {
// {{SQL CARBON EDIT}} - Temporarily used to handle aliased ids from vscode-translations-export - https://github.com/microsoft/azuredatastudio/issues/24411
let areaList = messages['contents'];
if (name.startsWith('extensions/') && key.startsWith('contents') && areaList) {
for (const areaKey of Object.keys(areaList)) {
let stringList = messages['contents'][areaKey];
for (const stringKey of Object.keys(stringList)) {
let shortName = name.substring(11); //remove 'extensions/' (size 11) from name to get extension name by itself.
let keyAlias = aliasStrings as StringMap<StringMap<string>>
// '++CODE++' comes from @vscode/l10n-dev/dist/main.js#L358 which replaces any id that is the same as the string message.
if (stringKey.startsWith('++CODE++') && keyAlias[shortName]) {
let shortBundleKey = stringKey.substring(8); //remove '++CODE++' (size 8) and only use hash to lookup.
let aliasKey = keyAlias[shortName][shortBundleKey];
if (aliasKey) {
let originalMessage = messages['contents'][areaKey][stringKey];
messages['contents'][areaKey][stringKey] = undefined;
messages['contents'][areaKey][aliasKey] = originalMessage;
}
}
}
}
}
// {{SQL CARBON EDIT}} - End
result[key] = messages[key];
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,321 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const aliasStrings = {
"Microsoft.data-workspace": {
'60dc6b3745804caa2d48a35dbb7306bb3f4f05286e7f9de259423f6abe87ec8f': "SelectProjectFileAction"
},
"Microsoft.query-store": {
'9cb725c039170871de7978892c2fdf0f763f58359bd66bd0b1a06b0bdf3f6b38': "DOPLabel",
'17bc05152f339d6dc2fb2844595760e9009662c4315fa1ac0d61c7e47dfbdbb3': "UTC"
},
"Microsoft.sql-database-projects": {
'99c40ab405926cb5ad1def9cff4d7ce624f8f8abfff4e85f655347fcb949d08e': "Date",
'031a8f0f659df890dfd53c92e45295b0f14c997185bae46e168831e403b273f7': "Failed",
'6ecc3df6bffdd06c58cd4f6e276929e119c8f653c53f5a6a5a5e66dfa1c3fc93': "Move",
'920e413c7d411b61ef3e8c63b1cb6ad058d5f95f8b481dbafe60248387d8c355': "Status",
'c88a0b907419a70c27ab7c1f8e5fb54441a4d9c3567e4c928fa7b2091194aecf': "Success",
'33b93476cf597a3330653b66a658983d892ac264b5d6029a2dc642b9b1f30870': "Time",
'b1d6b91b67c2afa5e322988d9462638d354ddf8a1ef79dba987f815c22b4baee': "at",
'37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f': "default",
'3f3427aca58e7fc32ec5cbdb6672708a22cf47187860405366a7c07144c668d9': "fileObject",
'eb0cc5d4abfad6f62ea7a9c502352824ac2f6a263ef9c8b96b795df59f8f6870': "folderObject",
'1b52f3a2e15148731314bf167145c54565ed2385a862b5eb7771eaf719e4f82e': "hr",
'1f6fa6f69d185e6086d04e7330361bf9001a3b8d0ce511171055dc34eb90c1c5': "min",
'b2c1822878838eb52770e9845b4582d503d975b484897b83048ea841e0c5c6b6': "msec",
'add93534eeb463800fe0ed0946048d33636dd2a014fab92e8a37f77ce98c740b': "sec"
},
"vscode.git": {
'a93447605ef4b2cc8eda934a1e9af7ad57f8d2d2e5dc1defbaa121ed13550e57': "$(info) Remote \"{0}\" has no tags.",
'd33636398d4d33c00d489b6b7a46b224e0b779fcf33fd6c3e3d6e40c2933373a': "$(info) This repository has no tags.",
'96ab5dc0020f2126bcb175ec9f0fe83b01c1b357fd2a9f0a3afc3d1f2860ee85': "\"{0}\" has fingerprint \"{1}\"",
'59dacc1ec703cf2cd4c3f087ed4ff2d7da089b9634de61200779a5007bac6af0': "A branch named \"{0}\" already exists",
'621321bc491d0f5f5702b38ee93f4b2f0b07bb9f72e3c1ad3ce06ce6b0f06219': "A git repository was found in the parent folders of the workspace or the open file(s). Would you like to open the repository?",
'1da1a00fd75ac0a5f8e6d1c1649dec3b58f5c987faaffe73078f7296a636312f': "Absolute paths not supported in \"git.scanRepositories\" setting.",
'6fa5252bce4290bcd9ff56fe10025f8bdfc5d4e24691f6fa68f27ed431c063a2': "Add Remote",
'060c966a30504cab8cdc4cd05de72451e3a644e0bfe14080fc49722e00e93f75': "Add a new remote...",
'd5eca92389f946b04241308e4a3b9b92fc39429ee9348a6c24448dc1a4b24c6f': "Add remote from URL",
'd6641e7833cbdcd1456edcd6d584a99f9d005f5cd0b4c8bbcbf18099e680f089': "Add remote from {0}",
'de161ac4087726413ce474f53279a95dc36167a2274bb58721f8720b87bfd611': "Add to Workspace",
'b9f653e0e3af44de571212f85ec3f499df207e29bd1f28ab02cb527899690926': "All Repositories",
'de9f057a471cdb8d3b082719bdc7ad2031788d042947349723fa83c9d13a517a': "Always",
'2c707611079d56814a3db49f113e4b83c4825cc85ed4a25ec42c3d93196a4b0b': "Always Pull",
'4d9f6cfd4b0c13b17c73c16f9ad939310ef950e9e6d5a20ecf0a24663669d8be': "Are you sure you want to DELETE {0} files?\\nThis is IRREVERSIBLE!\\nThese files will be FOREVER LOST if you proceed.",
'405467178639c4f62d3a56a1ae70edb4b6a2526bcc4f3dbc8ee8b34e5f49e6c0': "Are you sure you want to DELETE {0}?\\nThis is IRREVERSIBLE!\\nThis file will be FOREVER LOST if you proceed.",
'46d379e48de8077187857870eaed5866f00e7d88fee7d4f6ab609ca34912c244': "Are you sure you want to continue connecting?",
'ffb8582a7ae040adfcc7adbee5a8207a55754268d09fa3b06b21a86c0893b609': "Are you sure you want to create an empty commit?",
'ec1000557d338870dea0e872589afc8fd1758ab4bf53a9fa2721bc8ec9a3261e': "Are you sure you want to discard ALL changes in {0} files?\\nThis is IRREVERSIBLE!\\nYour current working set will be FOREVER LOST if you proceed.",
'2169b04f53a8d7b7c06071bc23579d940de5187c1f3e3df2dd4bbf9724f1e4e3': "Are you sure you want to discard changes in {0} files?",
'f8a5199a5d46ea80a9e9b2626e8181906ca21c5a37e2425379945161e76f6a6f': "Are you sure you want to discard changes in {0}?",
'6f875b4f8d4f7d28e6dc570891696be992d21c501c1d04ae0a91adb407418b9d': "Are you sure you want to drop ALL stashes? There are {0} stashes that will be subject to pruning, and MAY BE IMPOSSIBLE TO RECOVER.",
'24ab570db1c20d8c4ec76c5a64104f95d1ddff931a4194f0c0f975a22a5df50d': "Are you sure you want to drop ALL stashes? There is 1 stash that will be subject to pruning, and MAY BE IMPOSSIBLE TO RECOVER.",
'76f1fe23e2bbf8ac3061a3fdd5bd60802fcf476e1b2ee914f93825bd1b0faf70': "Are you sure you want to drop the stash: {0}?",
'32961fc63b06971d43dae40be139f80907bbbff6767b9b2f49269adc85416813': "Are you sure you want to restore {0} files?",
'c88929a2d06f38f89607f487372203d45323cf7b8af3ccaedcb18de0e25f4e1a': "Are you sure you want to restore {0}?",
'329f9a037f3c5a986261e6a6e542e87bfa0ee72b98c08c0345a67fbe360f935c': "Are you sure you want to stage {0} files with merge conflicts?",
'd0d9c64e1041439f769f99f8c2e321f3c0448095a9d175f2dbb9a422e0de437f': "Are you sure you want to stage {0} with merge conflicts?",
'fca24e51f77ed30ee8b875dba3000717e817f65dacb9130a9b1f1dffe8fdc679': "Ask Me Later",
'06f6bb7108ffdb5caf844b4538b5ec8f44cc1b3bc6b577624d32fc57eff9fe3f': "Branch name",
'69c5b417453bbe27e9b739db7bbb93c3ee3b7a3698a808d28fa6115e685c36f7': "Branch name needs to match regex: {0}",
'fc84c23a4b9614dda0c2bff6659a5b1fdd3d211de84fe26b42e79efc1d95dcef': "Can\\'t push refs to remote. Try running \"Pull\" first to integrate your changes.",
'9409f5afddffd4a93106de025d9682aecf16664dea804f2e6401b8464a5584dc': "Can\\'t undo because HEAD doesn\\'t point to any commit.",
'bbd4b6a86bc65b6ac8e79e97afc61499158edb40f7bb404c70637b46d80a7ad2': "Changes",
'c393643a0d2b8afb59b5368249e1aa94ac44dbd6aab25347a4c8788acf7065a1': "Checking Out Branch/Tag...",
'06c1c85316f574170dfd57c5f7fde4af263c41616826fe806c2e032cc4ffed0a': "Checking Out Changes...",
'870cef993507d1e51e03f108fccd4ba158542d9d3617e0d6065fa9ff2957fea8': "Checkout Branch/Tag...",
'3de23bd5c86856018b0b9b70b96e257b66c8efce795c7864e6a68c779464b25e': "Checkout detached...",
'ef12959262a90a02838d73d524e3dae6a0271a013f2017051508ce526016175d': "Choose Folder...",
'339efbb5f4e6a1cb79b21d625f068b11022acd5e37857d396d4d2a5fa5fce451': "Choose a folder to clone {0} into",
'61cc7bd271a5a5b8784320285c1920a502420a5bef95f8a159323ddd4064a820': "Choose a repository",
'f0b79e95174d85877c16dd82f0c4d4d6f36a31c31c4b47419039da94dbd22ddd': "Choose which repository to clone",
'd425c4cb46b4dbd6b73ee7bc369b63795cefbe0702c041f581fc0be71739c4b5': "Clone from URL",
'58987b3663ca5a076846d352605196819f81c5e118d93937d9480b26520120d7': "Clone from {0}",
'dc4a4db67704a975c2d0d65338d136d6f9ad7336dec08ffe2dac1e42b42f21d0': "Cloning git repository \"{0}\"...",
'82a9c46ffa4789945d9f2359d75891558ef6faa8dee09e4b25e4e0597704f5bd': "Commit",
'd0018212c7ec56f7dec88df64cea48c03cd22fb7294f5a731061fb6fe037c171': "Commit & Push Changes",
'8ee870c3b9de2b0f27c0b858a94a0d8b6e605caf6c1a481c5ee1fe1cafd73cd5': "Commit & Sync Changes",
'6ead59e71e458fb4011c59193f4aca9b0c9aa84ae5be108386fbbf1527973788': "Commit Anyway",
'749e00cf6618bc6ef3d0fbe34d822881466a634f5c7b85d166df2fb1460f0056': "Commit Changes",
'f1902e6bba725c6d3fcf51683aabc4686fb2a0f0dd682e1d6a9adf32fa0441d9': "Commit Changes on \"{0}\"",
'2a8cf21232f60e18a2463520f642e8744cbb02e52bf28da24679207e4302b447': "Commit Changes to New Branch",
'cb039e43bfd1824728db88aee47282a1362819ca8ccbfec5b311ee5af0e89760': "Commit Hash",
'ed1fdf6e6ca057297a99375eca0f051f9ffbec49a1767e2126918b24e1350dff': "Commit Staged Changes",
'26306d203c4a6f1a77f32cd065d7d11593ba0c7a9b5c52c188b98f22b620941f': "Commit message",
'853333402637451d6aa3b25ece807151fc432e65654ef1a92683c08d2f469a08': "Commit operation was cancelled due to empty commit message.",
'c561966032532f5cb4e661520907ce9195227eab5a7a8502ed432c65d2cec33c': "Commit to New Branch & Push Changes",
'3807b76456b337798395543fd7f71add47058cc837ec3ce97557869b96a5a178': "Commit to New Branch & Synchronize Changes",
'c5803c644368982b5ba18930ba87da76d777035a01c0404d0a738689513da3c1': "Commit to a New Branch",
'd713d959ee6b9ef81c29bf51aa9a1e02cd00557b1d256630a191495aef81788b': "Commits without verification are not allowed, please enable them with the \"git.allowNoVerifyCommit\" setting.",
'222889674324947cdb3d7362d9c932658d6035ca96fa1b2d03e8243c2a494ebe': "Committing & Pushing Changes...",
'0670568e2bce6ac7ba3dd75805187f7e4b7bf4660f663ce69edc04bcddaa6b79': "Committing & Synchronizing Changes...",
'094f485ef9934983ca0d9a7980a869fbf0b1cdc609a840d1eb2f0a13dacd8c11': "Committing Changes to New Branch...",
'e00dcd402be4da03cd33575153acf4ae2f39273fecefe7c78f13b743f4ca887a': "Committing Changes...",
'7e9af1cefa5907c0ad11ae3d77a1116494026ffc9419dc3f9d51eee1e5c0f87c': "Committing to New Branch & Pushing Changes...",
'c1de8d4fc91a72a414f95fb6e7ddaa42e846c3862560e6ad81ec2508c9c95542': "Committing to New Branch & Synchronizing Changes...",
'26727a77b60784d2907788f4dcd2c528470f39420c7d89cf6b2fb7017bd0d973': "Conflict: Added By Them",
'e60a6686b1c40266a21a7fb54613a90683e298c8373488c8c9b09b9b696e7dc6': "Conflict: Added By Us",
'cf655e271c68cfa38a63d55a83b3f244fdf668f6102a8b2f7dedb774e1a53fcd': "Conflict: Both Added",
'90a447188c3e8f03122432f6eadb32a86a3d3f2a7bfe47973c5268a43cfa482b': "Conflict: Both Deleted",
'9b10e40394e51ee85ee978d10dcd4e39508bc7b7dbfaca0ff1c0fb1d34a4f48b': "Conflict: Both Modified",
'a7f3173b4ff7b9d91eeae6f949c39727b52e7620a66d6f4335335fc762506332': "Conflict: Deleted By Them",
'313cc973de4d5d23fd082327d53acce5fc69559e3a717dbac4fde62c7033f1bf': "Conflict: Deleted By Us",
'c38d012d028807fe8d3ac2fbc2fc2458388aeae57372a45be95c4357f48d3c34': "Continue Rebase",
'416df53dc1046300db7c7db89015858f86d148ea5e66f0152592e046c04a100d': "Continuing Rebase...",
'c5422e509267a427656ce69d6d0aed53ffcfe5eb313def9a960db7cb5b8c9c4d': "Could not clone your repository as Git is not installed.",
'978fa11dc34a758c8d99fce0d36a97740cb8abe19bd39a1be049b57bb9a98e57': "Create Empty Commit",
'fb35e61360cb5fe2fbdef3c15a4ac4ae3edd46fc19913a84305f8e128b441c3d': "Create new branch from...",
'3c198f713861e91b8d3bf53ff23b4fd65849b602ba85b3e2397b09aa65597b61': "Create new branch...",
'e0d1b68224bf0b31ef16b206c65b5f8f6b89d18161f4a7cdcb8d0ac8d952549a': "Current",
'd2c753607fd4607a83f71c14f48c474f08562ccb59c23e8799cfebaa2d15c655': "Current commit message only contains whitespace characters",
'06da38448937c5ca3cf8a9a4e91edb8a50fcfb20885e7d93d5019bf591fdc5c0': "Delete Branch",
'e1e5fe2043bd3003147a785a42a5edddccbf57d465ca32ad0f033cf7b64f04c8': "Delete File",
'93617a8503951c38871d9a8a3152d84ff1671eb5dfe9c240595b24ec55c4492e': "Delete Files",
'28e18dc9db382d81d5c2e056abe2655575404a55828822b0757419101a346de2': "Delete file",
'b48ff39c2e0f5451b9b29b09c2a74d2760db230749ffd48a6e901cc91fef9a8d': "Deleted",
'ecf1d885169c7d720890312e456270950a4fb8436c6c29132559f44398a81641': "Discard 1 File",
'92cbd25a58021e00fde8fe8247b6a62746304c19327ce600b1e3408922d43c10': "Discard 1 Tracked File",
'da0cd4de5d64172a4fffefb1068f8644fb1c91e7247d3ad433f2d6b98a2d1a90': "Discard All {0} Files",
'e07e053c2e10b3f1b6aef657d937cd91d45df4e40242788d7d621faea3380c27': "Discard Changes",
'0208f13819883488a07422dacea98808be6cea4cc2e67d5e52b6c3ca33a95113': "Discard {0} Tracked Files",
'ff334811c3daeb430bf1fc25d912064178fbd14eab61e156e8c1c08bc8e7d8ce': "Don\\'t Pull",
'acfa223353d8377425be54cf045adeac692b65ffd91850a365d508179cb64ac5': "Don\\'t Show Again",
'64488bcdbc42e52d74ab9bb817297e8e3c66c04011677d381ca0428664bb5f03': "Download Git",
'969ccbd3cf6300ecd5c880459d81ae9027df7517563184a1b8b15282db230621': "Email",
'f9e38e00f92b08ea1873eb83b3a80656bca1da49a4b862e70d1a34d654a052dd': "Failed to authenticate to git remote.",
'f4154fae85d6442f7aa7a5d154396ecb33eedeb2a5b2b66927e0e5caf5d208fb': "Failed to authenticate to git remote:\\n\\n{0}",
'6a66e0c4a1187c2d6f73bfdcb24f18ae955a7605966123ca96e3de6867ab2630': "File \"{0}\" was deleted by them and modified by us.\\n\\nWhat would you like to do?",
'46d6d9362c923eaebd6cee4e18bd246f1da95871cf454e96d99d989d2be68cca': "File \"{0}\" was deleted by us and modified by them.\\n\\nWhat would you like to do?",
'c801735bdcbaef47f4f9fdc4e6db3ef65f65738dd91850477f7a4c89d4b5b60b': "Force Checkout",
'dea241f37f7b03284af862a9376f0b02d561af0bcaa05f80bec1226bc26c8bca': "Force push is not allowed, please enable it with the \"git.allowForcePush\" setting.",
'a39de9d1a73052f9e82004d14cd2ac6cf1a4da3f959a50b5f5a7a9507c094ef8': "Git History",
'6030c83165fb700fcca51c74a9940aeefaf8084c612f5b57eea3723737c5f57d': "Git error",
'0b6123eb22cd4cf46d32366cda6edad66e902cb5f5865aa4c2a93697a497ca11': "Git local working changes",
'6a29332d3557881b20eb99f45dcbce35edccdb3f47128fbf67b1795e1b8c75c9': "Git repositories were found in the parent folders of the workspace or the open file(s). Would you like to open the repositories?",
'854b5b2f0c2de71cd9efe57794a6f669b49e3d554ba7c7c175d78154d2bd28c9': "Git: {0}",
'0c3b2f01bfd0bbe594a1e89ebf29c9ba17e93abd909f66330bf0ab7320d2b482': "HEAD version of \"{0}\" is not available.",
'7d648f5b47f34afb32946011a07e32176ad966f44ad9efff8380c73dfc5c5b87': "Ignored",
'e301820ac83931005088b32674481b184df58276cd0e79f0c8c8f7615dc023a6': "Incoming",
'4bc49b7e3107933d6c3033c90e34518e26bf9af94ce830042b13eee60f0134d6': "Index Added",
'39520d0f752236ebe985a9ab539075bb3961e0b2b3d54494689e724aa460dbc7': "Index Copied",
'606a5aedaa4178761d620b63ca8f7ddabd6cc481415cdbf64bc952f6a3d6fc8b': "Index Deleted",
'26f13b9c8050f9ac86037d900a1aa7e429efa319836c75edcb5eb0857a1da984': "Index Modified",
'0fab3d719bfe30418fa5b3301a3d2ea05178de4451bfe358cad5fc22ebdad0e6': "Index Renamed",
'905dd9958f630cdc089ae37a56c186841863cb5192c59c886dede1fa4eba71ed': "Initialize Repository",
'da5494fdeba5f3b5e1dd5b73c79aeab8c5d28830990fa85d01210710cfc805d5': "Intent to Add",
'93c86a252e562f412c0322b6348bae591b3c1fe7f09460fb40083f9ec8011981': "Intent to Rename",
'96fb1f951270c90a70612cc71ad71290be1afd46011b51131a4954b898d66dcf': "Invalid branch name",
'cd20f59f1dd9f869d17a79e25727c8fb29fa0fb4514d93857985bde8ea3d0c8a': "It looks like the current branch \"{0}\" might have been rebased. Are you sure you still want to pull into it?",
'5d5cabe4050fdd7a47b6188df4bb4137acc7d06474495edcfa62d7a8fc4aad70': "It looks like the current branch might have been rebased. Are you sure you still want to pull into it?",
'59666b50ef3b41a833f9d754d1880bfcdc934fe14df5930556c87663f39d7de9': "It\\'s not possible to change the commit message in the middle of a rebase. Please complete the rebase operation and use interactive rebase instead.",
'60c138e94a1d502e1392e9ca62e5393e93e280a7f28e4f5a3ff4a575d56c388b': "Keep Our Version",
'e9f8f78f902c9e4bbe0a5c91eb57172bbc53f6698bb4521006df79aa6b280dbe': "Keep Their Version",
'8d8cd546b58d91c300d3149ef40b8d98d3061dc38f15ea937d2ed785a3f25771': "Learn More",
'e3e4bd64cdeb80cce6901d2b155f16e51b36db5d01952c893be3e7fa3eb1b094': "Log level: {0}",
'fa0f601f537c892e522505a224c5996f94857505214c507f5745273c327b3333': "Make sure you configure your \"user.name\" and \"user.email\" in git.",
'4eaae38d7115a0c0cb42e2c87cc2043f6897eab74e688450588c109cbb2496ed': "Manage Unsafe Repositories",
'c08f87c6bf2a44ca177005eb990385dde9b14cc5289bc4420a45c199ec474e90': "Merge Changes",
'2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91': "Message",
'ad33f83890a4c1ba0086d4d728279e8e61d185c14352ea3d6663449460aad18d': "Message (commit on \"{0}\")",
'2ee8b430941cdf1bf2209d255c8463471ba4c3de2d94129c257ab035a1d42a8e': "Message ({0} to commit on \"{1}\")",
'f0f141c12a17f52bcd64321cf6969ffbc81f015b584641cd783d89904c1f72ea': "Message ({0} to commit)",
'd45c9f6ecdd755947ace0120f734f99da7328ecb87b04c3b10d780117a94c2ed': "Migrate Changes",
'e8ce5dcaf408935ff76747226d2e8bee4319a2f593c1d7a838115e56183d1f37': "Modified",
'6300ef800bb884295b0b4b35682b75cecd7cc550d202db56d04a0643b8fb873f': "Never",
'1ea442a134b2a184bd5d40104401f2a37fbc09ccf3f4bc9da161c6099be3691d': "No",
'440633c6285d225a6e3849eb5e17f33c608ad0285fdf7acc14f7e4d912516ed9': "No rebase in progress.",
'565339bc4d33d72817b583024112eb7f5cdf3e5eef0252d6ec1b9c9a94e12bb3': "OK",
'e78008c3f3637c142067bbec565bb0d623b5a2113699795765c09e4f95cb7bd0': "OK, Don\\'t Ask Again",
'a863d11492e395445acc633ced9be38f332c9aa0d0607dc83b5ab3b60a6d9fbd': "OK, Don\\'t Show Again",
'ed077f3d8125d60dca1979c7133601bd187d47c73ed9975028f677e49e709942': "Open",
'd77d0470fcb6e709dbc646f6ae4b68a4db64162b769b2914a3a760a1bbadb4df': "Open Comparison",
'893fcb727fc6ee5a7516324e78ec23f7c12b62546a74b0b37f86d7e30d205547': "Open Git Log",
'6fba1de2739c8e7ee835016e3340ef0b6c11d1b7cb2123af7ee23abf7f124682': "Open Merge",
'f10c3c817a26227242cc20133608ec65402399011cff683c49aed7ea3b4e5436': "Open Repositories In Parent Folders",
'2466923190a5c2d42540382922f01b6091b99ac2253c9eac5a066ccc129fac1d': "Open Repository",
'e8e0ccba8b0da9ab15259028d04ab1bb9e9ae240bae643e8e07c87dae591120b': "Open in New Window",
'4085b549321e7af912c77c7eaf2313790ad7d283eb11d32780764b816c2a3c34': "Optionally provide a stash message",
'e7611f0537df5fc5d0177da520628219fccf065a1d4176cfbde2f75d824821f4': "Passphrase",
'93abc930718bf1254198727dd8023b30499c5f833319550cdf7a20490a5ee744': "Pick a branch to pull from",
'23a1e19a9fdf977e37f940b03ad56faab51a9a907bba6a975e35a707e5469c50': "Pick a provider to publish the branch \"{0}\" to:",
'3e7c9d7d3ffce6d2931f8f2ec3cb30afce7f4786401f1391b97866c4f8739ccf': "Pick a remote to publish the branch \"{0}\" to:",
'9b097971a9f0ce4309cddca492d9689f9e39b5b37cb374442960925f227c0776': "Pick a remote to pull the branch from",
'e60dcf7dfc306478e6b869345c50ad6ac41a4b2697c8c449ab03e2b74ed81754': "Pick a remote to remove",
'1db2709f2fc57a3e38685eeb075e00235bad5ee2538a98973dc2f5cb6b09c4ec': "Pick a repository to mark as safe and open",
'6e2c8ec7bb53a72cb08507098e1cd6685bb5b0defbf4bb4751a91f73fd4ab061': "Pick a repository to open",
'4409fc12fb9667fbb6713fe6c40de5a69128fafb717e7f925f9829d842769a66': "Pick a stash to apply",
'8c4d9b659312323368fa1e554a7aaf11f36cb27249a24c81435d66ffb3633e36': "Pick a stash to drop",
'e7ae4efa4b2f3d2f0dfc06be57bd0d9b4a693241f232b00f301497beb274a7eb': "Pick a stash to pop",
'75fba89ae3e3799730e92c23de5c58ee0ea959aa5da12542326144c238174630': "Pick workspace folder to initialize git repo in",
'3fa8ce1777f7ddc400c486a158fcb785fe326b88693300df8417d8cb7747cc52': "Please check out a branch to push to a remote.",
'afd39827f783ddaf8c31a86ba2a80713ab112800005041f8819c14f5a121d6e1': "Please clean your repository working tree before checkout.",
'ec5aa3af193303194748ccfa4adc86db1954ea441cb3ca754747829c73082e55': "Please provide a commit message",
'e1ac5b25ecf9376124ae3505bdd6ffea60e96fb3744db2d6b08b9ec5dbbabd72': "Please provide a message to annotate the tag",
'90aebb5a363734633e81d596dbc87a7083af97c15029ec4ed00ed85d3018c20e': "Please provide a new branch name",
'a0d728e7c6fd83c9267a9b4bf25b543be6cded7d82d72c9d958ea552ddcaf1c7': "Please provide a remote name",
'fc2a1795716d5b38e136f05edebeea54359088832fc36dcf048a92deba47971d': "Please provide a tag name",
'00b3526ea21a69a7bbd09c6f006cce721c78be5995e2eb6c3cb8f0c2ede22879': "Please provide the commit hash",
'fe4e7d8ab1a693b8d287c28b1fe5b6f772a2afbaa5063ebbd0766c52e54f161a': "Publish Branch",
'c293a1d51314232c4ec79dce0e0ba928b4fc287124feb00c8c5cd98914a0f9ab': "Publish Branch/{Locked=\"Branch\"}Do not translate \"Branch\" as it is a git term",
'7b7fce492a49fe2194302f4d5f2d1b1d22fe41602d876524174f6c819d9d05da': "Publish Branch \"{0}\"/{Locked=\"Branch\"}Do not translate \"Branch\" as it is a git term",
'260304d6c22e64ea2f796f4f4a3ff96dcf866e99b747e759b12bcd31e8b52c0a': "Publish to {0}",
'095bbfcf66c550a934f58c2bf959ecdcde72853a70196b86e619503c41b3dbdc': "Publish to...",
'0dd87f831d7eff59524e2c4567b7ef14f691d2956d887315793bd818f29cfca0': "Publishing Branch \"{0}\".../{Locked=\"Branch\"}Do not translate \"Branch\" as it is a git term",
'f401b998c2c5d9bcffc048b2e4ab1484559b14e6d232742a05671ca3e75cf311': "Publishing Branch.../{Locked=\"Branch\"}Do not translate \"Branch\" as it is a git term",
'b66d044181a0e29642a958723512a8706ae494ccf63552c08cddca418d1cf097': "Pull",
'2fa67ee4b98c8e901e1c778121ae4ffded7b1b732bbea170aa7f751847aa399f': "Pull {0} and push {1} commits between {2}/{3}",
'02f3c611e65bc29302de5c9875f7ff07a7ce87d0d0452f9daa175b8fdcc8ad5f': "Pull {0} commits from {1}/{2}",
'591937c4982b465f47118b1e37d9e2eac87a8d8d43125721e347585ec544f12a': "Push {0} commits to {1}/{2}",
'276cd31a44092264bf1967b71011e0bf264668edf0e6872bf767b75cf60ec3a0': "Rebasing",
'c780499abfa9079473c8de8595fd16c2f601d0695e95f691a5abe35286604b1d': "Remote \"{0}\" already exists.",
'bd5bc169c6e722863058ba5e309b4a9a775d3419563c2a06a6c147291a81055d': "Remote branch at {0}",
'96c1a5aafd493223d4edf01cfcd541cfbb69b57c438ed03db51bc3ee2510a377': "Remote name",
'2e141cb8b2a2a6376c496e0068e12538b13e4b1e7a12386b9e9907699866cf45': "Remote name format invalid",
'25202086021659225a6b0065ed7ea55875f99c94859e62037b4e00bf1aead47b': "Replace Local Tag(s)",
'79b6a575a54e574a842c9e02e87858cb7596b721ae632a41755f20726c9aa23f': "Restore file",
'7e420ff8a2ebf63aa024db900f0707a6d4f457c8048f6cc72523b2f709e8e0f1': "Restore files",
'e98f3fe796a6bb3a6a887b34998889dc6aad09782c4abf35f15e75aa0a1c32d5': "Save All & Commit",
'73bd1493a71408520de7d84d0c500708f92ae677a49fe1cec7350d5363f1088e': "Save All & Stash",
'037c1c212912fcec15b3d4126ce0e79c0593c0f74cf8668451ca698b7bc52475': "Select a branch or tag to checkout",
'be8e59066232b90b3820f1ad5bafd5d609e5d3ab42d30fb11a27c7e6cd8e2448': "Select a branch to checkout in detached mode",
'5410dd4e0d2b06155ae6bd36e52b58b7358ce288ef781b45e9852016e2394b7a': "Select a branch to delete",
'92529e041289d83949ecddfbff14a45431a230e115bea765a0b8757bba4a8d9b': "Select a branch to merge from",
'6f8226b637c0f77b71ff88c5ec433a57f3ce11bbe7053bc43d1aa8a6589e75a2': "Select a branch to rebase onto",
'34412b9ae0d9a8f1243ae6c065eacf2f2d3febce0e38f5df0b6e8d8cdbed0c20': "Select a ref to create the branch from",
'9fd471b3f11fb4a7e5f87c9f2a87aee1c38c65ff43a596cb75a23f605bc43b17': "Select a remote to delete a tag from",
'f549e4b0d6b56de82dafefee73dd06920cc27a791ad66fa19d99017abae64158': "Select a remote to fetch",
'28c2080e378f1d291ab790609682492e0a165b461868f8546b32bc1aa497c3da': "Select a tag to delete",
'a2f33e4d476de1d0148d5cdc59a5d6d85769b8980e454594cb34dde1372ab35c': "Select as Repository Destination",
'edd969c69f64aff645b3027bab51746e3b4b8bbafdc573981df42125e9e85dbe': "Show Changes",
'6b6f44c50d93c59d9c56dce2d44335706fc24ecf4e926d7eabbb6e34c226ae47': "Show Command Output",
'3b9a10ffe5b4930c1891d29191418182fd5334195fedd2ce60dfd04c721d3b69': "Skipped found git in: \"{0}\"",
'b5ff1947b664c6719dfbb25602ff832dd7fcfc5068944fa750a36fad11a9f7e6': "Staged Changes",
'1b0a609aede05f4f39c423b8a4b57d004741211ef76980e4a37179df32d731a5': "Stash & Checkout",
'9af34d9f6e18cfc2c71f9bfa484d075cda9121682aba174a6fca7a915f403ff1': "Stash Anyway",
'ec8df3d159f741b74f7099bbd10d817aa40b3df5b7ae075629351f950cd462ff': "Stash message",
'3601420ab6a0cf864306d9d83b2714b1b2c7976e1affe639d813d280267aa3e2': "Stashed Changes",
'376ab71f351b85d3afac0fcbd859636e97909a7fe85d5c049dff55139600db27': "Successfully pushed.",
'e8cd388771e552260257ad74ec3080faa98ffa7598b8e782b2a8c08ae1f8107a': "Synchronize Changes",
'720bccb504d6429a9e4ec1f87fae45a608701f32f298c17a874e884064b0b9cc': "Synchronizing Changes...",
'c620cca03e560f7ed57a468dddc1935ece81ff2095dda0f98d987226857b60cc': "Syncing. Cancelling may cause serious damages to the repository",
'44b333daa4f9e6decfc3260fee4c03285e7b4d9c5315de608d5710283e49e54a': "Tag at {0}",
'1ace926bc7cdee5323e297d439d2d268286749252b1c7f5e332d5003681d092d': "Tag name",
'3bb614b0a444e925eb3e24b58dda2d4cc23de94c0968d0db2340b60acefdeab2': "The \"{0}\" repository has {1} submodules which won\\'t be opened automatically. You can still open each one individually by opening a file within.",
'a19a357466e3cc3926579645f74ec7860df52578196b7b4147b221046f946d8d': "The branch \"{0}\" has no remote branch. Would you like to publish this branch?",
'a213b755cc8239f62a4220d72ca8756a1ef91aec1ca885d2ddec7604f9718675': "The branch \"{0}\" is not fully merged. Delete anyway?",
'96bbc2b6d0b5fa5726a6c8930a2bbcd4cfb8a4b95edd9f2a6666260ec402564d': "The current branch is not published to the remote. Would you like to publish it to access your changes elsewhere?",
'31ac359d3ec1d704b0100940cf5eea360a13749b909afeff6fd6afac9944de77': "The following file has unsaved changes which won\\'t be included in the commit if you proceed: {0}.\\n\\nWould you like to save it before committing?",
'a04370991d0a37372ec445bf861013866402b3caf1379a06445405c80a53712c': "The following file has unsaved changes which won\\'t be included in the stash if you proceed: {0}.\\n\\nWould you like to save it before stashing?",
'23ba98146c9e50555dba1090bfd5e783e2ed2dd0823bb47fbe5f67ce258a9eb5': "The following untracked file will be DELETED FROM DISK if discarded: {0}.",
'e109d755dd32053afa001e1e366b7a51561c73d2fcea81e79cdb7a46dc7fc47a': "The git repositories in the current folder are potentially unsafe as the folders are owned by someone other than the current user.",
'02c2cdd6b3ac71010ce7c47a400c9719fead4aa3269d72b8f462ff61a45d4ab3': "The git repository at \"{0}\" has too many active changes, only a subset of Git features will be enabled.",
'8d01c87529131c0fe41305b68799b99052dc4a274a4affcc1cea877cc14346d7': "The git repository in the current folder is potentially unsafe as the folder is owned by someone other than the current user.",
'5fd10738fc1c6f99d48f2d972e7a4c4fa0ffa39ff4f89ae5cba4055c08eb98d4': "The last commit was a merge commit. Are you sure you want to undo it?",
'b45f0ffa9a6ab73edb905b626d6fe3ed00854ca7abf7303b919cf686315b9f99': "The new branch will be \"{0}\"",
'4360153c542717595a316b4979c6bba0e30dd9ccd312e1c4c852a00bdd6366d6': "The repository does not have any commits. Please make an initial commit before creating a stash.",
'27ee389973941a5e4c33938ada96f71810852631100b4c853fde3b8ff00a4b5c': "The selection range does not contain any changes.",
'abbd48f372807f93e0988532fd3acb1f1eb758ec9a414c4a0bbde208ca64ea73': "There are merge conflicts. Resolve them before committing.",
'4a9bc15b4ed0cf72587423bf0e2d14780f2050bfbb59d187cf98cc081e0d1d1b': "There are no available repositories",
'ae1a589b1c95953ed140c40811e495dcbaea430a742c8f895231e3c270e852ef': "There are no changes to commit.",
'1817660c6b621c7c863521e96a45227469758a3f51d690448de5d1b50c46bc2d': "There are no changes to stash.",
'0eb60d4befa938a3a146ef5031aaffff7f5c3b290ca2524472b36a3ef99259da': "There are no staged changes to commit.\\n\\nWould you like to stage all your changes and commit them directly?",
'0a6f7df2d272dbe9feb4bf0dd43c6a93144be7e5192b330ca7a1b191666c5b93': "There are no staged changes to stash.",
'46031808b597269632b77fb15757e8f4e0f56b9028ddf7b5889e68f5753668c9': "There are no stashes in the repository.",
'be81fa311df402c9d32e9f0d31240455ba7bd8c5a968fd9c4261854469666a80': "There are {0} unsaved files.\\n\\nWould you like to save them before committing?",
'bd3d54b7b5279debc1b7120498741a9123d3247573fb0b03ee2b356e799ec807': "There are {0} unsaved files.\\n\\nWould you like to save them before stashing?",
'17a302d9654f49beddb9c262df6083f2295f88a618de2130cd94a71c13c9a815': "There are {0} untracked files which will be DELETED FROM DISK if discarded.",
'1547ede309e6d1f85da487e614b5c06ecb8be8280e4d7edc5431a29025a0cf49': "There were merge conflicts while applying the stash.",
'4e5370c14c2e52f7bc248222f1d743cfeecaef3f484f987facbf4604af7d7bdd': "This action will pull and push commits from and to \"{0}/{1}\".",
'a3bfed7d5da3d9d87e3ffe75f75ecb1c47b3d635177a918a421dbc3da4789012': "This repository has no remotes configured to fetch from.",
'946fda221b3c1389605a25d3c1836cbe2931594e7f17b1d406c6794e16bf7060': "This will DELETE {0} untracked files!\\nThis is IRREVERSIBLE!\\nThese files will be FOREVER LOST.",
'8a31a9a33b1daab0d79eae0dc86548abb75d8210f058d99a3ef4b6f3ece60162': "This will create a Git repository in \"{0}\". Are you sure you want to continue?",
'05f7892749ae2c9768ce4044a9df51b9f9bb38485c7c42049a15b1b99b9535d9': "Too many changes were detected. Only the first {0} changes will be shown below.",
'4460d1b1316e9beeda90bd568c3e9d13b47a3710674433fd1022371f8e1d3108': "Unable to pull from remote repository due to conflicting tag(s): {0}. Would you like to resolve the conflict by replacing the local tag(s)?",
'0d0b4290628654ca57e79767b0c2c66ab30fd9b41dfe4eb48495003a199bf27f': "Uncommitted Changes",
'35a96c53b643b0cfb6501a078cb24a26c2158f732df4e497c68292ab9b2fb387': "Undo merge commit",
'c7ba5477e19cf0bb25460d840cc2e67341e81e1c2d274d00b3054c73898d4d27': "Untracked",
'd9dbf89a0df1e2e894271aa0784f5a497aa621698eca5da8c125870ead7b718e': "Untracked Changes",
'eda6b0f61d9c085625dc90eb871b839a26cdbd818b39a6198eb4cc9a8fcc4ea5': "Using git \"{0}\" from \"{1}\"",
'e7fde14b366ecaa13e8419d872a4b9f4008fa1e14c03f17d947b76c8e2130d91': "Validating found git in: \"{0}\"",
'7f1d79b89e7e2a73fb77da103a8f48ff6a1d82d197245b96a00bd0bb1b807301': "Would you like to add \"{0}\" to .gitignore?",
'a9b2a56ef24209b80c6e9e0508fae6e0cd8dde12582670f4867730d234fa660f': "Would you like to open the cloned repository, or add it to the current workspace?",
'8e3e2fa1eac65813d54533388a9394094f68b3af6c8408dde1e4a3d4e57d91d7': "Would you like to open the cloned repository?",
'2f583a9a7e36a2087285836c950f99f22099e18fd2565543ba73d4b175fdd72f': "Would you like to open the initialized repository, or add it to the current workspace?",
'01cedefc7a6bda340489ba5bce02d9cf13cf3344b44ff23845566a379edf01a5': "Would you like to open the initialized repository?",
'0d956bc1273b2c3663c075e95965229e067e6aa8baf635905a73feec866b0ce6': "Would you like {0} to [periodically run \"git fetch\"]({1})?",
'85a39ab345d672ff8ca9b9c6876f3adcacf45ee7c1e2dbd2408fd338bd55e07e': "Yes",
'568b3eef26e3360a32fba05157ba2b75657ca22b5929211279821ff88bd2fa3d': "Yes, Don\\'t Show Again",
'08b041935798fbf6fd6ff51099ffedb140a475889986d14f5559ff8e7fc571dd': "You",
'30757342a07b54b8546d73b091103bc1ec0e1d5b015265bb6a21b5f4716b0d53': "You are about to commit your changes without verification, this skips pre-commit hooks and can be undesirable.\\n\\nAre you sure to continue?",
'0907e6f3642577f3302552d8e71bbc82073e9de0fe7c04c02c095e7ad6176750': "You are about to force push your changes, this can be destructive and could inadvertently overwrite changes made by others.\\n\\nAre you sure to continue?",
'fe2df0f8d1bf9e45d9afaf5ca1a24523803f19221bec807bfc00f13cc519aa77': "You are trying to commit to a protected branch and you might not have permission to push your commits to the remote.\\n\\nHow would you like to proceed?",
'802759f1e5e53993fd0ea369ce7f0ae28138651ca90cffb363771432692e5630': "Your local changes would be overwritten by checkout.",
'4006ee78c8bf7a85704c33264a1bdfcce6e88144b698cccdfc9b73d259294da3': "Your repository has no remotes configured to publish to.",
'b85f634ce5d7b0c897cffccadc3bd1827a2b7d3022f77288e460892af9e561a2': "Your repository has no remotes configured to pull from.",
'b2cfea1b73b4855e2c9788d34218761d0345b040ca237bdc9d0d4fc2577e6be5': "Your repository has no remotes configured to push to.",
'390f001b0ad6b35e9d11767949fbe88481014bff0abcdb95925ca74bcee7cd90': "Your repository has no remotes.",
'9390298f3fb0c5b160498935d79cb139aef28e1c47358b4bbba61862b9c26e59': "no",
'8a798890fe93817163b10b5f7bd2ca4d25d84c52739a645a889c173eee7d9d3d': "yes",
'87bd11c53118b1c7e013a7abab752a62a22b8ab546323fa0daa6ceae4474fadb': "{0} (Deleted)",
'2902a2172b4cd18aff8b58fe9754a4d14b8f14caf5faee5f32b52092ecafbf05': "{0} (Index)",
'd6bd8cfa8b318f8c3845ea4c575f6dfc48f3db10ebec956199cb5afe75ced8f7': "{0} (Intent to add)",
'aac7b4cbb9b0b84aa84433090d5b052e903003ebbe61d74bff4b1609e302f98f': "{0} (Ours)",
'84d560d3629f1574ce6136b005e80785cc48e18319cdaf6e8736dfdc9d5bf899': "{0} (Theirs)",
'236384de21336e110098c378d5fbdee9628af5281f36a15d98daa43702757ff0': "{0} (Untracked)",
'da0616325ba5bc9c1849caff89e19cc03b34b23ed3bc73ddfc6ac06a2db891d7': "{0} (Working Tree)",
'fa1e7180cf6c8ea611aeffecae3ff04d94f9558bbd8f2c69960ac883c1f31595': "{0} ({1})",
'10e858c003479d92e7f97dcfac77c7ac8950cc2017a2edacb99f84eceacc5e3b': "{0} ({1}) ↔ {0} ({2})",
'82a451fe75f2a900d68020e00d21556defd511eccbd8b2e5743ac8ec3168c9fa': "{0} Commit",
'ba938268068ea08ae956bde42d00e5794a9213cfe5766936cacb2f3758b72dc0': "{0} Commit & Push",
'9e5f10ce1f838d861901ebb2c83f8824296843cff8472960cfafc0098182383c': "{0} Commit & Sync",
'5ea8624f43aa58ee102eae1842f3ba8a08c5bc1e1541440e5fcf3d9c91f78463': "{0} Continue",
'22b70b7e3d265ec2795798f823257aae227228dc4191a3cc85fd00bd2f368f3a': "{0} Fetch all remotes",
'81ad1e4c7e769dcad02d582dd25ee2810c51cc4989b92b5d32a2f1e5467d9927': "{0} Publish Branch/{Locked=\"Branch\"}Do not translate \"Branch\" as it is a git term",
'da089f5ddfe606c3dc6f961bcb1316e41e11cf382afe908f8371b88e97b89225': "{0} Sync Changes{1}{2}",
'24cf0fac66cc6a565ec23f5b2b9d58f2c8606cb7313b2591836da1f8d0a53993': "{0} characters left in current line",
'8de94f809d2ce26a9db6bd5c9e3fe247254b40c6888ad3044050a147374dbd91': "{0} characters over {1} in current line",
'93264f176451ecdd4985efc6ce3e65eb7759381031de21dcdf8809bc3e90e810': "{0} ↔ {1}",
'86b933c7292229ebcd6fc4977d94683a09568745f08b5eff0ddf6249ca56a11d': "{0}\\n\\nThis is IRREVERSIBLE, your current working set will be FOREVER LOST."
}
}

View File

@@ -6,11 +6,11 @@
"@actions/core": "1.9.1",
"@actions/github": "2.1.1",
"@azure/cosmos": "^3.17.3",
"@azure/identity": "^2.1.0",
"@azure/storage-blob": "^12.13.0",
"@azure/identity": "^3.3.0",
"@azure/storage-blob": "^12.16.0",
"@electron/get": "^1.12.4",
"@types/ansi-colors": "^3.2.0",
"@types/azure": "0.9.19",
"@types/azure": "0.9.20",
"@types/byline": "^4.2.32",
"@types/cssnano": "^4.0.0",
"@types/debounce": "^1.0.0",

View File

@@ -53,6 +53,15 @@
"@azure/abort-controller" "^1.0.0"
tslib "^2.2.0"
"@azure/core-auth@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.5.0.tgz#a41848c5c31cb3b7c84c409885267d55a2c92e44"
integrity sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-util" "^1.1.0"
tslib "^2.2.0"
"@azure/core-client@^1.4.0":
version "1.6.1"
resolved "https://registry.npmjs.org/@azure/core-client/-/core-client-1.6.1.tgz"
@@ -140,6 +149,14 @@
dependencies:
tslib "^2.2.0"
"@azure/core-util@^1.1.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.5.0.tgz#ffe49c3e867044da67daeb8122143fa065e1eb0e"
integrity sha512-GZBpVFDtQ/15hW1OgBcRdT4Bl7AEpcEZqLfbAvOtm1CQUncKWiYapFHVD588hmlV27NbOOtSm3cnLF3lvoHi4g==
dependencies:
"@azure/abort-controller" "^1.0.0"
tslib "^2.2.0"
"@azure/core-util@^1.1.1":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.3.0.tgz#ea736a0cb0437ac0d049d57ff627c240b41479ec"
@@ -167,21 +184,21 @@
universal-user-agent "^6.0.0"
uuid "^8.3.0"
"@azure/identity@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-2.1.0.tgz#89f0bfc1d1264dfd3d0cb19837c33a9c6706d548"
integrity sha512-BPDz1sK7Ul9t0l9YKLEa8PHqWU4iCfhGJ+ELJl6c8CP3TpJt2urNCbm0ZHsthmxRsYoMPbz2Dvzj30zXZVmAFw==
"@azure/identity@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-3.3.0.tgz#0166cfdfa892d73eeb69c390dac91796c6f85f79"
integrity sha512-gISa/dAAxrWt6F2WiDXZY0y2xY4MLlN2wkNW4cPuq5OgPQKLSkxLc4I2WR04puTfZyQZnpXbAapAMEj1b96fgg==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-auth" "^1.5.0"
"@azure/core-client" "^1.4.0"
"@azure/core-rest-pipeline" "^1.1.0"
"@azure/core-tracing" "^1.0.0"
"@azure/core-util" "^1.0.0"
"@azure/logger" "^1.0.0"
"@azure/msal-browser" "^2.26.0"
"@azure/msal-common" "^7.0.0"
"@azure/msal-node" "^1.10.0"
"@azure/msal-browser" "^2.37.1"
"@azure/msal-common" "^13.1.0"
"@azure/msal-node" "^1.17.3"
events "^3.0.0"
jws "^4.0.0"
open "^8.0.0"
@@ -196,36 +213,31 @@
dependencies:
tslib "^2.0.0"
"@azure/msal-browser@^2.26.0":
version "2.37.0"
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.37.0.tgz#32d7af74eef53f2692f8a9d6bd6818c78faf4c1b"
integrity sha512-YNGD/W/tw/5wDWlXOfmrVILaxVsorVLxYU2ovmL1PDvxkdudbQRyGk/76l4emqgDAl/kPQeqyivxjOU6w1YfvQ==
"@azure/msal-browser@^2.37.1":
version "2.38.2"
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.38.2.tgz#707725c892258fe6b3af4dd410e1daff608521b5"
integrity sha512-71BeIn2we6LIgMplwCSaMq5zAwmalyJR3jFcVOZxNVfQ1saBRwOD+P77nLs5vrRCedVKTq8RMFhIOdpMLNno0A==
dependencies:
"@azure/msal-common" "13.0.0"
"@azure/msal-common" "13.3.0"
"@azure/msal-common@13.0.0":
version "13.0.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.0.0.tgz#9c39184903b5d0fd6e643ccc12193fae220e912b"
integrity sha512-GqCOg5H5bouvLij9NFXFkh+asRRxsPBRwnTDsfK7o0KcxYHJbuidKw8/VXpycahGXNxgtuhqtK/n5he+5NhyEA==
"@azure/msal-common@13.3.0", "@azure/msal-common@^13.1.0":
version "13.3.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.3.0.tgz#dfa39810e0fbce6e07ca85a2cf305da58d30b7c9"
integrity sha512-/VFWTicjcJbrGp3yQP7A24xU95NiDMe23vxIU1U6qdRPFsprMDNUohMudclnd+WSHE4/McqkZs/nUU3sAKkVjg==
"@azure/msal-common@^7.0.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-7.6.0.tgz#b52e97ef540275f72611cff57937dfa0b34cdcca"
integrity sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==
"@azure/msal-node@^1.10.0":
version "1.17.2"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.17.2.tgz#42566443e0cdf476bcb43854c9fe47a2def40baf"
integrity sha512-l8edYnA2LQj4ue3pjxVz1Qy4HuU5xbcoebfe2bGTRvBL9Q6n2Df47aGftkLIyimD1HxHuA4ZZOe23a/HshoYXw==
"@azure/msal-node@^1.17.3":
version "1.18.3"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.18.3.tgz#e265556d4db0340590eeab5341469fb6740251d0"
integrity sha512-lI1OsxNbS/gxRD4548Wyj22Dk8kS7eGMwD9GlBZvQmFV8FJUXoXySL1BiNzDsHUE96/DS/DHmA+F73p1Dkcktg==
dependencies:
"@azure/msal-common" "13.0.0"
"@azure/msal-common" "13.3.0"
jsonwebtoken "^9.0.0"
uuid "^8.3.0"
"@azure/storage-blob@^12.13.0":
version "12.14.0"
resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.14.0.tgz#32d3e5fa3bb2a12d5d44b186aed11c8e78f00178"
integrity sha512-g8GNUDpMisGXzBeD+sKphhH5yLwesB4JkHr1U6be/X3F+cAMcyGLPD1P89g2M7wbEtUJWoikry1rlr83nNRBzg==
"@azure/storage-blob@^12.16.0":
version "12.16.0"
resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.16.0.tgz#c41fb1e538d6f6e2a6756bfcc69382eededf4fa1"
integrity sha512-jz33rUSUGUB65FgYrTRgRDjG6hdPHwfvHe+g/UrwVG8MsyLqSxg9TaW7Yuhjxu1v1OZ5xam2NU6+IpCN0xJO8Q==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-http" "^3.0.0"
@@ -540,10 +552,10 @@
resolved "https://registry.npmjs.org/@types/ansi-colors/-/ansi-colors-3.2.0.tgz"
integrity sha512-0caWAhXht9N2lOdMzJLXybsSkYCx1QOdxx6pae48tswI9QV3DFX26AoOpy0JxwhCb+zISTqmd6H8t9Zby9BoZg==
"@types/azure@0.9.19":
version "0.9.19"
resolved "https://registry.npmjs.org/@types/azure/-/azure-0.9.19.tgz"
integrity sha1-Gmqb2Fa0N93s8/n8hAemg8hpugI=
"@types/azure@0.9.20":
version "0.9.20"
resolved "https://registry.yarnpkg.com/@types/azure/-/azure-0.9.20.tgz#ce00ed2546c5dc5c63489162c804a2f773b95cfa"
integrity sha512-5+YeTSAruOEjCtmRJlqnhUTJtA4+kjPhOwUUT6Eo4O3MDQIlGzGwJw70umHgaSw0hZoWIB2g/iCRXtmesn9F2w==
dependencies:
"@types/node" "*"
@@ -2627,14 +2639,14 @@ mimic-response@^3.1.0:
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
minimatch@^3.0.3, minimatch@^3.1.1:
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==

View File

@@ -1213,7 +1213,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1227,6 +1227,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -1151,7 +1151,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1165,6 +1165,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -1214,7 +1214,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1228,6 +1228,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -1467,7 +1467,7 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "1.44.0"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1481,6 +1481,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -520,12 +520,13 @@
"hasAzureResourceProviders": true
},
"dependencies": {
"@azure/arm-resourcegraph": "^4.0.0",
"@azure/arm-resourcegraph": "^4.2.1",
"@azure/arm-subscriptions": "^3.0.0",
"@azure/msal-common": "^11.0.0",
"@azure/msal-node": "^1.16.0",
"@azure/msal-common": "^13.3.0",
"@azure/msal-node": "^1.18.3",
"@azure/ms-rest-js": "^2.2.0",
"@azure/storage-blob": "^12.13.0",
"axios": "^0.27.2",
"axios": "^1.5.0",
"lockfile": "1.0.4",
"@microsoft/ads-extension-telemetry": "^3.0.1",
"node-fetch": "^2.6.7",

View File

@@ -22,8 +22,7 @@ import { MemoryDatabase } from '../utils/memoryDatabase';
import { Logger } from '../../utils/Logger';
import { AzureAuthError } from './azureAuthError';
import { AccountInfo, AuthError, AuthenticationResult, InteractionRequiredAuthError, PublicClientApplication } from '@azure/msal-node';
import { HttpClient } from './httpClient';
import { getProxyEnabledHttpClient, getTenantIgnoreList, updateTenantIgnoreList } from '../../utils';
import { getTenantIgnoreList, updateTenantIgnoreList } from '../../utils';
import { errorToPromptFailedResult } from './networkUtils';
import { MsalCachePluginProvider } from '../utils/msalCachePlugin';
import { isErrorResponseBodyWithError } from '../../azureResource/utils';
@@ -32,6 +31,7 @@ const localize = nls.loadMessageBundle();
export type GetTenantsResponseData = {
value: TenantResponse[];
error?: string;
}
export abstract class AzureAuth implements vscode.Disposable {
@@ -44,7 +44,7 @@ export abstract class AzureAuth implements vscode.Disposable {
protected readonly scopesString: string;
protected readonly clientId: string;
protected readonly resources: Resource[];
protected readonly httpClient: HttpClient;
private readonly _disposableStore: vscode.Disposable[];
constructor(
protected readonly metadata: AzureAccountProviderMetadata,
@@ -55,7 +55,7 @@ export abstract class AzureAuth implements vscode.Disposable {
protected readonly authType: AzureAuthType,
public readonly userFriendlyName: string
) {
this._disposableStore = [];
this.loginEndpointUrl = this.metadata.settings.host;
this.commonTenant = {
id: 'common',
@@ -68,8 +68,7 @@ export abstract class AzureAuth implements vscode.Disposable {
this.redirectUri = this.metadata.settings.redirectUri;
this.clientId = this.metadata.settings.clientId;
this.resources = [
this.metadata.settings.armResource,
this.metadata.settings.graphResource,
this.metadata.settings.armResource
];
if (this.metadata.settings.sqlResource) {
this.resources.push(this.metadata.settings.sqlResource);
@@ -99,7 +98,7 @@ export abstract class AzureAuth implements vscode.Disposable {
this.scopes = [...this.metadata.settings.scopes];
this.scopesString = this.scopes.join(' ');
this.httpClient = getProxyEnabledHttpClient();
this._disposableStore.push(this.uriEventEmitter);
}
public async startLogin(): Promise<AzureAccount | azdata.PromptFailedResult> {
@@ -310,6 +309,7 @@ export abstract class AzureAuth implements vscode.Disposable {
|| error.errorMessage.includes(Constants.AADSTS50078)
|| error.errorMessage.includes(Constants.AADSTS50085)
|| error.errorMessage.includes(Constants.AADSTS50089)
|| error.errorMessage.includes(Constants.AADSTS700082)
|| error.errorMessage.includes(Constants.AADSTS700084);
}
@@ -510,8 +510,7 @@ export abstract class AzureAuth implements vscode.Disposable {
this.clientApplication.clearCache();
// unlink both cache files
await this.msalCacheProvider.unlinkMsalCache();
await this.msalCacheProvider.unlinkLocalCache();
await this.msalCacheProvider.unlinkCacheFiles();
// Delete Encryption Keys
await this.msalCacheProvider.clearCacheEncryptionKeys();
@@ -541,7 +540,9 @@ export abstract class AzureAuth implements vscode.Disposable {
await this.msalCacheProvider.clearAccountFromLocalCache(accountKey.accountId);
}
public async dispose() { }
public async dispose() {
this._disposableStore.forEach(d => d.dispose());
}
public async autoOAuthCancelled(): Promise<void> { }
@@ -624,7 +625,7 @@ export interface TokenClaims { // https://docs.microsoft.com/en-us/azure/active-
aud: string;
/**
* Identifies the issuer, or "authorization server" that constructs and
* returns the token. It also identifies the Azure AD tenant for which
* returns the token. It also identifies the Microsoft Entra tenant for which
* the user was authenticated. If the token was issued by the v2.0 endpoint,
* the URI will end in /v2.0. The GUID that indicates that the user is a consumer
* user from a Microsoft account is 9188040d-6c67-4c5b-b112-36a304b66dad.
@@ -642,7 +643,7 @@ export interface TokenClaims { // https://docs.microsoft.com/en-us/azure/active-
* account not in the same tenant as the issuer - guests, for instance.
* If the claim isn't present, it means that the value of iss can be used instead.
* For personal accounts being used in an organizational context (for instance,
* a personal account invited to an Azure AD tenant), the idp claim may be
* a personal account invited to a Microsoft Entra tenant), the idp claim may be
* 'live.com' or an STS URI containing the Microsoft account tenant
* 9188040d-6c67-4c5b-b112-36a304b66dad.
*/
@@ -675,7 +676,7 @@ export interface TokenClaims { // https://docs.microsoft.com/en-us/azure/active-
*/
at_hash: string;
/**
* An internal claim used by Azure AD to record data for token reuse. Should be ignored.
* An internal claim used by Microsoft Entra ID to record data for token reuse. Should be ignored.
*/
aio: string;
/**

View File

@@ -1,413 +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 { AzureNetworkResponse } from 'azurecore';
import * as http from 'http';
import * as https from 'https';
import { TextEncoder } from 'util';
import { NetworkRequestOptions, urlToHttpOptions } from './networkUtils';
/**
* http methods
*/
export enum HttpMethod {
GET = 'get',
POST = 'post',
PUT = 'put',
DELETE = 'delete',
PATCH = 'patch'
}
export enum HttpStatus {
SUCCESS_RANGE_START = 200,
SUCCESS_RANGE_END = 299,
REDIRECT = 302,
CLIENT_ERROR_RANGE_START = 400,
CLIENT_ERROR_RANGE_END = 499,
SERVER_ERROR_RANGE_START = 500,
SERVER_ERROR_RANGE_END = 599
}
export enum ProxyStatus {
SUCCESS_RANGE_START = 200,
SUCCESS_RANGE_END = 299,
SERVER_ERROR = 500
}
/**
* This class implements the API for network requests.
*/
export class HttpClient {
private proxyUrl: string;
private customAgentOptions: http.AgentOptions | https.AgentOptions;
static readonly AUTHORIZATION_PENDING: string = 'authorization_pending';
constructor(
proxyUrl?: string,
customAgentOptions?: http.AgentOptions | https.AgentOptions
) {
this.proxyUrl = proxyUrl || '';
this.customAgentOptions = customAgentOptions || {};
}
/**
* Http Get request
* @param url
* @param options
*/
async sendGetRequestAsync<T>(
url: string,
options?: NetworkRequestOptions,
cancellationToken?: number | undefined
): Promise<AzureNetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.GET, options, this.customAgentOptions as http.AgentOptions, cancellationToken);
} else {
return networkRequestViaHttps(url, HttpMethod.GET, options, this.customAgentOptions as https.AgentOptions, cancellationToken);
}
}
/**
* Http Post request
* @param url
* @param options
*/
async sendPostRequestAsync<T>(
url: string,
options?: NetworkRequestOptions,
cancellationToken?: number
): Promise<AzureNetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.POST, options, this.customAgentOptions as http.AgentOptions, cancellationToken);
} else {
return networkRequestViaHttps(url, HttpMethod.POST, options, this.customAgentOptions as https.AgentOptions, cancellationToken);
}
}
/**
* Http Put request
* @param url
* @param options
*/
async sendPutRequestAsync<T>(
url: string,
options?: NetworkRequestOptions,
cancellationToken?: number
): Promise<AzureNetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.PUT, options, this.customAgentOptions as http.AgentOptions, cancellationToken);
} else {
return networkRequestViaHttps(url, HttpMethod.PUT, options, this.customAgentOptions as https.AgentOptions, cancellationToken);
}
}
/**
* Http Delete request
* @param url
* @param options
*/
async sendDeleteRequestAsync<T>(
url: string,
options?: NetworkRequestOptions
): Promise<AzureNetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.DELETE, options, this.customAgentOptions as http.AgentOptions);
} else {
return networkRequestViaHttps(url, HttpMethod.DELETE, options, this.customAgentOptions as https.AgentOptions);
}
}
/**
* Http Patch request
* @param url
* @param options
*/
async sendPatchRequestAsync<T>(
url: string,
options?: NetworkRequestOptions,
cancellationToken?: number
): Promise<AzureNetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.PATCH, options, this.customAgentOptions as http.AgentOptions, cancellationToken);
} else {
return networkRequestViaHttps(url, HttpMethod.PATCH, options, this.customAgentOptions as https.AgentOptions, cancellationToken);
}
}
}
const networkRequestViaProxy = <T>(
destinationUrlString: string,
proxyUrlString: string,
httpMethod: string,
options?: NetworkRequestOptions,
agentOptions?: http.AgentOptions,
timeout?: number
): Promise<AzureNetworkResponse<T>> => {
const destinationUrl = new URL(destinationUrlString);
const proxyUrl = new URL(proxyUrlString);
// 'method: connect' must be used to establish a connection to the proxy
const headers = options?.headers || {} as Record<string, string>;
const tunnelRequestOptions: https.RequestOptions = {
host: proxyUrl.hostname,
port: proxyUrl.port,
method: 'CONNECT',
path: destinationUrl.hostname,
headers: headers
};
if (timeout) {
tunnelRequestOptions.timeout = timeout;
}
if (agentOptions && Object.keys(agentOptions).length) {
tunnelRequestOptions.agent = new http.Agent(agentOptions);
}
// compose a request string for the socket
let postRequestStringContent: string = '';
if (httpMethod === HttpMethod.POST || httpMethod === HttpMethod.PUT) {
// Note: Text Encoder is necessary here because otherwise it was not able to handle Chinese characters in table names.
const body = (new TextEncoder()).encode(JSON.stringify(options?.body || ''));
postRequestStringContent =
'Content-Type: application/json\r\n' +
`Content-Length: ${body.length}\r\n` +
`\r\n${body}`;
}
const outgoingRequestString = `${httpMethod.toUpperCase()} ${destinationUrl.href} HTTP/1.1\r\n` +
`Host: ${destinationUrl.host}\r\n` +
'Connection: close\r\n' +
postRequestStringContent +
'\r\n';
return new Promise<AzureNetworkResponse<T>>(((resolve, reject) => {
const request = http.request(tunnelRequestOptions);
if (tunnelRequestOptions.timeout) {
request.on('timeout', () => {
request.destroy();
reject(new Error('Request time out'));
});
}
request.end();
// establish connection to the proxy
request.on('connect', (response, socket) => {
const proxyStatusCode = response?.statusCode || ProxyStatus.SERVER_ERROR;
if ((proxyStatusCode < ProxyStatus.SUCCESS_RANGE_START) || (proxyStatusCode > ProxyStatus.SUCCESS_RANGE_END)) {
request.destroy();
socket.destroy();
reject(new Error(`Error connecting to proxy. Http status code: ${response.statusCode}. Http status message: ${response?.statusMessage || 'Unknown'}`));
}
if (tunnelRequestOptions.timeout) {
socket.setTimeout(tunnelRequestOptions.timeout);
socket.on('timeout', () => {
request.destroy();
socket.destroy();
reject(new Error('Request time out'));
});
}
// make a request over an HTTP tunnel
socket.write(outgoingRequestString);
const data: Buffer[] = [];
socket.on('data', (chunk) => {
data.push(chunk);
});
socket.on('end', () => {
// combine all received buffer streams into one buffer, and then into a string
const dataString = Buffer.concat([...data]).toString();
// separate each line into it's own entry in an arry
const dataStringArray = dataString.split('\r\n');
// the first entry will contain the statusCode and statusMessage
const httpStatusCode = parseInt(dataStringArray[0].split(' ')[1], undefined);
// remove 'HTTP/1.1' and the status code to get the status message
const statusMessage = dataStringArray[0].split(' ').slice(2).join(' ');
// the last entry will contain the body
const body = dataStringArray[dataStringArray.length - 1];
// everything in between the first and last entries are the headers
const headersArray = dataStringArray.slice(1, dataStringArray.length - 2);
// build an object out of all the headers
const entries = new Map();
headersArray.forEach((header) => {
/**
* the header might look like 'Content-Length: 1531', but that is just a string
* it needs to be converted to a key/value pair
* split the string at the first instance of ':'
* there may be more than one ':' if the value of the header is supposed to be a JSON object
*/
const headerKeyValue = header.split(new RegExp(/:\s(.*)/s));
entries.set(headerKeyValue[0], headerKeyValue[1]);
});
const parsedHeaders = Object.fromEntries(entries) as Record<string, string>;
const networkResponse: AzureNetworkResponse<T> = {
headers: parsedHeaders,
data: parseBody(httpStatusCode, statusMessage, parsedHeaders, body) as T,
status: httpStatusCode
};
if (((httpStatusCode < HttpStatus.SUCCESS_RANGE_START) || (httpStatusCode > HttpStatus.SUCCESS_RANGE_END)) &&
// do not destroy the request for the device code flow
// @ts-ignore
networkResponse.data['error'] !== HttpClient.AUTHORIZATION_PENDING) {
request.destroy();
}
resolve(networkResponse);
});
socket.on('error', (chunk) => {
request.destroy();
socket.destroy();
reject(new Error(chunk.toString()));
});
});
request.on('error', (chunk) => {
request.destroy();
reject(new Error(chunk.toString()));
});
}));
};
const networkRequestViaHttps = <T>(
urlString: string,
httpMethod: string,
options?: NetworkRequestOptions,
agentOptions?: https.AgentOptions,
timeout?: number
): Promise<AzureNetworkResponse<T>> => {
const isPostRequest = httpMethod === HttpMethod.POST;
const isPutRequest = httpMethod === HttpMethod.PUT;
const isPatchRequest = httpMethod === HttpMethod.PATCH;
// Note: Text Encoder is necessary here because otherwise it was not able to handle Chinese characters in table names.
const body = (new TextEncoder()).encode(options?.body || '');
const url = new URL(urlString);
const optionHeaders = options?.headers || {} as Record<string, string>;
let customOptions: https.RequestOptions = {
method: httpMethod,
headers: optionHeaders,
...urlToHttpOptions(url)
};
if (timeout) {
customOptions.timeout = timeout;
}
if (agentOptions && Object.keys(agentOptions).length) {
customOptions.agent = new https.Agent(agentOptions);
}
if (isPostRequest || isPutRequest || isPatchRequest) {
// needed for post request to work
customOptions.headers = {
...customOptions.headers,
'Content-Length': body.length
};
}
return new Promise<AzureNetworkResponse<T>>((resolve, reject) => {
const request = https.request(customOptions);
if (timeout) {
request.on('timeout', () => {
request.destroy();
reject(new Error('Request timed out'));
});
}
if (isPostRequest || isPutRequest || isPatchRequest) {
request.write(body);
}
request.end();
request.on('response', (response) => {
const headers = response.headers;
const statusCode = response.statusCode as number;
const statusMessage = response.statusMessage;
const data: Buffer[] = [];
response.on('data', (chunk) => {
data.push(chunk);
});
response.on('end', () => {
// combine all received buffer streams into one buffer, and then into a string
const dataBody = Buffer.concat([...data]).toString();
const parsedHeaders = headers as Record<string, string>;
const networkResponse: AzureNetworkResponse<T> = {
headers: parsedHeaders,
data: parseBody(statusCode, statusMessage, parsedHeaders, dataBody) as T,
status: statusCode
};
if (((statusCode < HttpStatus.SUCCESS_RANGE_START) || (statusCode > HttpStatus.SUCCESS_RANGE_END)) &&
// do not destroy the request for the device code flow
// @ts-ignore
networkResponse.data['error'] !== HttpClient.AUTHORIZATION_PENDING) {
request.destroy();
}
resolve(networkResponse);
});
});
request.on('error', (chunk) => {
request.destroy();
reject(new Error(chunk.toString()));
});
});
};
/**
* Check if extra parsing is needed on the response from the server
* @param statusCode {number} the status code of the response from the server
* @param statusMessage {string | undefined} the status message of the response from the server
* @param headers {Record<string, string>} the headers of the response from the server
* @param body {string} the body from the response of the server
* @returns JSON parsed body or error object
*/
const parseBody = (statusCode: number, statusMessage: string | undefined, headers: Record<string, string>, body: string) => {
/*
* Informational responses (100 - 199)
* Successful responses (200 - 299)
* Redirection messages (300 - 399)
* Client error responses (400 - 499)
* Server error responses (500 - 599)
*/
let parsedBody: unknown;
try {
parsedBody = JSON.parse(body);
} catch (error) {
let errorType;
let errorDescriptionHelper;
if ((statusCode >= HttpStatus.CLIENT_ERROR_RANGE_START) && (statusCode <= HttpStatus.CLIENT_ERROR_RANGE_END)) {
errorType = 'client_error';
errorDescriptionHelper = 'A client';
} else if ((statusCode >= HttpStatus.SERVER_ERROR_RANGE_START) && (statusCode <= HttpStatus.SERVER_ERROR_RANGE_END)) {
errorType = 'server_error';
errorDescriptionHelper = 'A server';
} else {
errorType = 'unknown_error';
errorDescriptionHelper = 'An unknown';
}
parsedBody = {
error: errorType,
error_description: `${errorDescriptionHelper} error occurred.\nHttp status code: ${statusCode}\nHttp status message: ${statusMessage || 'Unknown'}\nHeaders: ${JSON.stringify(headers)}`
};
}
return parsedBody;
};

View File

@@ -7,7 +7,6 @@ import * as azurecore from 'azurecore';
export const enum SettingIds {
marm = 'marm',
graph = 'graph',
msgraph = 'msgraph',
arm = 'arm',
sql = 'sql',
@@ -49,7 +48,6 @@ export type ProviderSettingsJson = {
host: string,
clientId: string,
microsoftResource: string,
graphResource: string,
msGraphResource?: string,
armResource: string,
sqlResource: string,

View File

@@ -23,11 +23,6 @@ const publicAzureSettings: ProviderSettings = {
endpoint: 'https://management.core.windows.net/',
azureResourceId: AzureResource.MicrosoftResourceManagement
},
graphResource: {
id: SettingIds.graph,
endpoint: 'https://graph.windows.net/',
azureResourceId: AzureResource.Graph
},
msGraphResource: {
id: SettingIds.msgraph,
endpoint: 'https://graph.microsoft.com/',
@@ -103,11 +98,6 @@ const usGovAzureSettings: ProviderSettings = {
endpoint: 'https://management.core.usgovcloudapi.net/',
azureResourceId: AzureResource.MicrosoftResourceManagement
},
graphResource: {
id: SettingIds.graph,
endpoint: 'https://graph.windows.net/',
azureResourceId: AzureResource.Graph
},
msGraphResource: {
id: SettingIds.msgraph,
endpoint: 'https://graph.microsoft.us/',
@@ -177,11 +167,6 @@ const chinaAzureSettings: ProviderSettings = {
endpoint: 'https://management.core.chinacloudapi.cn/',
azureResourceId: AzureResource.MicrosoftResourceManagement
},
graphResource: {
id: SettingIds.graph,
endpoint: 'https://graph.chinacloudapi.cn',
azureResourceId: AzureResource.Graph
},
msGraphResource: {
id: SettingIds.msgraph,
endpoint: 'https://microsoftgraph.chinacloudapi.cn',

View File

@@ -75,7 +75,7 @@ export class MsalCachePluginProvider {
// Handle deserialization error in cache file in case file gets corrupted.
// Clearing cache here will ensure account is marked stale so re-authentication can be triggered.
Logger.verbose(`MsalCachePlugin: Error occurred when trying to read cache file, file will be deleted: ${e.message}`);
await fsPromises.unlink(this._msalCacheConfiguration.cacheFilePath);
await this.unlinkCache(this._msalCacheConfiguration);
}
}
@@ -177,17 +177,11 @@ export class MsalCachePluginProvider {
}
/**
* Deletes Msal access token cache file
* Deletes both cache files.
*/
public async unlinkMsalCache(): Promise<void> {
await fsPromises.unlink(this._msalCacheConfiguration.cacheFilePath);
}
/**
* Deletes local access token cache file.
*/
public async unlinkLocalCache(): Promise<void> {
await fsPromises.unlink(this._localCacheConfiguration.cacheFilePath);
public async unlinkCacheFiles(): Promise<void> {
await this.unlinkCache(this._msalCacheConfiguration);
await this.unlinkCache(this._localCacheConfiguration);
}
//#region Private helper methods
@@ -225,13 +219,12 @@ export class MsalCachePluginProvider {
else {
Logger.error(`MsalCachePlugin: Failed to read from cache file: ${e}`);
Logger.verbose(`MsalCachePlugin: Error occurred when trying to read cache file ${currentConfig.name}, file will be deleted: ${e.message}`);
await fsPromises.unlink(currentConfig.cacheFilePath);
await this.unlinkCache(currentConfig);
// Ensure both configurations are not same.
if (currentConfig.name !== alternateConfig.name) {
// Delete alternate cache file as well.
alternateConfig.lockTaken = await this.waitAndLock(alternateConfig.lockFilePath, alternateConfig.lockTaken);
await fsPromises.unlink(alternateConfig.cacheFilePath);
await this.unlinkCache(alternateConfig);
lockFile.unlockSync(alternateConfig.lockFilePath);
alternateConfig.lockTaken = false;
Logger.verbose(`MsalCachePlugin: Cache file for ${alternateConfig.name} cache also deleted.`);
@@ -276,5 +269,16 @@ export class MsalCachePluginProvider {
}
return lockTaken;
}
/**
* Deletes access token cache file for specified config
*/
private async unlinkCache(config: CacheConfiguration): Promise<void> {
try {
await fsPromises.unlink(config.cacheFilePath);
} catch (e) {
Logger.info(`An error occurred when clearing ${config.name} Cache, safely ignored: ${e}`);
}
}
//#endregion
}

View File

@@ -8,7 +8,6 @@ import * as vscode from 'vscode';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { AzureAccount, azureResource } from 'azurecore';
import { IAzureResourceSubscriptionService } from '../interfaces';
import { TokenCredentials } from '@azure/ms-rest-js';
import { AzureSubscriptionError } from '../errors';
import { AzureResourceErrorMessageUtil } from '../utils';
import { Logger } from '../../utils/Logger';
@@ -16,6 +15,7 @@ import { Logger } from '../../utils/Logger';
import * as nls from 'vscode-nls';
import { TenantIgnoredError } from '../../utils/TenantIgnoredError';
import { multiple_matching_tokens_error } from '../../constants';
import { TokenCredentials } from '@azure/ms-rest-js';
const localize = nls.loadMessageBundle();
export class AzureResourceSubscriptionService implements IAzureResourceSubscriptionService {

View File

@@ -9,7 +9,7 @@ import * as nls from 'vscode-nls';
import * as Constants from '../constants';
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
import { TokenCredentials } from '@azure/ms-rest-js';
import { AzureRestResponse, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult, HttpRequestMethod, GetLocationsResult, GetManagedDatabasesResult, CreateResourceGroupResult, GetBlobsResult, GetStorageAccountAccessKeyResult, AzureAccount, azureResource, AzureAccountProviderMetadata, AzureNetworkResponse } from 'azurecore';
import { AzureRestResponse, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult, HttpRequestMethod, GetLocationsResult, GetManagedDatabasesResult, CreateResourceGroupResult, GetBlobsResult, GetStorageAccountAccessKeyResult, AzureAccount, azureResource, AzureAccountProviderMetadata } from 'azurecore';
import { EOL } from 'os';
import { AppContext } from '../appContext';
import { invalidAzureAccount, invalidTenant, unableToFetchTokenError } from '../localizedConstants';
@@ -18,9 +18,6 @@ import { IAzureResourceSubscriptionFilterService, IAzureResourceSubscriptionServ
import { AzureResourceGroupService } from './providers/resourceGroup/resourceGroupService';
import { BlobServiceClient, StorageSharedKeyCredential } from '@azure/storage-blob';
import providerSettings from '../account-provider/providerSettings';
import { getProxyEnabledHttpClient } from '../utils';
import { HttpClient } from '../account-provider/auths/httpClient';
import { NetworkRequestOptions } from '@azure/msal-common';
import { ErrorResponseBody } from '@azure/arm-subscriptions/esm/models';
import { TenantIgnoredError } from '../utils/TenantIgnoredError';
import { AzureMonitorResourceService } from './providers/azuremonitor/azuremonitorService';
@@ -52,6 +49,7 @@ import { PostgresFlexibleServerTreeDataProvider } from './providers/postgresFlex
import { PostgresFlexibleServerService } from './providers/postgresFlexibleServer/postgresFlexibleServerService';
import { CosmosDbPostgresTreeDataProvider } from './providers/cosmosdb/postgres/cosmosDbPostgresTreeDataProvider';
import { CosmosDbPostgresService } from './providers/cosmosdb/postgres/cosmosDbPostgresService';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
const localize = nls.loadMessageBundle();
@@ -463,7 +461,6 @@ export async function makeHttpRequest<B>(
requestHeaders: Record<string, string> = {}
): Promise<AzureRestResponse<B>> {
const result: AzureRestResponse<B> = { response: undefined, errors: [] };
const httpClient: HttpClient = getProxyEnabledHttpClient();
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
const error = new Error(invalidAzureAccount);
@@ -509,10 +506,9 @@ export async function makeHttpRequest<B>(
...requestHeaders
}
const body = JSON.stringify(requestBody || '');
let networkRequestOptions: NetworkRequestOptions = {
const config: AxiosRequestConfig = {
headers: reqHeaders,
body
validateStatus: () => true // Never throw
};
// Adding '/' if path does not begin with it.
@@ -527,26 +523,22 @@ export async function makeHttpRequest<B>(
requestUrl = `${account.properties.providerSettings.settings.armResource.endpoint}${path}`;
}
let response: AzureNetworkResponse<B | ErrorResponseBodyWithError> | undefined = undefined;
let response: AxiosResponse<B | ErrorResponseBodyWithError> | undefined;
switch (requestType) {
case HttpRequestMethod.GET:
response = await httpClient.sendGetRequestAsync<B | ErrorResponseBodyWithError>(requestUrl, {
headers: reqHeaders
});
response = await axios.get(requestUrl, config);
break;
case HttpRequestMethod.POST:
response = await httpClient.sendPostRequestAsync<B | ErrorResponseBodyWithError>(requestUrl, networkRequestOptions);
response = await axios.post(requestUrl, requestBody, config);
break;
case HttpRequestMethod.PUT:
response = await httpClient.sendPutRequestAsync<B | ErrorResponseBodyWithError>(requestUrl, networkRequestOptions);
response = await axios.put(requestUrl, requestBody, config);
break;
case HttpRequestMethod.DELETE:
response = await httpClient.sendDeleteRequestAsync<B | ErrorResponseBodyWithError>(requestUrl, {
headers: reqHeaders
});
response = await axios.delete(requestUrl, config);
break;
case HttpRequestMethod.PATCH:
response = await httpClient.sendPatchRequestAsync<B | ErrorResponseBodyWithError>(requestUrl, networkRequestOptions);
response = await axios.patch(requestUrl, config);
break;
default:
const error = new Error(`Unknown RequestType "${requestType}"`);
@@ -576,7 +568,7 @@ export async function makeHttpRequest<B>(
result.errors.push(error);
} else {
// We know this isn't an error response at this point
result.response = response as AzureNetworkResponse<B>;
result.response = response as AxiosResponse<B>;
}
return result;

View File

@@ -8,6 +8,7 @@ declare module 'azurecore' {
import * as vscode from 'vscode';
import * as msRest from '@azure/ms-rest-js';
import { BlobItem } from '@azure/storage-blob';
import { AxiosResponse } from 'axios';
/**
* Covers defining what the azurecore extension exports to other extensions
@@ -93,11 +94,6 @@ declare module 'azurecore' {
*/
microsoftResource: Resource
/**
* Information that describes the AAD graph resource
*/
graphResource: Resource;
/**
* Information that describes the MS graph resource
*/
@@ -172,7 +168,7 @@ declare module 'azurecore' {
}
/**
* Represents a resource exposed by an Azure Active Directory
* Represents a resource exposed by a Microsoft Entra identity
*/
export interface Resource {
/**
@@ -197,7 +193,7 @@ declare module 'azurecore' {
}
/**
* Represents a tenant (an Azure Active Directory instance) to which a user has access
* Represents a Microsoft Entra tenant to which a user has access
*/
export interface Tenant {
/**
@@ -278,17 +274,6 @@ declare module 'azurecore' {
PATCH
}
/**
* Custom version of NetworkResponse from @azure\msal-common\dist\network\NetworkManager.d.ts
* with body renamed to data to avoid breaking changes with extensions. See
* https://github.com/microsoft/azuredatastudio/pull/22761 for details.
*/
export type AzureNetworkResponse<T> = {
headers: Record<string, string>;
data: T;
status: number;
};
export interface IExtension {
/**
* Gets the list of subscriptions for the specified AzureAccount
@@ -355,7 +340,7 @@ declare module 'azurecore' {
export type GetFileSharesResult = { fileShares: azureResource.FileShare[], errors: Error[] };
export type CreateResourceGroupResult = { resourceGroup: azureResource.AzureResourceResourceGroup | undefined, errors: Error[] };
export type ResourceQueryResult<T extends azureResource.AzureGraphResource> = { resources: T[], errors: Error[] };
export type AzureRestResponse<B> = { response: AzureNetworkResponse<B> | undefined, errors: Error[] };
export type AzureRestResponse<B> = { response: AxiosResponse<B> | undefined, errors: Error[] };
export type GetBlobsResult = { blobs: azureResource.Blob[], errors: Error[] };
export type GetStorageAccountAccessKeyResult = { keyName1: string, keyName2: string, errors: Error[] };
export type CacheEncryptionKeys = { key: string; iv: string; }

View File

@@ -112,6 +112,12 @@ export const AADSTS50085 = 'AADSTS50085';
* or are revoked by the user or an admin. The app will request a new login from the user.
*/
export const AADSTS50089 = 'AADSTS50089';
/**
* ExpiredOrRevokedGrantInactiveToken - The refresh token has expired due to inactivity.
* The token was issued on {issueDate} and was inactive for {time}. Expected part of the token lifecycle -
* the user went an extended period of time without using the application, so the token was expired when the app attempted to refresh it.
*/
export const AADSTS700082 = 'AADSTS700082';
/**
* The refresh token was issued to a single page app (SPA), and therefore has a fixed, limited lifetime of {time}, which can't be extended.
* It is now expired and a new sign in request must be sent by the SPA to the sign in page. The token was issued on {issueDate}.

View File

@@ -10,19 +10,12 @@ import * as constants from './constants';
import { AzureRegion, azureResource } from 'azurecore';
import { AppContext } from './appContext';
import { HttpClient } from './account-provider/auths/httpClient';
import { parse } from 'url';
import { getProxyAgentOptions } from './proxy';
import { HttpsProxyAgentOptions } from 'https-proxy-agent';
import { ProviderSettings, ProviderSettingsJson, SettingIds } from './account-provider/interfaces';
import { AzureResource } from 'azdata';
import { Logger } from './utils/Logger';
import { TelemetryAction, TelemetryReporter, TelemetryViews } from './telemetry';
const localize = nls.loadMessageBundle();
const configProxy = 'proxy';
const configProxyStrictSSL = 'proxyStrictSSL';
const configProxyAuthorization = 'proxyAuthorization';
/**
* Converts a region value (@see AzureRegion) into the localized Display Name
@@ -145,10 +138,6 @@ export function getResourceTypeDisplayName(type: string): string {
return type;
}
function getHttpConfiguration(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(constants.httpConfigSectionName);
}
/**
* Gets tenants to be ignored.
* @returns Tenants configured in ignore list
@@ -217,11 +206,6 @@ function buildCustomCloudProviderSettings(customProvider: ProviderSettingsJson):
endpoint: customProvider.settings.metadata.endpoints.armResource,
azureResourceId: AzureResource.ResourceManagement
},
graphResource: {
id: SettingIds.graph,
endpoint: customProvider.settings.metadata.endpoints.graphResource,
azureResourceId: AzureResource.Graph
},
azureStorageResource: {
id: SettingIds.storage,
endpoint: customProvider.settings.metadata.endpoints.azureStorageResource.endpoint,
@@ -308,25 +292,6 @@ export interface IPackageInfo {
aiKey: string;
}
export function getProxyEnabledHttpClient(): HttpClient {
const proxy = <string>getHttpConfiguration().get(configProxy);
const strictSSL = getHttpConfiguration().get(configProxyStrictSSL, true);
const authorization = getHttpConfiguration().get(configProxyAuthorization);
const url = parse(proxy);
let agentOptions = getProxyAgentOptions(url, proxy, strictSSL);
if (authorization && url.protocol === 'https:') {
let httpsAgentOptions = agentOptions as HttpsProxyAgentOptions;
httpsAgentOptions!.headers = Object.assign(httpsAgentOptions!.headers || {}, {
'Proxy-Authorization': authorization
});
agentOptions = httpsAgentOptions;
}
return new HttpClient(proxy, agentOptions);
}
/**
* Display notification with button to reload
* @param sectionName Name of section to reload

View File

@@ -9,22 +9,24 @@
dependencies:
tslib "^2.0.0"
"@azure/arm-resourcegraph@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@azure/arm-resourcegraph/-/arm-resourcegraph-4.0.0.tgz#9f8b1e521124eaec20ac8224935af718ce2d5e7d"
integrity sha512-2iCedUV2WACNKeivlt1YLpHDTFaMLvaWMizdkocaHp+e4K8QiV/ToB0FxBWHtT0l9SH9RK4hoHEcgtW5bEEnAg==
"@azure/arm-resourcegraph@^4.2.1":
version "4.2.1"
resolved "https://registry.yarnpkg.com/@azure/arm-resourcegraph/-/arm-resourcegraph-4.2.1.tgz#d529d5da40356393a22eb51a2af4ba91ef1ae1ec"
integrity sha512-PDuRJ6I7wpy/bu2dqX3OVvX6fpM3YzXkFLGnmYpevYFBQBgueNhHruBAk5r1xh2VRTv1M0lAdaYy6LmVHiCRTw==
dependencies:
"@azure/ms-rest-azure-js" "^2.0.1"
"@azure/ms-rest-js" "^2.0.4"
"@azure/core-auth" "^1.1.4"
"@azure/ms-rest-azure-js" "^2.1.0"
"@azure/ms-rest-js" "^2.2.0"
tslib "^1.10.0"
"@azure/arm-subscriptions@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@azure/arm-subscriptions/-/arm-subscriptions-3.0.0.tgz#e47b57ee35452c289d820ccd5fcb59ac107616ec"
integrity sha512-EIPbFJsjLtp6sEDyCJqqt9UIwYm4sAcMEA5pDVXQmEwKPtUckxmqalmFUN9754crv63QRR+Vy01gccJZDR5m1Q==
version "3.1.2"
resolved "https://registry.yarnpkg.com/@azure/arm-subscriptions/-/arm-subscriptions-3.1.2.tgz#6afb0754789942f190c2d8e244a521c9e2cdb886"
integrity sha512-fO1Sxjn27At53Zkgs0tKW9l6iYavfbVgkK4rCFYa2d3M5yofGctHafYDTHQLnp7dYwUzGzTHrBMlyrKo92QpAQ==
dependencies:
"@azure/ms-rest-azure-js" "^2.0.1"
"@azure/ms-rest-js" "^2.0.4"
"@azure/core-auth" "^1.1.4"
"@azure/ms-rest-azure-js" "^2.1.0"
"@azure/ms-rest-js" "^2.2.0"
tslib "^1.10.0"
"@azure/core-auth@^1.1.4":
@@ -102,7 +104,7 @@
dependencies:
tslib "^2.2.0"
"@azure/ms-rest-azure-js@^2.0.1":
"@azure/ms-rest-azure-js@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.1.0.tgz#8c90b31468aeca3146b06c7144b386fd4827f64c"
integrity sha512-CjZjB8apvXl5h97Ck6SbeeCmU0sk56YPozPtTyGudPp1RGoHXNjFNtoOvwOG76EdpmMpxbK10DqcygI16Lu60Q==
@@ -111,7 +113,7 @@
"@azure/ms-rest-js" "^2.2.0"
tslib "^1.10.0"
"@azure/ms-rest-js@^2.0.4", "@azure/ms-rest-js@^2.2.0":
"@azure/ms-rest-js@^2.2.0":
version "2.6.6"
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-2.6.6.tgz#a2ae4a515565ae1b73729b52b25875853bb3240a"
integrity sha512-WYIda8VvrkZE68xHgOxUXvjThxNf1nnGPPe0rAljqK5HJHIZ12Pi3YhEDOn3Ge7UnwaaM3eFO0VtAy4nGVI27Q==
@@ -126,24 +128,24 @@
uuid "^8.3.2"
xml2js "^0.5.0"
"@azure/msal-common@^11.0.0":
version "11.0.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-11.0.0.tgz#d35bfa6cdd2a5b8c036ce427aa3fd36f8f985239"
integrity sha512-SZH8ObQ3Hq5v3ogVGBYJp1nNW7p+MtM4PH4wfNadBP9wf7K0beQHF9iOtRcjPOkwZf+ZD49oXqw91LndIkdk8g==
"@azure/msal-common@13.3.0", "@azure/msal-common@^13.3.0":
version "13.3.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.3.0.tgz#dfa39810e0fbce6e07ca85a2cf305da58d30b7c9"
integrity sha512-/VFWTicjcJbrGp3yQP7A24xU95NiDMe23vxIU1U6qdRPFsprMDNUohMudclnd+WSHE4/McqkZs/nUU3sAKkVjg==
"@azure/msal-node@^1.16.0":
version "1.16.0"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.16.0.tgz#0bd469916f5a9da22d844edc879ac7e8225c0ccb"
integrity sha512-eGXPp65i++mAIvziafbCH970TCeECB6iaQP7aRzZEjtU238cW4zKm40U8YxkiCn9rR1G2VeMHENB5h6WRk7ZCQ==
"@azure/msal-node@^1.18.3":
version "1.18.3"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.18.3.tgz#e265556d4db0340590eeab5341469fb6740251d0"
integrity sha512-lI1OsxNbS/gxRD4548Wyj22Dk8kS7eGMwD9GlBZvQmFV8FJUXoXySL1BiNzDsHUE96/DS/DHmA+F73p1Dkcktg==
dependencies:
"@azure/msal-common" "^11.0.0"
"@azure/msal-common" "13.3.0"
jsonwebtoken "^9.0.0"
uuid "^8.3.0"
"@azure/storage-blob@^12.13.0":
version "12.13.0"
resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.13.0.tgz#9209cbb5c2cd463fb967a0f2ae144ace20879160"
integrity sha512-t3Q2lvBMJucgTjQcP5+hvEJMAsJSk0qmAnjDLie2td017IiduZbbC9BOcFfmwzR6y6cJdZOuewLCNFmEx9IrXA==
version "12.16.0"
resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.16.0.tgz#c41fb1e538d6f6e2a6756bfcc69382eededf4fa1"
integrity sha512-jz33rUSUGUB65FgYrTRgRDjG6hdPHwfvHe+g/UrwVG8MsyLqSxg9TaW7Yuhjxu1v1OZ5xam2NU6+IpCN0xJO8Q==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-http" "^3.0.0"
@@ -596,13 +598,14 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
axios@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267"
integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==
dependencies:
follow-redirects "^1.14.9"
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
balanced-match@^1.0.0:
version "1.0.0"
@@ -991,10 +994,10 @@ flat@^5.0.2:
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
follow-redirects@^1.14.9:
version "1.15.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4"
integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==
follow-redirects@^1.15.0:
version "1.15.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
form-data@^2.5.0:
version "2.5.1"
@@ -1582,7 +1585,7 @@ mime-types@^2.1.12:
dependencies:
mime-db "1.43.0"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1596,6 +1599,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
@@ -1866,6 +1876,11 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
@@ -1877,9 +1892,9 @@ punycode@^2.1.1:
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
qs@^6.9.1:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
version "6.11.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
dependencies:
side-channel "^1.0.4"
@@ -2332,9 +2347,9 @@ wrappy@1:
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^7.4.6:
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
version "7.5.9"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
xml2js@^0.5.0:
version "0.5.0"

View File

@@ -209,7 +209,7 @@
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-azuremonitor ./syntaxes/azuremonitor.tmLanguage"
},
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8",
"figures": "^2.0.0",
"find-remove": "1.2.1",
"@microsoft/ads-service-downloader": "^1.2.1",

View File

@@ -27,7 +27,7 @@
"azuremonitor.connectionOptions.databaseName.description": "The name of the initial catalog or database in the data source",
"azuremonitor.connectionProperties.authType.displayName": "Authentication type",
"azuremonitor.connectionProperties.authType.description": "Specifies the method of authenticating with Azure Monitor",
"azuremonitor.connectionProperties.authType.categoryValues.azureMFA": "Azure Active Directory - Universal with MFA support",
"azuremonitor.connectionProperties.authType.categoryValues.azureMFA": "Microsoft Entra ID - Universal with MFA support",
"azuremonitor.connectionProperties.groupName.source": "Source",
"azuremonitor.connectionProperties.groupName.security": "Security"
}

View File

@@ -75,9 +75,9 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7":
version "1.3.7"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d"
dependencies:
vscode-languageclient "5.2.1"
@@ -180,9 +180,9 @@ inherits@2:
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"

View File

@@ -53,7 +53,7 @@
"cms.connectionOptions.authType.description": "Specifies the method of authenticating with SQL Server",
"cms.connectionOptions.authType.categoryValues.sqlLogin": "SQL Login",
"cms.connectionOptions.authType.categoryValues.integrated": "Windows Authentication",
"cms.connectionOptions.authType.categoryValues.azureMFA": "Azure Active Directory - Universal with MFA support",
"cms.connectionOptions.authType.categoryValues.azureMFA": "Microsoft Entra ID - Universal with MFA support",
"cms.connectionOptions.userName.displayName": "User name",
"cms.connectionOptions.userName.description": "Indicates the user ID to be used when connecting to the data source",
"cms.connectionOptions.password.displayName": "Password",

View File

@@ -1139,9 +1139,9 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
@@ -1153,6 +1153,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -288,6 +288,7 @@ export function createViewContext(): ViewTestContext {
modelBuilder: {
listView: undefined!,
radioCardGroup: undefined!,
chart: undefined!,
navContainer: undefined!,
divContainer: () => divBuilder,
flexContainer: () => flexBuilder,

View File

@@ -1297,7 +1297,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1311,6 +1311,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -1285,7 +1285,7 @@ micromatch@^4.0.4:
braces "^3.0.1"
picomatch "^2.2.3"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1299,6 +1299,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -107,7 +107,7 @@
"dependencies": {
"@microsoft/ads-extension-telemetry": "^3.0.1",
"@microsoft/ads-service-downloader": "^1.2.1",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8",
"vscode-nls": "^5.2.0"
},
"devDependencies": {

View File

@@ -597,6 +597,9 @@ export class MockModelBuilder implements azdata.ModelBuilder {
listView(): azdata.ComponentBuilder<azdata.ListViewComponent, azdata.ListViewComponentProperties> {
throw new Error('Method not implemented.');
}
chart<TChartType extends azdata.ChartType, TData extends azdata.ChartData<TChartType>, TOptions extends azdata.ChartOptions<TChartType>>(): azdata.ComponentBuilder<azdata.ChartComponent<TChartType, TData, TOptions>, azdata.ChartComponentProperties<TChartType, TData, TOptions>> {
throw new Error('Method not implemented.');
}
slider(): azdata.ComponentBuilder<azdata.SliderComponent, azdata.SliderComponentProperties> {
throw new Error('Method not implemented.');
}

View File

@@ -497,9 +497,9 @@ crypt@0.0.2:
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7":
version "1.3.7"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d"
dependencies:
vscode-languageclient "5.2.1"
@@ -903,9 +903,9 @@ minimatch@5.0.1:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"

View File

@@ -1,6 +1,6 @@
# Git static contributions and remote repository picker
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
**Notice:** This extension is bundled with Azure Data Studio. It can be disabled but not uninstalled.
## Features

View File

@@ -1,6 +1,6 @@
# Git integration for Visual Studio Code
# Git integration for Azure Data Studio
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
**Notice:** This extension is bundled with Azure Data Studio. It can be disabled but not uninstalled.
## Features
@@ -17,4 +17,4 @@ The Git extension exposes an API, reachable by any other extension.
```ts
const gitExtension = vscode.extensions.getExtension<GitExtension>('vscode.git').exports;
const git = gitExtension.getAPI(1);
```
```

View File

@@ -1,6 +1,6 @@
# GitHub for Visual Studio Code
# GitHub for Azure Data Studio
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
**Notice:** This extension is bundled with Azure Data Studio. It can be disabled but not uninstalled.
## Features

View File

@@ -155,9 +155,9 @@ graphql-tag@^2.10.3:
tslib "^2.1.0"
graphql@^16.0.0:
version "16.6.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb"
integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==
version "16.8.1"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07"
integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==
is-plain-object@^5.0.0:
version "5.0.0"

View File

@@ -77,7 +77,7 @@
}
},
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8",
"htmlparser2": "^3.10.1",
"@microsoft/ads-service-downloader": "^1.2.1",
"@microsoft/ads-extension-telemetry": "^3.0.1",

View File

@@ -572,9 +572,9 @@ crypt@~0.0.1:
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7":
version "1.3.7"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d"
dependencies:
vscode-languageclient "5.2.1"
@@ -1325,7 +1325,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1339,6 +1339,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -154,24 +154,29 @@
tslib "^2.2.0"
"@azure/msal-browser@^2.26.0":
version "2.27.0"
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.27.0.tgz#3db38db6bc2bae44485025ba9bb99c43ed7f4302"
integrity sha512-PyATq2WvK+x32waRqqikym8wvn939iO9UhpFqhLwitNrfLa3PHUgJuuI9oLSQOS3/UzjYb8aqN+XzchU3n/ZuQ==
version "2.38.2"
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.38.2.tgz#707725c892258fe6b3af4dd410e1daff608521b5"
integrity sha512-71BeIn2we6LIgMplwCSaMq5zAwmalyJR3jFcVOZxNVfQ1saBRwOD+P77nLs5vrRCedVKTq8RMFhIOdpMLNno0A==
dependencies:
"@azure/msal-common" "^7.1.0"
"@azure/msal-common" "13.3.0"
"@azure/msal-common@^7.0.0", "@azure/msal-common@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-7.1.0.tgz#b77dbf9ae581f1ed254f81d56422e3cdd6664b32"
integrity sha512-WyfqE5mY/rggjqvq0Q5DxLnA33KSb0vfsUjxa95rycFknI03L5GPYI4HTU9D+g0PL5TtsQGnV3xzAGq9BFCVJQ==
"@azure/msal-common@13.3.0":
version "13.3.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.3.0.tgz#dfa39810e0fbce6e07ca85a2cf305da58d30b7c9"
integrity sha512-/VFWTicjcJbrGp3yQP7A24xU95NiDMe23vxIU1U6qdRPFsprMDNUohMudclnd+WSHE4/McqkZs/nUU3sAKkVjg==
"@azure/msal-common@^7.0.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-7.6.0.tgz#b52e97ef540275f72611cff57937dfa0b34cdcca"
integrity sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==
"@azure/msal-node@^1.10.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.11.0.tgz#d8bd3f15c1f05bf806ba6f9479c48c2eddd6a98d"
integrity sha512-KW/XEexfCrPzdYbjY7NVmhq9okZT3Jvck55CGXpz9W5asxeq3EtrP45p+ZXtQVEfko0YJdolpCNqWUyXvanWZg==
version "1.18.3"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-1.18.3.tgz#e265556d4db0340590eeab5341469fb6740251d0"
integrity sha512-lI1OsxNbS/gxRD4548Wyj22Dk8kS7eGMwD9GlBZvQmFV8FJUXoXySL1BiNzDsHUE96/DS/DHmA+F73p1Dkcktg==
dependencies:
"@azure/msal-common" "^7.1.0"
jsonwebtoken "^8.5.1"
"@azure/msal-common" "13.3.0"
jsonwebtoken "^9.0.0"
uuid "^8.3.0"
"@babel/code-frame@^7.10.1":
@@ -1402,7 +1407,7 @@ json5@^2.1.2:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
jsonwebtoken@9.0.0, jsonwebtoken@^8.5.1:
jsonwebtoken@9.0.0, jsonwebtoken@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d"
integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==
@@ -1524,7 +1529,7 @@ mime-types@^2.1.12:
dependencies:
mime-db "~1.30.0"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1538,6 +1543,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -6,7 +6,8 @@
"version": "1.0.0",
"license": "MIT",
"engines": {
"vscode": "^1.57.0"
"vscode": "^1.57.0",
"azdata": "*"
},
"enabledApiProposals": [
"documentPaste",
@@ -14,7 +15,7 @@
"dropMetadata"
],
"activationEvents": [
"*"
"onNotebook:jupyter-notebook"
],
"extensionKind": [
"workspace",

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as azdata from 'azdata'; // {{SQL CARBON EDIT}}
import { NotebookSerializer } from './notebookSerializer';
import { ensureAllNewCellsHaveCellIds } from './cellIdService';
import { notebookImagePasteSetup } from './notebookImagePaste';
@@ -58,21 +59,27 @@ export function activate(context: vscode.ExtensionContext) {
});
context.subscriptions.push(vscode.commands.registerCommand('ipynb.newUntitledIpynb', async () => {
const language = 'python';
const cell = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '', language);
const data = new vscode.NotebookData([cell]);
data.metadata = {
custom: {
cells: [],
metadata: {
orig_nbformat: 4
},
nbformat: 4,
nbformat_minor: 2
}
};
const doc = await vscode.workspace.openNotebookDocument('jupyter-notebook', data);
await vscode.window.showNotebookDocument(doc);
// {{SQL CARBON EDIT}} Open new notebooks using the default ADS notebook viewer if VSCode notebooks aren't enabled.
let useVSCodeNotebooks = vscode.workspace.getConfiguration('workbench')?.get<boolean>('useVSCodeNotebooks');
if (useVSCodeNotebooks) {
const language = 'python';
const cell = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '', language);
const data = new vscode.NotebookData([cell]);
data.metadata = {
custom: {
cells: [],
metadata: {
orig_nbformat: 4
},
nbformat: 4,
nbformat_minor: 2
}
};
const doc = await vscode.workspace.openNotebookDocument('jupyter-notebook', data);
await vscode.window.showNotebookDocument(doc);
} else {
await azdata.nb.showNotebookDocument(vscode.Uri.from({ scheme: 'untitled' }));
}
}));
context.subscriptions.push(vscode.commands.registerCommand('ipynb.openIpynbInNotebookEditor', async (uri: vscode.Uri) => {

10
extensions/ipynb/src/typings/refs.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// {{SQL CARBON EDIT}} Import ADS extension APIs
/// <reference path='../../../../src/sql/azdata.d.ts'/>
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
/// <reference path='../../../../src/vscode-dts/vscode.d.ts'/>
/// <reference path='../../../resource-deployment/src/typings/resource-deployment.d.ts'/>

View File

@@ -427,7 +427,7 @@
}
},
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8",
"figures": "^2.0.0",
"find-remove": "1.2.1",
"@microsoft/ads-service-downloader": "^1.2.1",

View File

@@ -26,7 +26,7 @@
"kusto.connectionOptions.databaseName.description": "The name of the initial catalog or database in the data source",
"kusto.connectionOptions.authType.displayName": "Authentication type",
"kusto.connectionOptions.authType.description": "Specifies the method of authenticating with Kusto Server",
"kusto.connectionOptions.authType.categoryValues.azureMFA": "Azure Active Directory - Universal with MFA support",
"kusto.connectionOptions.authType.categoryValues.azureMFA": "Microsoft Entra ID - Universal with MFA support",
"kusto.connectionOptions.authType.categoryValues.none": "No Authentication",
"kusto.connectionOptions.authType.categoryValues.sqlLogin": "User Authentication",
"kusto.connectionOptions.userName.displayName": "User name",

View File

@@ -124,9 +124,9 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7":
version "1.3.7"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d"
dependencies:
vscode-languageclient "5.2.1"
@@ -255,9 +255,9 @@ mime-types@^2.1.12:
mime-db "~1.38.0"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"

View File

@@ -71,7 +71,7 @@ export class SqlRPackageManageProvider extends SqlPackageManageProviderBase impl
if (connection) {
connectionParts.push(utils.getKeyValueString('driver', `"${constants.supportedODBCDriver}"`));
let server = connection.serverName.replace('\\', '\\\\');
let server = connection.serverName.replace(/\\/g, '\\\\');
if (databaseName) {
connectionParts.push(utils.getKeyValueString('database', `"${databaseName}"`));
}

View File

@@ -234,6 +234,7 @@ export function createViewContext(): ViewTestContext {
modelBuilder: {
listView: undefined!,
radioCardGroup: undefined!,
chart: undefined!,
navContainer: undefined!,
divContainer: () => divBuilder,
flexContainer: () => flexBuilder,

View File

@@ -1451,7 +1451,7 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "1.40.0"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1465,6 +1465,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -10,8 +10,9 @@
</head>
<body>
<a class="branding" href="https://code.visualstudio.com/">
Visual Studio Code
<!-- {{SQL CARBON EDIT}} Update application name and URL to Azure Data Studio -->
<a class="branding" href="https://aka.ms/azuredatastudio/">
Azure Data Studio
</a>
<div class="message-container">
<div class="message">

View File

@@ -1,6 +1,6 @@
{
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "4.9.0.37",
"version": "4.10.0.17",
"downloadFileNames": {
"Windows_86": "win-x86-net7.0.zip",
"Windows_64": "win-x64-net7.0.zip",

View File

@@ -156,6 +156,7 @@
},
{
"command": "mssql.clearPooledConnections",
"category": "MSSQL",
"title": "%mssql.connection.clearPooledConnections%"
}
],
@@ -178,14 +179,16 @@
"description": "%mssql.query.displayBitAsNumber%"
},
"mssql.query.maxXmlCharsToStore": {
"type": "number",
"type": "integer",
"default": 2097152,
"description": "%mssql.query.maxXmlCharsToStore%"
"description": "%mssql.query.maxXmlCharsToStore%",
"maximum": 2147483647
},
"mssql.query.maxCharsToStore": {
"type": "number",
"type": "integer",
"default": 65535,
"description": "%mssql.query.maxCharsToStore%"
"description": "%mssql.query.maxCharsToStore%",
"maximum": 2147483647
},
"mssql.format.alignColumnDefinitionsInColumns": {
"type": "boolean",
@@ -316,19 +319,22 @@
]
},
"mssql.query.rowCount": {
"type": "number",
"type": "integer",
"default": 0,
"description": "%mssql.query.setRowCount%"
"description": "%mssql.query.setRowCount%",
"maximum": 2147483647
},
"mssql.query.textSize": {
"type": "number",
"type": "integer",
"default": 2147483647,
"description": "%mssql.query.textSize%"
"description": "%mssql.query.textSize%",
"maximum": 2147483647
},
"mssql.query.executionTimeout": {
"type": "number",
"type": "integer",
"default": 0,
"description": "%mssql.query.executionTimeout%"
"description": "%mssql.query.executionTimeout%",
"maximum": 2147483647
},
"mssql.query.noCount": {
"type": "boolean",
@@ -384,14 +390,16 @@
"description": "%mssql.query.deadlockPriority%"
},
"mssql.query.lockTimeout": {
"type": "number",
"type": "integer",
"default": -1,
"description": "%mssql.query.lockTimeout%"
"description": "%mssql.query.lockTimeout%",
"maximum": 2147483647
},
"mssql.query.queryGovernorCostLimit": {
"type": "number",
"type": "integer",
"default": -1,
"description": "%mssql.query.queryGovernorCostLimit%"
"description": "%mssql.query.queryGovernorCostLimit%",
"maximum": 2147483647
},
"mssql.query.ansiDefaults": {
"type": "boolean",
@@ -474,10 +482,11 @@
"description": "%mssql.objectExplorer.groupBySchema%"
},
"mssql.objectExplorer.expandTimeout": {
"type": "number",
"type": "integer",
"default": 45,
"minimum": 1,
"description": "%mssql.objectExplorer.expandTimeout%"
"description": "%mssql.objectExplorer.expandTimeout%",
"maximum": 2147483647
}
}
},
@@ -570,7 +579,7 @@
},
{
"command": "mssql.renameObject",
"when": "connectionProvider == MSSQL && nodeType =~ /^(ServerLevelLogin|User|Table|View|ServerLevelServerRole|ApplicationRole|DatabaseRole)$/ && config.workbench.enablePreviewFeatures",
"when": "connectionProvider == MSSQL && nodeType =~ /^(ServerLevelLogin|User|Table|View|ServerLevelServerRole|ApplicationRole|DatabaseRole|Database)$/ && config.workbench.enablePreviewFeatures",
"group": "1_objectManagement@1"
},
{
@@ -580,7 +589,7 @@
},
{
"command": "mssql.detachDatabase",
"when": "connectionProvider == MSSQL && nodeType == Database && !isCloud && !(nodePath =~ /^.*\\/System Databases\\/.*$/) && config.workbench.enablePreviewFeatures && (productQualityType =~ /^(insider|dev)$/ || isDevelopment)",
"when": "connectionProvider == MSSQL && nodeType == Database && !isCloud && !(nodePath =~ /^.*\\/System Databases\\/.*$/) && config.workbench.enablePreviewFeatures",
"group": "1_objectManagement@2"
},
{
@@ -611,7 +620,7 @@
},
{
"command": "mssql.objectProperties",
"when": "connectionProvider == MSSQL && serverInfo && !isCloud && nodeType =~ /^(Database|Server)$/ && mssql:engineedition != 11 && config.workbench.enablePreviewFeatures && (productQualityType =~ /^(insider|dev)$/ || isDevelopment)",
"when": "connectionProvider == MSSQL && serverInfo && !isCloud && nodeType =~ /^(Database|Server)$/ && mssql:engineedition != 11 && config.workbench.enablePreviewFeatures",
"group": "z_objectexplorer@3"
},
{
@@ -628,6 +637,11 @@
"when": "connectionProvider == MSSQL && nodeType == Folder && objectType == Tables",
"group": "inline@0"
},
{
"command": "mssql.newDatabase",
"when": "connectionProvider == MSSQL && nodeType == Folder && objectType == Databases && config.workbench.enablePreviewFeatures",
"group": "inline@0"
},
{
"command": "mssql.newObject",
"when": "connectionProvider == MSSQL && nodeType == Folder && objectType =~ /^(ServerLevelLogins|Users|ServerLevelServerRoles|ApplicationRoles|DatabaseRoles)$/ && config.workbench.enablePreviewFeatures",
@@ -1567,7 +1581,7 @@
"dependencies": {
"@microsoft/ads-extension-telemetry": "^3.0.1",
"@microsoft/ads-service-downloader": "^1.2.1",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.8",
"find-remove": "1.2.1",
"vscode-languageclient": "5.2.1",
"vscode-nls": "^4.0.0"

View File

@@ -91,7 +91,7 @@
"mssql.connectionOptions.authType.description": "Specifies the method of authenticating with SQL Server",
"mssql.connectionOptions.authType.categoryValues.sqlLogin": "SQL Login",
"mssql.connectionOptions.authType.categoryValues.integrated": "Windows Authentication",
"mssql.connectionOptions.authType.categoryValues.azureMFA": "Azure Active Directory - Universal with MFA support",
"mssql.connectionOptions.authType.categoryValues.azureMFA": "Microsoft Entra ID - Universal with MFA support",
"mssql.connectionOptions.userName.displayName": "User name",
"mssql.connectionOptions.userName.description": "Indicates the user ID to be used when connecting to the data source",
"mssql.connectionOptions.password.displayName": "Password",
@@ -174,10 +174,10 @@
"title.newTable": "New Table",
"title.designTable": "Design",
"title.changeNotebookConnection": "Change SQL Notebook Connection",
"mssql.connection.clearPooledConnections": "SQL Server: Clear Pooled Connections",
"mssql.connection.clearPooledConnections": "Clear Pooled Connections",
"mssql.parallelMessageProcessing": "[Experimental] Whether the requests to the SQL Tools Service should be handled in parallel. This is introduced to discover the issues there might be when handling all requests in parallel. The default value is false. Azure Data Studio is required to be relaunched when the value is changed.",
"mssql.enableSqlAuthenticationProvider": "Enables use of the Sql Authentication Provider for 'Active Directory Interactive' authentication mode when user selects 'AzureMFA' authentication. This enables Server-side resource endpoint integration when fetching access tokens. This option is only supported for 'MSAL' Azure Authentication Library. Azure Data Studio is required to be relaunched when the value is changed.",
"mssql.enableConnectionPooling": "Enables connection pooling on MSSQL connections to improve overall performance of Azure Data Studio connectivity. This setting is enabled by default. Azure Data Studio is required to be relaunched when the value is changed. To clear pooled connections, run the command: 'SQL Server: Clear Pooled Connections'",
"mssql.enableConnectionPooling": "Enables connection pooling on MSSQL connections to improve overall performance of Azure Data Studio connectivity. This setting is enabled by default. Azure Data Studio is required to be relaunched when the value is changed. To clear pooled connections, run the command: 'MSSQL: Clear Pooled Connections'",
"mssql.tableDesigner.preloadDatabaseModel": "Whether to preload the database model when the database node in the object explorer is expanded. When enabled, the loading time of table designer can be reduced. Note: You might see higher than normal memory usage if you need to expand a lot of database nodes.",
"mssql.tableDesigner.allowDisableAndReenableDdlTriggers": "Whether to allow table designer to disable and re-enable DDL triggers during publish",
"mssql.objectExplorer.groupBySchema": "When enabled, the database objects in Object Explorer will be categorized by schema.",

View File

@@ -33,6 +33,8 @@ export const configObjectExplorerGroupBySchemaFlagName = 'mssql.objectExplorer.g
export const configAsyncParallelProcessingName = 'mssql.parallelMessageProcessing';
export const configEnableSqlAuthenticationProviderName = 'mssql.enableSqlAuthenticationProvider';
export const configEnableConnectionPoolingName = 'mssql.enableConnectionPooling';
export const configHttpProxy = 'http.proxy';
export const configHttpProxyStrictSSL = 'http.proxyStrictSSL';
// COMMANDNAMES //////////////////////////////////////////////////////////
export const cmdObjectExplorerEnableGroupBySchemaCommand = 'mssql.enableGroupBySchema';

View File

@@ -1649,7 +1649,6 @@ export namespace SearchObjectRequest {
export interface DetachDatabaseRequestParams {
connectionUri: string;
database: string;
objectUrn: string;
dropConnections: boolean;
updateStatistics: boolean;
generateScript: boolean;
@@ -1662,7 +1661,6 @@ export namespace DetachDatabaseRequest {
export interface DropDatabaseRequestParams {
connectionUri: string;
database: string;
objectUrn: string;
dropConnections: boolean;
deleteBackupHistory: boolean;
generateScript: boolean;
@@ -1700,13 +1698,12 @@ export namespace GetAssociatedFilesRequest {
}
export namespace PurgeQueryStoreDataRequest {
export const type = new RequestType<purgeQueryStoreDataRequestParams, void, void, void>('objectManagement/purgeQueryStoreData');
export const type = new RequestType<PurgeQueryStoreDataRequestParams, void, void, void>('objectManagement/purgeQueryStoreData');
}
export interface purgeQueryStoreDataRequestParams {
export interface PurgeQueryStoreDataRequestParams {
connectionUri: string;
database: string;
objectUrn: string;
}
// ------------------------------- < Object Management > ------------------------------------

View File

@@ -153,6 +153,10 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
}
await displayReloadAds();
}
// Prompt to reload ADS as we send the proxy URL to STS to instantiate Http Client instances.
if (e.affectsConfiguration(Constants.configHttpProxy) || e.affectsConfiguration(Constants.configHttpProxyStrictSSL)) {
await displayReloadAds();
}
}));
registerTableDesignerCommands(appContext);

View File

@@ -981,13 +981,12 @@ declare module 'mssql' {
* Detach a database.
* @param connectionUri The URI of the server connection.
* @param database The target database.
* @param objectUrn SMO Urn of the database to be detached. More information: https://learn.microsoft.com/sql/relational-databases/server-management-objects-smo/overview-smo
* @param dropConnections Whether to drop active connections to this database.
* @param updateStatistics Whether to update the optimization statistics related to this database.
* @param generateScript Whether to generate a TSQL script for the operation instead of detaching the database.
* @returns A string value representing the generated TSQL query if generateScript was set to true, and an empty string otherwise.
*/
detachDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Thenable<string>;
detachDatabase(connectionUri: string, database: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Thenable<string>;
/**
* Attach one or more databases.
* @param connectionUri The URI of the server connection.
@@ -1000,13 +999,12 @@ declare module 'mssql' {
* Drop a database.
* @param connectionUri The URI of the server connection.
* @param database The target database.
* @param objectUrn SMO Urn of the database to be detached. More information: https://learn.microsoft.com/sql/relational-databases/server-management-objects-smo/overview-smo
* @param dropConnections Whether to drop active connections to this database.
* @param deleteBackupHistory Whether to delete backup and restore history information for this database.
* @param generateScript Whether to generate a TSQL script for the operation instead of detaching the database.
* @returns A string value representing the generated TSQL query if generateScript was set to true, and an empty string otherwise.
*/
dropDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Thenable<string>;
dropDatabase(connectionUri: string, database: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Thenable<string>;
/**
* Gets the file path for the default database file folder for a SQL Server instance.
* @param connectionUri The URI of the connection for the specific server.
@@ -1024,9 +1022,8 @@ declare module 'mssql' {
* Clears all query store data from the database
* @param connectionUri The URI of the server connection.
* @param database The target database.
* @param objectUrn SMO Urn of the database to be detached. More information: https://learn.microsoft.com/sql/relational-databases/server-management-objects-smo/overview-smo
*/
purgeQueryStoreData(connectionUri: string, database: string, objectUrn: string): Thenable<void>;
purgeQueryStoreData(connectionUri: string, database: string): Thenable<void>;
}
export interface DatabaseFileData {

View File

@@ -130,7 +130,13 @@ async function handleNewObjectDialogCommand(context: azdata.ObjectExplorerContex
objectExplorerContext: context
};
const dialog = getDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenNewObjectDialog, {
objectType: objectType
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenNewObjectDialog, err).withAdditionalProperties({
@@ -146,31 +152,33 @@ async function handleObjectPropertiesDialogCommand(context: azdata.ObjectExplore
if (!connectionUri) {
return;
}
const object = await getObjectInfoForContext(context);
try {
const parentUrn = context.isConnectionNode ? undefined : await getParentUrn(context);
const objectType = context.nodeInfo ? context.nodeInfo.nodeType as ObjectManagement.NodeType : (context.connectionProfile.databaseName === '' ? ObjectManagement.NodeType.Server : ObjectManagement.NodeType.Database);
const objectName = context.nodeInfo ? context.nodeInfo.label : (!context.connectionProfile.databaseName ? context.connectionProfile.serverName : context.connectionProfile.databaseName);
const objectUrn = context.nodeInfo ? context.nodeInfo!.metadata!.urn : (context.connectionProfile.databaseName === '' ? 'Server' : `Server/Database[@Name='${escapeSingleQuotes(context.connectionProfile.databaseName)}']`);
const options: ObjectManagementDialogOptions = {
connectionUri: connectionUri,
isNewObject: false,
database: context.connectionProfile!.databaseName!,
objectType: objectType,
objectName: objectName,
parentUrn: parentUrn,
objectUrn: objectUrn,
database: context.connectionProfile?.databaseName,
objectType: object.type,
objectName: object.name,
parentUrn: object.parentUrn,
objectUrn: object.urn,
objectExplorerContext: context
};
const dialog = getDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenPropertiesDialog, {
objectType: object.type
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenPropertiesDialog, err).withAdditionalProperties({
objectType: context.nodeInfo!.nodeType
objectType: object.type
}).send();
console.error(err);
await vscode.window.showErrorMessage(objectManagementLoc.OpenObjectPropertiesDialogError(objectManagementLoc.getNodeTypeDisplayName(context.nodeInfo!.nodeType), context.nodeInfo!.label, getErrorMessage(err)));
await vscode.window.showErrorMessage(objectManagementLoc.OpenObjectPropertiesDialogError(objectManagementLoc.getNodeTypeDisplayName(object.type), object.name, getErrorMessage(err)));
}
}
@@ -179,16 +187,18 @@ async function handleDropObjectCommand(context: azdata.ObjectExplorerContext, se
if (!connectionUri) {
return;
}
const object = await getObjectInfoForContext(context);
let additionalConfirmationMessage: string | undefined = undefined;
switch (context.nodeInfo!.nodeType) {
switch (object.type) {
case ObjectManagement.NodeType.ServerLevelLogin:
additionalConfirmationMessage = objectManagementLoc.DropLoginConfirmationText;
break;
default:
break;
}
const nodeTypeDisplayName = objectManagementLoc.getNodeTypeDisplayName(context.nodeInfo!.nodeType);
let confirmMessage = objectManagementLoc.DropObjectConfirmationText(nodeTypeDisplayName, context.nodeInfo!.label);
const nodeTypeDisplayName = objectManagementLoc.getNodeTypeDisplayName(object.type);
let confirmMessage = objectManagementLoc.DropObjectConfirmationText(nodeTypeDisplayName, object.name);
if (additionalConfirmationMessage) {
confirmMessage = `${additionalConfirmationMessage} ${confirmMessage}`;
}
@@ -197,23 +207,23 @@ async function handleDropObjectCommand(context: azdata.ObjectExplorerContext, se
return;
}
azdata.tasks.startBackgroundOperation({
displayName: objectManagementLoc.DropObjectOperationDisplayName(nodeTypeDisplayName, context.nodeInfo!.label),
displayName: objectManagementLoc.DropObjectOperationDisplayName(nodeTypeDisplayName, object.name),
description: '',
isCancelable: false,
operation: async (operation) => {
try {
const startTime = Date.now();
await service.drop(connectionUri, context.nodeInfo.nodeType as ObjectManagement.NodeType, context.nodeInfo!.metadata!.urn);
await service.drop(connectionUri, object.type, object.urn);
TelemetryReporter.sendTelemetryEvent(TelemetryActions.DropObject, {
objectType: context.nodeInfo!.nodeType
objectType: object.type
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
operation.updateStatus(azdata.TaskStatus.Failed, objectManagementLoc.DropObjectError(nodeTypeDisplayName, context.nodeInfo!.label, getErrorMessage(err)));
operation.updateStatus(azdata.TaskStatus.Failed, objectManagementLoc.DropObjectError(nodeTypeDisplayName, object.name, getErrorMessage(err)));
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.DropObject, err).withAdditionalProperties({
objectType: context.nodeInfo!.nodeType
objectType: object.type
}).send();
console.error(err);
return;
@@ -229,11 +239,12 @@ async function handleRenameObjectCommand(context: azdata.ObjectExplorerContext,
if (!connectionUri) {
return;
}
const nodeTypeDisplayName = objectManagementLoc.getNodeTypeDisplayName(context.nodeInfo!.nodeType);
const originalName = context.nodeInfo!.metadata!.name;
const object = await getObjectInfoForContext(context);
const nodeTypeDisplayName = objectManagementLoc.getNodeTypeDisplayName(object.type);
const newName = await vscode.window.showInputBox({
title: objectManagementLoc.RenameObjectDialogTitle,
value: originalName,
value: object.name,
validateInput: (value: string): string | undefined => {
if (!value) {
return objectManagementLoc.NameCannotBeEmptyError;
@@ -245,28 +256,28 @@ async function handleRenameObjectCommand(context: azdata.ObjectExplorerContext,
});
// return if no change was made or the dialog was canceled.
if (newName === originalName || !newName) {
if (newName === object.name || !newName) {
return;
}
azdata.tasks.startBackgroundOperation({
displayName: objectManagementLoc.RenameObjectOperationDisplayName(nodeTypeDisplayName, originalName, newName),
displayName: objectManagementLoc.RenameObjectOperationDisplayName(nodeTypeDisplayName, object.name, newName),
description: '',
isCancelable: false,
operation: async (operation) => {
try {
const startTime = Date.now();
await service.rename(connectionUri, context.nodeInfo.nodeType as ObjectManagement.NodeType, context.nodeInfo!.metadata!.urn, newName);
await service.rename(connectionUri, object.type, object.urn, newName);
TelemetryReporter.sendTelemetryEvent(TelemetryActions.RenameObject, {
objectType: context.nodeInfo!.nodeType
objectType: object.type
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
operation.updateStatus(azdata.TaskStatus.Failed, objectManagementLoc.RenameObjectError(nodeTypeDisplayName, originalName, newName, getErrorMessage(err)));
operation.updateStatus(azdata.TaskStatus.Failed, objectManagementLoc.RenameObjectError(nodeTypeDisplayName, object.name, newName, getErrorMessage(err)));
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.RenameObject, err).withAdditionalProperties({
objectType: context.nodeInfo!.nodeType
objectType: object.type
}).send();
console.error(err);
return;
@@ -282,24 +293,33 @@ async function handleDetachDatabase(context: azdata.ObjectExplorerContext, servi
if (!connectionUri) {
return;
}
const object = await getObjectInfoForContext(context);
try {
const parentUrn = await getParentUrn(context);
if (object.type !== ObjectManagement.NodeType.Database) {
throw new Error(objectManagementLoc.NotSupportedError(ObjectManagement.NodeType.Database));
}
const options: ObjectManagementDialogOptions = {
connectionUri: connectionUri,
isNewObject: false,
database: context.connectionProfile!.databaseName!,
objectType: context.nodeInfo.nodeType as ObjectManagement.NodeType,
objectName: context.nodeInfo.label,
parentUrn: parentUrn,
objectUrn: context.nodeInfo!.metadata!.urn,
database: object.name,
objectType: object.type,
objectName: object.name,
parentUrn: object.parentUrn,
objectUrn: object.urn,
objectExplorerContext: context
};
const dialog = new DetachDatabaseDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenDetachDatabaseDialog, {
objectType: object.type
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenDetachDatabaseDialog, err).withAdditionalProperties({
objectType: context.nodeInfo!.nodeType
objectType: object.type
}).send();
console.error(err);
await vscode.window.showErrorMessage(objectManagementLoc.OpenDetachDatabaseDialogError(getErrorMessage(err)));
@@ -323,7 +343,13 @@ async function handleAttachDatabase(context: azdata.ObjectExplorerContext, servi
objectExplorerContext: context
};
const dialog = new AttachDatabaseDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenAttachDatabaseDialog, {
objectType: ObjectManagement.NodeType.Database
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenAttachDatabaseDialog, err).withAdditionalProperties({
@@ -339,26 +365,33 @@ async function handleDropDatabase(context: azdata.ObjectExplorerContext, service
if (!connectionUri) {
return;
}
const object = await getObjectInfoForContext(context);
try {
const parentUrn = await getParentUrn(context);
const objectName = context.nodeInfo?.label ?? context.connectionProfile.databaseName;
const objectUrn = context.nodeInfo?.metadata?.urn ?? `Server/Database[@Name='${escapeSingleQuotes(context.connectionProfile.databaseName)}']`;
if (object.type !== ObjectManagement.NodeType.Database) {
throw new Error(objectManagementLoc.NotSupportedError(ObjectManagement.NodeType.Database));
}
const options: ObjectManagementDialogOptions = {
connectionUri: connectionUri,
isNewObject: false,
database: context.connectionProfile!.databaseName!,
objectType: ObjectManagement.NodeType.Database,
objectName: objectName,
parentUrn: parentUrn,
objectUrn: objectUrn,
database: object.name,
objectType: object.type,
objectName: object.name,
parentUrn: object.parentUrn,
objectUrn: object.urn,
objectExplorerContext: context
};
const dialog = new DropDatabaseDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenDropDatabaseDialog, {
objectType: object.type
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenDropDatabaseDialog, err).withAdditionalProperties({
objectType: ObjectManagement.NodeType.Database
objectType: object.type
}).send();
console.error(err);
await vscode.window.showErrorMessage(objectManagementLoc.OpenDropDatabaseDialogError(getErrorMessage(err)));
@@ -407,3 +440,39 @@ async function getParentUrn(context: azdata.ObjectExplorerContext): Promise<stri
}
return parentUrn;
}
interface ObjectInfo {
parentUrn: string;
name: string;
type: ObjectManagement.NodeType;
urn: string;
}
async function getObjectInfoForContext(context: azdata.ObjectExplorerContext): Promise<ObjectInfo> {
let nodeType: ObjectManagement.NodeType;
let objectName: string;
let objectUrn: string;
if (context.nodeInfo) {
nodeType = context.nodeInfo.nodeType as ObjectManagement.NodeType;
objectName = context.nodeInfo.metadata?.name;
objectUrn = context.nodeInfo.metadata?.urn;
} else {
// Node info will be missing for top level connection items like servers and databases, so make a best guess here based on connection info.
if (context.connectionProfile?.databaseName?.length > 0) {
nodeType = ObjectManagement.NodeType.Database;
objectName = context.connectionProfile.databaseName;
objectUrn = `Server/Database[@Name='${escapeSingleQuotes(objectName)}']`;
} else {
nodeType = ObjectManagement.NodeType.Server;
objectName = context.connectionProfile.serverName;
objectUrn = 'Server';
}
}
let parentUrn = await getParentUrn(context);
return {
parentUrn: parentUrn,
name: objectName,
type: nodeType,
urn: objectUrn
}
}

View File

@@ -16,6 +16,7 @@ export const enum FolderType {
}
export const PublicServerRoleName = 'public';
export const Windows = 'Windows';
export const CreateUserDocUrl = 'https://learn.microsoft.com/sql/t-sql/statements/create-user-transact-sql';
export const AlterUserDocUrl = 'https://learn.microsoft.com/sql/t-sql/statements/alter-user-transact-sql';
@@ -53,7 +54,9 @@ export const enum TelemetryActions {
UpdateObject = 'UpdateObject',
OpenDetachDatabaseDialog = 'OpenDetachDatabaseDialog',
OpenAttachDatabaseDialog = 'OpenAttachDatabaseDialog',
OpenDropDatabaseDialog = 'OpenDropDatabaseDialog'
OpenDropDatabaseDialog = 'OpenDropDatabaseDialog',
AttachDatabase = 'AttachDatabase',
DetachDatabase = 'DetachDatabase'
}
export const ObjectManagementViewName = 'ObjectManagement';

View File

@@ -276,7 +276,7 @@ export const enum UserType {
*/
SqlAuthentication = 'SqlAuthentication',
/**
* Authenticate with Azure Active Directory.
* Authenticate with Microsoft Entra.
*/
AADAuthentication = 'AADAuthentication',
/**
@@ -476,7 +476,7 @@ export interface DatabaseViewInfo extends ObjectManagement.ObjectViewInfo<Databa
azureMaxSizes?: AzureEditionDetails[];
pageVerifyOptions?: string[];
restrictAccessOptions?: string[];
dscOnOffOptions?: string[];
propertiesOnOffOptions?: string[];
dscElevateOptions?: string[];
dscEnableDisableOptions?: string[];
rowDataFileGroupsOptions?: string[];
@@ -498,7 +498,7 @@ export interface QueryStoreOptions {
queryStoreCaptureMode: string;
sizeBasedCleanupMode: string;
staleQueryThresholdInDays: number;
waitStatisticsCaptureMode?: boolean;
waitStatisticsCaptureMode?: string;
capturePolicyOptions?: QueryStoreCapturePolicyOptions;
currentStorageSizeInMB: number;
}
@@ -544,7 +544,7 @@ export enum AffinityType {
}
export interface Server extends ObjectManagement.SqlObject {
hardwareGeneration: string;
hardwareGeneration?: string;
language: string;
memoryInMB: number;
operatingSystem: string;
@@ -553,14 +553,14 @@ export interface Server extends ObjectManagement.SqlObject {
version: string;
isClustered: boolean;
isHadrEnabled: boolean;
isPolyBaseInstalled: boolean;
isXTPSupported: boolean;
isPolyBaseInstalled?: boolean;
isXTPSupported?: boolean;
product: string;
reservedStorageSizeMB: number;
reservedStorageSizeMB?: number;
rootDirectory: string;
serverCollation: string;
serviceTier: string;
storageSpaceUsageInMB: number;
serviceTier?: string;
storageSpaceUsageInMB?: number;
minServerMemory: NumericServerProperty;
maxServerMemory: NumericServerProperty;
autoProcessorAffinityMaskForAll: boolean;
@@ -593,8 +593,8 @@ export interface Server extends ObjectManagement.SqlObject {
* The server login types.
*/
export const enum ServerLoginMode {
Integrated, //windows auth only
Mixed // both sql server and windows auth
Integrated = 1, //windows auth only
Mixed = 2// both sql server and windows auth
}
/**

View File

@@ -56,6 +56,7 @@ export const allFiles = localize('objectManagement.allFiles', "All Files");
export const labelSelectFolder = localize('objectManagement.labelSelectFolder', "Select Folder");
export const DataFileLabel = localize('objectManagement.dataFileLabel', "Data");
export const LogFileLabel = localize('objectManagement.logFileLabel', "Log");
export const BackButtonLabel = localize('objectManagement.backButtonLabel', "Back");
export function ExplicitPermissionsTableLabelSelected(name: string): string { return localize('objectManagement.explicitPermissionsTableLabelSelected', "Explicit permissions for: {0}", name); }
export function EffectivePermissionsTableLabelSelected(name: string): string { return localize('objectManagement.effectivePermissionsTableLabelSelected', "Effective permissions for: {0}", name); }
@@ -247,7 +248,7 @@ export const PermissionToConnectText = localize('objectManagement.login.permissi
export const LoginLockedOutText = localize('objectManagement.login.lockedOutLabel', "Login is locked out");
export const WindowsAuthenticationTypeDisplayText = localize('objectManagement.login.windowsAuthenticationType', "Windows Authentication");
export const SQLAuthenticationTypeDisplayText = localize('objectManagement.login.sqlAuthenticationType', "SQL Authentication");
export const AADAuthenticationTypeDisplayText = localize('objectManagement.login.aadAuthenticationType', "Azure Active Directory Authentication");
export const AADAuthenticationTypeDisplayText = localize('objectManagement.login.aadAuthenticationType', "Microsoft Entra ID Authentication");
export const OldPasswordCannotBeEmptyError = localize('objectManagement.login.oldPasswordCannotBeEmptyError', "Old password cannot be empty.");
// User
@@ -255,7 +256,7 @@ export const UserTypeText = localize('objectManagement.user.type', "Type");
export const UserType_LoginMapped = localize('objectManagement.user.loginMapped', "Mapped to a server login");
export const UserType_WindowsUser = localize('objectManagement.user.windowsUser', "Mapped to a Windows user/group");
export const UserType_SqlAuthentication = localize('objectManagement.user.sqlAuth', "Authenticate with password");
export const UserType_AADAuthentication = localize('objectManagement.user.aadAuth', "Authenticate with Azure Active Directory");
export const UserType_AADAuthentication = localize('objectManagement.user.aadAuth', "Authenticate with Microsoft Entra");
export const UserType_NoLoginAccess = localize('objectManagement.user.noLogin', "No Login Access");
export const DefaultSchemaText = localize('objectManagement.user.defaultSchemaLabel', "Default schema");
export const LoginText = localize('objectManagement.user.loginLabel', "Login");
@@ -350,6 +351,7 @@ export const scanStartupProcsLabel = localize('objectManagement.scanStartupProcs
export const twoDigitYearCutoffLabel = localize('objectManagement.twoDigitYearCutoffLabel', "Two Digit Year Cutoff");
export const costThresholdParallelismLabel = localize('objectManagement.costThresholdParallelismLabel', "Cost Threshold Parallelism");
export const locksLabel = localize('objectManagement.locksLabel', "Locks");
export function locksValidation(minValue: number): string { return localize('objectManagement.locksValidation', "Value should be greater than {0}. Choose 0 for default settings.", minValue); }
export const maxDegreeParallelismLabel = localize('objectManagement.maxDegreeParallelismLabel', "Max Degree Parallelism");
export const queryWaitLabel = localize('objectManagement.queryWaitLabel', "Query Wait");
@@ -464,7 +466,9 @@ export const QueryStoreUsedText = localize('objectManagement.databaseProperties.
export const QueryStoreAvailableText = localize('objectManagement.databaseProperties.queryStoreAvailableText', "Query Store Available");
export const PurgeQueryDataButtonText = localize('objectManagement.databaseProperties.purgeQueryDataButtonText', "Purge Query Store Data");
export const YesText = localize('objectManagement.databaseProperties.yesText', "Yes");
export const NotAvailableText = localize('objectManagement.databaseProperties.notAvailableText', "N/A");
export const PurgeQueryStoreDataMessage = (databaseName: string) => localize('objectManagement.databaseProperties.purgeQueryStoreDataMessage', "Are you sure you want to purge the Query Store data from '{0}'?", databaseName);
export const fileGroupsNameInput = localize('objectManagement.filegroupsNameInput', "Filegroup Name");
// Util functions
export function getNodeTypeDisplayName(type: string, inTitle: boolean = false): string {

View File

@@ -66,13 +66,13 @@ export class ObjectManagementService extends BaseService implements IObjectManag
return this.runWithErrorHandling(contracts.SearchObjectRequest.type, params);
}
async detachDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Promise<string> {
const params: contracts.DetachDatabaseRequestParams = { connectionUri, database, objectUrn, dropConnections, updateStatistics, generateScript };
async detachDatabase(connectionUri: string, database: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Promise<string> {
const params: contracts.DetachDatabaseRequestParams = { connectionUri, database, dropConnections, updateStatistics, generateScript };
return this.runWithErrorHandling(contracts.DetachDatabaseRequest.type, params);
}
async dropDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Promise<string> {
const params: contracts.DropDatabaseRequestParams = { connectionUri, database, objectUrn, dropConnections, deleteBackupHistory, generateScript };
async dropDatabase(connectionUri: string, database: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Promise<string> {
const params: contracts.DropDatabaseRequestParams = { connectionUri, database, dropConnections, deleteBackupHistory, generateScript };
return this.runWithErrorHandling(contracts.DropDatabaseRequest.type, params);
}
@@ -91,8 +91,8 @@ export class ObjectManagementService extends BaseService implements IObjectManag
return this.runWithErrorHandling(contracts.GetAssociatedFilesRequest.type, params);
}
async purgeQueryStoreData(connectionUri: string, database: string, objectUrn: string): Promise<void> {
const params: contracts.purgeQueryStoreDataRequestParams = { connectionUri, database, objectUrn };
async purgeQueryStoreData(connectionUri: string, database: string): Promise<void> {
const params: contracts.PurgeQueryStoreDataRequestParams = { connectionUri, database };
return this.runWithErrorHandling(contracts.PurgeQueryStoreDataRequest.type, params);
}
}
@@ -262,7 +262,7 @@ export class TestObjectManagementService implements IObjectManagementService {
return this.delayAndResolve(items);
}
async detachDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Promise<string> {
async detachDatabase(connectionUri: string, database: string, dropConnections: boolean, updateStatistics: boolean, generateScript: boolean): Promise<string> {
return this.delayAndResolve('');
}
@@ -270,7 +270,7 @@ export class TestObjectManagementService implements IObjectManagementService {
return this.delayAndResolve('');
}
dropDatabase(connectionUri: string, database: string, objectUrn: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Thenable<string> {
dropDatabase(connectionUri: string, database: string, dropConnections: boolean, deleteBackupHistory: boolean, generateScript: boolean): Thenable<string> {
return this.delayAndResolve('');
}
@@ -282,7 +282,7 @@ export class TestObjectManagementService implements IObjectManagementService {
return this.delayAndResolve([]);
}
async purgeQueryStoreData(connectionUri: string, database: string, objectUrn: string): Promise<void> {
async purgeQueryStoreData(connectionUri: string, database: string): Promise<void> {
return this.delayAndResolve([]);
}
@@ -512,7 +512,7 @@ export class TestObjectManagementService implements IObjectManagementService {
pageVerifyOptions: ['CHECKSUM', 'NONE', 'TORN_PAGE_DETECTION'],
dscElevateOptions: ['OFF', 'WHEN_SUPPORTED', 'FAIL_UNSUPPORTED'],
dscEnableDisableOptions: ['ENABLED', 'DISABLED'],
dscOnOffOptions: ['ON', 'OFF'],
propertiesOnOffOptions: ['ON', 'OFF'],
rowDataFileGroupsOptions: ['PRIMARY', 'RowDataGroup1', 'RowDataGroup2'],
fileStreamFileGroupsOptions: ['PRIMARY', 'FileStreamGroup1', 'FileStreamGroup2'],
fileTypesOptions: ['ROWS', 'LOG', 'FILESTREAM'],

View File

@@ -7,7 +7,7 @@ import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { DatabaseFileData, IObjectManagementService, ObjectManagement } from 'mssql';
import { Database, DatabaseViewInfo } from '../interfaces';
import { AttachDatabaseDocUrl } from '../constants';
import { AttachDatabaseDocUrl, TelemetryActions } from '../constants';
import * as loc from '../localizedConstants';
import { RemoveText } from '../../ui/localizedConstants';
import { DefaultMinTableRowCount, DialogButton, getTableHeight } from '../../ui/dialogBase';
@@ -62,16 +62,20 @@ export class AttachDatabaseDialog extends ObjectManagementDialogBase<Database, D
const buttonContainer = this.addButtonsForTable(this._databasesTable, addButton, removeButton);
this._nameField = this.createInputBox(async newValue => {
let selectedRow = this._databasesTable.selectedRows[0];
let dbFile = this._databasesToAttach[selectedRow];
dbFile.databaseName = newValue;
if (this._databasesTable.selectedRows?.length > 0) {
let selectedRow = this._databasesTable.selectedRows[0];
let dbFile = this._databasesToAttach[selectedRow];
dbFile.databaseName = newValue;
}
}, {});
this._nameContainer = this.createLabelInputContainer(loc.AttachAsText, this._nameField);
this._ownerDropdown = this.createDropdown(loc.OwnerText, async newValue => {
let selectedRow = this._databasesTable.selectedRows[0];
let dbFile = this._databasesToAttach[selectedRow];
dbFile.owner = newValue;
if (this._databasesTable.selectedRows?.length > 0) {
let selectedRow = this._databasesTable.selectedRows[0];
let dbFile = this._databasesToAttach[selectedRow];
dbFile.owner = newValue;
}
}, this.viewInfo.loginNames.options, this.viewInfo.loginNames.options[this.viewInfo.loginNames.defaultValueIndex]);
this._ownerContainer = this.createLabelInputContainer(loc.OwnerText, this._ownerDropdown);
@@ -174,6 +178,10 @@ export class AttachDatabaseDialog extends ObjectManagementDialogBase<Database, D
return AttachDatabaseDocUrl;
}
protected override get actionName(): string {
return TelemetryActions.AttachDatabase;
}
protected override async validateInput(): Promise<string[]> {
let errors = [];
if (this._databasesToAttach.length === 0) {

View File

@@ -12,13 +12,13 @@ import { CreateDatabaseDocUrl, DatabaseGeneralPropertiesDocUrl, DatabaseFilesPro
import { Database, DatabaseFile, DatabaseScopedConfigurationsInfo, DatabaseViewInfo, FileGrowthType, FileGroup, FileGroupType } from '../interfaces';
import { convertNumToTwoDecimalStringInMB } from '../utils';
import { isUndefinedOrNull } from '../../types';
import { deepClone } from '../../util/objects';
import { DatabaseFileDialog } from './databaseFileDialog';
import * as vscode from 'vscode';
const MAXDOP_Max_Limit = 32767;
const PAUSED_RESUMABLE_INDEX_Max_Limit = 71582;
const DscTableRowLength = 15;
const Dialog_Width = '750px';
export class DatabaseDialog extends ObjectManagementDialogBase<Database, DatabaseViewInfo> {
// Database Properties tabs
@@ -59,8 +59,14 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private filestreamFilegroupsTable: azdata.TableComponent;
private memoryOptimizedFilegroupsTable: azdata.TableComponent;
private rowsFilegroupNameInput: azdata.InputBoxComponent;
private rowsFilegroupNameContainer: azdata.FlexContainer;
private rowsFileGroupButtonContainer: azdata.FlexContainer;
private filestreamFilegroupNameInput: azdata.InputBoxComponent;
private filestreamFilegroupNameContainer: azdata.FlexContainer;
private filestreamFileGroupButtonContainer: azdata.FlexContainer;
private memoryOptimizedFilegroupNameInput: azdata.InputBoxComponent;
private memoryOptimizedFilegroupNameContainer: azdata.FlexContainer;
private memoryOptimizedFileGroupButtonContainer: azdata.FlexContainer;
private newFileGroupTemporaryId: number = 0;
private rowDataFileGroupsTableRows: FileGroup[] = [];
private filestreamDataFileGroupsTableRows: FileGroup[] = [];
@@ -82,7 +88,6 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private readonly dscTabId: string = 'dscDatabaseId';
private dscTabSectionsContainer: azdata.Component[] = [];
private dscTable: azdata.TableComponent;
private dscOriginalData: DatabaseScopedConfigurationsInfo[];
private currentRowId: number;
private valueForPrimaryDropdown: azdata.DropDownComponent;
private valueForSecondaryDropdown: azdata.DropDownComponent;
@@ -90,12 +95,10 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private valueForPrimaryInput: azdata.InputBoxComponent;
private valueForSecondaryInput: azdata.InputBoxComponent;
private setSecondaryCheckboxForInputType: azdata.CheckBoxComponent;
private dscPrimaryValueDropdownGroup: azdata.GroupContainer;
private dscSecondaryValueDropdownGroup: azdata.GroupContainer;
private dscSecondaryCheckboxForDropdownGroup: azdata.GroupContainer;
private dscPrimaryValueInputGroup: azdata.GroupContainer;
private dscSecondaryValueInputGroup: azdata.GroupContainer;
private dscSecondaryCheckboxForInputGroup: azdata.GroupContainer;
private dscPrimaryValueDropdown: azdata.FlexContainer;
private dscSecondaryValueDropdown: azdata.FlexContainer;
private dscPrimaryValueInput: azdata.FlexContainer;
private dscSecondaryValueInput: azdata.FlexContainer;
private setFocusToInput: azdata.InputBoxComponent = undefined;
private currentRowObjectInfo: DatabaseScopedConfigurationsInfo;
// Query store Tab
@@ -110,7 +113,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private queryStoreCaptureMode: azdata.DropDownComponent;
private sizeBasedCleanupMode: azdata.DropDownComponent;
private stateQueryThresholdInDays: azdata.InputBoxComponent;
private waitStatisticsCaptureMode: azdata.CheckBoxComponent;
private waitStatisticsCaptureMode: azdata.DropDownComponent;
private executionCount: azdata.InputBoxComponent;
private staleThreshold: azdata.DropDownComponent;
private totalCompileCPUTimeInMS: azdata.InputBoxComponent;
@@ -120,6 +123,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
options.width = Dialog_Width;
super(objectManagementService, options);
}
@@ -213,8 +217,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Initilaize FileGroups Tab
if (!isUndefinedOrNull(this.objectInfo.filegroups)) {
const rowsFileGroupSection = await this.initializeRowsFileGroupSection();
const fileStreamFileGroupSection = this.initializeFileStreamFileGroupSection();
const memoryOptimizedFileGroupSection = this.initializeMemoryOptimizedFileGroupSection();
const fileStreamFileGroupSection = await this.initializeFileStreamFileGroupSection();
const memoryOptimizedFileGroupSection = await this.initializeMemoryOptimizedFileGroupSection();
this.fileGroupsTab = {
title: localizedConstants.FileGroupsSectionHeader,
id: this.fileGroupsTabId,
@@ -265,6 +269,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
const propertiesTabGroup = { title: '', tabs: tabs };
const propertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
.withTabs([propertiesTabGroup])
.withLayout({
orientation: azdata.TabOrientation.Vertical
})
.withProps({
CSSStyles: {
'margin': '-10px 0px 0px -10px'
@@ -740,8 +747,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
defaultFileGrowthInMb: defaultFileGrowthInMb,
defaultFileGrowthInPercent: defaultFileGrowthInPercent,
defaultMaxFileSizeLimitedToInMb: defaultMaxFileSizeLimitedToInMb
}
});
},
connectionUri: this.options.connectionUri
}, this.objectManagementService);
await dialog.open();
return await dialog.waitForClose();
}
@@ -785,17 +793,16 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
'margin-left': '10px'
}
}).component();
this.rowsFilegroupNameInput = this.getFilegroupNameInput(this.rowsFilegroupsTable, FileGroupType.RowsFileGroup);
this.rowsFilegroupNameContainer = await this.getFilegroupNameGroup(this.rowsFilegroupsTable, FileGroupType.RowsFileGroup);
const addButtonComponent: DialogButton = {
buttonAriaLabel: localizedConstants.AddFilegroupText,
buttonHandler: () => this.onAddDatabaseFileGroupsButtonClicked(this.rowsFilegroupsTable)
};
const removeButtonComponent: DialogButton = {
buttonAriaLabel: localizedConstants.RemoveButton,
buttonHandler: () => this.onAddDatabaseFileGroupsButtonClicked(this.rowsFilegroupsTable)
buttonHandler: () => this.onRemoveDatabaseFileGroupsButtonClicked(this.rowsFilegroupsTable)
};
const rowsFileGroupButtonContainer = this.addButtonsForTable(this.rowsFilegroupsTable, addButtonComponent, removeButtonComponent);
this.rowsFileGroupButtonContainer = this.addButtonsForTable(this.rowsFilegroupsTable, addButtonComponent, removeButtonComponent);
this.disposables.push(
this.rowsFilegroupsTable.onCellAction(async (arg: azdata.ICheckboxCellActionEventArgs) => {
let filegroup = this.rowDataFileGroupsTableRows[arg.row];
@@ -821,23 +828,21 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
async () => {
if (this.rowsFilegroupsTable.selectedRows.length === 1) {
const fileGroup = this.rowDataFileGroupsTableRows[this.rowsFilegroupsTable.selectedRows[0]];
await this.rowsFilegroupNameInput.updateCssStyles({ 'visibility': fileGroup.id < 0 ? 'visible' : 'hidden' });
this.rowsFilegroupNameContainer.display = fileGroup.id < 0 ? 'inline-flex' : 'none';
this.rowsFilegroupNameInput.value = fileGroup.name;
this.onFormFieldChange();
}
}
)
);
const rowContainer = this.modelView.modelBuilder.flexContainer().withItems([this.rowsFilegroupNameInput]).component();
rowContainer.addItems([rowsFileGroupButtonContainer], { flex: '0 0 auto' });
return this.createGroup(localizedConstants.RowsFileGroupsSectionText, [this.rowsFilegroupsTable, rowContainer], true);
return this.createGroup(localizedConstants.RowsFileGroupsSectionText, [this.rowsFilegroupsTable, this.rowsFilegroupNameContainer, this.rowsFileGroupButtonContainer], true);
}
/**
* Initializes the filestream filegroups section and updates the table data
* @returns filestream data filegroups container
*/
private initializeFileStreamFileGroupSection(): azdata.GroupContainer {
private async initializeFileStreamFileGroupSection(): Promise<azdata.GroupContainer> {
const data = this.getTableData(FileGroupType.FileStreamDataFileGroup);
this.filestreamFilegroupsTable = this.modelView.modelBuilder.table().withProps({
columns: [{
@@ -861,7 +866,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
'margin-left': '10px'
}
}).component();
this.filestreamFilegroupNameInput = this.getFilegroupNameInput(this.filestreamFilegroupsTable, FileGroupType.FileStreamDataFileGroup);
this.filestreamFilegroupNameContainer = await this.getFilegroupNameGroup(this.filestreamFilegroupsTable, FileGroupType.FileStreamDataFileGroup);
const addButtonComponent: DialogButton = {
buttonAriaLabel: localizedConstants.AddFilegroupText,
buttonHandler: () => this.onAddDatabaseFileGroupsButtonClicked(this.filestreamFilegroupsTable)
@@ -870,8 +875,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
buttonAriaLabel: localizedConstants.RemoveButton,
buttonHandler: () => this.onRemoveDatabaseFileGroupsButtonClicked(this.filestreamFilegroupsTable)
};
const filestreamFileGroupButtonContainer = this.addButtonsForTable(this.filestreamFilegroupsTable, addButtonComponent, removeButtonComponent);
this.filestreamFileGroupButtonContainer = this.addButtonsForTable(this.filestreamFilegroupsTable, addButtonComponent, removeButtonComponent);
this.disposables.push(
this.filestreamFilegroupsTable.onCellAction(async (arg: azdata.ICheckboxCellActionEventArgs) => {
let filegroup = this.filestreamDataFileGroupsTableRows[arg.row];
@@ -893,7 +897,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
async () => {
if (this.filestreamFilegroupsTable.selectedRows.length === 1) {
const fileGroup = this.filestreamDataFileGroupsTableRows[this.filestreamFilegroupsTable.selectedRows[0]];
await this.filestreamFilegroupNameInput.updateCssStyles({ 'visibility': fileGroup.id < 0 ? 'visible' : 'hidden' });
this.filestreamFilegroupNameContainer.display = fileGroup.id < 0 ? 'inline-flex' : 'none';
this.filestreamFilegroupNameInput.value = fileGroup.name;
this.onFormFieldChange();
}
@@ -901,16 +905,14 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
)
);
const filestreamContainer = this.modelView.modelBuilder.flexContainer().withItems([this.filestreamFilegroupNameInput]).component();
filestreamContainer.addItems([filestreamFileGroupButtonContainer], { flex: '0 0 auto' });
return this.createGroup(localizedConstants.FileStreamFileGroupsSectionText, [this.filestreamFilegroupsTable, filestreamContainer], true);
return this.createGroup(localizedConstants.FileStreamFileGroupsSectionText, [this.filestreamFilegroupsTable, this.filestreamFilegroupNameContainer, this.filestreamFileGroupButtonContainer], true);
}
/**
* Initializes the memory optimized filegroups section and updates the table data
* @returns Memory optimized filegroups container
*/
private initializeMemoryOptimizedFileGroupSection(): azdata.GroupContainer {
private async initializeMemoryOptimizedFileGroupSection(): Promise<azdata.GroupContainer> {
const data = this.getTableData(FileGroupType.MemoryOptimizedDataFileGroup);
this.memoryOptimizedFilegroupsTable = this.modelView.modelBuilder.table().withProps({
columns: [{
@@ -928,23 +930,23 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
'margin-left': '10px'
}
}).component();
this.memoryOptimizedFilegroupNameInput = this.getFilegroupNameInput(this.memoryOptimizedFilegroupsTable, FileGroupType.MemoryOptimizedDataFileGroup);
this.memoryOptimizedFilegroupNameContainer = await this.getFilegroupNameGroup(this.memoryOptimizedFilegroupsTable, FileGroupType.MemoryOptimizedDataFileGroup);
const addButtonComponent: DialogButton = {
buttonAriaLabel: localizedConstants.AddFilegroupText,
buttonHandler: () => this.onAddDatabaseFileGroupsButtonClicked(this.memoryOptimizedFilegroupsTable)
buttonHandler: () => this.onAddDatabaseFileGroupsButtonClicked(this.memoryOptimizedFilegroupsTable),
enabled: this.memoryoptimizedFileGroupsTableRows.length < 1
};
const removeButtonComponent: DialogButton = {
buttonAriaLabel: localizedConstants.RemoveButton,
buttonHandler: () => this.onRemoveDatabaseFileGroupsButtonClicked(this.memoryOptimizedFilegroupsTable)
};
const memoryOptimizedFileGroupButtonContainer = this.addButtonsForTable(this.memoryOptimizedFilegroupsTable, addButtonComponent, removeButtonComponent);
this.memoryOptimizedFileGroupButtonContainer = this.addButtonsForTable(this.memoryOptimizedFilegroupsTable, addButtonComponent, removeButtonComponent);
this.disposables.push(
this.memoryOptimizedFilegroupsTable.onRowSelected(
async () => {
if (this.memoryOptimizedFilegroupsTable.selectedRows.length === 1) {
const fileGroup = this.memoryoptimizedFileGroupsTableRows[this.memoryOptimizedFilegroupsTable.selectedRows[0]];
await this.memoryOptimizedFilegroupNameInput.updateCssStyles({ 'visibility': fileGroup.id < 0 ? 'visible' : 'hidden' });
this.memoryOptimizedFilegroupNameContainer.display = fileGroup.id < 0 ? 'inline-flex' : 'none';
this.memoryOptimizedFilegroupNameInput.value = fileGroup.name;
this.onFormFieldChange();
}
@@ -952,9 +954,20 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
)
);
const memoryOptimizedContainer = this.modelView.modelBuilder.flexContainer().withItems([this.memoryOptimizedFilegroupNameInput]).component();
memoryOptimizedContainer.addItems([memoryOptimizedFileGroupButtonContainer], { flex: '0 0 auto' });
return this.createGroup(localizedConstants.MemoryOptimizedFileGroupsSectionText, [this.memoryOptimizedFilegroupsTable, memoryOptimizedContainer], true);
return this.createGroup(localizedConstants.MemoryOptimizedFileGroupsSectionText, [this.memoryOptimizedFilegroupsTable, this.memoryOptimizedFilegroupNameContainer, this.memoryOptimizedFileGroupButtonContainer], true);
}
/**
* Overrides declarative table add button enabled/disabled state
* @param table table component
* @returns table add button enabled/disabled state
*/
public override addButtonEnabled(table: azdata.TableComponent | azdata.DeclarativeTableComponent): boolean {
let enabled = true;
if (table === this.memoryOptimizedFilegroupsTable) {
enabled = this.memoryoptimizedFileGroupsTableRows.length < 1;
}
return enabled;
}
/**
@@ -1014,6 +1027,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Refresh the table with new row data
this.updateFileGroupsOptionsAndTableRows();
await this.setTableData(table, newData, DefaultMaxTableRowCount);
table.setActiveCell(table.data?.length - 1, 0);
}
}
@@ -1046,7 +1060,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
const removeFilegroupIndex = this.objectInfo.filegroups.indexOf(this.rowDataFileGroupsTableRows[this.rowsFilegroupsTable.selectedRows[0]]);
this.objectInfo.filegroups?.splice(removeFilegroupIndex, 1);
var newData = this.getTableData(FileGroupType.RowsFileGroup);
await this.rowsFilegroupNameInput.updateCssStyles({ 'visibility': 'hidden' });
this.rowsFilegroupNameContainer.display = 'none';
}
}
else if (table === this.filestreamFilegroupsTable) {
@@ -1054,7 +1068,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
const removeFilegroupIndex = this.objectInfo.filegroups.indexOf(this.filestreamDataFileGroupsTableRows[this.filestreamFilegroupsTable.selectedRows[0]]);
this.objectInfo.filegroups?.splice(removeFilegroupIndex, 1);
var newData = this.getTableData(FileGroupType.FileStreamDataFileGroup);
await this.filestreamFilegroupNameInput.updateCssStyles({ 'visibility': 'hidden' });
this.filestreamFilegroupNameContainer.display = 'none';
}
}
else if (table === this.memoryOptimizedFilegroupsTable) {
@@ -1062,13 +1076,38 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
const removeFilegroupIndex = this.objectInfo.filegroups.indexOf(this.memoryoptimizedFileGroupsTableRows[this.memoryOptimizedFilegroupsTable.selectedRows[0]]);
this.objectInfo.filegroups?.splice(removeFilegroupIndex, 1);
var newData = this.getTableData(FileGroupType.MemoryOptimizedDataFileGroup);
await this.memoryOptimizedFilegroupNameInput.updateCssStyles({ 'visibility': 'hidden' });
this.memoryOptimizedFilegroupNameContainer.display = 'none';
}
}
// Refresh the individual table rows object and table with updated data
this.updateFileGroupsOptionsAndTableRows();
await this.setTableData(table, newData)
await this.setTableData(table, newData);
if (table.selectedRows !== undefined && table.selectedRows[0] !== undefined && table.selectedRows[0] < table.data?.length) {
table.setActiveCell(table.selectedRows[0], 0);
}
}
/**
* Creates the group container for filegroups input section
* @param table table component
* @param filegroupType filegroup type
* @returns filegroup name group container
*/
private async getFilegroupNameGroup(table: azdata.TableComponent, filegroupType: FileGroupType): Promise<azdata.FlexContainer> {
const fgInput = this.getFilegroupNameInput(table, filegroupType);
if (table === this.rowsFilegroupsTable) {
this.rowsFilegroupNameInput = fgInput;
} else if (table === this.filestreamFilegroupsTable) {
this.filestreamFilegroupNameInput = fgInput;
} else if (table === this.memoryOptimizedFilegroupsTable) {
this.memoryOptimizedFilegroupNameInput = fgInput;
}
let fgInputGroupcontainer = this.createLabelInputContainer(localizedConstants.fileGroupsNameInput, [fgInput], false);
await fgInputGroupcontainer.updateCssStyles({ 'margin': '0px 0px -10px 10px' });
fgInputGroupcontainer.display = 'none';
return fgInputGroupcontainer;
}
/**
@@ -1100,9 +1139,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
inputType: 'text',
enabled: true,
value: '',
width: 200,
CSSStyles: { 'margin': '5px 0px 0px 10px', 'visibility': 'hidden' }
})
width: DefaultInputWidth
});
}
/**
@@ -1297,7 +1335,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
//#region Database Properties - Data Scoped configurations Tab
private async initializeDatabaseScopedConfigurationSection(): Promise<void> {
this.dscOriginalData = deepClone(this.objectInfo.databaseScopedConfigurations);
// Configurations that doesn't support secondary replica
let secondaryUnsupportedConfigsSet = new Set<number>([11, 12, 25, 6, 21]);
const dscNameColumn: azdata.TableColumn = {
type: azdata.ColumnType.text,
value: localizedConstants.DatabaseScopedOptionsColumnHeader,
@@ -1317,9 +1356,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
this.dscTable = this.modelView.modelBuilder.table().withProps({
columns: [dscNameColumn, primaryValueColumn, secondaryValueColumn],
data: this.objectInfo.databaseScopedConfigurations.map(metaData => {
return [metaData.name,
return [metaData.name.toLocaleUpperCase(),
metaData.valueForPrimary,
metaData.valueForSecondary]
secondaryUnsupportedConfigsSet.has(metaData.id) ? localizedConstants.NotAvailableText : metaData.valueForSecondary]
}),
height: getTableHeight(this.objectInfo.databaseScopedConfigurations.length, 1, DscTableRowLength),
width: DefaultTableWidth
@@ -1355,7 +1394,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Cannot set the 'ELEVATE_ONLINE (11) and ELEVATE_RESUMABLE (12)' option for the secondaries replica while this option is only allowed to be set for the primary
if (this.currentRowObjectInfo.id === 11 || this.currentRowObjectInfo.id === 12) {
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'visible' });
await this.dscPrimaryValueDropdown.updateCssStyles({ 'display': 'inline-flex' });
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.dscElevateOptions) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
@@ -1378,7 +1417,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
}
// Cannot set the 'AUTO_ABORT_PAUSED_INDEX (25)' option for the secondaries replica while this option is only allowed to be set for the primary.
else if (this.currentRowObjectInfo.id === 25) {
await this.dscPrimaryValueInputGroup.updateCssStyles({ 'visibility': 'visible', 'margin-top': '-175px' });
await this.dscPrimaryValueInput.updateCssStyles({ 'display': 'inline-flex' });
await this.valueForPrimaryInput.updateProperties({
value: this.currentRowObjectInfo.valueForPrimary
, max: PAUSED_RESUMABLE_INDEX_Max_Limit
@@ -1387,18 +1426,18 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Can only set OFF/Azure blob storage endpoint to the 'LEDGER_DIGEST_STORAGE_ENDPOINT (38)'s primary and secondary values
else if (this.currentRowObjectInfo.id === 38) {
await this.showDropdownsSection(isSecondaryCheckboxChecked);
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify([this.viewInfo.dscOnOffOptions[1]]) ||
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify([this.viewInfo.propertiesOnOffOptions[1]]) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: [this.viewInfo.dscOnOffOptions[1]] // Only OFF is allowed for primary value
values: [this.viewInfo.propertiesOnOffOptions[1]] // Only OFF is allowed for primary value
, value: this.currentRowObjectInfo.valueForPrimary
, editable: true // This is to allow the user to enter the Azure blob storage endpoint
});
}
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify([this.viewInfo.dscOnOffOptions[1]]) ||
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify([this.viewInfo.propertiesOnOffOptions[1]]) ||
this.valueForSecondaryDropdown.value !== this.currentRowObjectInfo.valueForSecondary) {
await this.valueForSecondaryDropdown.updateProperties({
values: [this.viewInfo.dscOnOffOptions[1]] // Only OFF is allowed for secondary value
values: [this.viewInfo.propertiesOnOffOptions[1]] // Only OFF is allowed for secondary value
, value: this.currentRowObjectInfo.valueForSecondary
, editable: true // This is to allow the user to enter the Azure blob storage endpoint
});
@@ -1407,11 +1446,11 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Cannot set the 'IDENTITY_CACHE (6)' option for the secondaries replica while this option is only allowed to be set for the primary.
// Cannot set the 'GLOBAL_TEMPORARY_TABLE_AUTO_DROP (21)' option for the secondaries replica while this option is only allowed to be set for the primary.
else if (this.currentRowObjectInfo.id === 6 || this.currentRowObjectInfo.id === 21) {
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'visible' });
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
await this.dscPrimaryValueDropdown.updateCssStyles({ 'display': 'inline-flex' });
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForPrimary
});
}
@@ -1437,17 +1476,17 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// All other options accepts primary and seconday values as ON/OFF/PRIMARY(only secondary)
else {
await this.showDropdownsSection(isSecondaryCheckboxChecked);
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForPrimary
});
}
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForSecondaryDropdown.value !== this.currentRowObjectInfo.valueForSecondary) {
await this.valueForSecondaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForSecondary
});
}
@@ -1481,22 +1520,20 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
width: 150,
min: 0
});
const primaryContainer = this.createLabelInputContainer(localizedConstants.ValueForPrimaryColumnHeader, this.valueForPrimaryInput);
this.dscPrimaryValueInputGroup = this.createGroup('', [primaryContainer], false, true);
await this.dscPrimaryValueInputGroup.updateCssStyles({ 'visibility': 'hidden' });
this.dscPrimaryValueInput = this.createLabelInputContainer(localizedConstants.ValueForPrimaryColumnHeader, this.valueForPrimaryInput);
this.dscPrimaryValueInput.display = 'none';
// Apply Primary To Secondary checkbox
this.setSecondaryCheckboxForInputType = this.createCheckbox(localizedConstants.SetSecondaryText, async (checked) => {
await this.dscSecondaryValueInputGroup.updateCssStyles({ 'visibility': checked ? 'hidden' : 'visible' });
this.currentRowObjectInfo.valueForSecondary = checked ? this.currentRowObjectInfo.valueForPrimary : this.dscOriginalData[this.currentRowId].valueForSecondary;
await this.dscSecondaryValueInput.updateCssStyles({ 'display': checked ? 'none' : 'inline-flex' });
this.currentRowObjectInfo.valueForSecondary = this.currentRowObjectInfo.valueForPrimary;
await this.valueForSecondaryInput.updateProperties({ value: this.currentRowObjectInfo.valueForSecondary });
if (this.dscTable.data[this.currentRowId][2] !== this.currentRowObjectInfo.valueForSecondary) {
this.dscTable.data[this.currentRowId][2] = this.currentRowObjectInfo.valueForSecondary;
await this.updateDscTable(this.dscTable.data);
}
}, true);
this.dscSecondaryCheckboxForInputGroup = this.createGroup('', [this.setSecondaryCheckboxForInputType], false, true);
await this.dscSecondaryCheckboxForInputGroup.updateCssStyles({ 'visibility': 'hidden' });
this.setSecondaryCheckboxForInputType.display = 'none';
// Value for Secondary
this.valueForSecondaryInput = this.createInputBox(async (newValue) => {
@@ -1513,13 +1550,12 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
width: 150,
min: 0
});
const secondaryContainer = this.createLabelInputContainer(localizedConstants.ValueForSecondaryColumnHeader, this.valueForSecondaryInput);
this.dscSecondaryValueInputGroup = this.createGroup('', [secondaryContainer], false, true);
await this.dscSecondaryValueInputGroup.updateCssStyles({ 'visibility': 'hidden' });
this.dscSecondaryValueInput = this.createLabelInputContainer(localizedConstants.ValueForSecondaryColumnHeader, this.valueForSecondaryInput);
this.dscSecondaryValueInput.display = 'none';
const maxDopGroup = this.createGroup('', [this.dscPrimaryValueInputGroup, this.dscSecondaryCheckboxForInputGroup, this.dscSecondaryValueInputGroup], false, true);
await maxDopGroup.updateCssStyles({ 'margin-left': '-10px' });
return maxDopGroup;
const inputTypegroup = this.createGroup('', [this.dscPrimaryValueInput, this.setSecondaryCheckboxForInputType, this.dscSecondaryValueInput], false, true);
await inputTypegroup.updateCssStyles({ 'margin-top': '-30px' });
return inputTypegroup;
}
/**
@@ -1543,18 +1579,16 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
await this.updateDscTable(this.dscTable.data);
}
}, [], '', true, 150)
const primaryContainer = this.createLabelInputContainer(localizedConstants.ValueForPrimaryColumnHeader, this.valueForPrimaryDropdown);
this.dscPrimaryValueDropdownGroup = this.createGroup('', [primaryContainer], false, true);
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
this.dscPrimaryValueDropdown = this.createLabelInputContainer(localizedConstants.ValueForPrimaryColumnHeader, this.valueForPrimaryDropdown);
this.dscPrimaryValueDropdown.display = 'none';
// Apply Primary To Secondary checkbox
this.setSecondaryCheckboxForDropdowns = this.createCheckbox(localizedConstants.SetSecondaryText, async (checked) => {
await this.dscSecondaryValueDropdownGroup.updateCssStyles({ 'visibility': checked ? 'hidden' : 'visible' });
this.currentRowObjectInfo.valueForSecondary = checked ? this.currentRowObjectInfo.valueForPrimary : this.dscOriginalData[this.currentRowId].valueForSecondary;
await this.dscSecondaryValueDropdown.updateCssStyles({ 'display': checked ? 'none' : 'inline-flex' });
this.currentRowObjectInfo.valueForSecondary = this.currentRowObjectInfo.valueForPrimary;
await this.valueForSecondaryDropdown.updateProperties({ value: this.currentRowObjectInfo.valueForSecondary });
}, true);
this.dscSecondaryCheckboxForDropdownGroup = this.createGroup('', [this.setSecondaryCheckboxForDropdowns], false, true);
await this.dscSecondaryCheckboxForDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
this.setSecondaryCheckboxForDropdowns.display = 'none';
// Value for Secondary
this.valueForSecondaryDropdown = this.createDropdown(localizedConstants.ValueForSecondaryColumnHeader, async (newValue) => {
@@ -1566,13 +1600,10 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
}
}
}, [], '', true, 150);
const secondaryContainer = this.createLabelInputContainer(localizedConstants.ValueForSecondaryColumnHeader, this.valueForSecondaryDropdown);
this.dscSecondaryValueDropdownGroup = this.createGroup('', [secondaryContainer], false, true);
await this.dscSecondaryValueDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
this.dscSecondaryValueDropdown = this.createLabelInputContainer(localizedConstants.ValueForSecondaryColumnHeader, this.valueForSecondaryDropdown);
this.dscSecondaryValueDropdown.display = 'none';
const valueGroup = this.createGroup('', [this.dscPrimaryValueDropdownGroup, this.dscSecondaryCheckboxForDropdownGroup, this.dscSecondaryValueDropdownGroup], true, true);
await valueGroup.updateCssStyles({ 'margin-left': '-10px' });
return valueGroup;
return this.createGroup('', [this.dscPrimaryValueDropdown, this.setSecondaryCheckboxForDropdowns, this.dscSecondaryValueDropdown], true, true);
}
/**
@@ -1581,9 +1612,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
*/
private async showDropdownsSection(isSecondaryCheckboxChecked: boolean): Promise<void> {
this.setSecondaryCheckboxForDropdowns.checked = isSecondaryCheckboxChecked;
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'visible' });
await this.dscSecondaryCheckboxForDropdownGroup.updateCssStyles({ 'visibility': 'visible' });
await this.dscSecondaryValueDropdownGroup.updateCssStyles({ 'visibility': isSecondaryCheckboxChecked ? 'hidden' : 'visible' });
this.setSecondaryCheckboxForDropdowns.display = 'inline-flex';
await this.dscPrimaryValueDropdown.updateCssStyles({ 'display': 'inline-flex' });
await this.dscSecondaryValueDropdown.updateCssStyles({ 'display': isSecondaryCheckboxChecked ? 'none' : 'inline-flex' });
}
/**
@@ -1592,21 +1623,21 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
*/
private async showInputSection(isSecondaryCheckboxChecked: boolean): Promise<void> {
this.setSecondaryCheckboxForInputType.checked = isSecondaryCheckboxChecked;
await this.dscPrimaryValueInputGroup.updateCssStyles({ 'visibility': 'visible', 'margin-top': '-175px' });
await this.dscSecondaryCheckboxForInputGroup.updateCssStyles({ 'visibility': 'visible', 'margin-top': '-120px' });
await this.dscSecondaryValueInputGroup.updateCssStyles({ 'visibility': isSecondaryCheckboxChecked ? 'hidden' : 'visible', 'margin-top': '-85px' });
this.setSecondaryCheckboxForInputType.display = 'inline-flex';
await this.dscPrimaryValueInput.updateCssStyles({ 'display': 'inline-flex' });
await this.dscSecondaryValueInput.updateCssStyles({ 'display': isSecondaryCheckboxChecked ? 'none' : 'inline-flex' });
}
/**
* Set all primary and secondary groups to hidden
*/
private async hideDropdownAndInputSections(): Promise<void> {
await this.dscPrimaryValueInputGroup.updateCssStyles({ 'visibility': 'hidden', 'margin-top': '0px' });
await this.dscSecondaryCheckboxForInputGroup.updateCssStyles({ 'visibility': 'hidden', 'margin-top': '0px' });
await this.dscSecondaryValueInputGroup.updateCssStyles({ 'visibility': 'hidden', 'margin-top': '0px' });
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
await this.dscSecondaryCheckboxForDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
await this.dscSecondaryValueDropdownGroup.updateCssStyles({ 'visibility': 'hidden' });
await this.dscPrimaryValueInput.updateCssStyles({ 'display': 'none' });
this.setSecondaryCheckboxForInputType.display = 'none';
await this.dscSecondaryValueInput.updateCssStyles({ 'display': 'none' });
await this.dscPrimaryValueDropdown.updateCssStyles({ 'display': 'none' });
this.setSecondaryCheckboxForDropdowns.display = 'none';
await this.dscSecondaryValueDropdown.updateCssStyles({ 'display': 'none' });
}
/**
@@ -1727,12 +1758,13 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Wait Statistics Capture Mode - supported from 2017 or higher
if (!isUndefinedOrNull(this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode)) {
this.waitStatisticsCaptureMode = this.createCheckbox(localizedConstants.WaitStatisticsCaptureModeText, async (checked) => {
this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode = checked;
}, this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode, this.areQueryStoreOptionsEnabled);
containers.push(this.waitStatisticsCaptureMode);
this.waitStatisticsCaptureMode = this.createDropdown(localizedConstants.WaitStatisticsCaptureModeText, async (newValue) => {
// waitStatisticsCaptureMode value comes as On/Off, but options we provide are ON/OFF, handling selected value to match with the incoming value
this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode = newValue.charAt(0) + newValue.slice(1).toLowerCase() as string;
}, this.viewInfo.propertiesOnOffOptions, this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode.toUpperCase(), this.areQueryStoreOptionsEnabled, DefaultInputWidth);
containers.push(this.createLabelInputContainer(localizedConstants.WaitStatisticsCaptureModeText, this.waitStatisticsCaptureMode));
}
const retentionSection = this.createGroup(localizedConstants.WaitStatisticsCaptureModeText, containers, true);
const retentionSection = this.createGroup(localizedConstants.QueryStoreRetentionSectionText, containers, true);
this.queryStoreTabSectionsContainer.push(retentionSection);
}
@@ -1834,7 +1866,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
return;
}
await this.objectManagementService.purgeQueryStoreData(this.options.connectionUri, this.options.database, this.options.objectUrn);
await this.objectManagementService.purgeQueryStoreData(this.options.connectionUri, this.options.database);
}
private async toggleQueryStoreOptions(): Promise<void> {
@@ -1848,7 +1880,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
if (!isUndefinedOrNull(this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode)) {
this.waitStatisticsCaptureMode.enabled = this.areQueryStoreOptionsEnabled
}
await this.toggleQueryCapturePolicySection(this.areQueryStoreOptionsEnabled);
await this.toggleQueryCapturePolicySection(this.areQueryStoreOptionsEnabled &&
this.queryStoreCaptureMode.value === localizedConstants.QueryStoreCapturemodeCustomText);
}
private async toggleQueryCapturePolicySection(enable: boolean): Promise<void> {

View File

@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as path from 'path';
import { DefaultInputWidth, DialogBase } from '../../ui/dialogBase';
import * as localizedConstants from '../localizedConstants';
import { DatabaseFile, DatabaseViewInfo, FileGrowthType } from '../interfaces';
import { isUndefinedOrNull } from '../../types';
import { deepClone } from '../../util/objects';
import { IObjectManagementService } from 'mssql';
export interface NewDatabaseFileDialogOptions {
title: string;
@@ -27,6 +27,7 @@ export interface NewDatabaseFileDialogOptions {
defaultFileGrowthInMb: number,
defaultMaxFileSizeLimitedToInMb: number
};
connectionUri: string;
}
const fileSizeInputMaxValueInMbForDataType = 16776192; // Row type supports up to 16 TB (SSMS allows =~ 15.99TB)
@@ -58,7 +59,7 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
private originalFileName: string;
private isEditingFile: boolean;
constructor(private readonly options: NewDatabaseFileDialogOptions) {
constructor(private readonly options: NewDatabaseFileDialogOptions, private readonly objectManagementService: IObjectManagementService) {
super(options.title, 'DatabaseFileDialog');
}
@@ -92,7 +93,10 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
errors.push(localizedConstants.FileNameExistsError(this.result.name.trim()));
}
// If new file, verify if the file name with extension already exists
if (this.options.isNewFile && !!this.options.files.find(file => { return (path.join(file.path, file.fileNameWithExtension) === path.join(this.result.path, this.result.fileNameWithExtension)) })) {
if (this.options.isNewFile && !!this.options.files.find(file => {
return (this.result.name === file.name &&
path.join(file.path, file.fileNameWithExtension) === path.join(this.result.path, this.result.fileNameWithExtension))
})) {
errors.push(localizedConstants.FileAlreadyExistsError(path.join(this.result.path, this.result.fileNameWithExtension)));
}
}
@@ -157,7 +161,8 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
ariaLabel: localizedConstants.SizeInMbText,
inputType: 'number',
enabled: this.options.databaseFile.type !== localizedConstants.FilestreamFileType,
value: String(this.options.databaseFile.sizeInMb)
value: String(this.options.databaseFile.sizeInMb),
min: 1
});
const fileSizeContainer = this.createLabelInputContainer(localizedConstants.SizeInMbText, this.fileSizeInput);
containers.push(fileSizeContainer);
@@ -212,9 +217,9 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
= this.inMegabytesAutogrowth.enabled
= this.autoFilegrowthInput.enabled
= this.limitedToMbFileSize.enabled
= this.limitedToMbFileSizeInput.enabled
= this.unlimitedFileSize.enabled
= this.result.isAutoGrowthEnabled = checked;
this.limitedToMbFileSizeInput.enabled = checked && this.limitedToMbFileSize.checked;
}, true, true);
// Autogrowth radio button and input section
@@ -292,23 +297,12 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
* Creates a file browser and sets the path to the filePath
*/
private async createFileBrowser(): Promise<void> {
let fileUris = await vscode.window.showOpenDialog(
{
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
defaultUri: vscode.Uri.file(this.options.databaseFile.path),
openLabel: localizedConstants.SelectText
}
);
if (!fileUris || fileUris.length === 0) {
return;
let dataFolder = await this.objectManagementService.getDataFolder(this.options.connectionUri);
let filePath = await azdata.window.openServerFileBrowserDialog(this.options.connectionUri, dataFolder, [{ label: localizedConstants.allFiles, filters: ['*'] }], true);
if (filePath?.length > 0) {
this.filePathTextBox.value = filePath;
this.result.path = filePath;
}
let fileUri = fileUris[0];
this.filePathTextBox.value = fileUri.fsPath;
this.result.path = fileUri.fsPath;
}
/**
@@ -328,11 +322,11 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
if (selectedOption === localizedConstants.LogFiletype) {
fileGroupDdOptions = [localizedConstants.FileGroupForLogTypeText];
fileGroupDdValue = localizedConstants.FileGroupForLogTypeText;
fileSizeInputMaxValue = fileSizeInputMaxValueInMbForLogType
fileSizeInputMaxValue = fileSizeInputMaxValueInMbForLogType;
}
// File Stream
else if (selectedOption === localizedConstants.FilestreamFileType) {
fileGroupDdOptions = this.options.filestreamFilegroups;
fileGroupDdOptions = this.options.filestreamFilegroups.length > 0 ? this.options.filestreamFilegroups : [localizedConstants.FileGroupForFilestreamTypeText];
fileGroupDdValue = this.result.fileGroup;
visibility = 'hidden';
maxSizeGroupMarginTop = '-130px';

View File

@@ -6,7 +6,7 @@
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql';
import { Database, DatabaseViewInfo } from '../interfaces';
import { DetachDatabaseDocUrl } from '../constants';
import { DetachDatabaseDocUrl, TelemetryActions } from '../constants';
import * as loc from '../localizedConstants';
export class DetachDatabaseDialog extends ObjectManagementDialogBase<Database, DatabaseViewInfo> {
@@ -48,12 +48,16 @@ export class DetachDatabaseDialog extends ObjectManagementDialogBase<Database, D
return DetachDatabaseDocUrl;
}
protected override get actionName(): string {
return TelemetryActions.DetachDatabase;
}
protected override async saveChanges(contextId: string, object: ObjectManagement.SqlObject): Promise<void> {
await this.objectManagementService.detachDatabase(this.options.connectionUri, this.options.database, this.options.objectUrn, this._dropConnections, this._updateStatistics, false);
await this.objectManagementService.detachDatabase(this.options.connectionUri, this.options.database, this._dropConnections, this._updateStatistics, false);
}
protected override async generateScript(): Promise<string> {
return await this.objectManagementService.detachDatabase(this.options.connectionUri, this.options.database, this.options.objectUrn, this._dropConnections, this._updateStatistics, true);
return await this.objectManagementService.detachDatabase(this.options.connectionUri, this.options.database, this._dropConnections, this._updateStatistics, true);
}
protected override async validateInput(): Promise<string[]> {

View File

@@ -6,7 +6,7 @@
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql';
import { Database, DatabaseViewInfo } from '../interfaces';
import { DropDatabaseDocUrl } from '../constants';
import { DropDatabaseDocUrl, TelemetryActions } from '../constants';
import * as loc from '../localizedConstants';
export class DropDatabaseDialog extends ObjectManagementDialogBase<Database, DatabaseViewInfo> {
@@ -52,12 +52,16 @@ export class DropDatabaseDialog extends ObjectManagementDialogBase<Database, Dat
return DropDatabaseDocUrl;
}
protected override get actionName(): string {
return TelemetryActions.DropObject;
}
protected override async saveChanges(contextId: string, object: ObjectManagement.SqlObject): Promise<void> {
await this.objectManagementService.dropDatabase(this.options.connectionUri, this.options.database, this.options.objectUrn, this._dropConnections, this._deleteBackupHistory, false);
await this.objectManagementService.dropDatabase(this.options.connectionUri, this.options.database, this._dropConnections, this._deleteBackupHistory, false);
}
protected override async generateScript(): Promise<string> {
return await this.objectManagementService.dropDatabase(this.options.connectionUri, this.options.database, this.options.objectUrn, this._dropConnections, this._deleteBackupHistory, true);
return await this.objectManagementService.dropDatabase(this.options.connectionUri, this.options.database, this._dropConnections, this._deleteBackupHistory, true);
}
protected override async validateInput(): Promise<string[]> {

View File

@@ -47,6 +47,11 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
constructor(private readonly objectManagementService: mssql.IObjectManagementService, private readonly options: FindObjectDialogOptions) {
super(options.title, 'FindObjectDialog');
this.dialogObject.okButton.label = localizedConstants.SelectText;
this.dialogObject.okButton.enabled = false;
// Relabel Cancel button to Back, since clicking cancel on an inner dialog makes it seem like it would close the whole dialog overall
this.dialogObject.cancelButton.label = localizedConstants.BackButtonLabel;
this.result = {
selectedObjects: []
};
@@ -54,7 +59,6 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
}
protected override async initialize(): Promise<void> {
this.dialogObject.okButton.enabled = false;
this.objectTypesTable = this.createTableList<ObjectTypeInfo>(localizedConstants.ObjectTypesText,
[localizedConstants.ObjectTypeText],
this.options.objectTypes,

View File

@@ -18,7 +18,6 @@ export class LoginDialog extends PrincipalDialogBase<Login, LoginViewInfo> {
private generalSection: azdata.GroupContainer;
private sqlAuthSection: azdata.GroupContainer;
private serverRoleSection: azdata.GroupContainer;
private advancedSection: azdata.GroupContainer;
private nameInput: azdata.InputBoxComponent;
private authTypeDropdown: azdata.DropDownComponent;
private passwordInput: azdata.InputBoxComponent;
@@ -99,14 +98,11 @@ export class LoginDialog extends PrincipalDialogBase<Login, LoginViewInfo> {
sections.push(this.serverRoleSection);
sections.push(this.securableSection);
if (this.viewInfo.supportAdvancedOptions) {
this.initializeAdvancedSection();
sections.push(this.advancedSection);
}
this.formContainer.addItems(sections, this.getSectionItemLayout());
}
private initializeGeneralSection(): void {
const items: azdata.Component[] = [];
this.nameInput = this.createInputBox(async (newValue) => {
this.objectInfo.name = newValue;
}, {
@@ -115,8 +111,9 @@ export class LoginDialog extends PrincipalDialogBase<Login, LoginViewInfo> {
enabled: this.options.isNewObject,
value: this.objectInfo.name
});
const nameContainer = this.createLabelInputContainer(objectManagementLoc.NameText, this.nameInput);
items.push(nameContainer);
this.authTypeDropdown = this.createDropdown(objectManagementLoc.AuthTypeText,
async (newValue) => {
this.objectInfo.authenticationType = objectManagementLoc.getAuthenticationTypeByDisplayName(newValue);
@@ -125,13 +122,34 @@ export class LoginDialog extends PrincipalDialogBase<Login, LoginViewInfo> {
this.viewInfo.authenticationTypes.map(authType => objectManagementLoc.getAuthenticationTypeDisplayName(authType)),
objectManagementLoc.getAuthenticationTypeDisplayName(this.objectInfo.authenticationType),
this.options.isNewObject);
const authTypeContainer = this.createLabelInputContainer(objectManagementLoc.AuthTypeText, this.authTypeDropdown);
items.push(authTypeContainer);
this.enabledCheckbox = this.createCheckbox(objectManagementLoc.EnabledText, async (checked) => {
this.objectInfo.isEnabled = checked;
}, this.objectInfo.isEnabled);
this.generalSection = this.createGroup(objectManagementLoc.GeneralSectionHeader, [nameContainer, authTypeContainer, this.enabledCheckbox], false);
items.push(this.enabledCheckbox);
if (this.viewInfo.supportAdvancedOptions) {
this.defaultDatabaseDropdown = this.createDropdown(objectManagementLoc.DefaultDatabaseText, async (newValue) => {
this.objectInfo.defaultDatabase = newValue;
}, this.viewInfo.databases, this.objectInfo.defaultDatabase);
const defaultDatabaseContainer = this.createLabelInputContainer(objectManagementLoc.DefaultDatabaseText, this.defaultDatabaseDropdown);
items.push(defaultDatabaseContainer);
this.defaultLanguageDropdown = this.createDropdown(objectManagementLoc.DefaultLanguageText, async (newValue) => {
this.objectInfo.defaultLanguage = newValue;
}, this.viewInfo.languages, this.objectInfo.defaultLanguage);
const defaultLanguageContainer = this.createLabelInputContainer(objectManagementLoc.DefaultLanguageText, this.defaultLanguageDropdown);
items.push(defaultLanguageContainer);
this.connectPermissionCheckbox = this.createCheckbox(objectManagementLoc.PermissionToConnectText, async (checked) => {
this.objectInfo.connectPermission = checked;
}, this.objectInfo.connectPermission);
items.push(this.connectPermissionCheckbox);
}
this.generalSection = this.createGroup(objectManagementLoc.GeneralSectionHeader, items, false);
}
private initializeSqlAuthSection(): void {
@@ -207,28 +225,6 @@ export class LoginDialog extends PrincipalDialogBase<Login, LoginViewInfo> {
return this.objectInfo.password !== this.originalObjectInfo.password
}
private initializeAdvancedSection(): void {
const items: azdata.Component[] = [];
if (this.viewInfo.supportAdvancedOptions) {
this.defaultDatabaseDropdown = this.createDropdown(objectManagementLoc.DefaultDatabaseText, async (newValue) => {
this.objectInfo.defaultDatabase = newValue;
}, this.viewInfo.databases, this.objectInfo.defaultDatabase);
const defaultDatabaseContainer = this.createLabelInputContainer(objectManagementLoc.DefaultDatabaseText, this.defaultDatabaseDropdown);
this.defaultLanguageDropdown = this.createDropdown(objectManagementLoc.DefaultLanguageText, async (newValue) => {
this.objectInfo.defaultLanguage = newValue;
}, this.viewInfo.languages, this.objectInfo.defaultLanguage);
const defaultLanguageContainer = this.createLabelInputContainer(objectManagementLoc.DefaultLanguageText, this.defaultLanguageDropdown);
this.connectPermissionCheckbox = this.createCheckbox(objectManagementLoc.PermissionToConnectText, async (checked) => {
this.objectInfo.connectPermission = checked;
}, this.objectInfo.connectPermission);
items.push(defaultDatabaseContainer, defaultLanguageContainer, this.connectPermissionCheckbox);
}
this.advancedSection = this.createGroup(objectManagementLoc.AdvancedSectionHeader, items, true, true);
}
private initializeServerRolesSection(): void {
this.serverRoleTable = this.createTableList(objectManagementLoc.ServerRoleSectionHeader,
[objectManagementLoc.ServerRoleTypeDisplayNameInTitle],

View File

@@ -68,6 +68,10 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
: localizedConstants.UpdateObjectOperationDisplayName(typeDisplayName, this.options.objectName);
}
protected get actionName(): string {
return this.options.isNewObject ? TelemetryActions.CreateObject : TelemetryActions.UpdateObject;
}
protected override async initialize(): Promise<void> {
await super.initialize();
this.dialogObject.registerOperation({
@@ -75,7 +79,6 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
description: '',
isCancelable: false,
operation: async (operation: azdata.BackgroundOperation): Promise<void> => {
const actionName = this.options.isNewObject ? TelemetryActions.CreateObject : TelemetryActions.UpdateObject;
try {
if (this.isDirty) {
const startTime = Date.now();
@@ -89,7 +92,7 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
}
}
TelemetryReporter.sendTelemetryEvent(actionName, {
TelemetryReporter.sendTelemetryEvent(this.actionName, {
objectType: this.options.objectType
}, {
elapsedTimeMs: Date.now() - startTime
@@ -99,7 +102,7 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
}
catch (err) {
operation.updateStatus(azdata.TaskStatus.Failed, getErrorMessage(err));
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, actionName, err).withAdditionalProperties({
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, this.actionName, err).withAdditionalProperties({
objectType: this.options.objectType
}).send();
} finally {

View File

@@ -40,6 +40,9 @@ export class ObjectSelectionMethodDialog extends DialogBase<ObjectSelectionMetho
schema: undefined,
objectTypes: []
};
// Relabel Cancel button to Back, since clicking cancel on an inner dialog makes it seem like it would close the whole dialog overall
this.dialogObject.cancelButton.label = localizedConstants.BackButtonLabel;
}
protected override async initialize(): Promise<void> {

View File

@@ -10,6 +10,9 @@ import { IObjectManagementService } from 'mssql';
import * as localizedConstants from '../localizedConstants';
import * as constants from '../constants';
import { Server, ServerViewInfo, NumaNode, AffinityType, ServerLoginMode, AuditLevel } from '../interfaces';
import { isUndefinedOrNull } from '../../types';
const Dialog_Width = '750px';
export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, ServerViewInfo> {
private generalTab: azdata.Tab;
@@ -90,9 +93,13 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
private shouldRestartServer: boolean = false;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
options.width = Dialog_Width;
super(objectManagementService, options);
this.disposables.push(this.dialogObject.onClosed(async () => {
await this.notifyServerRestart();
this.disposables.push(this.dialogObject.onClosed(async (reason: azdata.window.CloseReason) => {
if (reason === 'ok') {
// only show message if user apply changes
await this.notifyServerRestart();
}
}));
}
@@ -135,6 +142,9 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab, this.processorsTab, this.securityTab, this.databaseSettingsTab, this.advancedTab] };
const serverPropertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
.withTabs([serverPropertiesTabGroup])
.withLayout({
orientation: azdata.TabOrientation.Vertical
})
.withProps({
CSSStyles: {
'margin': '-10px 0px 0px -10px'
@@ -148,6 +158,19 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}
private initializeGeneralSection(): void {
// Information about the platform that the SQL instance is running on
let platformItems: azdata.Component[] = [];
if (this.objectInfo.hardwareGeneration) {
this.hardwareGenerationInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.HardwareGenerationText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.hardwareGeneration.toString()
});
const hardwareGenerationContainer = this.createLabelInputContainer(localizedConstants.HardwareGenerationText, this.hardwareGenerationInput);
platformItems.push(hardwareGenerationContainer);
}
this.nameInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.NameText,
inputType: 'text',
@@ -155,17 +178,11 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.name
});
const nameContainer = this.createLabelInputContainer(localizedConstants.NameText, this.nameInput);
this.hardwareGenerationInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.HardwareGenerationText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.hardwareGeneration.toString()
});
const hardwareGenerationContainer = this.createLabelInputContainer(localizedConstants.HardwareGenerationText, this.hardwareGenerationInput);
platformItems.push(nameContainer);
this.languageDropdown = this.createDropdown(localizedConstants.LanguageText, async () => { }, [this.objectInfo.language], this.objectInfo.language, this.options.isNewObject);
const languageContainer = this.createLabelInputContainer(localizedConstants.LanguageText, this.languageDropdown);
platformItems.push(languageContainer);
this.memoryInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.MemoryText,
@@ -174,6 +191,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: localizedConstants.StringValueInMB(this.objectInfo.memoryInMB.toString())
});
const memoryContainer = this.createLabelInputContainer(localizedConstants.MemoryText, this.memoryInput);
platformItems.push(memoryContainer);
this.operatingSystemInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.OperatingSystemText,
@@ -182,6 +200,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.operatingSystem
});
const operatingSystemContainer = this.createLabelInputContainer(localizedConstants.OperatingSystemText, this.operatingSystemInput);
platformItems.push(operatingSystemContainer);
this.platformInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.PlatformText,
@@ -190,6 +209,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.platform
});
const platformContainer = this.createLabelInputContainer(localizedConstants.PlatformText, this.platformInput);
platformItems.push(platformContainer);
this.processorsInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ProcessorsText,
@@ -198,7 +218,10 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.processors
});
const processorsContainer = this.createLabelInputContainer(localizedConstants.ProcessorsText, this.processorsInput);
platformItems.push(processorsContainer);
// Information about the SQL instance itself
let sqlServerItems: azdata.Component[] = [];
this.isClusteredInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsClusteredText,
inputType: 'text',
@@ -206,6 +229,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.isClustered.toString()
});
const isClusteredContainer = this.createLabelInputContainer(localizedConstants.IsClusteredText, this.isClusteredInput);
sqlServerItems.push(isClusteredContainer);
this.isHadrEnabledInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsHadrEnabledText,
@@ -214,22 +238,29 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.isHadrEnabled.toString()
});
const isHadrEnabledContainer = this.createLabelInputContainer(localizedConstants.IsHadrEnabledText, this.isHadrEnabledInput);
sqlServerItems.push(isHadrEnabledContainer);
this.isPolyBaseInstalledInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsPolyBaseInstalledText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.isPolyBaseInstalled.toString()
});
const isPolyBaseInstalledContainer = this.createLabelInputContainer(localizedConstants.IsPolyBaseInstalledText, this.isPolyBaseInstalledInput);
if (!isUndefinedOrNull(this.objectInfo.isPolyBaseInstalled)) {
this.isPolyBaseInstalledInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsPolyBaseInstalledText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.isPolyBaseInstalled.toString()
});
const isPolyBaseInstalledContainer = this.createLabelInputContainer(localizedConstants.IsPolyBaseInstalledText, this.isPolyBaseInstalledInput);
sqlServerItems.push(isPolyBaseInstalledContainer);
}
this.isXTPSupportedInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsXTPSupportedText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.isXTPSupported.toString()
});
const isXTPSupportedContainer = this.createLabelInputContainer(localizedConstants.IsXTPSupportedText, this.isXTPSupportedInput);
if (!isUndefinedOrNull(this.objectInfo.isXTPSupported)) {
this.isXTPSupportedInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.IsXTPSupportedText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.isXTPSupported.toString()
});
const isXTPSupportedContainer = this.createLabelInputContainer(localizedConstants.IsXTPSupportedText, this.isXTPSupportedInput);
sqlServerItems.push(isXTPSupportedContainer);
}
this.productInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ProductText,
@@ -238,14 +269,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.product
});
const productContainer = this.createLabelInputContainer(localizedConstants.ProductText, this.productInput);
this.reservedStorageSizeInMBInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ReservedStorageSizeInMBText,
inputType: 'text',
enabled: this.options.isNewObject,
value: localizedConstants.StringValueInMB(this.objectInfo.reservedStorageSizeMB.toString())
});
const reservedStorageSizeInMBContainer = this.createLabelInputContainer(localizedConstants.ReservedStorageSizeInMBText, this.reservedStorageSizeInMBInput);
sqlServerItems.push(productContainer);
this.rootDirectoryInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.RootDirectoryText,
@@ -254,6 +278,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.rootDirectory
});
const rootDirectoryContainer = this.createLabelInputContainer(localizedConstants.RootDirectoryText, this.rootDirectoryInput);
sqlServerItems.push(rootDirectoryContainer);
this.serverCollationInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ServerCollationText,
@@ -262,22 +287,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.serverCollation
});
const serverCollationContainer = this.createLabelInputContainer(localizedConstants.ServerCollationText, this.serverCollationInput);
this.serviceTierInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ServiceTierText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.serviceTier
});
const serviceTierContainer = this.createLabelInputContainer(localizedConstants.ServiceTierText, this.serviceTierInput);
this.storageSpaceUsageInMBInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.StorageSpaceUsageInMBText,
inputType: 'text',
enabled: this.options.isNewObject,
value: localizedConstants.StringValueInMB(this.objectInfo.storageSpaceUsageInMB.toString())
});
const storageSpaceUsageInMbContainer = this.createLabelInputContainer(localizedConstants.StorageSpaceUsageInMBText, this.storageSpaceUsageInMBInput);
sqlServerItems.push(serverCollationContainer);
this.versionInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.VersionText,
@@ -286,32 +296,39 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
value: this.objectInfo.version
});
const versionContainer = this.createLabelInputContainer(localizedConstants.VersionText, this.versionInput);
sqlServerItems.push(versionContainer);
let platformItems = [
nameContainer,
languageContainer,
memoryContainer,
operatingSystemContainer,
platformContainer,
processorsContainer
];
if (!isUndefinedOrNull(this.objectInfo.reservedStorageSizeMB)) {
this.reservedStorageSizeInMBInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ReservedStorageSizeInMBText,
inputType: 'text',
enabled: this.options.isNewObject,
value: localizedConstants.StringValueInMB(this.objectInfo.reservedStorageSizeMB.toString())
});
const reservedStorageSizeInMBContainer = this.createLabelInputContainer(localizedConstants.ReservedStorageSizeInMBText, this.reservedStorageSizeInMBInput);
sqlServerItems.push(reservedStorageSizeInMBContainer);
}
let sqlServerItems = [
isClusteredContainer,
isHadrEnabledContainer,
isPolyBaseInstalledContainer,
isXTPSupportedContainer,
productContainer,
rootDirectoryContainer,
serverCollationContainer,
versionContainer
];
if (this.objectInfo.serviceTier) {
this.serviceTierInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.ServiceTierText,
inputType: 'text',
enabled: this.options.isNewObject,
value: this.objectInfo.serviceTier
});
const serviceTierContainer = this.createLabelInputContainer(localizedConstants.ServiceTierText, this.serviceTierInput);
sqlServerItems.push(serviceTierContainer);
}
if (this.engineEdition === azdata.DatabaseEngineEdition.SqlManagedInstance) {
platformItems.unshift(hardwareGenerationContainer);
sqlServerItems.push(reservedStorageSizeInMBContainer, serviceTierContainer, storageSpaceUsageInMbContainer);
// remove isXTPSupported
sqlServerItems.splice(3, 1);
if (!isUndefinedOrNull(this.objectInfo.storageSpaceUsageInMB)) {
this.storageSpaceUsageInMBInput = this.createInputBox(async () => { }, {
ariaLabel: localizedConstants.StorageSpaceUsageInMBText,
inputType: 'text',
enabled: this.options.isNewObject,
value: localizedConstants.StringValueInMB(this.objectInfo.storageSpaceUsageInMB.toString())
});
const storageSpaceUsageInMbContainer = this.createLabelInputContainer(localizedConstants.StorageSpaceUsageInMBText, this.storageSpaceUsageInMBInput);
sqlServerItems.push(storageSpaceUsageInMbContainer);
}
this.platformSection = this.createGroup('Platform', platformItems, true);
@@ -501,8 +518,9 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}
private initializeSecuritySection(): void {
const isWindows = this.objectInfo.platform === constants.Windows;
// cannot change auth mode in sql managed instance or non windows instances
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance && this.objectInfo.platform === 'Windows';
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance && isWindows;
const radioServerGroupName = 'serverAuthenticationRadioGroup';
this.onlyWindowsAuthRadioButton = this.createRadioButton(localizedConstants.onlyWindowsAuthModeText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Integrated, async () => { await this.handleAuthModeChange(); });
this.sqlServerAndWindowsAuthRadioButton = this.createRadioButton(localizedConstants.sqlServerAndWindowsAuthText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Mixed, async () => { await this.handleAuthModeChange(); });
@@ -518,6 +536,11 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.failedLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.failedLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Failure, async () => { await this.handleAuditLevelChange(); });
this.successfulLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.successfulLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Success, async () => { await this.handleAuditLevelChange(); });
this.bothFailedAndSuccessfulLoginsRadioButton = this.createRadioButton(localizedConstants.bothFailedAndSuccessfulLoginsText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.All, async () => { await this.handleAuditLevelChange(); });
// cannot change values in serverLogin section on Linux
this.noneRadioButton.enabled = isWindows;
this.failedLoginsOnlyRadioButton.enabled = isWindows;
this.successfulLoginsOnlyRadioButton.enabled = isWindows;
this.bothFailedAndSuccessfulLoginsRadioButton.enabled = isWindows;
const serverLoginSection = this.createGroup(localizedConstants.loginAuditingText, [
this.noneRadioButton,
this.failedLoginsOnlyRadioButton,
@@ -652,24 +675,12 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}
public async selectFolder(location: string): Promise<string | undefined> {
const allFilesFilter = localizedConstants.allFiles;
let filter: any = {};
filter[allFilesFilter] = '*';
let uris = await vscode.window.showOpenDialog({
filters: filter,
canSelectFiles: false,
canSelectMany: false,
canSelectFolders: true,
defaultUri: vscode.Uri.file(location),
openLabel: localizedConstants.labelSelectFolder
});
if (uris && uris.length > 0) {
return uris[0].fsPath;
}
return undefined;
let dataFolder = await this.objectManagementService.getDataFolder(this.options.connectionUri);
return await azdata.window.openServerFileBrowserDialog(this.options.connectionUri, dataFolder, [{ label: localizedConstants.allFiles, filters: ['*'] }], true);
}
private initializeAdvancedSection(): void {
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance;
this.allowTriggerToFireOthersDropdown = this.createDropdown(localizedConstants.allowTriggerToFireOthersLabel, async (newValue) => {
this.objectInfo.allowTriggerToFireOthers = newValue === 'True';
}, ['True', 'False'], this.objectInfo.allowTriggerToFireOthers ? 'True' : 'False');
@@ -733,7 +744,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.scanStartupProcsDropdown = this.createDropdown(localizedConstants.scanStartupProcsLabel, async (newValue) => {
this.objectInfo.scanStartupProcs = newValue === 'True';
}, ['True', 'False'], this.objectInfo.scanStartupProcs ? 'True' : 'False');
}, ['True', 'False'], this.objectInfo.scanStartupProcs ? 'True' : 'False', isEnabled);
const scanStartupProcsContainer = this.createLabelInputContainer(localizedConstants.scanStartupProcsLabel, this.scanStartupProcsDropdown);
this.twoDigitYearCutoffInput = this.createInputBox(async (newValue) => {
@@ -761,8 +772,13 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}, {
ariaLabel: localizedConstants.locksLabel,
inputType: 'number',
enabled: isEnabled,
max: this.objectInfo.locks.maximumValue,
value: this.objectInfo.locks.value.toString()
min: 0,
value: this.objectInfo.locks.value.toString(),
validationErrorMessage: localizedConstants.locksValidation(this.objectInfo.locks.minimumValue)
}, async () => {
return !(+this.locksInput.value < this.objectInfo.locks.minimumValue && +this.locksInput.value !== 0);
});
const locksContainer = this.createLabelInputContainer(localizedConstants.locksLabel, this.locksInput);

View File

@@ -28,16 +28,18 @@ export function registerTableDesignerCommands(appContext: AppContext) {
}
const tableIcon = context.nodeInfo!.nodeSubType as azdata.designers.TableIcon;
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
let nonDefaultOptions = await azdata.connection.getNonDefaultOptions(context.connectionProfile);
await azdata.designers.openTableDesigner(sqlProviderName, {
title: NewTableText,
tooltip: `${context.connectionProfile!.serverName} - ${context.connectionProfile!.databaseName} - ${NewTableText}`,
tooltip: context.connectionProfile!.connectionName ? `${context.connectionProfile!.connectionName} - ${NewTableText}` : `${context.connectionProfile!.serverName} - ${context.connectionProfile!.databaseName} - ${NewTableText}`,
server: context.connectionProfile!.serverName,
database: context.connectionProfile!.databaseName,
isNewTable: true,
id: generateUuid(),
connectionString: connectionString,
accessToken: context.connectionProfile!.options.azureAccountToken as string,
tableIcon: tableIcon
tableIcon: tableIcon,
additionalInfo: `${context.connectionProfile!.serverName + ' - ' + context.connectionProfile!.databaseName}${nonDefaultOptions}`
}, telemetryInfo, context);
} catch (error) {
console.error(error);
@@ -48,6 +50,7 @@ export function registerTableDesignerCommands(appContext: AppContext) {
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.designTable', async (context: azdata.ObjectExplorerContext) => {
try {
void showPreloadDbModelSettingPrompt(appContext);
const connName = context.connectionProfile!.connectionName;
const server = context.connectionProfile!.serverName;
const database = context.connectionProfile!.databaseName;
const schema = context.nodeInfo!.metadata!.schema;
@@ -58,9 +61,10 @@ export function registerTableDesignerCommands(appContext: AppContext) {
}
const tableIcon = context.nodeInfo!.nodeSubType as azdata.designers.TableIcon;
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
let nonDefaultOptions = await azdata.connection.getNonDefaultOptions(context.connectionProfile);
await azdata.designers.openTableDesigner(sqlProviderName, {
title: `${schema}.${name}`,
tooltip: `${server} - ${database} - ${schema}.${name}`,
tooltip: connName ? `${connName} - ${schema}.${name}` : `${server} - ${database} - ${schema}.${name}`,
server: server,
database: database,
isNewTable: false,
@@ -69,7 +73,8 @@ export function registerTableDesignerCommands(appContext: AppContext) {
id: `${sqlProviderName}|${server}|${database}|${schema}|${name}`,
connectionString: connectionString,
accessToken: context.connectionProfile!.options.azureAccountToken as string,
tableIcon: tableIcon
tableIcon: tableIcon,
additionalInfo: `${server + ' - ' + database}${nonDefaultOptions}`
}, telemetryInfo, context);
} catch (error) {
console.error(error);

View File

@@ -24,7 +24,8 @@ export function getTableHeight(rowCount: number, minRowCount: number = DefaultMi
export interface DialogButton {
buttonAriaLabel: string;
buttonHandler: (button: azdata.ButtonComponent) => Promise<void>
buttonHandler: (button: azdata.ButtonComponent) => Promise<void>,
enabled?: boolean
}
export type TableListItemEnabledStateGetter<T> = (item: T) => boolean;
@@ -80,6 +81,8 @@ export abstract class DialogBase<DialogResult> {
protected removeButtonEnabled(table: azdata.TableComponent): boolean { return true; }
protected addButtonEnabled(table: azdata.TableComponent): boolean { return true; }
protected validateInput(): Promise<string[]> { return Promise.resolve([]); }
public async open(): Promise<void> {
@@ -295,12 +298,13 @@ export abstract class DialogBase<DialogResult> {
if (editButton !== undefined) {
editButtonComponent.enabled = tableSelectedRowsLengthCheck;
}
addButtonComponent.enabled = this.addButtonEnabled(table);
removeButtonComponent.enabled = !!isRemoveEnabled && tableSelectedRowsLengthCheck;
}
addButtonComponent = this.createButton(uiLoc.AddText, addbutton.buttonAriaLabel, async () => {
await addbutton.buttonHandler(addButtonComponent);
updateButtons();
});
}, addbutton.enabled ?? true);
buttonComponents.push(addButtonComponent);
if (editButton !== undefined) {

View File

@@ -63,13 +63,16 @@ export abstract class ScriptableDialogBase<OptionsType extends ScriptableDialogO
protected abstract get isDirty(): boolean;
protected override onFormFieldChange(): void {
this._scriptButton.enabled = this.isDirty;
this.updateScriptButtonState();
this.dialogObject.okButton.enabled = this.isDirty;
}
protected override async initialize(): Promise<void> {
await this.initializeData();
await this.initializeUI();
this.disposables.push(this.modelView.onValidityChanged(() => {
this.updateScriptButtonState();
}));
}
protected override updateLoadingStatus(isLoading: boolean, loadingText?: string, loadingCompletedText?: string): void {
@@ -131,4 +134,8 @@ export abstract class ScriptableDialogBase<OptionsType extends ScriptableDialogO
this.updateLoadingStatus(false, localizedConstants.GeneratingScriptText, localizedConstants.GeneratingScriptCompletedText);
}
}
private updateScriptButtonState(): void {
this._scriptButton.enabled = this.isDirty && this.modelView.valid;
}
}

View File

@@ -22,6 +22,9 @@ const parallelMessageProcessingConfig = 'parallelMessageProcessing';
const enableSqlAuthenticationProviderConfig = 'enableSqlAuthenticationProvider';
const enableConnectionPoolingConfig = 'enableConnectionPooling';
const tableDesignerPreloadConfig = 'tableDesigner.preloadDatabaseModel';
const httpConfig = 'http';
const configProxy = 'proxy';
const configProxyStrictSSL = 'proxyStrictSSL';
/**
*
@@ -85,6 +88,19 @@ export function getConfigLogRetentionSeconds(): number | undefined {
}
}
export function getHttpProxyUrl(): string | undefined {
let config = getConfiguration(httpConfig);
if (config) {
return config[configProxy];
} return undefined;
}
export function getHttpProxyStrictSSL(): boolean {
let config = getConfiguration(httpConfig);
if (config) {
return config.get<boolean>(configProxyStrictSSL, true); // true by default
} return true; // true by default.
}
/**
* The tracing level defined in the package.json
*/
@@ -202,6 +218,15 @@ export function getCommonLaunchArgsAndCleanupOldLogFiles(logPath: string, fileNa
}
// Always enable autoflush so that log entries are written immediately to disk, otherwise we can end up with partial logs
launchArgs.push('--autoflush-log');
let httpProxy = getHttpProxyUrl();
if (httpProxy) {
launchArgs.push('--http-proxy-url');
launchArgs.push(httpProxy);
if (getHttpProxyStrictSSL()) {
launchArgs.push('--http-proxy-strict-ssl')
}
}
return launchArgs;
}

View File

@@ -511,9 +511,9 @@ crypt@~0.0.1:
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.7":
version "1.3.7"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0f07d03394eeebc2924971746470ac8224348fa4"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/828b7a5e5c1c077a0f6eb7f6acecd191fbaae13d"
dependencies:
vscode-languageclient "5.2.1"
@@ -1080,7 +1080,7 @@ md5@^2.1.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
minimatch@3.0.4, minimatch@^3.0.4:
minimatch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -1094,6 +1094,13 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"

View File

@@ -370,7 +370,7 @@
},
{
"command": "jupyter.cmd.managePackages",
"when": "false"
"when": "notebook:pythonInstalled && !notebook:runningOnSAW"
},
{
"command": "notebook.command.saveBook",

View File

@@ -38,7 +38,7 @@
"config.jupyter.kernelConfigValuesDescription": "Configuration options for Jupyter kernels. This is automatically managed and not recommended to be manually edited.",
"title.reinstallNotebookDependencies": "Reinstall Notebook dependencies",
"title.configurePython": "Configure Python for Notebooks",
"title.managePackages": "Manage Packages",
"title.managePackages": "Manage Notebook Packages",
"title.SQL19PreviewBook": "SQL Server 2019 Guide",
"books-preview-category": "Jupyter Books",
"title.saveJupyterBook": "Save Jupyter Book",

View File

@@ -52,6 +52,10 @@ export function executeBufferedCommand(cmd: string, options: childProcess.ExecOp
});
}
export function executeBufferedCommandSync(cmd: string, options: childProcess.ExecOptions): string {
return childProcess.execSync(cmd, options).toString();
}
export function executeStreamedCommand(cmd: string, options: childProcess.SpawnOptions, outputChannel?: vscode.OutputChannel): Thenable<void> {
return new Promise<void>((resolve, reject) => {
// Start the command

View File

@@ -27,7 +27,7 @@ export class ManagePackagesDialog {
* Opens a dialog to manage packages used by notebooks.
*/
public showDialog(): void {
this.dialog = azdata.window.createModelViewDialog(localize('managePackages.dialogName', "Manage Packages"));
this.dialog = azdata.window.createModelViewDialog(localize('managePackages.dialogName', "Manage Notebook Packages"));
this.installedPkgTab = new InstalledPackagesTab(this, this.jupyterInstallation);
this.addNewPkgTab = new AddNewPackageTab(this, this.jupyterInstallation);

View File

@@ -12,7 +12,7 @@ import { AppContext } from './common/appContext';
import { IExtensionApi, IPackageManageProvider } from './types';
import { CellType } from './contracts/content';
import { NotebookUriHandler } from './protocol/notebookUriHandler';
import { BuiltInCommands, unsavedBooksContextKey } from './common/constants';
import { BuiltInCommands, CommandContext, unsavedBooksContextKey } from './common/constants';
import { RemoteBookController } from './book/remoteBookController';
import { RemoteBookDialog } from './dialog/remoteBookDialog';
import { RemoteBookDialogModel } from './dialog/remoteBookDialogModel';
@@ -22,6 +22,7 @@ import { BookTreeItem } from './book/bookTreeItem';
import Logger from './common/logger';
import { sendNotebookActionEvent, NbTelemetryView, NbTelemetryAction } from './telemetry';
import { TelemetryReporter } from './telemetry';
import { JupyterServerInstallation } from './jupyter/jupyterServerInstallation';
const localize = nls.loadMessageBundle();
@@ -39,6 +40,11 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
if (vscode.env.uiKind === vscode.UIKind.Web) {
await config.update('allowRoot', true, vscode.ConfigurationTarget.Global);
}
// Check if python is already installed in order to enable the Manage Notebook Packages dialog
let pythonInstalled = JupyterServerInstallation.isPythonInstalled();
await vscode.commands.executeCommand(BuiltInCommands.SetContext, CommandContext.NotebookPythonInstalled, pythonInstalled);
/**
* ***** IMPORTANT *****
* If changes are made to bookTreeView.openBook, please ensure backwards compatibility with its current state.
@@ -154,7 +160,6 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
return undefined;
}
const bookTreeViewProvider = appContext.bookTreeViewProvider;
await bookTreeViewProvider.initialized;
const providedBookTreeViewProvider = appContext.providedBookTreeViewProvider;

View File

@@ -155,21 +155,26 @@ export class JupyterController {
}
public async doManagePackages(options?: ManagePackageDialogOptions | vscode.Uri): Promise<void> {
try {
if (!options || options instanceof vscode.Uri) {
options = {
defaultLocation: constants.localhostName,
defaultProviderId: LocalPipPackageManageProvider.ProviderId
};
}
let model = new ManagePackagesDialogModel(this._jupyterInstallation, this._packageManageProviders, options);
// Handle the edge case where python is installed and then deleted manually from the user settings.
if (!JupyterServerInstallation.isPythonInstalled()) {
await vscode.window.showErrorMessage(localize('pythonNotSetup', "Python is not currently configured for notebooks. The 'Configure Python for Notebooks' command must be run before being able to manage notebook packages."));
} else {
try {
if (!options || options instanceof vscode.Uri) {
options = {
defaultLocation: constants.localhostName,
defaultProviderId: LocalPipPackageManageProvider.ProviderId
};
}
let model = new ManagePackagesDialogModel(this._jupyterInstallation, this._packageManageProviders, options);
await model.init();
let packagesDialog = new ManagePackagesDialog(model, this.extensionContext);
packagesDialog.showDialog();
} catch (error) {
let message = utils.getErrorMessage(error);
void vscode.window.showErrorMessage(message);
await model.init();
let packagesDialog = new ManagePackagesDialog(model, this.extensionContext);
packagesDialog.showDialog();
} catch (error) {
let message = utils.getErrorMessage(error);
await vscode.window.showErrorMessage(message);
}
}
}

View File

@@ -18,6 +18,7 @@ import * as utils from '../common/utils';
import { Deferred } from '../common/promise';
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
import { IKernelInfo } from '../contracts/content';
import { requiredJupyterPackages } from './requiredJupyterPackages';
const localize = nls.loadMessageBundle();
const msgInstallPkgProgress = localize('msgInstallPkgProgress', "Notebook dependencies installation is in progress");
@@ -78,22 +79,6 @@ export interface IJupyterServerInstallation {
installedPythonVersion: string;
}
export const requiredJupyterPkg: PythonPkgDetails = {
name: 'jupyter',
version: '1.0.0'
};
export const requiredNotebookPkg: PythonPkgDetails = {
name: 'notebook',
version: '6.5.5',
installExactVersion: true
};
export const requiredPowershellPkg: PythonPkgDetails = {
name: 'powershell-kernel',
version: '0.1.4'
};
export class JupyterServerInstallation implements IJupyterServerInstallation {
public extensionPath: string;
public pythonBinPath: string;
@@ -113,14 +98,14 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
private _oldUserInstalledPipPackages: PythonPkgDetails[] = [];
private _upgradePrompted: boolean = false;
private _installInProgress: boolean;
private _installInProgress = false;
private _installCompletion: Deferred<void>;
public static readonly DefaultPythonLocation = path.join(utils.getUserHome(), 'azuredatastudio-python');
private _kernelSetupCache: Map<string, boolean>;
private readonly _requiredKernelPackages: Map<string, PythonPkgDetails[]>;
private readonly _requiredPackagesSet: Set<string>;
private readonly _kernelSetupCache = new Map<string, boolean>();
private readonly _requiredKernelPackages = new Map<string, PythonPkgDetails[]>();
private readonly _requiredPackageNames: Set<string>;
private readonly _runningOnSAW: boolean;
private readonly _tsgopsweb: boolean;
@@ -144,22 +129,21 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
this._pythonInstallationPath = JupyterServerInstallation.getPythonInstallPath();
this._usingExistingPython = JupyterServerInstallation.getExistingPythonSetting();
}
this._installInProgress = false;
this._kernelSetupCache = new Map<string, boolean>();
this._requiredKernelPackages = new Map<string, PythonPkgDetails[]>();
let allPackages = requiredJupyterPackages.sharedPackages;
for (let kernelInfo of requiredJupyterPackages.kernels) {
// Add this kernel's specific dependencies to the running list of packages for All Kernels.
allPackages = allPackages.concat(kernelInfo.packages);
this._requiredKernelPackages.set(constants.ipykernelDisplayName, [requiredJupyterPkg, requiredNotebookPkg]);
this._requiredKernelPackages.set(constants.python3DisplayName, [requiredJupyterPkg, requiredNotebookPkg]);
this._requiredKernelPackages.set(constants.powershellDisplayName, [requiredJupyterPkg, requiredPowershellPkg, requiredNotebookPkg]);
// Combine this kernel's specific dependencies with the shared list of packages to get its
// full list of dependencies
let packages = requiredJupyterPackages.sharedPackages.concat(kernelInfo.packages);
this._requiredKernelPackages.set(kernelInfo.name, packages);
}
let allPackages = [requiredJupyterPkg, requiredNotebookPkg, requiredPowershellPkg];
this._requiredKernelPackages.set(constants.allKernelsName, allPackages);
this._requiredPackagesSet = new Set<string>();
allPackages.forEach(pkg => {
this._requiredPackagesSet.add(pkg.name);
});
this._requiredPackageNames = new Set<string>(allPackages.map(pkg => pkg.name));
}
private async installDependencies(backgroundOperation: azdata.BackgroundOperation, forceInstall: boolean, packages: PythonPkgDetails[]): Promise<void> {
@@ -453,8 +437,10 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
await notebookConfig.update(constants.existingPythonConfigKey, this._usingExistingPython, vscode.ConfigurationTarget.Global);
await this.configurePackagePaths();
await vscode.commands.executeCommand(constants.BuiltInCommands.SetContext, constants.CommandContext.NotebookPythonInstalled, true);
this._installCompletion.resolve();
this._installInProgress = false;
if (this._upgradeInProcess) {
// Pass in false for restartJupyterServer parameter since the jupyter server has already been shutdown
// when removing the old Python version on Windows.
@@ -627,7 +613,7 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
public uninstallPipPackages(packages: PythonPkgDetails[]): Promise<void> {
for (let pkg of packages) {
if (this._requiredPackagesSet.has(pkg.name)) {
if (this._requiredPackageNames.has(pkg.name)) {
this._kernelSetupCache.clear();
break;
}
@@ -679,7 +665,7 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
public async uninstallCondaPackages(packages: PythonPkgDetails[]): Promise<void> {
if (this.condaExecutable) {
for (let pkg of packages) {
if (this._requiredPackagesSet.has(pkg.name)) {
if (this._requiredPackageNames.has(pkg.name)) {
this._kernelSetupCache.clear();
break;
}

View File

@@ -14,7 +14,6 @@ import { JupyterServerInstallation } from './jupyterServerInstallation';
import * as utils from '../common/utils';
import { IServerInstance } from './common';
import { PerFolderServerInstance, IInstanceOptions } from './serverInstance';
import { CommandContext, BuiltInCommands } from '../common/constants';
export interface IServerManagerOptions {
documentPath: string;
@@ -105,7 +104,6 @@ export class LocalJupyterServerManager implements nb.ServerManager, vscode.Dispo
private async doStartServer(kernelSpec: nb.IKernelSpec): Promise<IServerInstance> { // We can't find or create servers until the installation is complete
let installation = this.options.jupyterInstallation;
await installation.promptForPythonInstall(kernelSpec.display_name);
void vscode.commands.executeCommand(BuiltInCommands.SetContext, CommandContext.NotebookPythonInstalled, true);
// Calculate the path to use as the notebook-dir for Jupyter based on the path of the uri of the
// notebook to open. This will be the workspace folder if the notebook uri is inside a workspace

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