Compare commits

..

203 Commits
1.2.4 ... 1.3.9

Author SHA1 Message Date
kisantia
cacf0777c7 Moving onValidityChanged listener to showPage() so that it gets added to pages that are added to the wizard after the initial start up (#3691) 2019-01-14 15:01:54 -08:00
Karl Burtram
cb433fbeac Bump Azure Data Studio to 1.3.9 2019-01-14 14:24:28 -08:00
Kevin Cunnane
8f6736df5e Fix #3736 Notebook: cannot connect to SQL big data cluster due to empty config.json file (#3738)
- Writing the config file in the core for now, will look to move to the extension in Feb release
2019-01-14 14:19:45 -08:00
Anthony Dresser
ef76d730e3 fix html formatting in grid (#3722) 2019-01-14 14:15:25 -08:00
Karl Burtram
aabbeeffa9 Add connection dialog icon dark theme and HC styles (#3721) 2019-01-14 14:13:43 -08:00
Anthony Dresser
7a513de543 Duplicate Result sets (fix merge conflicts) 2019-01-14 14:12:29 -08:00
Karl Burtram
abbd5ec037 Add Idera extension to recommendation list (#3709) 2019-01-14 14:09:08 -08:00
Karl Burtram
84009f65ec Save grid selection/vertical scroll when switching tabs 2019-01-08 15:37:20 -08:00
kisantia
191648df0a Fix database not getting set correctly in DacFx wizard deploy scenario (#3641)
* fix db not getting set correctly for deploy scenario if coming from import page

* removed space so that comments go directly after //
2019-01-07 12:06:20 -08:00
Matt Irvine
1265a56ff4 Update edit data for result set streaming changes (#3634) 2019-01-07 12:06:11 -08:00
Aditya Bist
2171d44922 removed potentially PII (#3619) 2018-12-12 14:13:50 -08:00
Anthony Dresser
812f315e69 Account for different situations for stream setting (#3615)
* add cases for different situation

* default streaming setting false
2018-12-12 12:12:18 -08:00
Karl Burtram
d48258a0fb Turn off "something went wrong" message (#3606) 2018-12-11 16:19:23 -08:00
Karl Burtram
8ec78f67af Merge branch 'master' into release/1.3 2018-12-11 15:10:32 -08:00
Anthony Dresser
0ac0175bb1 update table size on result set update (#3604) 2018-12-11 15:05:28 -08:00
Anthony Dresser
f39007cd2d wrong variable name (#3603) 2018-12-11 15:05:11 -08:00
Karl Burtram
348b03327e Merge branch 'master' into release/1.3 2018-12-11 11:29:01 -08:00
Yurong He
2349aa4df8 Fixed #3596 by change URI.parse to URI.file to get the path (#3597) 2018-12-11 11:23:29 -08:00
Karl Burtram
6497bbcc38 Merge branch 'master' into release/1.3 2018-12-10 17:39:23 -08:00
Yurong He
a93a173183 The CSS class is overwritten by the previous change. Add it back (#3583) 2018-12-10 17:36:58 -08:00
Karl Burtram
a1abca26df Remove a style that is breaking the "Clear MRU" list (#3587) 2018-12-10 17:36:55 -08:00
Anthony Dresser
42e55dd2dd Result Streaming settings (#3537)
* add setting control for result streaming

* change default result streaming to true
2018-12-10 17:36:35 -08:00
Raj
ca3146d38f Filetype while prmopting for save #3552 (#3575) 2018-12-10 17:02:16 -08:00
Alan Ren
7f6cd514a5 Alanren/profiler search (#3525)
* further improve the search experience for profiler

* change the default value for parameter
2018-12-10 16:43:58 -08:00
Aditya Bist
88e24e92b5 Agent: features and suggestions (#3512)
* removed row highlighting overlap with scrollbars

* fixed more styling suggestions

* made async calls parallel and improved UI

* cleared style
2018-12-10 16:36:41 -08:00
Anthony Dresser
8b447e361f change cancelation in the async data loader to correctly cancel requests (#3516) 2018-12-10 16:29:02 -08:00
Chris LaFreniere
a92dd2d4e4 Fix for PySpark3 not being selected by default (#3554) 2018-12-10 16:26:57 -08:00
Karl Burtram
852ec44567 Fix DataTier wizard null ref looking up provider with no active connection (#3528) 2018-12-10 16:26:06 -08:00
Raj
b6e32cdeb4 Rename notebook editor (fixes #3521) (#3536)
* Rename notebook editor #3521

* Review comments #3521
2018-12-10 13:26:29 -08:00
Alan Yu
4bd264d9be Add feature request template (#3487)
* Add feature request template

Github recently added feature for issue templates to also automatically assign a label. By setting this template, we can have some guidance for users who want to ask a feature request instead of an issue.

We can also have this be the default within the product when a user clicks "request a missing feature" on the smiley face button

* update label
2018-12-10 11:40:39 -08:00
Karl Burtram
4a4b8574d0 Update Azure Data Studio to 1.3.8 2018-12-10 11:30:20 -08:00
Yurong He
ded073edd9 Added clear output to ToggleMoreAction and added it to markdown preview (#3535)
* Added toggleMoreActions to Markdown Preview only.
When it is in editor mode, only editor display ToggleMoreActions.

* Added clear output back
2018-12-10 11:17:35 -08:00
Alan Yu
568f95e7a3 Update SQL Server Import readme extension (#3519)
Added DacFx wizard text
2018-12-10 10:42:13 -08:00
Chris LaFreniere
5adcabc8de Add back Notebook Completion List IntelliSense (#3520)
* Static notebook intellisense working

* Intellisense dynamic cells working

* Remove launch.json erroneous change

* PR comments #1

* PR feedback to change a minor condition
2018-12-07 18:04:32 -08:00
Kevin Cunnane
e3bce7172c Handle delayed Notebook provider registration (#3526)
* Handle delayed Notebook provider registration
- Fixes #3197 Notebooks: builtin provider always used on reopen with notebook file visible
- Fixes #3414 Can't refresh kernel after connect to big data cluster

There are 3 parts to this fix:
- If no notebook provider other than the default is installed, we warn users and prompt to install the SQL2019 extension
- We wait on the extension host registration to complete before determining which provider to use
- We know that the extension registration of the provider instance will be after package.json is read, so if we wait after registration for 10 seconds to give this a chance to happen before returning a provider to the front end

* Remove launch.json change that was added accidentally

* Fix timeout not being the expected value

* Removed console log left in during debugging

* Remove unnecessary whitespace

* Fix unit test failure

* Name the registration better, and remove outdated comments
2018-12-07 17:56:21 -08:00
Raj
96fb618390 Notebook saves are broken #3432 (#3478)
* Notebook saves are broken #3432

* Misc change

* Save notebook uri to This

* Untitled notebook save including review comments #3432

* Cleanup

* Misc changes
2018-12-07 16:27:23 -08:00
Alan Yu
2d4fdcb661 Updated SQL Server Import extension readme
Added Data-Tier Application Wizard
2018-12-07 15:26:48 -08:00
Yurong He
7a84cff5b4 Fixed #3508 by removing the fixed height of toolbar (#3518) 2018-12-07 15:16:53 -08:00
Yurong He
2af627b704 Fixed #3497 (#3517) 2018-12-07 14:16:00 -08:00
Alan Ren
77fdf18686 improve the visual effect for selected card (#3509)
* improve the visual effect for selected card

* remove shadow for unselected card as per Smitha's suggestion

* fix the issue of status icon not changing when new theme selected
2018-12-07 14:13:52 -08:00
Yurong He
944a77fe42 Fixed #3287 adding loading-spinner to markdown cell (#3505) 2018-12-07 13:07:00 -08:00
Chris LaFreniere
049678b32e Change notebook width to 100 (#3423) 2018-12-07 12:22:19 -08:00
Kevin Cunnane
3325e4d854 Fix #3422 Notebooks opened from within ADS should be Trusted by default. (#3498) 2018-12-07 12:14:57 -08:00
Kevin Cunnane
1e90e88d4b Fix #3481 Notebook: Markdown coloring appears incorrect (#3499)
- Set markdown as language for markdown cell
- Fix issue where after loading language from cell metadata, always override it. This made the "language" feature irrelevant in the cell.
- Fixed tests with new behavior (assumption: cell-level language overrides notebook-level definition) and added new test to cover this too
2018-12-07 12:14:43 -08:00
Kevin Cunnane
8aeb33c98c Fix #3470 Notebook: Switching between Servers and File Explorer opens a duplicate notebook (#3500)
- We missed implementing matches functionality. This is required in order to skip reopening of the notebook
2018-12-07 12:14:26 -08:00
Yurong He
3b08721835 Fixed #3415 add padding-left/right 8px (#3462)
* Fixed #3415 add padding-left/right 8px

* We will keep CSS consistent for review and editing mode. So removed codes not used.
2018-12-07 09:02:20 -08:00
Karl Burtram
5a30878599 Bump agent, import, profiler extension versions 2018-12-06 18:11:11 -08:00
Karl Burtram
c8a8935db0 Bump SQL Tools Service to 1.5.0-alpha.63 2018-12-06 17:58:49 -08:00
Aditya Bist
ec196f57bb Agent feature - ability to start at step (#3483)
* added ability to start at certain step

* fixed width for scrollbar

* localized string
2018-12-06 17:43:26 -08:00
Matt Irvine
f7809ec3a7 Add ability to select AAD tenant when connecting (#3475) 2018-12-06 10:46:27 -08:00
Kevin Cunnane
71d3ec3616 Fix #3420 Analyze in notebook doesn't include text (#3482)
- Add edit API that can be used in the extension
- Separated document and editor classes out since this is the point those get big. I can refactor back in if needed to ease code review
- Based this off text editing APIs but tweaked for the fact this is a cell/array based set of edits
2018-12-06 10:33:32 -08:00
Yurong He
4a7cf8d870 Disable key binding for this release. (#3466) 2018-12-06 10:04:02 -08:00
Alan Ren
4bf8836c0a profiler extension bug fixes (#3490) 2018-12-06 09:58:33 -08:00
ranasaria
1ca36ee29c bumping to version 62 to toolsservice to pick up resutlstreaming backend fixes 2018-12-05 22:39:23 -08:00
Yurong He
3446ff88cf Fixed #3472 check SaveKernelInfo not null (#3473) 2018-12-05 14:21:14 -08:00
Chris LaFreniere
de5a91a13f Allow for Notebook Cell Unselection (#3460)
* Allow for cell unselection

* PR Feedback: use event.stopPropagation() when multiple events can fire

* Ensure markdown goes into Preview mode when  cell not selected
2018-12-05 13:22:56 -08:00
Karl Burtram
814cd73019 Dispose of query grid memory on tab switch (#3458) 2018-12-05 12:17:16 -08:00
Aditya Bist
c21611661b Agent feature usage metrics (#3346)
* agent feature usage metrics

* generalized feature telemetry via dialogs

* renamed eventName property to dialogName

* made dialogName an optional field
2018-12-05 11:01:46 -08:00
Yurong He
8f817ce689 Fixed Notebooks regression: invalid kernels aren't handled #3404 (#3447)
* Fixed the not supported kernel in saved notebook

* Resolve PR comment.
2018-12-05 10:54:37 -08:00
Aditya Bist
971b5111e7 Agent: Scrolling (#3427)
* change height calcs to proper tree height

* agent fixes

* fit step tree

* fix rendering issue

* fixed spinning wheel position

* added horizontal scrolling to steps tree

* removed typo
2018-12-05 10:16:39 -08:00
Chris LaFreniere
07069a64ae Tweak notebook cell box shadow/border-width (#3454) 2018-12-04 19:21:55 -08:00
Karl Burtram
6acea51f12 Bump SQL Tools to 1.5.0-alpha.61 2018-12-04 17:51:51 -08:00
Raj
7aa2dab307 Defaulting 'attach to' to localhost when no extension is installed #3419 (#3426) 2018-12-04 13:45:10 -08:00
Raj
3091be8f67 Set active editor with dirty value before and after save #3411 (#3417) 2018-12-04 13:21:13 -08:00
Kevin Cunnane
487531cc52 Fix build break due to rename of APIs prior to checkin of unit tests (#3418) 2018-12-04 10:42:32 -08:00
Yurong He
58bfcb4273 Fixed can't read indexof exception when no big data cluster connection and switch to PySpark3 (#3413) 2018-12-04 10:36:34 -08:00
Kevin Cunnane
8d8be27f22 Add basic notebook model tests (#3396)
- Ported from the extension
- Only adding tests that related to the internally implemented functionality, not to anything provider-specific.
2018-12-04 10:01:10 -08:00
Yurong He
27a978cba5 Fixed #3387 (#3401) 2018-12-04 09:41:31 -08:00
Chris LaFreniere
71b4e6afa4 Fix Notebook Code Cell Height when Lines Wrap (#3403)
* Fix Notebook Code Cell Height when Lines Wrap

* Addressing PR comments
2018-12-03 20:55:46 -08:00
Chris LaFreniere
e1f3b19c0c Ensure Selectboxes in Notebook Toolbar have Minimum Size (#3393)
* Setting minimum width on selectboxes in notebook toolbar

* Fix spacing
2018-12-03 20:31:08 -08:00
Kevin Cunnane
649c2aa5a6 Fix preview handling so the untitled notebooks are pinned by default (#3405) 2018-12-03 20:26:42 -08:00
Kevin Cunnane
cac8cc99e1 Notebook extensibility: Move New Notebook and configuration to an extension (#3382)
initial support for Notebook extensibility. Fixes #3148 , Fixes #3382.

## Design notes
The extensibility patterns are modeled after the VSCode Document and Editor APIs but need to be different since core editor concepts are different - for example Notebooks have cells, and cells have contents rather than editors which have text lines.

Most importantly, a lot of the code is based on the MainThreadDocumentsAndEditors class, with some related classes (the MainThreadDocuments, and MainThreadEditors) brought in too. Given our current limitations I felt moving to add 3 full sets of extension host API classes was overkill so am currently using one. Will see if we need to change this in the future based on what we add in the additional APIs

## Limitations
The current implementation is limited to visible editors, rather than all documents in the workspace. We are not following the `openDocument` -> `showDocument` pattern, but instead just supporting `showDocument` directly.

## Changes in this PR
- Renamed existing APIs to make clear that they were about notebook contents, not about notebook behavior
- Added new APIs for querying notebook documents and editors 
- Added new API for opening a notebook
- Moved `New Notebook` command to an extension, and added an `Open Notebook` command too
- Moved notebook feature flag to the extension

## Not covered in this PR
- Need to actually implement support for defining the provider and connection IDs for a notebook. this will be important to support New Notebook from a big data connection in Object Explorer
- Need to add APIs for adding cells, to support 
- Need to implement the metadata for getting full notebook contents. I've only implemented to key APIs needed to make this all work.
2018-12-03 18:50:44 -08:00
Raj
cb162b16f2 No kernel is shown when open a new notebook from command palette (#3374)
Fixes #3271. Ensure a provider is defined when opening through command palette
2018-12-03 18:12:25 -08:00
Karl Burtram
86e54ce145 Bump Azure Data Studio to 1.3.7 2018-12-03 17:43:12 -08:00
Anthony Dresser
efd809971f fix row select (#3390) 2018-12-03 14:10:50 -08:00
Karl Burtram
38ae14cc4d Use UTF8 for Azure token cache (#3391)
* Switch token cache encryption encoding to UTF8

* Try to parse as binary in fallback

* Code review feedback
2018-12-03 14:09:42 -08:00
Chris LaFreniere
c7e33a90fe Notebook toolbar extensibility (#3362)
* Notebook Toolbar Contribution

* Address CR comments, ensure CSS can be passed in for contributed items
2018-12-03 11:15:14 -08:00
Yurong He
5add835750 Fixed issue: Notebook: Can't use PySpark3 even though having big data cluster connected #3363 (#3380) 2018-12-03 10:53:04 -08:00
Karl Burtram
734c614cba Update installer to regkeys for per-user install (#3376) 2018-11-30 16:56:19 -08:00
Karl Burtram
f6b347fa62 Bump Azure Data Studio to 1.3.6 2018-11-30 16:51:27 -08:00
Alan Ren
08d2f3125e Fix for issue 3133 (#3375)
* Fix for issue 3133

* fix test error
2018-11-30 15:53:36 -08:00
Matt Irvine
385c48dcad Wait for account provider registration when using account service (#3221) 2018-11-30 11:52:01 -08:00
Yurong He
0926057bfe Fixed #3294 removed dead code for "attach to" and remove disable to make it respond theme change (#3349)
* Fixed #3294

* Fixed #3294
2018-11-29 19:28:08 -08:00
Karl Burtram
6912e3893e Bump Azure Data Studio to 1.3.5 2018-11-29 17:12:32 -08:00
Karl Burtram
d3052657df Bump SQL Tools to 1.5.0-alpha.60 2018-11-29 17:12:05 -08:00
Karl Burtram
a5ca4d8edf Add ALTER and PROC to the colorization list (#3353) 2018-11-29 17:04:45 -08:00
Anthony Dresser
afb1ebebd5 Result Streaming (#3319)
* handle releasing data when the grid is unrendered

* update sqlops

* add complete to sqlops

* update protocol

* update protocol

* formatting

* update sqlops.d.ts

* stash

* better handling of results streaming

* formatting

* improvments to result streaming

* bump slickgrid and address a performance bottleneck

* remove unnecessary code

* formatting

* update locks

* optimize large values in the grid

* formatting

* formatting

* update yarn

* bump packages

* yarn

* bump

* yarn lock

* locking

* yarn

* fix duplicate result sets

* fix event stream versions

* yarn
2018-11-29 15:16:53 -08:00
Matt Irvine
a04a9eb5ad Hide connection account picker when there are no auth type options (#3350) 2018-11-29 14:54:46 -08:00
Cory Rivera
027badd21f Fix capitalization in dataTierApplicationWizard imports. (#3351) 2018-11-29 14:32:45 -08:00
Raj
1affc760e6 Notebook save functionality through button (#3340)
* 3268: Notebook save using button

* 3268: Misc change

* Handle promise while saving notebook

* Async await functions to run action
2018-11-29 14:10:16 -08:00
Yurong He
3ca72b7398 Fixed Spark UI links within Notebooks are not working notebooks sql2019Preview (#3344)
#3277
2018-11-29 12:52:18 -08:00
Yurong He
702dbddd78 Fixed some issues for Markdown and CSS (#3336)
* Fixed few markdown cell issues
* Change the boolean value from 1 to true
2018-11-29 12:50:53 -08:00
Aditya Bist
8fbecc0227 Fixed agent step update (#3308)
* fixed agent step update

* enabled reordering of steps in edit job
2018-11-29 10:48:12 -08:00
Alan Ren
421271acfa hide the profiler commands meant for internal use (#3339) 2018-11-28 15:03:53 -08:00
Raj
98af76b3ac Build error (#3335) 2018-11-28 10:45:21 -08:00
Raj
3952fdbe2d 3240: Empty cells show thick border (#3242)
* 3240: Empty cells show thick border

* 3240: Refactoring code and markdown css selection +output UI improvement
2018-11-28 09:45:34 -08:00
Yurong He
bc13beaa85 Revert "Hide run button in markdown editor and pull toggleMoreAction to a seperate class (#3321)" (#3328)
This reverts commit 9ea8baca05.
2018-11-27 23:43:16 -08:00
Karl Burtram
59b2e706ca Bump Import extension to 0.4.2 2018-11-27 17:59:34 -08:00
Karl Burtram
8bf835c531 Update SQL Tools Service to 1.5.0-alpha.59 2018-11-27 16:37:46 -08:00
Matt Irvine
087ed7c132 Make resource parameter optional for getSecurityToken API (#3322) 2018-11-27 16:12:30 -08:00
kisantia
4c075df327 DacFx import/export wizard (#3162)
Basic wizard to import/export bacpacs and deploy/extract dacpacs
2018-11-27 16:10:17 -08:00
Yurong He
9ea8baca05 Hide run button in markdown editor and pull toggleMoreAction to a seperate class (#3321) 2018-11-27 15:32:20 -08:00
Karl Burtram
9b6784720e Add EXCEPT,INTERSECT and DATALENGTH to color syntax (#3320) 2018-11-27 13:52:07 -08:00
Karl Burtram
3761e1dd60 Port event-stream changes from vscode (#3317) 2018-11-27 12:55:44 -08:00
Yurong He
b3eb809550 Hide ToggleMoreAction for inactive cell (#3235)
* Hide ToggleMoreAction for inactive cell

* Revert wrong merge

* Undo bad merge

* Enable markdown to hide ToggleMoreAction

* Resolve PR comments

* Fixed the name

* Change name

* Fix toggleMoreActions by passing in CellContext instead of just nb model

* Fixed the warning by removing notificationService from the caller
2018-11-27 12:54:27 -08:00
Matt Irvine
cb72865dcc Enable Azure Active Directory MFA authentication (#3125) 2018-11-27 11:13:47 -08:00
Anthony Dresser
d646b4729b Revert "Result Streaming (#3124)" (#3312)
This reverts commit 8925d44807.
2018-11-27 10:42:41 -08:00
Karl Burtram
a2dd903d0d Bump import, profiler, and agent extensions 2018-11-27 07:25:31 -08:00
Karl Burtram
28ed378ee7 Bump Azure Data Studio to 1.3.4 2018-11-27 05:53:43 -08:00
Karl Burtram
15ae55136f Bump event-stream to 3.3.4 2018-11-26 16:34:03 -08:00
Karl Burtram
b18abd954f Update Azure Data Studio to 1.3.3 2018-11-26 16:32:34 -08:00
Allen Cook
b45f79a1f8 Add Routine_Type to CreateStoredProc fixes #3257 (#3286) 2018-11-26 15:26:12 -08:00
Alan Ren
01a03b4c84 revert the taskbar icon size change (#3306) 2018-11-26 15:14:36 -08:00
Anthony Dresser
e48328af34 Handle qp clear input correctly (#3258)
* handle clearing xml in qp view

* formatting
2018-11-26 14:49:06 -08:00
Anthony Dresser
8925d44807 Result Streaming (#3124)
* handle releasing data when the grid is unrendered

* update sqlops

* add complete to sqlops

* update protocol

* update protocol

* formatting

* update sqlops.d.ts

* stash

* better handling of results streaming

* formatting

* improvments to result streaming

* bump slickgrid and address a performance bottleneck

* remove unnecessary code

* formatting

* update locks

* optimize large values in the grid

* formatting

* formatting

* update yarn

* bump packages

* yarn

* bump

* yarn lock

* locking

* yarn
2018-11-26 14:30:35 -08:00
Karl Burtram
213283510f Bump SQL Tools to 1.5.0-alpha.58 for results streaming 2018-11-26 13:54:56 -08:00
Alan Ren
9f8190dc28 make taskbar more readable (#3290) 2018-11-20 15:09:24 -08:00
Alan Ren
c32d4ee2f7 fix for 3245 (#3281) 2018-11-19 14:47:41 -08:00
Aditya Bist
2c867a4b2c unlocalized string (#3259) 2018-11-17 08:37:42 -08:00
Alan Ren
da5194bdcb fix for 3262 (#3263) 2018-11-16 21:19:32 -08:00
Chris LaFreniere
bbb27aed10 Notebook: Re-Enable Attach to Dropdown Functionality (#3250)
* first attach to working

* Transfer changes from sqlopsstudioextensions PR 448

* Transfer changes from sqlopsstudioextensions PR 447

* Transfer changes from sqlopsstudioextensions PR 456

* Transfer changes from sqlopsstudioextensions PR 465

* Transfer changes from sqlopsstudioextensions PR 463

* Transfer changes from sqlopsstudioextensions PR 482

* Transfer changes from sqlopsstudioextensions PR 485

* Session and Kernel implementation except executeRequest

* Attach to port compiling

* Further tweaks to attach to dropdown, re-enable opening connection dialog

* Revert "Merge remote-tracking branch 'origin/Notebook/sessionExtension' into feature/workingAttachTo"

This reverts commit 94703db87c85416c4ae36762afc1094d6e71166a, reversing
changes made to e4dc25331036d259e9c762cfe8741f957bb5c590.

* Fix code formatting

* Fix for new Add new connection issue
2018-11-16 20:47:58 -08:00
Alan Ren
c02fbaeae7 min height for event detail view when expanding (#3255) 2018-11-16 15:07:56 -08:00
Karl Burtram
847218da73 Disconnect Object Explorer node when session is disconnected from SQL Tools Service (#3249)
* WIP

* WIP

* Send disconnect event to OE

* Bump dataprotocol to 0.2.9

* Cleanupps

* Address a couple feedback
2018-11-16 13:08:20 -08:00
Kevin Cunnane
90dc788893 Implement Session support through the extension host (#3228)
Full plumb through of Session support. Also fixed some test issues

- Load session and get necessary information in kernels list
- Run Cell button now works as expected
- Added a ToggleAction base class which can be used for anything that switches icons. I'd still prefer to have this be dynamic and as clean as the extension classes
- Fixed account test unhandled promise rejections (caused by incorrect / invalid tests) that made it hard to see all the test run output.
2018-11-16 10:35:03 -08:00
Karl Burtram
f3525cc555 Bump Azure Data Studio to 1.3.2 2018-11-15 17:24:12 -08:00
abist
198f243181 scoped the agent action bar class style 2018-11-15 16:11:20 -08:00
Alan Ren
8e049f4af5 align the radio button with text (#3241) 2018-11-15 14:01:32 -08:00
Danny McCormick
ff465a59b6 Remove travis and appveyor (#3234)
* Delete .travis.yml

* Delete appveyor.yml
2018-11-15 11:52:36 -08:00
Danny McCormick
68b4f3ca04 Add Azure Pipelines status badge (#3233) 2018-11-15 11:51:42 -08:00
Chris LaFreniere
6b31f2b3f2 Stop Showing Overview Rulers in Notebooks (#3226)
* Stop showing decorationsOverviewRuler in notebook code cells by setting hidden visibility in css

* Also change overviewRuler options in IEdtorOptions for safety

* address CR comments in css file
2018-11-15 11:47:03 -08:00
Raj
63cf0f1548 Trusted/Not-trusted functionality implementation (#3211)
* 3194: Hookup trusted/not-trusted functionality and css changes

* 3194: Trusted implementation changes

* 3194: Code review changes

* 3225: No border in between code-cell and output
2018-11-14 19:07:10 -08:00
Yurong He
e607f68b3e Add more actions to cell (#3217)
* Added toggle more actions to cell

* Resolve PR comments
-- Added INotificationService for notification msg

* Reduced ToggleMoreAction to smaller size. So the dropdown could be displayed closer to it instead of at the buttom of the cell.
2018-11-14 17:51:59 -08:00
Yurong He
db3bb82dbd Change code and text font to 11 (#3216)
Ajust the padding top to 0
Change task bar height to 36
2018-11-14 15:36:24 -08:00
Yurong He
5889c600fa Resend selectBox change to on against master. PR against nativeNotebook was approved already. (#3215) 2018-11-14 13:48:41 -08:00
Matt Irvine
d7d4c7236c Update azure-pipelines-windows file test path (#3214) 2018-11-14 13:41:55 -08:00
Kevin Cunnane
f54d8ce36f Merge changes from the Notebook feature branch.
These will be preserved as they have important history.
2018-11-14 11:33:59 -08:00
Kevin Cunnane
43faa13cb5 Add notebook feature flag that is enabled by default (#3210)
* Add notebook feature flag that is enabled by default
- After this, the `notebook.enabled` flag must be set to true when testing notebook integration
2018-11-14 11:33:22 -08:00
Matt Irvine
85a2d994f3 Don't close connection dialog when cancelling a connection (#3207) 2018-11-13 16:44:26 -08:00
Kevin Cunnane
d8cd78cd6b Merge master 2018-11-13 16:35:17 -08:00
Alan Ren
3e59a5bcd2 update version to 0.4.0 (#3205) 2018-11-13 15:20:31 -08:00
Aditya Bist
0efb89d6ff fix loading perf when switching tabs (#3169) 2018-11-13 13:06:45 -08:00
Matt Irvine
6697c075cb Use newer version of request in azurecore (#3202) 2018-11-13 12:59:16 -08:00
Chris LaFreniere
06660160e7 Vertical Toolbar Improvements and Fix for Untitled File Load Issue (#3189)
* Add horizontal toolbar

* Add vertical toolbar

* Fix for untitled scheme file load

* further fixes to vertical toolbar

* Addressing PR comments
2018-11-13 11:05:54 -08:00
Kevin Cunnane
0b571737b7 Support notebook file types contribution (#3196)
* Support notebook file types contribution
- Extensions can define a provider and what file types it should be used for
- Verified that this works for Jupyter Content & Server Managers.
- Starts Jupyter server as expected

Not in this PR:
- Support for session manager end to end
- Tests
2018-11-12 17:32:53 -08:00
Raj
0a486a280d 3190: Code and Text cells from tool bar (#3191)
* 3190: Code and Text cells from tool bar

* 3190: Adding images under media folder and to css
2018-11-12 11:41:02 -08:00
Alan Ren
bd53e685d0 bump to .53 (#3187) 2018-11-09 10:57:30 -08:00
Raj
a2bbf3f44e 3147: Notebook markdown cell should be opened in preview mode (#3168)
* 3147: Notebook markdown cell should be opened in preview mode

* 3147: Default ability to double click a cell to add text

* Misc changes

* CSS cleanup

* Localization stuff

* Remove constants file in Notebook codebase
2018-11-09 10:38:14 -08:00
Alan Ren
410bb62906 fix for stop session error and session selection lost issue (#3167)
* fix for stop session error and session selection lost issue

* remove the console.error call
2018-11-08 16:51:39 -08:00
Alan Ren
cbb4ac3e20 make it preserve the line breaks (#3176) 2018-11-08 16:34:27 -08:00
Yurong He
7508192ab9 Added empty kernel and hook up with Kernel drop down (#3173)
* Initial toolbar work
- This is in-progress and needs additional fixes

* Resolve PR comments

* Added empty kernel and hook up with Kernel dropdown

* Resolve PR comments
2018-11-08 14:27:20 -08:00
Raj
bbf6cbd8fb Hookup trusted flag to both code cell and markdown preview (#3166)
* 1133: Notebook file registration changes

* File registration stuff

* Yarn files

* Outputview Changes

* Misc changes

* Changes to code component name space

* Output view changes

* notebook output view changes

* Latest changes

* Output view changes

* Code review changes on output view

* CSS file and misc changes

* Hookup trusted mode to code cell and markdown

* Return default sanitizer

* Misc changes - code review comments
2018-11-08 14:12:59 -08:00
Kevin Cunnane
9765269d27 Begin defining Extension-based Notebook Provider (#3172)
Implements provider contribution in the MainThreadNotebook, with matching function calls in the ExtHostNotebook class. This will allow us to proxy through notebook providers (specifically, creation of a notebook manager with required content, server managers) from an extension up through to the main process.

Implemented in this PR:
- Callthroughs for content and server manager APIs
- Very basic unit tests covering provider & manager registration

Not implemented:
- Fuller unit tests on the specific callthrough methods for content & server manager.
- Contribution point needed to test this (so we can actually pass through the extension's existing Notebook implementation)
2018-11-08 13:06:40 -08:00
Alan Ren
61746b7ff7 Update UX-Design-Guidelines.md 2018-11-08 10:37:45 -08:00
Alan Ren
e6066c2cb5 Rename UX-Design-Guidelines to UX-Design-Guidelines.md 2018-11-08 10:29:43 -08:00
Alan Ren
633a918590 Create UX-Design-Guidelines 2018-11-08 10:29:16 -08:00
Raj
71c14a0837 Output view changes (#3146)
* 1133: Notebook file registration changes

* File registration stuff

* Yarn files

* Outputview Changes

* Misc changes

* Changes to code component name space

* Output view changes

* notebook output view changes

* Latest changes

* Output view changes

* Code review changes on output view

* CSS file and misc changes
2018-11-07 14:19:33 -08:00
Alan Ren
9bbed2c275 fix for issue 3157 (#3158)
* fix for issue 3157

* use state instead of _state
2018-11-07 12:00:51 -08:00
Alan Ren
d9ba4d9130 profiler improvements (#3151)
* profiler improvements

* fix for issue 3114
2018-11-07 11:25:24 -08:00
Kevin Cunnane
ecd40de7ec Integrate notebook service with notebook UI (#3143)
Port notebookView code over to notebook.component.ts.
Integrate loading of notebook contents into the UI
2018-11-06 16:31:37 -08:00
Olivier Truong
e2bd6c06ec typo (#3025)
without instead of wihtout
2018-11-06 11:22:27 -08:00
Karl Burtram
a26be76d79 Update readme for Nov release (#3138) 2018-11-06 11:21:40 -08:00
Danny McCormick
3b68c1eb69 Add Azure Pipelines (#3140)
* Adding ci files

* Single pipeline

* Add test reporting

* Try adding mocha-junit-reporter

* More complete test reporting

* Cleaning up

* Trying to find location of test file

* Added searching logic to wrong file

* Trying different method of getting test results

* Add reporter option

* Adding alternate way of getting mac os

* Get rid of bad comments
2018-11-06 11:21:26 -08:00
Alan Ren
f7879bdbf9 Alanren/custom message box location (#3139)
* make message box associated with wizard page

* missed one condition check after renaming

* fix compilation error
2018-11-06 10:44:02 -08:00
Karl Burtram
dbb0fc519f Update Azure Data Studio to 1.3.1 2018-11-06 10:40:58 -08:00
Alan Ren
b931ccfabf fix for 1705 (#3131) 2018-11-06 10:34:58 -08:00
Matt Irvine
eeab048f46 Use correct foreground color for copy details button (#3126) 2018-11-06 10:14:25 -08:00
Yurong He
5da89ac05b Add localContentManger and dummy sessionManager (#3130)
* - keyboard binding to arrow keys
- toggle markdown editor by double click

* Added localContentManger and dummpy sessionManager
2018-11-05 17:55:13 -08:00
Anthony Dresser
e2b446be1c change default setting for showing default connection info in settings (#3043) 2018-11-05 16:08:55 -08:00
Anthony Dresser
5f2e17a738 Query Editor Memory improvements (#3041)
* working through memory issues

* work in progress

* add missing value

* work in progress

* more work in progress

* various more memory fixes

* additional improvements

* fix imports

* change test that we dispose queries on close not dispose

* update tests
2018-11-05 16:08:41 -08:00
Aditya Bist
399d6d0045 fixed operator typo (#3113) 2018-11-05 10:19:50 -08:00
Alan Ren
f36f3ffd21 connect dialog ux improvement (#3105)
* connect dialog ux improvement

* more style updates
2018-11-04 17:10:05 -08:00
Kevin Cunnane
3c785ae7d8 Merge master 2018-11-04 15:15:27 -08:00
Kevin Cunnane
00cd772cbc Snippets: fix sqlCreateTable, remove database refs & use dbo schema (#3094)
- Fixed issues with sqlCreateTable snippet, which meant it couldn't effectively be used to tab through all fields and then hit execute without errors. Specifically fixed bugs where types like NVARCHAR were incorrectly escaped and the Id part of a column was outside the name section, both causing intellisense & execution breaks
- Changed SchemaName to dbo. This helps hit the "80% case" where objects are in the most common schema
- Removed DatabaseName from most snippets. The core issue is this requires you to manually type the exact database name into the snippet which is really hard. We should consider having separate "with Database" snippets or support SQLCMD variables which would let us default to the current database without needing users to manually type them in as alternatives, but having basic snippets just work on current DB is important.
2018-11-02 14:26:03 -07:00
Kevin Cunnane
d434724a54 Remove handle from API (#3093)
- This was missed in previous checkin
2018-11-01 17:00:46 -07:00
Karl Burtram
b6c9a3bb89 Bump Azure Data Studio to 1.2.4 2018-11-01 15:06:58 -07:00
Kevin Cunnane
fc3bf45a7f Port most notebook model code over to be behind a service (#3068)
- Defines a new NotebookService in Azure Data Studio which will be used to interact with notebooks. Since notebooks can require per-file instantiation the provider is just used to create & track managers for a given URI.
- Inject this into notebook.component.ts and pass required parameters that'll be used to properly initialize a manger into the method. Actual initialization not done yet.
- Port over & recompile notebook model code
- Define most required APIs in sqlops.proposed.d.ts. In the future, these will be used by extensions to contribute their own providers.
2018-10-31 22:01:40 -07:00
Karl Burtram
cbf6c06e4b Bump SQL Tools to 1.5.0-alpha.52 2018-10-31 20:37:47 -07:00
Anthony Dresser
cff21124da Auto Scale Axis (#3070)
* fix input to chart that was causes scales to not auto size

* formatting

* formatting

* added comments
2018-10-31 20:27:40 -07:00
Aditya Bist
ce7893c2e5 Agent/edit job logic (#3023)
* lumped stepdata with jobdata in job dialog

* fix bug with empty steps

* added clumped and update steps and schedules from job dialog

* edit data sends one call instead of multiple

* cleaned code
2018-10-31 16:40:36 -07:00
Alan Ren
f7dcaa38ff fix for issue 3065 (#3067)
* fix for 3065

* remove the parameter, no need to save connection
2018-10-31 16:13:09 -07:00
Karl Burtram
8ce1013a26 Remove SQL Import dashboard tab (#3064) 2018-10-31 15:23:24 -07:00
Aditya Bist
114d67b408 fixed null ref (#3061) 2018-10-31 13:50:44 -07:00
Alan Ren
56c2d16560 a few ux improvements (#3057)
* style update

* checkbox styler

* casing update
2018-10-31 13:44:12 -07:00
Alan Ren
2238c42432 fix for issue 2719 (#3060) 2018-10-31 13:22:08 -07:00
Karl Burtram
64f6cf6747 Bump SQL Tools to 1.5.0-alpha.51 2018-10-31 13:16:38 -07:00
Karl Burtram
c0e9f1ca43 Fix build break in previous Query Plan commit 2018-10-31 13:00:23 -07:00
David Shiflet
7f66087d8c Add a command line interface for connecting to a SQL Server (#3047)
* Add switches for server, database, user, integrated auth

* Refactor into new commandline service

* Open query editor when passed server on command line

* Add tests
2018-10-31 13:05:37 -04:00
Ryan
18671b7cca Add query plan theme support (#2991) (#3031)
Add monaco-editor and monaco-editor-hover to output otherwise backgrounds collide.
2018-10-31 10:03:02 -07:00
Alan Ren
233156c744 fix missing footer for backup dialog (#3056)
@MattIrv  Thanks for helping out
2018-10-30 16:17:14 -07:00
Kevin Cunnane
ac0ffab99c Merge remote-tracking branch 'origin/master' into feature/nativeNotebook 2018-10-30 16:08:19 -07:00
Ruturaj Gujar
5e964d2105 Fixed some typos and grammatical errors (#3027) 2018-10-30 11:54:48 -07:00
Karl Burtram
59e7a5fa4b Change 'None' to 'Do not save' in Connection Dialog (#3051) 2018-10-30 10:45:47 -07:00
Karl Burtram
8452f577d2 Bump Azure Data Studio to 1.2.3 2018-10-30 10:27:03 -07:00
Abbie Petchtes
533f2734f1 Add markdown cell to Notebook (#3014)
* add markdown cell

* add markdown preview for Notebook

* formatting

* address comment
2018-10-26 16:20:06 -07:00
Raj
2859bee4c0 1133: Notebook file registration changes (#2969)
* 1133: Notebook file registration changes

* File registration stuff
2018-10-24 13:47:41 -07:00
Abbie Petchtes
972f857c71 Cell code fit and finish (#2972)
* add the look and feel for code cell

* formatting

* adding the active cell

* formatting
2018-10-23 12:22:19 -07:00
AbbiePetcht
d2eb1488fd Merge branch 'master' into feature/nativeNotebook 2018-10-23 10:23:10 -07:00
AbbiePetcht
508e4eac61 Merge branch 'master' into feature/nativeNotebook 2018-10-17 10:58:49 -07:00
AbbiePetcht
fd1d807012 Merge branch 'master' into feature/nativeNotebook 2018-10-16 16:30:11 -07:00
Abbie Petchtes
906c4c7f39 Add code cell (#2909)
* initial work for addig code and code cell type

* add cell model and create editor for each cell

* formatting

* fix resizing issue

* small changes

* address comment
2018-10-16 16:28:15 -07:00
AbbiePetcht
668e43f57c Merge branch 'master' into feature/nativeNotebook 2018-10-12 13:01:43 -07:00
Abbie Petchtes
6d260c195f create new notebook editor and add the place holder for toolbar and cell list (#2817)
* create new notebook editor and add the place holder for toolbar and cell list

* address comments
2018-10-11 16:14:54 -07:00
AbbiePetcht
fdfecbb3f7 Merge branch 'master' into feature/nativeNotebook 2018-10-11 10:23:30 -07:00
325 changed files with 20008 additions and 2960 deletions

View File

@@ -1,6 +1,10 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
<!-- Please search existing issues to avoid creating duplicates. -->

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution or feature you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,58 +0,0 @@
sudo: false
language: cpp
os:
- linux
- osx
cache:
directories:
- $HOME/.cache/yarn
notifications:
email: false
webhooks:
- http://vscode-probot.westus.cloudapp.azure.com:3450/travis/notifications
- http://vscode-test-probot.westus.cloudapp.azure.com:3450/travis/notifications
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.9
- g++-4.9
- gcc-4.9-multilib
- g++-4.9-multilib
- zip
- libgtk2.0-0
- libx11-dev
- libxkbfile-dev
- libsecret-1-dev
before_install:
- git submodule update --init --recursive
- nvm install 8.9.1
- nvm use 8.9.1
- npm i -g yarn
# - npm config set python `which python`
- if [ $TRAVIS_OS_NAME == "linux" ]; then
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;
sh -e /etc/init.d/xvfb start;
sleep 3;
fi
# Make npm logs less verbose
# - npm config set depth 0
# - npm config set loglevel warn
install:
- yarn
script:
- node_modules/.bin/gulp electron --silent
- node_modules/.bin/gulp compile --silent --max_old_space_size=4096
- node_modules/.bin/gulp optimize-vscode --silent --max_old_space_size=4096
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./scripts/test.sh --coverage --reporter dot; else ./scripts/test.sh --reporter dot; fi
after_success:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .build/coverage/lcov.info; fi

View File

@@ -1,5 +1,28 @@
# Change Log
## Version 1.2.4
* Release date: November 6, 2018
* Release status: General Availability
## What's new in this version
* Update to the SQL Server 2019 Preview extension
* Introducing Paste the Plan extension
* Introducing High Color queries extension, including SSMS editor theme
* Fixes in SQL Server Agent, Profiler, and Import extensions
* Fix .Net Core Socket KeepAlive issue causing dropped inactive connections on macOS
* Upgrade SQL Tools Service to .Net Core 2.2 Preview 3 (for eventual AAD support)
* Fix customer reported GitHub issues
## Contributions and "thank you"
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
* rdaniels6813 for `Add query plan theme support #3031`
* Ruturaj123 for `Fixed some typos and grammatical errors #3027`
* PromoFaux for `Use emoji shortcodes in CONTRIBUTING.md instead of <20> #3009`
* ckaczor for `Fix: DATETIMEOFFSET data types should be ISO formatted #714`
* hi-im-T0dd for `Fixed sync issue with my forked master so this commit is correct #2948`
* hi-im-T0dd for `Fixed when right clicking and selecting Manage-correct name displays #2794`
## Version 1.1.3
* Release date: October 18, 2018
* Release status: General Availability

View File

@@ -1,6 +1,7 @@
# Azure Data Studio
[![Join the chat at https://gitter.im/Microsoft/sqlopsstudio](https://badges.gitter.im/Microsoft/sqlopsstudio.svg)](https://gitter.im/Microsoft/sqlopsstudio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://dev.azure.com/ms/azuredatastudio/_apis/build/status/Microsoft.azuredatastudio)](https://dev.azure.com/ms/azuredatastudio/_build/latest?definitionId=4)
Azure Data Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
@@ -8,12 +9,12 @@ Azure Data Studio is a data management tool that enables you to work with SQL Se
Platform | Link
-- | --
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2030731
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2030736
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2030738
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2030741
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2030746
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2030750
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2038320
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2038323
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2038327
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2038332
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2038401
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2038405
Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions.
@@ -61,6 +62,12 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro
## Contributions and "Thank You"
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
* rdaniels6813 for `Add query plan theme support #3031`
* Ruturaj123 for `Fixed some typos and grammatical errors #3027`
* PromoFaux for `Use emoji shortcodes in CONTRIBUTING.md instead of <20> #3009`
* ckaczor for `Fix: DATETIMEOFFSET data types should be ISO formatted #714`
* hi-im-T0dd for `Fixed sync issue with my forked master so this commit is correct #2948`
* hi-im-T0dd for `Fixed when right clicking and selecting Manage-correct name displays #2794`
* philoushka for `center the icon #2760`
* anthonypants for `Typo #2775`
* kstolte for `Fix Invalid Configuration in Launch.json #2789`
@@ -103,7 +110,6 @@ We would like to thank all our users who raised issues, and in particular the fo
* Russian: Andrey Veselov, Anton Fontanov, Anton Savin, Elena Ostrovskaia, Igor Babichev, Maxim Zelensky, Rodion Fedechkin, Tasha T, Vladimir Zyryanov
* Portuguese Brazil: Daniel de Sousa, Diogo Duarte, Douglas Correa, Douglas Eccker, José Emanuel Mendes, Marcelo Fernandes, Marcondes Alexandre, Roberto Fonseca, Rodrigo Crespi
And of course, we'd like to thank the authors of all upstream dependencies. Please see a full list in the [ThirdPartyNotices.txt](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/ThirdPartyNotices.txt)
## License

View File

@@ -34,6 +34,7 @@ expressly granted herein, whether by implication, estoppel or otherwise.
jquery-ui: https://github.com/jquery/jquery-ui
jquery.event.drag: https://github.com/devongovett/jquery.event.drag
jschardet: https://github.com/aadsm/jschardet
JupyterLab: https://github.com/jupyterlab/jupyterlab
make-error: https://github.com/JsCommunity/make-error
minimist: https://github.com/substack/minimist
moment: https://github.com/moment/moment
@@ -1166,6 +1167,43 @@ That's all there is to it!
=========================================
END OF jschardet NOTICES AND INFORMATION
%% JupyterLab NOTICES AND INFORMATION BEGIN HERE
Copyright (c) 2015 Project Jupyter Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Semver File License
===================
The semver.py file is from https://github.com/podhmo/python-semver
which is licensed under the "MIT" license. See the semver.py file for details.
END OF JupyterLab NOTICES AND INFORMATION
%% make-error NOTICES AND INFORMATION BEGIN HERE
=========================================
ISC © Julien Fontanet

View File

@@ -1,19 +0,0 @@
environment:
ELECTRON_RUN_AS_NODE: 1
VSCODE_BUILD_VERBOSE: true
cache:
- '%LOCALAPPDATA%\Yarn\cache'
install:
- ps: Install-Product node 8.9.1 x64
build_script:
- yarn
- .\node_modules\.bin\gulp electron
- npm run compile
test_script:
- node --version
- .\scripts\test.bat
- .\scripts\test-integration.bat

View File

@@ -0,0 +1,38 @@
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- script: |
git submodule update --init --recursive
nvm install 8.9.1
nvm use 8.9.1
npm i -g yarn
displayName: 'preinstall'
- script: |
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
sleep 3
displayName: 'Linux preinstall'
condition: eq(variables['Agent.OS'], 'Linux')
- script: |
yarn
displayName: 'Install'
- script: |
node_modules/.bin/gulp electron --silent
node_modules/.bin/gulp compile --silent --max_old_space_size=4096
node_modules/.bin/gulp optimize-vscode --silent --max_old_space_size=4096
displayName: 'Scripts'
- script: |
./scripts/test.sh --reporter mocha-junit-reporter
displayName: 'Tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'
condition: succeededOrFailed()

View File

@@ -0,0 +1,26 @@
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.9'
displayName: 'Install Node.js'
- script: |
yarn
displayName: 'Yarn Install'
- script: |
.\node_modules\.bin\gulp electron
displayName: 'Electron'
- script: |
npm run compile
displayName: 'Compile'
- script: |
.\scripts\test.bat --reporter mocha-junit-reporter
displayName: 'Test'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'test-results.xml'
condition: succeededOrFailed()

29
azure-pipelines.yml Normal file
View File

@@ -0,0 +1,29 @@
trigger:
- master
- releases/*
jobs:
# All tasks on Windows
- job: build_all_windows
displayName: Build all tasks (Windows)
pool:
vmImage: vs2017-win2016
steps:
- template: azure-pipelines-windows.yml
# All tasks on Linux
- job: build_all_linux
displayName: Build all tasks (Linux)
pool:
vmImage: 'Ubuntu 16.04'
steps:
- template: azure-pipelines-linux-mac.yml
# All tasks on macOS
- job: build_all_darwin
displayName: Build all tasks (macOS)
pool:
vmImage: macos-10.13
steps:
- template: azure-pipelines-linux-mac.yml

View File

@@ -129,6 +129,7 @@ const vscodeResources = [
'out-build/sql/parts/jobManagement/common/media/*.svg',
'out-build/sql/media/objectTypes/*.svg',
'out-build/sql/media/icons/*.svg',
'out-build/sql/parts/notebook/media/**/*.svg',
'!**/test/**'
];

View File

@@ -9,20 +9,21 @@
"@types/mime": "0.0.29",
"@types/minimatch": "^3.0.3",
"@types/node": "8.0.33",
"@types/xml2js": "0.0.33",
"@types/request": "^2.47.0",
"@types/xml2js": "0.0.33",
"azure-storage": "^2.1.0",
"decompress": "^4.2.0",
"del": "^3.0.0",
"documentdb": "1.13.0",
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"fs-extra-promise": "^1.0.1",
"github-releases": "^0.4.1",
"mime": "^1.3.4",
"minimist": "^1.2.0",
"request": "^2.85.0",
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"typescript": "2.9.2",
"vscode": "^1.0.1",
"xml2js": "^0.4.17",
"github-releases": "^0.4.1",
"request": "^2.85.0"
"xml2js": "^0.4.17"
},
"scripts": {
"compile": "tsc -p tsconfig.build.json",
@@ -30,4 +31,4 @@
"postinstall": "npm run compile",
"npmCheckJs": "tsc --noEmit"
}
}
}

View File

@@ -91,17 +91,17 @@ Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong
#else
#define SoftwareClassesRootKey "HKLM"
#endif
Root: HKCR; Subkey: "{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
Root: HKCR; Subkey: "{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"
Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin'))
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.sql"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,SQL}"; Flags: uninsdeletekey; Tasks: associatewithfiles
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: "AppUserModelID"; ValueData: "{#AppUserId}"; Flags: uninsdeletekey; Tasks: associatewithfiles
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.sql"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,SQL}"; Flags: uninsdeletekey; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: "AppUserModelID"; ValueData: "{#AppUserId}"; Flags: uninsdeletekey; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
; Environment
#if "user" == InstallTarget
#define EnvironmentRootKey "HKCU"

View File

@@ -46,6 +46,7 @@
"@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node@*":
version "8.0.51"
@@ -570,6 +571,18 @@ deep-assign@^1.0.0:
dependencies:
is-obj "^1.0.0"
del@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
dependencies:
globby "^6.1.0"
is-path-cwd "^1.0.0"
is-path-in-cwd "^1.0.0"
p-map "^1.1.1"
pify "^3.0.0"
rimraf "^2.2.8"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -941,6 +954,29 @@ glob@^5.0.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globby@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
dependencies:
array-union "^1.0.1"
glob "^7.0.3"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
glogg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
@@ -1312,6 +1348,25 @@ is-obj@^1.0.0:
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
is-path-in-cwd@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==
dependencies:
is-path-inside "^1.0.0"
is-path-inside@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
dependencies:
path-is-inside "^1.0.1"
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
@@ -1777,6 +1832,11 @@ os-tmpdir@~1.0.2:
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
p-map@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
@@ -1797,6 +1857,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-is-inside@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
pause-stream@0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
@@ -1819,7 +1884,7 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
pify@^2.3.0:
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
@@ -2117,7 +2182,7 @@ requires-port@~1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
rimraf@2:
rimraf@2, rimraf@^2.2.8:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==

View File

@@ -0,0 +1 @@

View File

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

View File

@@ -69,7 +69,7 @@ export class AlertData implements IAgentDialogData {
this.eventDescriptionKeyword = alertInfo.eventDescriptionKeyword;
this.eventSource = alertInfo.eventSource;
this.hasNotification = alertInfo.hasNotification;
this.includeEventDescription = alertInfo.includeEventDescription.toString();
this.includeEventDescription = alertInfo.includeEventDescription ? alertInfo.includeEventDescription.toString() : null;
this.isEnabled = alertInfo.isEnabled;
this.jobId = alertInfo.jobId;
this.lastOccurrenceDate = alertInfo.lastOccurrenceDate;
@@ -82,7 +82,7 @@ export class AlertData implements IAgentDialogData {
this.databaseName = alertInfo.databaseName;
this.countResetDate = alertInfo.countResetDate;
this.categoryName = alertInfo.categoryName;
this.alertType = alertInfo.alertType.toString();
this.alertType = alertInfo.alertType ? alertInfo.alertType.toString() : null;
this.wmiEventNamespace = alertInfo.wmiEventNamespace;
this.wmiEventQuery = alertInfo.wmiEventQuery;
}

View File

@@ -45,6 +45,7 @@ export class JobData implements IAgentDialogData {
public jobSchedules: sqlops.AgentJobScheduleInfo[];
public alerts: sqlops.AgentAlertInfo[];
public jobId: string;
public startStepId: number;
constructor(
ownerUri: string,
@@ -60,10 +61,11 @@ export class JobData implements IAgentDialogData {
this.category = jobInfo.category;
this.description = jobInfo.description;
this.enabled = jobInfo.enabled;
this.jobSteps = jobInfo.JobSteps;
this.jobSchedules = jobInfo.JobSchedules;
this.alerts = jobInfo.Alerts;
this.jobSteps = jobInfo.jobSteps;
this.jobSchedules = jobInfo.jobSchedules;
this.alerts = jobInfo.alerts;
this.jobId = jobInfo.jobId;
this.startStepId = jobInfo.startStepId;
}
}
@@ -141,17 +143,17 @@ export class JobData implements IAgentDialogData {
name: this.name,
owner: this.owner,
description: this.description,
EmailLevel: this.emailLevel,
PageLevel: this.pageLevel,
EventLogLevel: this.eventLogLevel,
DeleteLevel: this.deleteLevel,
OperatorToEmail: this.operatorToEmail,
OperatorToPage: this.operatorToPage,
emailLevel: this.emailLevel,
pageLevel: this.pageLevel,
eventLogLevel: this.eventLogLevel,
deleteLevel: this.deleteLevel,
operatorToEmail: this.operatorToEmail,
operatorToPage: this.operatorToPage,
enabled: this.enabled,
category: this.category,
Alerts: this.alerts,
JobSchedules: this.jobSchedules,
JobSteps: this.jobSteps,
alerts: this.alerts,
jobSchedules: this.jobSchedules,
jobSteps: this.jobSteps,
// The properties below are not collected from UI
// We could consider using a seperate class for create job request
//
@@ -166,7 +168,8 @@ export class JobData implements IAgentDialogData {
categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS
lastRun: '',
nextRun: '',
jobId: this.jobId
jobId: this.jobId,
startStepId: this.startStepId
};
}
}

View File

@@ -123,6 +123,7 @@ export class JobStepData implements IAgentDialogData {
stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName;
stepData.dialogMode = AgentDialogMode.EDIT;
stepData.viaJobDialog = true;
return stepData;
}

View File

@@ -20,6 +20,9 @@ export abstract class AgentDialog<T extends IAgentDialogData> {
public readonly onSuccess: vscode.Event<T> = this._onSuccess.event;
public dialog: sqlops.window.modelviewdialog.Dialog;
// Dialog Name for Telemetry
public dialogName: string;
constructor(public ownerUri: string, public model: T, public title: string) {
}
@@ -31,8 +34,9 @@ export abstract class AgentDialog<T extends IAgentDialogData> {
protected abstract async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog);
public async openDialog() {
this.dialog = sqlops.window.modelviewdialog.createDialog(this.title);
public async openDialog(dialogName?: string) {
let event = dialogName ? dialogName : null;
this.dialog = sqlops.window.modelviewdialog.createDialog(this.title, event);
await this.model.initialize();

View File

@@ -116,6 +116,10 @@ export class AlertDialog extends AgentDialog<AlertData> {
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
// Event Name strings
private readonly NewAlertDialog = 'NewAlertDialogOpen';
private readonly EditAlertDialog = 'EditAlertDialogOpened';
// UI Components
private generalTab: sqlops.window.modelviewdialog.DialogTab;
private responseTab: sqlops.window.modelviewdialog.DialogTab;
@@ -149,6 +153,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
private delayMinutesTextBox: sqlops.InputBoxComponent;
private delaySecondsTextBox: sqlops.InputBoxComponent;
private isEdit: boolean = false;
private databases: string[];
private jobModel: JobData;
public jobId: string;
@@ -166,6 +171,8 @@ export class AlertDialog extends AgentDialog<AlertData> {
this.jobModel = jobModel;
this.jobId = this.jobId ? this.jobId : this.jobModel.jobId;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.isEdit = alertInfo ? true : false;
this.dialogName = this.isEdit ? this.EditAlertDialog : this.NewAlertDialog;
}
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {

View File

@@ -42,11 +42,12 @@ export class JobDialog extends AgentDialog<JobData> {
private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type');
private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success');
private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure');
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New...');
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit');
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete');
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New Step');
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit Step');
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete Step');
private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up');
private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Up');
private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Down');
private readonly StartStepDropdownString: string = localize('jobDialog.startStepAt', 'Start step');
// Notifications tab strings
private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes');
@@ -67,6 +68,10 @@ export class JobDialog extends AgentDialog<JobData> {
private readonly AlertEnabledLabelString: string = localize('jobDialog.alertEnabledLabel', 'Enabled');
private readonly AlertTypeLabelString: string = localize('jobDialog.alertTypeLabel', 'Type');
// Event Name strings
private readonly NewJobDialogEvent: string = 'NewJobDialogOpened';
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
// UI Components
private generalTab: sqlops.window.modelviewdialog.DialogTab;
private stepsTab: sqlops.window.modelviewdialog.DialogTab;
@@ -101,6 +106,7 @@ export class JobDialog extends AgentDialog<JobData> {
private eventLogConditionDropdown: sqlops.DropDownComponent;
private deleteJobCheckBox: sqlops.CheckBoxComponent;
private deleteJobConditionDropdown: sqlops.DropDownComponent;
private startStepDropdown: sqlops.DropDownComponent;
// Schedule tab controls
private schedulesTable: sqlops.TableComponent;
@@ -115,6 +121,7 @@ export class JobDialog extends AgentDialog<JobData> {
private steps: sqlops.AgentJobStepInfo[];
private schedules: sqlops.AgentJobScheduleInfo[];
private alerts: sqlops.AgentAlertInfo[] = [];
private startStepDropdownValues: sqlops.CategoryValue[] = [];
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
super(
@@ -125,6 +132,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
this.alerts = this.model.alerts ? this.model.alerts : [];
this.isEdit = jobInfo ? true : false;
this.dialogName = this.isEdit ? this.EditJobDialogEvent : this.NewJobDialogEvent;
}
protected async initializeDialog() {
@@ -218,19 +226,26 @@ export class JobDialog extends AgentDialog<JobData> {
this.StepsTable_FailureColumnString
],
data: data,
height: 750
height: 650
}).component();
this.startStepDropdown = view.modelBuilder.dropDown().withProperties({ width: 180 }).component();
this.startStepDropdown.enabled = this.steps.length > 1 ? true : false;
this.steps.forEach((step) => {
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
});
this.startStepDropdown.values = this.startStepDropdownValues;
this.moveStepUpButton = view.modelBuilder.button()
.withProperties({
label: this.MoveStepUpButtonString,
width: 80
width: 120
}).component();
this.moveStepDownButton = view.modelBuilder.button()
.withProperties({
label: this.MoveStepDownButtonString,
width: 80
width: 120
}).component();
this.moveStepUpButton.enabled = false;
@@ -238,7 +253,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.newStepButton = view.modelBuilder.button().withProperties({
label: this.NewStepButtonString,
width: 80
width: 140
}).component();
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true);
@@ -246,6 +261,11 @@ export class JobDialog extends AgentDialog<JobData> {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
this.steps.push(stepInfo);
this.stepsTable.data = this.convertStepsToData(this.steps);
this.startStepDropdownValues = [];
this.steps.forEach((step) => {
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
});
this.startStepDropdown.values = this.startStepDropdownValues;
});
this.newStepButton.onDidClick((e)=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
@@ -258,53 +278,127 @@ export class JobDialog extends AgentDialog<JobData> {
this.editStepButton = view.modelBuilder.button().withProperties({
label: this.EditStepButtonString,
width: 80
width: 140
}).component();
this.deleteStepButton = view.modelBuilder.button().withProperties({
label: this.DeleteStepButtonString,
width: 80
width: 140
}).component();
this.stepsTable.enabled = false;
this.editStepButton.enabled = false;
this.deleteStepButton.enabled = false;
this.stepsTable.onRowSelected(() => {
// only let edit or delete steps if there's
// one step selection
this.moveStepUpButton.onDidClick(() => {
let rowNumber = this.stepsTable.selectedRows[0];
let previousRow = rowNumber - 1;
let previousStep = this.steps[previousRow];
let previousStepId = this.steps[previousRow].id;
let currentStep = this.steps[rowNumber];
let currentStepId = this.steps[rowNumber].id;
this.steps[previousRow] = currentStep;
this.steps[rowNumber] = previousStep;
this.stepsTable.data = this.convertStepsToData(this.steps);
this.steps[previousRow].id = previousStepId;
this.steps[rowNumber].id = currentStepId;
});
this.moveStepDownButton.onDidClick(() => {
let rowNumber = this.stepsTable.selectedRows[0];
let nextRow = rowNumber + 1;
let nextStep = this.steps[nextRow];
let nextStepId = this.steps[nextRow].id;
let currentStep = this.steps[rowNumber];
let currentStepId = this.steps[rowNumber].id;
this.steps[nextRow] = currentStep;
this.steps[rowNumber] = nextStep;
this.stepsTable.data = this.convertStepsToData(this.steps);
this.steps[nextRow].id = nextStepId;
this.steps[rowNumber].id = currentStepId;
});
this.editStepButton.onDidClick(() => {
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
let stepData = this.model.jobSteps[rowNumber];
this.deleteStepButton.enabled = true;
this.editStepButton.enabled = true;
this.editStepButton.onDidClick(() => {
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
stepDialog.openDialog();
});
let editStepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
editStepDialog.onSuccess((step) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
for (let i = 0; i < this.steps.length; i++) {
if (this.steps[i].id === stepInfo.id) {
this.steps[i] = stepInfo;
}
}
this.stepsTable.data = this.convertStepsToData(this.steps);
this.startStepDropdownValues = [];
this.steps.forEach((step) => {
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
});
this.startStepDropdown.values = this.startStepDropdownValues;
this.deleteStepButton.onDidClick(() => {
AgentUtils.getAgentService().then((agentService) => {
let steps = this.model.jobSteps ? this.model.jobSteps : [];
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
if (result && result.success) {
delete steps[rowNumber];
let data = this.convertStepsToData(steps);
this.stepsTable.data = data;
}
});
});
editStepDialog.openDialog();
}
});
this.deleteStepButton.onDidClick(() => {
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
AgentUtils.getAgentService().then((agentService) => {
let steps = this.model.jobSteps ? this.model.jobSteps : [];
let stepData = this.model.jobSteps[rowNumber];
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
if (result && result.success) {
delete steps[rowNumber];
let data = this.convertStepsToData(steps);
this.stepsTable.data = data;
this.startStepDropdownValues = [];
this.steps.forEach((step) => {
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
});
this.startStepDropdown.values = this.startStepDropdownValues;
}
});
});
}
});
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
this.stepsTable.onRowSelected((row) => {
// only let edit or delete steps if there's
// one step selection
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
// if it's not the last step
if (this.steps.length !== rowNumber + 1) {
this.moveStepDownButton.enabled = true;
}
// if it's not the first step
if (rowNumber !== 0) {
this.moveStepUpButton.enabled = true;
}
this.deleteStepButton.enabled = true;
this.editStepButton.enabled = true;
}
});
let stepMoveContainer = this.createRowContainer(view).withItems([this.startStepDropdown, this.moveStepUpButton, this.moveStepDownButton]).component();
let stepsDialogContainer = this.createRowContainer(view).withItems([this.newStepButton, this.editStepButton, this.deleteStepButton]).component();
let formModel = view.modelBuilder.formContainer().withFormItems([
{
component: this.stepsTable,
title: this.JobStepsTopLabelString,
actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton]
}]).withLayout({ width: '100%' }).component();
title: this.JobStepsTopLabelString
},
{
component: stepMoveContainer,
title: this.StartStepDropdownString
},
{
component: stepsDialogContainer,
title: ''
}
]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
this.setConditionDropdownSelectedValue(this.startStepDropdown, this.model.startStepId);
});
}
@@ -567,6 +661,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
this.model.startStepId = +this.getDropdownValue(this.startStepDropdown);
if (!this.model.jobSteps) {
this.model.jobSteps = [];
}

View File

@@ -67,6 +67,9 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success');
private readonly QuitJobReportingFailure: string = localize('jobStepDialog.quitJobFailure', 'Quit the job reporting failure');
// Event Name strings
private readonly NewStepDialog = 'NewStepDialogOpened';
private readonly EditStepDialog = 'EditStepDialogOpened';
// UI Components
// Dialogs
@@ -131,6 +134,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.jobModel = jobModel;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.server = server;
this.dialogName = this.isEdit ? this.EditStepDialog : this.NewStepDialog;
}
private initializeUIComponents() {
@@ -519,6 +523,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.model.failureAction = this.failureActionDropdown.value as string;
this.model.outputFileName = this.outputFileNameBox.value;
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
this.model.command = this.commandTextBox.value ? this.commandTextBox.value : '';
}
public async initializeDialog() {

View File

@@ -35,7 +35,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
private static readonly PagerSundayCheckBoxLabel: string = localize('createOperator.PagerSundayCheckBox', 'Sunday');
private static readonly WorkdayBeginLabel: string = localize('createOperator.workdayBegin', 'Workday begin');
private static readonly WorkdayEndLabel: string = localize('createOperator.workdayEnd', 'Workday end');
private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schdule');
private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schedule');
// Notifications tab strings
private static readonly AlertsTableLabel: string = localize('createOperator.AlertListHeading', 'Alert list');
@@ -43,6 +43,10 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
private static readonly AlertEmailColumnLabel: string = localize('createOperator.AlertEmailColumnLabel', 'E-mail');
private static readonly AlertPagerColumnLabel: string = localize('createOperator.AlertPagerColumnLabel', 'Pager');
// Event strings
private readonly NewOperatorDialog = 'NewOperatorDialogOpened';
private readonly EditOperatorDialog = 'EditOperatorDialogOpened';
// UI Components
private generalTab: sqlops.window.modelviewdialog.DialogTab;
private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
@@ -68,12 +72,15 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
// Notification tab controls
private alertsTable: sqlops.TableComponent;
private isEdit: boolean = false;
constructor(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo = undefined) {
super(
ownerUri,
new OperatorData(ownerUri, operatorInfo),
operatorInfo ? OperatorDialog.EditDialogTitle : OperatorDialog.CreateDialogTitle);
this.isEdit = operatorInfo ? true : false;
this.dialogName = this.isEdit ? this.EditOperatorDialog : this.NewOperatorDialog;
}
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {

View File

@@ -36,6 +36,9 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
private static readonly PowerShellLabel: string = localize('createProxy.PowerShell', 'PowerShell');
private static readonly SubSystemHeadingLabel: string = localize('createProxy.subSystemHeading', 'Active to the following subsytems');
private readonly NewProxyDialog = 'NewProxyDialogOpened';
private readonly EditProxyDialog = 'EditProxyDialogOpened';
// UI Components
private generalTab: sqlops.window.modelviewdialog.DialogTab;
@@ -56,6 +59,7 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
private powershellCheckBox: sqlops.CheckBoxComponent;
private credentials: sqlops.CredentialInfo[];
private isEdit: boolean = false;
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
super(
@@ -63,6 +67,8 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
new ProxyData(ownerUri, proxyInfo),
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
this.credentials = credentials;
this.isEdit = proxyInfo ? true : false;
this.dialogName = this.isEdit ? this.EditProxyDialog : this.NewProxyDialog;
}
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {

View File

@@ -40,13 +40,13 @@ export class MainController {
public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo);
dialog.openDialog();
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
});
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: sqlops.AgentJobInfo, jobStepInfo: sqlops.AgentJobStepInfo) => {
AgentUtils.getAgentService().then((agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.openDialog();
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', (ownerUri: string, jobName: string) => {
@@ -57,17 +57,16 @@ export class MainController {
AgentUtils.getAgentService().then((agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.openDialog();
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.openDialog();
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
});
vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo, credentials: sqlops.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.openDialog();
MainController.showNotYetImplemented();
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
});
}

View File

@@ -147,7 +147,7 @@
}
},
"dependencies": {
"request": "2.63.0",
"request": "2.88.0",
"azure-arm-resource": "^7.0.0",
"azure-arm-sql": "^5.0.1",
"vscode-nls": "^4.0.0"

View File

@@ -69,8 +69,8 @@ export class AzureAccountProvider implements sqlops.AccountProvider {
return this._tokenCache.clear();
}
public getSecurityToken(account: AzureAccount): Thenable<AzureAccountSecurityTokenCollection> {
return this.doIfInitialized(() => this.getAccessTokens(account));
public getSecurityToken(account: AzureAccount, resource: sqlops.AzureResource): Thenable<AzureAccountSecurityTokenCollection> {
return this.doIfInitialized(() => this.getAccessTokens(account, resource));
}
public initialize(restoredAccounts: sqlops.Account[]): Thenable<sqlops.Account[]> {
@@ -90,7 +90,7 @@ export class AzureAccountProvider implements sqlops.AccountProvider {
// Attempt to get fresh tokens. If this fails then the account is stale.
// NOTE: Based on ADAL implementation, getting tokens should use the refresh token if necessary
let task = this.getAccessTokens(account)
let task = this.getAccessTokens(account, sqlops.AzureResource.ResourceManagement)
.then(
() => {
return account;
@@ -161,9 +161,14 @@ export class AzureAccountProvider implements sqlops.AccountProvider {
: Promise.reject(localize('accountProviderNotInitialized', 'Account provider not initialized, cannot perform action'));
}
private getAccessTokens(account: AzureAccount): Thenable<AzureAccountSecurityTokenCollection> {
private getAccessTokens(account: AzureAccount, resource: sqlops.AzureResource): Thenable<AzureAccountSecurityTokenCollection> {
let self = this;
const resourceIdMap = new Map<sqlops.AzureResource, string>([
[sqlops.AzureResource.ResourceManagement, self._metadata.settings.armResource.id],
[sqlops.AzureResource.Sql, self._metadata.settings.sqlResource.id]
]);
let accessTokenPromises: Thenable<void>[] = [];
let tokenCollection: AzureAccountSecurityTokenCollection = {};
for (let tenant of account.properties.tenants) {
@@ -172,7 +177,7 @@ export class AzureAccountProvider implements sqlops.AccountProvider {
let context = new adal.AuthenticationContext(authorityUrl, null, self._tokenCache);
context.acquireToken(
self._metadata.settings.armResource.id,
resourceIdMap.get(resource),
tenant.userId,
self._metadata.settings.clientId,
(error: Error, response: adal.TokenResponse | adal.ErrorResponse) => {

View File

@@ -81,6 +81,11 @@ export interface Settings {
*/
armResource?: Resource;
/**
* Information that describes the SQL Azure resource
*/
sqlResource?: Resource;
/**
* A list of tenant IDs to authenticate against. If defined, then these IDs will be used
* instead of querying the tenants endpoint of the armResource

View File

@@ -27,6 +27,10 @@ const publicAzureSettings: ProviderSettings = {
id: 'https://management.core.windows.net/',
endpoint: 'https://management.azure.com'
},
sqlResource: {
id: 'https://database.windows.net/',
endpoint: 'https://database.windows.net'
},
redirectUri: 'http://localhost/redirect'
}
}

View File

@@ -223,22 +223,16 @@ export default class TokenCache implements adal.TokenCache {
return this.getOrCreateEncryptionParams()
.then(encryptionParams => {
try {
let cacheCipher = fs.readFileSync(self._cacheSerializationPath, TokenCache.FsOptions);
let decipher = crypto.createDecipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
let cacheJson = decipher.update(cacheCipher, 'hex', 'binary');
cacheJson += decipher.final('binary');
// Deserialize the JSON into the array of tokens
let cacheObj = <adal.TokenResponse[]>JSON.parse(cacheJson);
for (let objIndex in cacheObj) {
// Rehydrate Date objects since they will always serialize as a string
cacheObj[objIndex].expiresOn = new Date(<string>cacheObj[objIndex].expiresOn);
}
return cacheObj;
return self.decryptCache('utf8', encryptionParams);
} catch (e) {
throw e;
try {
// try to parse using 'binary' encoding and rewrite cache as UTF8
let response = self.decryptCache('binary', encryptionParams);
self.writeCache(response);
return response;
} catch (e) {
throw e;
}
}
})
.then(null, err => {
@@ -248,6 +242,22 @@ export default class TokenCache implements adal.TokenCache {
});
}
private decryptCache(encoding: crypto.Utf8AsciiBinaryEncoding, encryptionParams: EncryptionParams): adal.TokenResponse[] {
let cacheCipher = fs.readFileSync(this._cacheSerializationPath, TokenCache.FsOptions);
let decipher = crypto.createDecipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
let cacheJson = decipher.update(cacheCipher, 'hex', encoding);
cacheJson += decipher.final(encoding);
// Deserialize the JSON into the array of tokens
let cacheObj = <adal.TokenResponse[]>JSON.parse(cacheJson);
for (let objIndex in cacheObj) {
// Rehydrate Date objects since they will always serialize as a string
cacheObj[objIndex].expiresOn = new Date(<string>cacheObj[objIndex].expiresOn);
}
return cacheObj;
}
private removeFromCache(cache: adal.TokenResponse[], entries: adal.TokenResponse[]): adal.TokenResponse[] {
entries.forEach((entry: adal.TokenResponse) => {
// Check to see if the entry exists
@@ -274,7 +284,7 @@ export default class TokenCache implements adal.TokenCache {
let cacheJson = JSON.stringify(cache);
let cipher = crypto.createCipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
let cacheCipher = cipher.update(cacheJson, 'binary', 'hex');
let cacheCipher = cipher.update(cacheJson, 'utf8', 'hex');
cacheCipher += cipher.final('hex');
fs.writeFileSync(self._cacheSerializationPath, cacheCipher, TokenCache.FsOptions);

View File

@@ -212,8 +212,8 @@ export class ApiWrapper {
return sqlops.accounts.getAllAccounts();
}
public getSecurityToken(account: sqlops.Account): Thenable<{}> {
return sqlops.accounts.getSecurityToken(account);
public getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
return sqlops.accounts.getSecurityToken(account, resource);
}
public readonly onDidChangeAccounts = sqlops.accounts.onDidChangeAccounts;

View File

@@ -6,7 +6,7 @@
'use strict';
import { window, QuickPickItem } from 'vscode';
import { IConnectionProfile } from 'sqlops';
import * as sqlops from 'sqlops';
import { generateGuid } from './utils';
import { ApiWrapper } from '../apiWrapper';
import { TreeNode } from '../treeNodes';
@@ -30,7 +30,7 @@ export function registerAzureResourceCommands(apiWrapper: ApiWrapper, tree: Azur
let subscriptions = await accountNode.getCachedSubscriptions();
if (!subscriptions || subscriptions.length === 0) {
const credentials = await servicePool.credentialService.getCredentials(accountNode.account);
const credentials = await servicePool.credentialService.getCredentials(accountNode.account, sqlops.AzureResource.ResourceManagement);
subscriptions = await servicePool.subscriptionService.getSubscriptions(accountNode.account, credentials);
}
@@ -71,7 +71,7 @@ export function registerAzureResourceCommands(apiWrapper: ApiWrapper, tree: Azur
});
apiWrapper.registerCommand('azureresource.connectsqldb', async (node?: TreeNode) => {
let connectionProfile: IConnectionProfile = {
let connectionProfile: sqlops.IConnectionProfile = {
id: generateGuid(),
connectionName: undefined,
serverName: undefined,

View File

@@ -6,29 +6,29 @@
'use strict';
import { ServiceClientCredentials } from 'ms-rest';
import { Account, DidChangeAccountsParams } from 'sqlops';
import * as sqlops from 'sqlops';
import { Event } from 'vscode';
import { AzureResourceSubscription, AzureResourceDatabaseServer, AzureResourceDatabase } from './models';
export interface IAzureResourceAccountService {
getAccounts(): Promise<Account[]>;
getAccounts(): Promise<sqlops.Account[]>;
readonly onDidChangeAccounts: Event<DidChangeAccountsParams>;
readonly onDidChangeAccounts: Event<sqlops.DidChangeAccountsParams>;
}
export interface IAzureResourceCredentialService {
getCredentials(account: Account): Promise<ServiceClientCredentials[]>;
getCredentials(account: sqlops.Account, resource: sqlops.AzureResource): Promise<ServiceClientCredentials[]>;
}
export interface IAzureResourceSubscriptionService {
getSubscriptions(account: Account, credentials: ServiceClientCredentials[]): Promise<AzureResourceSubscription[]>;
getSubscriptions(account: sqlops.Account, credentials: ServiceClientCredentials[]): Promise<AzureResourceSubscription[]>;
}
export interface IAzureResourceSubscriptionFilterService {
getSelectedSubscriptions(account: Account): Promise<AzureResourceSubscription[]>;
getSelectedSubscriptions(account: sqlops.Account): Promise<AzureResourceSubscription[]>;
saveSelectedSubscriptions(account: Account, selectedSubscriptions: AzureResourceSubscription[]): Promise<void>;
saveSelectedSubscriptions(account: sqlops.Account, selectedSubscriptions: AzureResourceSubscription[]): Promise<void>;
}
export interface IAzureResourceDatabaseServerService {

View File

@@ -5,7 +5,7 @@
'use strict';
import { Account } from 'sqlops';
import * as sqlops from 'sqlops';
import { TokenCredentials, ServiceClientCredentials } from 'ms-rest';
import { ApiWrapper } from '../../apiWrapper';
import * as nls from 'vscode-nls';
@@ -21,10 +21,10 @@ export class AzureResourceCredentialService implements IAzureResourceCredentialS
this._apiWrapper = apiWrapper;
}
public async getCredentials(account: Account): Promise<ServiceClientCredentials[]> {
public async getCredentials(account: sqlops.Account, resource: sqlops.AzureResource): Promise<ServiceClientCredentials[]> {
try {
let credentials: TokenCredentials[] = [];
let tokens = await this._apiWrapper.getSecurityToken(account);
let tokens = await this._apiWrapper.getSecurityToken(account, resource);
for (let tenant of account.properties.tenants) {
let token = tokens[tenant.id].token;

View File

@@ -5,7 +5,7 @@
'use strict';
import { Account } from 'sqlops';
import * as sqlops from 'sqlops';
import { ServiceClientCredentials } from 'ms-rest';
import { TreeNode } from '../../treeNodes';
@@ -28,7 +28,7 @@ export abstract class AzureResourceTreeNodeBase extends TreeNode {
export abstract class AzureResourceContainerTreeNodeBase extends AzureResourceTreeNodeBase {
public constructor(
public readonly account: Account,
public readonly account: sqlops.Account,
treeChangeHandler: IAzureResourceTreeChangeHandler,
parent: TreeNode
) {
@@ -45,7 +45,7 @@ export abstract class AzureResourceContainerTreeNodeBase extends AzureResourceTr
protected async getCredentials(): Promise<ServiceClientCredentials[]> {
try {
return await this.servicePool.credentialService.getCredentials(this.account);
return await this.servicePool.credentialService.getCredentials(this.account, sqlops.AzureResource.ResourceManagement);
} catch (error) {
if (error instanceof AzureResourceCredentialError) {
this.servicePool.contextService.showErrorMessage(error.message);

View File

@@ -87,7 +87,7 @@ describe('AzureResourceAccountTreeNode.info', function(): void {
mockServicePool.subscriptionService = mockSubscriptionService.object;
mockServicePool.subscriptionFilterService = mockSubscriptionFilterService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCredentialService.setup((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache.subscriptions[mockAccount.key.accountId] = mockSubscriptions);
});
@@ -164,7 +164,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function(): void {
mockServicePool.subscriptionService = mockSubscriptionService.object;
mockServicePool.subscriptionFilterService = mockSubscriptionFilterService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCredentialService.setup((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache.subscriptions[mockAccount.key.accountId] = mockSubscriptions);
});
@@ -177,7 +177,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function(): void {
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -213,7 +213,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function(): void {
await accountTreeNode.getChildren();
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.exactly(1));
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
@@ -267,7 +267,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function(): void {
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());

View File

@@ -118,7 +118,7 @@ describe('AzureResourceDatabaseContainerTreeNode.getChildren', function(): void
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.databaseService = mockDatabaseService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCredentialService.setup((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockDatabaseContainerCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockDatabaseContainerCache.databases[mockSubscription.id] = mockDatabases);
});
@@ -130,7 +130,7 @@ describe('AzureResourceDatabaseContainerTreeNode.getChildren', function(): void
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -160,7 +160,7 @@ describe('AzureResourceDatabaseContainerTreeNode.getChildren', function(): void
await databaseContainerTreeNode.getChildren();
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.exactly(1));
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
@@ -193,7 +193,7 @@ describe('AzureResourceDatabaseContainerTreeNode.getChildren', function(): void
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());

View File

@@ -118,7 +118,7 @@ describe('AzureResourceDatabaseServerContainerTreeNode.getChildren', function():
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.databaseServerService = mockDatabaseServerService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCredentialService.setup((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockDatabaseServerContainerCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockDatabaseServerContainerCache.databaseServers[mockSubscription.id] = mockDatabaseServers);
});
@@ -130,7 +130,7 @@ describe('AzureResourceDatabaseServerContainerTreeNode.getChildren', function():
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -160,7 +160,7 @@ describe('AzureResourceDatabaseServerContainerTreeNode.getChildren', function():
await databaseServerContainerTreeNode.getChildren();
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.exactly(1));
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
@@ -193,7 +193,7 @@ describe('AzureResourceDatabaseServerContainerTreeNode.getChildren', function():
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockCredentialService.verify((o) => o.getCredentials(mockAccount, sqlops.AzureResource.ResourceManagement), TypeMoq.Times.once());
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());

View File

@@ -10,6 +10,7 @@
"@types/node@^8.0.24":
version "8.10.36"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.36.tgz#eac05d576fbcd0b4ea3c912dc58c20475c08d9e4"
integrity sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw==
"@types/node@^8.0.47":
version "8.10.30"
@@ -41,18 +42,6 @@ ajv@^5.3.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
asn1@0.1.11:
version "0.1.11"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -65,10 +54,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
assert-plus@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
async@2.6.0:
version "2.6.0"
resolved "https://registry.npmjs.org/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
@@ -76,9 +61,10 @@ async@2.6.0:
dependencies:
lodash "^4.14.0"
async@>=0.6.0, async@^2.0.1:
async@>=0.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
dependencies:
lodash "^4.17.10"
@@ -87,10 +73,6 @@ asynckit@^0.4.0:
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
aws-sign2@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@@ -129,22 +111,6 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
bl@~1.0.0:
version "1.0.3"
resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e"
dependencies:
readable-stream "~2.0.5"
bluebird@^2.9.30:
version "2.11.0"
resolved "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
boom@2.x.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
dependencies:
hoek "2.x.x"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -163,25 +129,11 @@ buffer-equal-constant-time@1.0.1:
resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
caseless@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^1.0.0:
version "1.1.3"
resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
circular-json@^0.3.1:
version "0.3.3"
resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
@@ -199,9 +151,10 @@ combined-stream@1.0.6:
dependencies:
delayed-stream "~1.0.0"
combined-stream@^1.0.5, combined-stream@~1.0.1, combined-stream@~1.0.6:
combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
dependencies:
delayed-stream "~1.0.0"
@@ -210,28 +163,15 @@ commander@2.15.1:
resolved "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
commander@^2.8.1:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
core-util-is@1.0.2, core-util-is@~1.0.0:
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
dependencies:
boom "2.x.x"
ctype@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
dashdash@^1.12.0:
version "1.14.1"
@@ -282,13 +222,15 @@ ecdsa-sig-formatter@1.0.10:
dependencies:
safe-buffer "^5.0.1"
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2:
escape-string-regexp@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
extend@~3.0.0, extend@~3.0.2:
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extsprintf@1.3.0:
version "1.3.0"
@@ -310,17 +252,10 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
forever-agent@~0.6.0, forever-agent@~0.6.1:
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@~1.0.0-rc1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c"
dependencies:
async "^2.0.1"
combined-stream "^1.0.5"
mime-types "^2.1.11"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@~2.3.2:
version "2.3.2"
@@ -336,18 +271,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
generate-function@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
dependencies:
is-property "^1.0.2"
generate-object-property@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
dependencies:
is-property "^1.0.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@@ -377,15 +300,6 @@ har-schema@^2.0.0:
resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@^1.6.1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2"
dependencies:
bluebird "^2.9.30"
chalk "^1.0.0"
commander "^2.8.1"
is-my-json-valid "^2.12.0"
har-validator@~5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29"
@@ -394,43 +308,16 @@ har-validator@~5.1.0:
ajv "^5.3.0"
har-schema "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
dependencies:
ansi-regex "^2.0.0"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
hawk@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
dependencies:
boom "2.x.x"
cryptiles "2.x.x"
hoek "2.x.x"
sntp "1.x.x"
he@1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
http-signature@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6"
dependencies:
asn1 "0.1.11"
assert-plus "^0.1.5"
ctype "0.5.3"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -448,33 +335,16 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@~2.0.1:
inherits@2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
is-buffer@^1.1.6:
version "1.1.6"
resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-my-ip-valid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
is-my-json-valid@^2.12.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175"
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
is-my-ip-valid "^1.0.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-property@^1.0.0, is-property@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -485,13 +355,10 @@ is-typedarray@~1.0.0:
resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isstream@~0.1.1, isstream@~0.1.2:
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jsbn@~0.1.0:
version "0.1.1"
@@ -508,13 +375,10 @@ json-schema@0.2.3:
resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
jsonpointer@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsprim@^1.2.2:
version "1.4.1"
@@ -553,9 +417,10 @@ mime-db@~1.36.0:
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==
mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.2:
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.20"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19"
integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==
dependencies:
mime-db "~1.36.0"
@@ -631,14 +496,6 @@ ms@2.0.0:
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
node-uuid@~1.4.0:
version "1.4.8"
resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
oauth-sign@~0.8.0:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
@@ -666,10 +523,6 @@ postinstall-build@^5.0.1:
resolved "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7"
integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg==
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
psl@^1.1.24:
version "1.1.29"
resolved "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
@@ -680,53 +533,14 @@ punycode@^1.4.1:
resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
qs@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9"
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
readable-stream@~2.0.5:
version "2.0.6"
resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
request@2.63.0:
version "2.63.0"
resolved "http://registry.npmjs.org/request/-/request-2.63.0.tgz#c83e7c3485e5d9bf9b146318429bc48f1253d8be"
dependencies:
aws-sign2 "~0.5.0"
bl "~1.0.0"
caseless "~0.11.0"
combined-stream "~1.0.1"
extend "~3.0.0"
forever-agent "~0.6.0"
form-data "~1.0.0-rc1"
har-validator "^1.6.1"
hawk "~3.1.0"
http-signature "~0.11.0"
isstream "~0.1.1"
json-stringify-safe "~5.0.0"
mime-types "~2.1.2"
node-uuid "~1.4.0"
oauth-sign "~0.8.0"
qs "~5.1.0"
stringstream "~0.0.4"
tough-cookie ">=0.12.0"
tunnel-agent "~0.4.0"
"request@>= 2.52.0", request@^2.88.0:
request@2.88.0, "request@>= 2.52.0", request@^2.88.0:
version "2.88.0"
resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
dependencies:
aws-sign2 "~0.7.0"
@@ -804,12 +618,6 @@ should@^13.2.1:
should-type-adaptors "^1.0.1"
should-util "^1.0.0"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
dependencies:
hoek "2.x.x"
sshpk@^1.7.0:
version "1.14.2"
resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
@@ -826,20 +634,6 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
stringstream@~0.0.4:
version "0.0.6"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
strip-ansi@^3.0.0:
version "3.0.1"
resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
supports-color@5.4.0:
version "5.4.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
@@ -847,18 +641,15 @@ supports-color@5.4.0:
dependencies:
has-flag "^3.0.0"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
through@^2.3.8:
version "2.3.8"
resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
tough-cookie@>=0.12.0, tough-cookie@~2.4.3:
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"
@@ -870,10 +661,6 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
tunnel-agent@~0.4.0:
version "0.4.3"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
tunnel@0.0.5:
version "0.0.5"
resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.5.tgz#d1532254749ed36620fcd1010865495a1fa9d0ae"
@@ -898,10 +685,6 @@ typemoq@^2.1.0:
resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961"
integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
@@ -934,7 +717,3 @@ wrappy@1:
xpath.js@~1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1"
xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"

View File

@@ -1,9 +1,50 @@
# Microsoft SQL Server Import for Azure Data Studio
Microsoft SQL Server Import for Azure Data Studio is a simple way to copy data from a flat file (.csv, .txt, .json) to a SQL Server table. Checkout below the reasons for using the Import Flat File wizard, how to find this wizard, and a simple example.
Microsoft SQL Server Import for Azure Data Studio includes two wizards:
- [Import Flat File Wizard](#import-flat-file-wizard-preview)
- [Data-tier Application Wizard.](#data-tier-application-wizard-preview)
## Import Flat File Wizard *(preview)*
**The Import Flat File Wizard** is a simple way to copy data from a flat file (.csv, .txt, .json) to a SQL Server table. Checkout below the reasons for using the Import Flat File wizard, how to find this wizard, and a simple example.
This experience is currently in its initial preview. Please report issues and feature requests [here.](https://github.com/microsoft/azuredatastudio/issues)
<img src="https://user-images.githubusercontent.com/30873802/43433347-c958ed28-942b-11e8-8bbc-f4f2529c3978.png" width="800px" />
### Requirements
* This wizard requires an active connection to a SQL Server instance to start.
* This wizard only works on .txt and .csv files.
### How do I start the Import Flat File wizard?
* The main entry point for the wizard is to right click a database in the Object Explorer, and click **Import wizard**.
* If a user is connected to a SQL Server instance, the user can also press **Ctrl**+**I** to start the wizard.
### Why would I use the Import Flat File wizard?
This wizard was created to improve the current import experience leveraging an intelligent framework known as Program Synthesis using Examples ([PROSE](https://microsoft.github.io/prose/)). For a user without specialized domain knowledge, importing data can often be a complex, error prone, and tedious task. This wizard streamlines the import process as simple as selecting an input file and unique table name, and the PROSE framework handles the rest.
PROSE analyzes data patterns in your input file to infer column names, types, delimiters, and more. This framework learns the structure of the file and does all of the hard work so users don't have to.
Please note that the PROSE binary components used by this extension are licensed under the [MICROSOFT SQL TOOLS IMPORT FLAT FILE EULA](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/extensions/import/Microsoft_SQL_Server_Import_Extension_and_Tools_Import_Flat_File_Preview.docx).
## Data-tier Application Wizard *(preview)*
**The Data-tier Application Wizard** provides an easy to use experience to deploy and extract .dacpac files and import and export .bacpac files.
This experience is currently in its initial preview. Please report issues and feature requests [here.](https://github.com/microsoft/azuredatastudio/issues)
<img src="https://user-images.githubusercontent.com/30873802/49676289-f2df6880-fa2d-11e8-8bfa-6213b7734075.png" width="800px" />
### Requirements
* This wizard requires an active connection to a SQL Server instance to start.
### How do I start the Data-tier Application wizard?
* The main entry point for the wizard is to right click a database in the Object Explorer, and click **Data-tier Application wizard**.
* If a user is connected to a SQL Server instance, the user can also start the wizard from the command palette (Ctrl+Shift+P) by searching for **Data-tier Application wizard.**
### Why would I use the Data-tier Application wizard?
This wizard was created to add the ability to extract and deploy .dacpac files and import and export .bacpac files in Azure Data Studio.
To learn more about Data-Tier Applications and working with dacpac and bacpac files, [you can read more here.](https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/data-tier-applications?view=sql-server-2017)
## License
Copyright (c) Microsoft Corporation. All rights reserved.
@@ -12,21 +53,6 @@ Licensed under the [MICROSOFT SQL SERVER IMPORT EXTENSION EULA](https://raw.gith
> Note: Microsoft SQL Server Import for Azure Data Studio extension contains the Microsoft SQL Tools Import Flat File component which is also licensed under the above EULA.
## Requirements
* This wizard requires an active connection to a SQL Server instance to start.
* This wizard only works on .txt and .csv files.
## How do I start the Flat File Import wizard?
* The main entry point for the wizard is to right click a database in the Object Explorer, and click **Import wizard**.
* If a user is connected to a SQL Server instance, the user can also press **Ctrl**+**I** to start the wizard.
## Why would I use the Flat File Import wizard?
This wizard was created to improve the current import experience leveraging an intelligent framework known as Program Synthesis using Examples ([PROSE](https://microsoft.github.io/prose/)). For a user without specialized domain knowledge, importing data can often be a complex, error prone, and tedious task. This wizard streamlines the import process as simple as selecting an input file and unique table name, and the PROSE framework handles the rest.
PROSE analyzes data patterns in your input file to infer column names, types, delimiters, and more. This framework learns the structure of the file and does all of the hard work so users don't have to.
Please note that the PROSE binary components used by this extension are licensed under the [MICROSOFT SQL TOOLS IMPORT FLAT FILE EULA](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/extensions/import/Microsoft_SQL_Server_Import_Extension_and_Tools_Import_Flat_File_Preview.docx).
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@@ -2,7 +2,7 @@
"name": "import",
"displayName": "SQL Server Import",
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
"version": "0.4.0",
"version": "0.5.0",
"publisher": "Microsoft",
"preview": true,
"engines": {
@@ -33,6 +33,15 @@
"light": "./images/light_icon.svg",
"dark": "./images/dark_icon.svg"
}
},
{
"command": "dacFx.start",
"title": "Data-tier Application Wizard",
"category": "Data-tier Application",
"icon": {
"light": "./images/light_icon.svg",
"dark": "./images/dark_icon.svg"
}
}
],
"keybindings": [
@@ -48,12 +57,17 @@
"command": "flatFileImport.start",
"when": "connectionProvider == MSSQL && nodeType && nodeType == Database",
"group": "import"
},
{
"command": "dacFx.start",
"when": "connectionProvider == MSSQL && nodeType && nodeType == Database",
"group": "export"
}
]
}
},
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.7",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.10",
"opener": "^1.4.3",
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"vscode-extension-telemetry": "0.0.18",

View File

@@ -13,6 +13,7 @@ import { FlatFileWizard } from '../wizard/flatFileWizard';
import { ServiceClient } from '../services/serviceClient';
import { ApiType, managerInstance } from '../services/serviceApiManager';
import { FlatFileProvider } from '../services/contracts';
import { DataTierApplicationWizard } from '../wizard/dataTierApplicationWizard';
/**
* The main controller class that initializes the extension
@@ -35,10 +36,15 @@ export default class MainController extends ControllerBase {
this.initializeFlatFileProvider(provider);
});
this.initializeDacFxWizard();
return Promise.resolve(true);
}
private initializeFlatFileProvider(provider: FlatFileProvider) {
sqlops.tasks.registerTask('flatFileImport.start', (profile: sqlops.IConnectionProfile, ...args: any[]) => new FlatFileWizard(provider).start(profile, args));
}
private initializeDacFxWizard() {
sqlops.tasks.registerTask('dacFx.start', (profile: sqlops.IConnectionProfile, ...args: any[]) => new DataTierApplicationWizard().start(profile, args));
}
}

View File

@@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import { BaseDataModel } from './models';
export abstract class BasePage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly model: BaseDataModel;
protected readonly view: sqlops.ModelView;
/**
* This method constructs all the elements of the page.
* @returns {Promise<boolean>}
*/
public async abstract start(): Promise<boolean>;
/**
* This method is called when the user is entering the page.
* @returns {Promise<boolean>}
*/
public async abstract onPageEnter(): Promise<boolean>;
/**
* This method is called when the user is leaving the page.
* @returns {Promise<boolean>}
*/
async onPageLeave(): Promise<boolean> {
return true;
}
/**
* Override this method to cleanup what you don't need cached in the page.
* @returns {Promise<boolean>}
*/
public async cleanup(): Promise<boolean> {
return true;
}
/**
* Sets up a navigation validator.
* This will be called right before onPageEnter().
*/
public abstract setupNavigationValidator();
protected async getServerValues(): Promise<{ connection, displayName, name }[]> {
let cons = await sqlops.connection.getActiveConnections();
// This user has no active connections ABORT MISSION
if (!cons || cons.length === 0) {
return undefined;
}
let count = -1;
let idx = -1;
let values = cons.map(c => {
// Handle the code to remember what the user's choice was from before
count++;
if (idx === -1) {
if (this.model.server && c.connectionId === this.model.server.connectionId) {
idx = count;
} else if (this.model.serverId && c.connectionId === this.model.serverId) {
idx = count;
}
}
let db = c.options.databaseDisplayName;
let usr = c.options.user;
let srv = c.options.server;
if (!db) {
db = '<default>';
}
if (!usr) {
usr = 'default';
}
let finalName = `${srv}, ${db} (${usr})`;
return {
connection: c,
displayName: finalName,
name: c.connectionId
};
});
if (idx >= 0) {
let tmp = values[0];
values[0] = values[idx];
values[idx] = tmp;
} else {
this.deleteServerValues();
}
return values;
}
protected async getDatabaseValues(): Promise<{ displayName, name }[]> {
let idx = -1;
let count = -1;
let values = (await sqlops.connection.listDatabases(this.model.server.connectionId)).map(db => {
count++;
if (this.model.database && db === this.model.database) {
idx = count;
}
return {
displayName: db,
name: db
};
});
if (idx >= 0) {
let tmp = values[0];
values[0] = values[idx];
values[idx] = tmp;
} else {
this.deleteDatabaseValues();
}
return values;
}
protected deleteServerValues() {
delete this.model.server;
delete this.model.serverId;
delete this.model.database;
}
protected deleteDatabaseValues() {
return;
}
}

View File

@@ -0,0 +1,158 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as os from 'os';
import * as path from 'path';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxDataModel } from './models';
import { BasePage } from './basePage';
const localize = nls.loadMessageBundle();
export abstract class DacFxConfigPage extends BasePage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
protected serverDropdown: sqlops.DropDownComponent;
protected databaseTextBox: sqlops.InputBoxComponent;
protected databaseDropdown: sqlops.DropDownComponent;
protected databaseLoader: sqlops.LoadingComponent;
protected fileTextBox: sqlops.InputBoxComponent;
protected fileButton: sqlops.ButtonComponent;
protected fileExtension: string;
protected constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super();
this.instance = instance;
this.wizardPage = wizardPage;
this.model = model;
this.view = view;
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
return true;
});
}
protected async createServerDropdown(isTargetServer: boolean): Promise<sqlops.FormComponent> {
this.serverDropdown = this.view.modelBuilder.dropDown().withProperties({
required: true
}).component();
// Handle server changes
this.serverDropdown.onValueChanged(async () => {
this.model.server = (this.serverDropdown.value as ConnectionDropdownValue).connection;
this.model.serverName = (this.serverDropdown.value as ConnectionDropdownValue).displayName;
await this.populateDatabaseDropdown();
});
let targetServerTitle = localize('dacFx.targetServerDropdownTitle', 'Target Server');
let sourceServerTitle = localize('dacFx.sourceServerDropdownTitle', 'Source Server');
return {
component: this.serverDropdown,
title: isTargetServer ? targetServerTitle : sourceServerTitle
};
}
protected async populateServerDropdown(): Promise<boolean> {
let values = await this.getServerValues();
if (values === undefined) {
return false;
}
this.model.server = values[0].connection;
this.model.serverName = values[0].displayName;
this.serverDropdown.updateProperties({
values: values
});
return true;
}
protected async createDatabaseTextBox(): Promise<sqlops.FormComponent> {
this.databaseTextBox = this.view.modelBuilder.inputBox().withProperties({
required: true
}).component();
this.databaseTextBox.onTextChanged(async () => {
this.model.database = this.databaseTextBox.value;
});
return {
component: this.databaseTextBox,
title: localize('dacFx.databaseNameTextBox', 'Target Database')
};
}
protected async createDatabaseDropdown(): Promise<sqlops.FormComponent> {
this.databaseDropdown = this.view.modelBuilder.dropDown().withProperties({
required: true
}).component();
// Handle database changes
this.databaseDropdown.onValueChanged(async () => {
this.model.database = (<sqlops.CategoryValue>this.databaseDropdown.value).name;
this.fileTextBox.value = this.generateFilePath();
this.model.filePath = this.fileTextBox.value;
});
this.databaseLoader = this.view.modelBuilder.loadingComponent().withItem(this.databaseDropdown).component();
return {
component: this.databaseLoader,
title: localize('dacFx.sourceDatabaseDropdownTitle', 'Source Database')
};
}
protected async populateDatabaseDropdown(): Promise<boolean> {
this.databaseLoader.loading = true;
this.databaseDropdown.updateProperties({ values: [] });
if (!this.model.server) {
this.databaseLoader.loading = false;
return false;
}
let values = await this.getDatabaseValues();
this.model.database = values[0].name;
this.model.filePath = this.generateFilePath();
this.fileTextBox.value = this.model.filePath;
this.databaseDropdown.updateProperties({
values: values
});
this.databaseLoader.loading = false;
return true;
}
protected async createFileBrowserParts() {
this.fileTextBox = this.view.modelBuilder.inputBox().withProperties({
required: true
}).component();
this.fileButton = this.view.modelBuilder.button().withProperties({
label: '•••',
}).component();
}
protected generateFilePath(): string {
let now = new Date();
let datetime = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + '-' + now.getHours() + '-' + now.getMinutes();
return path.join(os.homedir(), this.model.database + '-' + datetime + this.fileExtension);
}
}
interface ConnectionDropdownValue extends sqlops.CategoryValue {
connection: sqlops.connection.Connection;
}

View File

@@ -8,8 +8,9 @@ import { ImportDataModel } from './models';
import * as sqlops from 'sqlops';
import { FlatFileProvider } from '../../services/contracts';
import { FlatFileWizard } from '../flatFileWizard';
import { BasePage } from './basePage';
export abstract class ImportPage {
export abstract class ImportPage extends BasePage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: FlatFileWizard;
@@ -18,42 +19,11 @@ export abstract class ImportPage {
protected readonly provider: FlatFileProvider;
protected constructor(instance: FlatFileWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: ImportDataModel, view: sqlops.ModelView, provider: FlatFileProvider) {
super();
this.instance = instance;
this.wizardPage = wizardPage;
this.model = model;
this.view = view;
this.provider = provider;
}
/**
* This method constructs all the elements of the page.
* @returns {Promise<boolean>}
*/
public async abstract start(): Promise<boolean>;
/**
* This method is called when the user is entering the page.
* @returns {Promise<boolean>}
*/
public async abstract onPageEnter(): Promise<boolean>;
/**
* This method is called when the user is leaving the page.
* @returns {Promise<boolean>}
*/
public async abstract onPageLeave(): Promise<boolean>;
/**
* Sets up a navigation validator.
* This will be called right before onPageEnter().
*/
public abstract setupNavigationValidator();
/**
* Override this method to cleanup what you don't need cached in the page.
* @returns {Promise<boolean>}
*/
public async cleanup(): Promise<boolean> {
return true;
}
}

View File

@@ -6,15 +6,19 @@
import * as sqlops from 'sqlops';
export interface BaseDataModel {
server: sqlops.connection.Connection;
serverId: string;
database: string;
}
/**
* The main data model that communicates between the pages.
*/
export interface ImportDataModel {
export interface ImportDataModel extends BaseDataModel {
ownerUri: string;
proseColumns: ColumnMetadata[];
proseDataPreview: string[][];
server: sqlops.connection.Connection;
serverId: string;
database: string;
table: string;
schema: string;
@@ -31,3 +35,14 @@ export interface ColumnMetadata {
primaryKey: boolean;
nullable: boolean;
}
/**
* Data model to communicate between DacFx pages
*/
export interface DacFxDataModel extends BaseDataModel {
serverName: string;
serverId: string;
filePath: string;
version: string;
upgradeExisting: boolean;
}

View File

@@ -0,0 +1,252 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as sqlops from 'sqlops';
import { SelectOperationPage } from './pages/selectOperationpage';
import { DeployConfigPage } from './pages/deployConfigPage';
import { DacFxSummaryPage } from './pages/dacFxSummaryPage';
import { ExportConfigPage } from './pages/exportConfigPage';
import { ExtractConfigPage } from './pages/extractConfigPage';
import { ImportConfigPage } from './pages/importConfigPage';
import { DacFxDataModel } from './api/models';
import { BasePage } from './api/basePage';
const localize = nls.loadMessageBundle();
class Page {
wizardPage: sqlops.window.modelviewdialog.WizardPage;
dacFxPage: BasePage;
constructor(wizardPage: sqlops.window.modelviewdialog.WizardPage) {
this.wizardPage = wizardPage;
}
}
export enum Operation {
deploy,
extract,
import,
export
}
export class DataTierApplicationWizard {
public wizard: sqlops.window.modelviewdialog.Wizard;
private connection: sqlops.connection.Connection;
private model: DacFxDataModel;
public pages: Map<string, Page> = new Map<string, Page>();
public selectedOperation: Operation;
constructor() {
}
public async start(p: any, ...args: any[]) {
this.model = <DacFxDataModel>{};
let profile = p ? <sqlops.IConnectionProfile>p.connectionProfile : undefined;
if (profile) {
this.model.serverId = profile.id;
this.model.database = profile.databaseName;
}
this.connection = await sqlops.connection.getCurrentConnection();
if (!this.connection) {
this.connection = await sqlops.connection.openConnectionDialog();
}
this.wizard = sqlops.window.modelviewdialog.createWizard('Data-tier Application Wizard');
let selectOperationWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.selectOperationPageName', 'Select an Operation'));
let deployConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.deployConfigPageName', 'Select Deploy Dacpac Settings'));
let summaryWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.summaryPageName', 'Summary'));
let extractConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.extractConfigPageName', 'Select Extract Dacpac Settings'));
let importConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.importConfigPageName', 'Select Import Bacpac Settings'));
let exportConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.exportConfigPageName', 'Select Export Bacpac Settings'));
this.pages.set('selectOperation', new Page(selectOperationWizardPage));
this.pages.set('deployConfig', new Page(deployConfigWizardPage));
this.pages.set('extractConfig', new Page(extractConfigWizardPage));
this.pages.set('importConfig', new Page(importConfigWizardPage));
this.pages.set('exportConfig', new Page(exportConfigWizardPage));
this.pages.set('summary', new Page(summaryWizardPage));
selectOperationWizardPage.registerContent(async (view) => {
let selectOperationDacFxPage = new SelectOperationPage(this, selectOperationWizardPage, this.model, view);
this.pages.get('selectOperation').dacFxPage = selectOperationDacFxPage;
await selectOperationDacFxPage.start().then(() => {
selectOperationDacFxPage.setupNavigationValidator();
selectOperationDacFxPage.onPageEnter();
});
});
deployConfigWizardPage.registerContent(async (view) => {
let deployConfigDacFxPage = new DeployConfigPage(this, deployConfigWizardPage, this.model, view);
this.pages.get('deployConfig').dacFxPage = deployConfigDacFxPage;
await deployConfigDacFxPage.start();
});
extractConfigWizardPage.registerContent(async (view) => {
let extractConfigDacFxPage = new ExtractConfigPage(this, extractConfigWizardPage, this.model, view);
this.pages.get('extractConfig').dacFxPage = extractConfigDacFxPage;
await extractConfigDacFxPage.start();
});
importConfigWizardPage.registerContent(async (view) => {
let importConfigDacFxPage = new ImportConfigPage(this, importConfigWizardPage, this.model, view);
this.pages.get('importConfig').dacFxPage = importConfigDacFxPage;
await importConfigDacFxPage.start();
});
exportConfigWizardPage.registerContent(async (view) => {
let exportConfigDacFxPage = new ExportConfigPage(this, exportConfigWizardPage, this.model, view);
this.pages.get('exportConfig').dacFxPage = exportConfigDacFxPage;
await exportConfigDacFxPage.start();
});
summaryWizardPage.registerContent(async (view) => {
let summaryDacFxPage = new DacFxSummaryPage(this, summaryWizardPage, this.model, view);
this.pages.get('summary').dacFxPage = summaryDacFxPage;
await summaryDacFxPage.start();
});
this.wizard.onPageChanged(async (event) => {
let idx = event.newPage;
let page: Page;
if (idx === 1) {
switch (this.selectedOperation) {
case Operation.deploy: {
page = this.pages.get('deployConfig');
break;
}
case Operation.extract: {
page = this.pages.get('extractConfig');
break;
}
case Operation.import: {
page = this.pages.get('importConfig');
break;
}
case Operation.export: {
page = this.pages.get('exportConfig');
break;
}
}
} else if (idx === 2) {
page = this.pages.get('summary');
}
if (page !== undefined) {
page.dacFxPage.setupNavigationValidator();
page.dacFxPage.onPageEnter();
}
});
this.wizard.pages = [selectOperationWizardPage, deployConfigWizardPage, summaryWizardPage];
this.wizard.generateScriptButton.hidden = true;
this.wizard.doneButton.onClick(async () => await this.executeOperation());
this.wizard.open();
}
public registerNavigationValidator(validator: (pageChangeInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo) => boolean) {
this.wizard.registerNavigationValidator(validator);
}
public setDoneButton(operation: Operation): void {
switch (operation) {
case Operation.deploy: {
this.wizard.doneButton.label = localize('dacFx.deployButton', 'Deploy');
this.selectedOperation = Operation.deploy;
break;
}
case Operation.extract: {
this.wizard.doneButton.label = localize('dacFx.extractButton', 'Extract');
this.selectedOperation = Operation.extract;
break;
}
case Operation.import: {
this.wizard.doneButton.label = localize('dacFx.importButton', 'Import');
this.selectedOperation = Operation.import;
break;
}
case Operation.export: {
this.wizard.doneButton.label = localize('dacFx.exportButton', 'Export');
this.selectedOperation = Operation.export;
break;
}
}
}
private async executeOperation() {
switch (this.selectedOperation) {
case Operation.deploy: {
await this.deploy();
break;
}
case Operation.extract: {
await this.extract();
break;
}
case Operation.import: {
await this.import();
break;
}
case Operation.export: {
await this.export();
break;
}
}
}
private async deploy() {
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
let result = await service.deployDacpac(this.model.filePath, this.model.database, this.model.upgradeExisting, ownerUri, sqlops.TaskExecutionMode.execute);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.deployErrorMessage', "Deploy failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
}
private async extract() {
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
let result = await service.extractDacpac(this.model.database, this.model.filePath, this.model.database, this.model.version, ownerUri, sqlops.TaskExecutionMode.execute);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.extractErrorMessage', "Extract failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
}
private async export() {
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
let result = await service.exportBacpac(this.model.database, this.model.filePath, ownerUri, sqlops.TaskExecutionMode.execute);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.exportErrorMessage', "Export failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
}
private async import() {
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
let result = await service.importBacpac(this.model.filePath, this.model.database, ownerUri, sqlops.TaskExecutionMode.execute);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.importErrorMessage', "Import failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
}
private static async getService(providerName: string): Promise<sqlops.DacFxServicesProvider> {
let service = sqlops.dataprotocol.getProvider<sqlops.DacFxServicesProvider>(providerName, sqlops.DataProviderType.DacFxServicesProvider);
return service;
}
}

View File

@@ -0,0 +1,112 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
import { BasePage } from '../api/basePage';
const localize = nls.loadMessageBundle();
export class DacFxSummaryPage extends BasePage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private form: sqlops.FormContainer;
private table: sqlops.TableComponent;
private loader: sqlops.LoadingComponent;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super();
this.instance = instance;
this.wizardPage = wizardPage;
this.model = model;
this.view = view;
}
async start(): Promise<boolean> {
this.table = this.view.modelBuilder.table().component();
this.loader = this.view.modelBuilder.loadingComponent().withItem(this.table).component();
this.form = this.view.modelBuilder.formContainer().withFormItems(
[
{
component: this.table,
title: ''
}
]
).component();
await this.view.initializeModel(this.form);
return true;
}
async onPageEnter(): Promise<boolean> {
this.populateTable();
this.loader.loading = false;
return true;
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
if (this.loader.loading) {
return false;
}
return true;
});
}
private populateTable() {
let data = [];
let targetServer = localize('dacfx.targetServerName', 'Target Server');
let targetDatabase = localize('dacfx.targetDatabaseName', 'Target Database');
let sourceServer = localize('dacfx.sourceServerName', 'Source Server');
let sourceDatabase = localize('dacfx.sourceDatabaseName', 'Source Database');
let fileLocation = localize('dacfx.fileLocation', 'File Location');
switch (this.instance.selectedOperation) {
case Operation.deploy: {
data = [
[targetServer, this.model.serverName],
[fileLocation, this.model.filePath],
[targetDatabase, this.model.database]];
break;
}
case Operation.extract: {
data = [
[sourceServer, this.model.serverName],
[sourceDatabase, this.model.database],
[localize('dacfxExtract.version', 'Version'), this.model.version],
[fileLocation, this.model.filePath]];
break;
}
case Operation.import: {
data = [
[targetServer, this.model.serverName],
[fileLocation, this.model.filePath],
[targetDatabase, this.model.database]];
break;
}
case Operation.export: {
data = [
[sourceServer, this.model.serverName],
[sourceDatabase, this.model.database],
[fileLocation, this.model.filePath]];
break;
}
}
this.table.updateProperties({
data: data,
columns: ['Setting', 'Value'],
width: 600,
height: 200
});
}
}

View File

@@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import * as path from 'path';
import * as os from 'os';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
const localize = nls.loadMessageBundle();
export class DeployConfigPage extends DacFxConfigPage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private databaseDropdownComponent: sqlops.FormComponent;
private databaseComponent: sqlops.FormComponent;
private formBuilder: sqlops.FormBuilder;
private form: sqlops.FormContainer;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super(instance, wizardPage, model, view);
this.fileExtension = '.bacpac';
}
async start(): Promise<boolean> {
let serverComponent = await this.createServerDropdown(true);
let fileBrowserComponent = await this.createFileBrowser();
this.databaseComponent = await this.createDatabaseTextBox();
this.databaseComponent.title = localize('dacFx.databaseNameTextBox', 'Database Name');
this.databaseDropdownComponent = await this.createDeployDatabaseDropdown();
this.databaseDropdownComponent.title = localize('dacFx.databaseNameDropdown', 'Database Name');
let radioButtons = await this.createRadiobuttons();
this.formBuilder = this.view.modelBuilder.formContainer()
.withFormItems(
[
fileBrowserComponent,
serverComponent,
radioButtons,
this.databaseDropdownComponent
], {
horizontal: true,
componentWidth: 400
});
this.form = this.formBuilder.component();
await this.view.initializeModel(this.form);
return true;
}
async onPageEnter(): Promise<boolean> {
let r1 = await this.populateServerDropdown();
let r2 = await this.populateDeployDatabaseDropdown();
return r1 && r2;
}
private async createFileBrowser(): Promise<sqlops.FormComponent> {
this.createFileBrowserParts();
this.fileButton.onDidClick(async (click) => {
let fileUris = await vscode.window.showOpenDialog(
{
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
defaultUri: vscode.Uri.file(os.homedir()),
openLabel: localize('dacFxDeploy.openFile', 'Open'),
filters: {
'dacpac Files': ['dacpac'],
}
}
);
if (!fileUris || fileUris.length === 0) {
return;
}
let fileUri = fileUris[0];
this.fileTextBox.value = fileUri.fsPath;
this.model.filePath = fileUri.fsPath;
});
this.fileTextBox.onTextChanged(async () => {
this.model.filePath = this.fileTextBox.value;
this.databaseTextBox.value = this.generateDatabaseName(this.model.filePath);
if (!this.model.upgradeExisting) {
this.model.database = this.databaseTextBox.value;
}
});
return {
component: this.fileTextBox,
title: localize('dacFxDeploy.fileTextboxTitle', 'File Location'),
actions: [this.fileButton]
};
}
private async createRadiobuttons(): Promise<sqlops.FormComponent> {
let upgradeRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'updateExisting',
label: localize('dacFx.upgradeRadioButtonLabel', 'Upgrade Existing Database'),
}).component();
let newRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'updateExisting',
label: localize('dacFx.newRadioButtonLabel', 'New Database'),
}).component();
upgradeRadioButton.onDidClick(() => {
this.model.upgradeExisting = true;
this.formBuilder.removeFormItem(this.databaseComponent);
this.formBuilder.addFormItem(this.databaseDropdownComponent, { horizontal: true, componentWidth: 400 });
this.model.database = (<sqlops.CategoryValue>this.databaseDropdown.value).name;
});
newRadioButton.onDidClick(() => {
this.model.upgradeExisting = false;
this.formBuilder.removeFormItem(this.databaseDropdownComponent);
this.formBuilder.addFormItem(this.databaseComponent, { horizontal: true, componentWidth: 400 });
this.model.database = this.databaseTextBox.value;
});
//Initialize with upgrade existing true
upgradeRadioButton.checked = true;
this.model.upgradeExisting = true;
let flexRadioButtonsModel = this.view.modelBuilder.flexContainer()
.withLayout({
flexFlow: 'row',
}).withItems([
upgradeRadioButton, newRadioButton]
).component();
return {
component: flexRadioButtonsModel,
title: localize('dacFx.targetDatabaseRadioButtonsTitle', 'Target Database')
};
}
protected async createDeployDatabaseDropdown(): Promise<sqlops.FormComponent> {
this.databaseDropdown = this.view.modelBuilder.dropDown().withProperties({
required: true
}).component();
//Handle database changes
this.databaseDropdown.onValueChanged(async () => {
this.model.database = (<sqlops.CategoryValue>this.databaseDropdown.value).name;
});
this.databaseLoader = this.view.modelBuilder.loadingComponent().withItem(this.databaseDropdown).component();
return {
component: this.databaseLoader,
title: localize('dacFx.targetDatabaseDropdownTitle', 'Database Name')
};
}
protected async populateDeployDatabaseDropdown(): Promise<boolean> {
this.databaseLoader.loading = true;
this.databaseDropdown.updateProperties({ values: [] });
if (!this.model.server) {
this.databaseLoader.loading = false;
return false;
}
let values = await this.getDatabaseValues();
//set the database to the first dropdown value if upgrading, otherwise it should get set to the textbox value
if (this.model.upgradeExisting) {
this.model.database = values[0].name;
}
this.databaseDropdown.updateProperties({
values: values
});
this.databaseLoader.loading = false;
return true;
}
private generateDatabaseName(filePath: string): string {
let result = path.parse(filePath);
return result.name;
}
}

View File

@@ -0,0 +1,100 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
const localize = nls.loadMessageBundle();
export class ExportConfigPage extends DacFxConfigPage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private form: sqlops.FormContainer;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super(instance, wizardPage, model, view);
this.fileExtension = '.bacpac';
}
async start(): Promise<boolean> {
let databaseComponent = await this.createDatabaseDropdown();
let serverComponent = await this.createServerDropdown(false);
let fileBrowserComponent = await this.createFileBrowser();
this.form = this.view.modelBuilder.formContainer()
.withFormItems(
[
serverComponent,
databaseComponent,
fileBrowserComponent,
], {
horizontal: true,
componentWidth: 400
}).component();
await this.view.initializeModel(this.form);
return true;
}
async onPageEnter(): Promise<boolean> {
let r1 = await this.populateServerDropdown();
let r2 = await this.populateDatabaseDropdown();
return r1 && r2;
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
if (this.databaseLoader.loading) {
return false;
}
return true;
});
}
private async createFileBrowser(): Promise<sqlops.FormComponent> {
this.createFileBrowserParts();
// default filepath
this.fileTextBox.value = this.generateFilePath();
this.model.filePath = this.fileTextBox.value;
this.fileButton.onDidClick(async (click) => {
let fileUri = await vscode.window.showSaveDialog(
{
defaultUri: vscode.Uri.file(this.fileTextBox.value),
saveLabel: localize('dacfxExport.saveFile', 'Save'),
filters: {
'bacpac Files': ['bacpac'],
}
}
);
if (!fileUri) {
return;
}
this.fileTextBox.value = fileUri.fsPath;
this.model.filePath = fileUri.fsPath;
});
this.fileTextBox.onTextChanged(async () => {
this.model.filePath = this.fileTextBox.value;
});
return {
component: this.fileTextBox,
title: localize('dacFxExport.fileTextboxTitle', 'File Location'),
actions: [this.fileButton]
};
}
}

View File

@@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
const localize = nls.loadMessageBundle();
export class ExtractConfigPage extends DacFxConfigPage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private form: sqlops.FormContainer;
private versionTextBox: sqlops.InputBoxComponent;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super(instance, wizardPage, model, view);
this.fileExtension = '.dacpac';
}
async start(): Promise<boolean> {
let databaseComponent = await this.createDatabaseDropdown();
let serverComponent = await this.createServerDropdown(false);
let fileBrowserComponent = await this.createFileBrowser();
let versionComponent = await this.createVersionTextBox();
this.form = this.view.modelBuilder.formContainer()
.withFormItems(
[
serverComponent,
databaseComponent,
versionComponent,
fileBrowserComponent,
], {
horizontal: true,
componentWidth: 400
}).component();
await this.view.initializeModel(this.form);
return true;
}
async onPageEnter(): Promise<boolean> {
let r1 = await this.populateServerDropdown();
let r2 = await this.populateDatabaseDropdown();
return r1 && r2;
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
if (this.databaseLoader.loading) {
return false;
}
return true;
});
}
private async createFileBrowser(): Promise<sqlops.FormComponent> {
this.createFileBrowserParts();
// default filepath
this.fileTextBox.value = this.generateFilePath();
this.model.filePath = this.fileTextBox.value;
this.fileButton.onDidClick(async (click) => {
let fileUri = await vscode.window.showSaveDialog(
{
defaultUri: vscode.Uri.file(this.fileTextBox.value),
saveLabel: localize('dacfxExtract.saveFile', 'Save'),
filters: {
'dacpac Files': ['dacpac'],
}
}
);
if (!fileUri) {
return;
}
this.fileTextBox.value = fileUri.fsPath;
this.model.filePath = fileUri.fsPath;
});
this.fileTextBox.onTextChanged(async () => {
this.model.filePath = this.fileTextBox.value;
});
return {
component: this.fileTextBox,
title: localize('dacFxExtract.fileTextboxTitle', 'File Location'),
actions: [this.fileButton]
};
}
private async createVersionTextBox(): Promise<sqlops.FormComponent> {
this.versionTextBox = this.view.modelBuilder.inputBox().withProperties({
required: true
}).component();
// default filepath
this.versionTextBox.value = '1.0.0.0';
this.model.version = this.versionTextBox.value;
this.versionTextBox.onTextChanged(async () => {
this.model.version = this.versionTextBox.value;
});
return {
component: this.versionTextBox,
title: localize('dacFxExtract.versionTextboxTitle', 'Version (use x.x.x.x where x is a number)'),
};
}
}

View File

@@ -102,57 +102,9 @@ export class FileConfigPage extends ImportPage {
}
private async populateServerDropdown(): Promise<boolean> {
let cons = await sqlops.connection.getActiveConnections();
// This user has no active connections ABORT MISSION
if (!cons || cons.length === 0) {
return true;
}
let count = -1;
let idx = -1;
let values = cons.map(c => {
// Handle the code to remember what the user's choice was from before
count++;
if (idx === -1) {
if (this.model.server && c.connectionId === this.model.server.connectionId) {
idx = count;
} else if (this.model.serverId && c.connectionId === this.model.serverId) {
idx = count;
}
}
let db = c.options.databaseDisplayName;
let usr = c.options.user;
let srv = c.options.server;
if (!db) {
db = '<default>';
}
if (!usr) {
usr = 'default';
}
let finalName = `${srv}, ${db} (${usr})`;
return {
connection: c,
displayName: finalName,
name: c.connectionId
};
});
if (idx >= 0) {
let tmp = values[0];
values[0] = values[idx];
values[idx] = tmp;
} else {
delete this.model.server;
delete this.model.serverId;
delete this.model.database;
delete this.model.schema;
let values = await this.getServerValues();
if (values === undefined) {
return false;
}
this.model.server = values[0].connection;
@@ -195,29 +147,7 @@ export class FileConfigPage extends ImportPage {
return false;
}
let idx = -1;
let count = -1;
let values = (await sqlops.connection.listDatabases(this.model.server.connectionId)).map(db => {
count++;
if (this.model.database && db === this.model.database) {
idx = count;
}
return {
displayName: db,
name: db
};
});
if (idx >= 0) {
let tmp = values[0];
values[0] = values[idx];
values[idx] = tmp;
} else {
delete this.model.database;
delete this.model.schema;
}
let values = await this.getDatabaseValues();
this.model.database = values[0].name;
@@ -377,6 +307,18 @@ export class FileConfigPage extends ImportPage {
return true;
}
protected deleteServerValues() {
delete this.model.server;
delete this.model.serverId;
delete this.model.database;
delete this.model.schema;
}
protected deleteDatabaseValues() {
delete this.model.database;
delete this.model.schema;
}
// private async populateTableNames(): Promise<boolean> {
// this.tableNames = [];
// let databaseName = (<sqlops.CategoryValue>this.databaseDropdown.value).name;

View File

@@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import * as path from 'path';
import * as os from 'os';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
const localize = nls.loadMessageBundle();
export class ImportConfigPage extends DacFxConfigPage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private form: sqlops.FormContainer;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super(instance, wizardPage, model, view);
this.fileExtension = '.bacpac';
}
async start(): Promise<boolean> {
let databaseComponent = await this.createDatabaseTextBox();
let serverComponent = await this.createServerDropdown(true);
let fileBrowserComponent = await this.createFileBrowser();
this.form = this.view.modelBuilder.formContainer()
.withFormItems(
[
fileBrowserComponent,
serverComponent,
databaseComponent,
], {
horizontal: true,
componentWidth: 400
}).component();
await this.view.initializeModel(this.form);
return true;
}
async onPageEnter(): Promise<boolean> {
let r1 = await this.populateServerDropdown();
return r1;
}
private async createFileBrowser(): Promise<sqlops.FormComponent> {
this.createFileBrowserParts();
this.fileButton.onDidClick(async (click) => {
let fileUris = await vscode.window.showOpenDialog(
{
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
defaultUri: vscode.Uri.file(os.homedir()),
openLabel: localize('dacFxImport.openFile', 'Open'),
filters: {
'bacpac Files': ['bacpac'],
}
}
);
if (!fileUris || fileUris.length === 0) {
return;
}
let fileUri = fileUris[0];
this.fileTextBox.value = fileUri.fsPath;
this.model.filePath = fileUri.fsPath;
this.model.database = this.generateDatabaseName(this.model.filePath);
this.databaseTextBox.value = this.model.database;
});
this.fileTextBox.onTextChanged(async () => {
this.model.filePath = this.fileTextBox.value;
this.model.database = this.generateDatabaseName(this.model.filePath);
this.databaseTextBox.value = this.model.database;
});
return {
component: this.fileTextBox,
title: localize('dacFxImport.fileTextboxTitle', 'File Location'),
actions: [this.fileButton]
};
}
private generateDatabaseName(filePath: string): string {
let result = path.parse(filePath);
return result.name;
}
}

View File

@@ -0,0 +1,174 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
import { BasePage } from '../api/basePage';
const localize = nls.loadMessageBundle();
export class SelectOperationPage extends BasePage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private deployRadioButton: sqlops.RadioButtonComponent;
private extractRadioButton: sqlops.RadioButtonComponent;
private importRadioButton: sqlops.RadioButtonComponent;
private exportRadioButton: sqlops.RadioButtonComponent;
private form: sqlops.FormContainer;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super();
this.instance = instance;
this.wizardPage = wizardPage;
this.model = model;
this.view = view;
}
async start(): Promise<boolean> {
let deployComponent = await this.createDeployRadioButton();
let extractComponent = await this.createExtractRadioButton();
let importComponent = await this.createImportRadioButton();
let exportComponent = await this.createExportRadioButton();
this.form = this.view.modelBuilder.formContainer()
.withFormItems(
[
deployComponent,
extractComponent,
importComponent,
exportComponent
], {
horizontal: true
}).component();
await this.view.initializeModel(this.form);
// default have the first radio button checked
this.deployRadioButton.checked = true;
this.instance.setDoneButton(Operation.deploy);
return true;
}
async onPageEnter(): Promise<boolean> {
let numPages = this.instance.wizard.pages.length;
for (let i = numPages - 1; i > 2; --i) {
await this.instance.wizard.removePage(i);
}
return true;
}
private async createDeployRadioButton(): Promise<sqlops.FormComponent> {
this.deployRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedOperation',
label: localize('dacFx.deployRadioButtonLabel', 'Deploy a data-tier application .dacpac file to an instance of SQL Server [Deploy Dacpac]'),
}).component();
this.deployRadioButton.onDidClick(() => {
// remove the previous page
this.instance.wizard.removePage(1);
// add deploy page
let page = this.instance.pages.get('deployConfig');
this.instance.wizard.addPage(page.wizardPage, 1);
// change button text and operation
this.instance.setDoneButton(Operation.deploy);
});
return {
component: this.deployRadioButton,
title: ''
};
}
private async createExtractRadioButton(): Promise<sqlops.FormComponent> {
this.extractRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedOperation',
label: localize('dacFx.extractRadioButtonLabel', 'Extract a data-tier application from an instance of SQL Server to a .dacpac file [Extract Dacpac]'),
}).component();
this.extractRadioButton.onDidClick(() => {
// remove the previous pages
this.instance.wizard.removePage(1);
// add the extract page
let page = this.instance.pages.get('extractConfig');
this.instance.wizard.addPage(page.wizardPage, 1);
// change button text and operation
this.instance.setDoneButton(Operation.extract);
});
return {
component: this.extractRadioButton,
title: ''
};
}
private async createImportRadioButton(): Promise<sqlops.FormComponent> {
this.importRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedOperation',
label: localize('dacFx.importRadioButtonLabel', 'Create a database from a .bacpac file [Import Bacpac]'),
}).component();
this.importRadioButton.onDidClick(() => {
// remove the previous page
this.instance.wizard.removePage(1);
// add the import page
let page = this.instance.pages.get('importConfig');
this.instance.wizard.addPage(page.wizardPage, 1);
// change button text and operation
this.instance.setDoneButton(Operation.import);
});
return {
component: this.importRadioButton,
title: ''
};
}
private async createExportRadioButton(): Promise<sqlops.FormComponent> {
this.exportRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedOperation',
label: localize('dacFx.exportRadioButtonLabel', 'Export the schema and data from a database to the logical .bacpac file format [Export Bacpac]'),
}).component();
this.exportRadioButton.onDidClick(() => {
// remove the 2 previous pages
this.instance.wizard.removePage(1);
// add the export pages
let page = this.instance.pages.get('exportConfig');
this.instance.wizard.addPage(page.wizardPage, 1);
// change button text and operation
this.instance.setDoneButton(Operation.export);
});
return {
component: this.exportRadioButton,
title: ''
};
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
return true;
});
}
}

View File

@@ -11,7 +11,8 @@ agent-base@4, agent-base@^4.1.0:
applicationinsights@1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
integrity sha1-U0Rrgw/o1dYZ7uKieLMdPSUDCSc=
dependencies:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "0.2.1"
@@ -35,7 +36,7 @@ buffer-alloc-unsafe@^1.1.0:
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
buffer-alloc@^1.1.0:
buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
@@ -74,19 +75,26 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.7":
version "0.2.6"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/85653d8b305af8aef334728d71f07bdc240dfcb7"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.10":
version "0.2.10"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/4de3f7caf0eba54159911b977ddb4f5d7c0a9ca8"
dependencies:
vscode-languageclient "3.5.1"
debug@3.1.0, debug@^3.1.0:
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
@@ -142,11 +150,13 @@ decompress@^4.2.0:
diagnostic-channel-publishers@0.2.1:
version "0.2.1"
resolved "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
diagnostic-channel@0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
dependencies:
semver "^5.3.0"
@@ -158,9 +168,9 @@ end-of-stream@^1.0.0:
once "^1.4.0"
es6-promise@^4.0.3:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
version "4.2.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
es6-promisify@^5.0.0:
version "5.0.0"
@@ -210,9 +220,9 @@ get-stream@^2.2.0:
pinkie-promise "^2.0.0"
graceful-fs@^4.1.10:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
"graceful-readlink@>= 1.0.0":
version "1.0.1"
@@ -284,6 +294,11 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -297,9 +312,9 @@ once@^1.4.0:
wrappy "1"
opener@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
version "1.5.1"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
os-tmpdir@~1.0.2:
version "1.0.2"
@@ -365,7 +380,8 @@ seek-bzip@^1.0.5:
semver@^5.3.0:
version "5.6.0"
resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
version "0.1.5"
@@ -393,16 +409,16 @@ strip-dirs@^2.0.0:
is-natural-number "^4.0.1"
tar-stream@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==
version "1.6.2"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
dependencies:
bl "^1.0.0"
buffer-alloc "^1.1.0"
buffer-alloc "^1.2.0"
end-of-stream "^1.0.0"
fs-constants "^1.0.0"
readable-stream "^2.3.0"
to-buffer "^1.1.0"
to-buffer "^1.1.1"
xtend "^4.0.0"
through@^2.3.6:
@@ -417,15 +433,15 @@ tmp@^0.0.33:
dependencies:
os-tmpdir "~1.0.2"
to-buffer@^1.1.0:
to-buffer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
unbzip2-stream@^1.0.9:
version "1.2.5"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
integrity sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==
version "1.3.1"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==
dependencies:
buffer "^3.0.1"
through "^2.3.6"
@@ -437,7 +453,8 @@ util-deprecate@~1.0.1:
vscode-extension-telemetry@0.0.18:
version "0.0.18"
resolved "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.18.tgz#602ba20d8c71453aa34533a291e7638f6e5c0327"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.18.tgz#602ba20d8c71453aa34533a291e7638f6e5c0327"
integrity sha512-Vw3Sr+dZwl+c6PlsUwrTtCOJkgrmvS3OUVDQGcmpXWAgq9xGq6as0K4pUx+aGqTjzLAESmWSrs6HlJm6J6Khcg==
dependencies:
applicationinsights "1.0.1"
@@ -467,9 +484,9 @@ vscode-languageserver-types@3.5.0:
integrity sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=
vscode-nls@^3.2.1:
version "3.2.4"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
integrity sha512-FTjdqa4jDDoBjJqr36O8lmmZf/55kQ2w4ZY/+GL6K92fq765BqO3aYw21atnXUno/P04V5DWagNl4ybDIndJsw==
version "3.2.5"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.5.tgz#25520c1955108036dec607c85e00a522f247f1a4"
integrity sha512-ITtoh3V4AkWXMmp3TB97vsMaHRgHhsSFPsUdzlueSL+dRZbSNTZeOmdQv60kjCV306ghPxhDeoNUEm3+EZMuyw==
wrappy@1:
version "1.0.2"
@@ -491,4 +508,5 @@ yauzl@^2.4.2:
zone.js@0.7.6:
version "0.7.6"
resolved "https://registry.npmjs.org/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=

View File

@@ -23,7 +23,8 @@
"onCommand:markdown.showLockedPreviewToSide",
"onCommand:markdown.showSource",
"onCommand:markdown.showPreviewSecuritySelector",
"onWebviewPanel:markdown.preview"
"onWebviewPanel:markdown.preview",
"onCommand:notebook.showPreview"
],
"contributes": {
"commands": [
@@ -77,6 +78,11 @@
"command": "markdown.preview.toggleLock",
"title": "%markdown.preview.toggleLock.title%",
"category": "Markdown"
},
{
"command": "notebook.showPreview",
"title": "notebook.showPreview",
"category": "Notebook"
}
],
"menus": {
@@ -154,6 +160,10 @@
{
"command": "markdown.preview.toggleLock",
"when": "markdownPreviewFocus"
},
{
"command": "notebook.showPreview",
"when": "false"
}
]
},

View File

@@ -8,7 +8,8 @@ import * as vscode from 'vscode';
export interface Command {
readonly id: string;
execute(...args: any[]): void;
// {{SQL CARBON EDIT}}
execute(...args: any[]): any;
}
export class CommandManager {
@@ -26,7 +27,8 @@ export class CommandManager {
return command;
}
private registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any) {
// {{SQL CARBON EDIT}}
private registerCommand(id: string, impl: (...args: any[]) => any, thisArg?: any) {
if (this.commands.has(id)) {
return;
}

View File

@@ -11,3 +11,5 @@ export { RefreshPreviewCommand } from './refreshPreview';
export { ShowPreviewSecuritySelectorCommand } from './showPreviewSecuritySelector';
export { MoveCursorToPositionCommand } from './moveCursorToPosition';
export { ToggleLockCommand } from './toggleLock';
// {{SQL CARBON EDIT}}
export { ShowNotebookPreview } from './showNotebookPreview';

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { Command } from '../commandManager';
import { MarkdownEngine } from '../markdownEngine';
export class ShowNotebookPreview implements Command {
public readonly id = 'notebook.showPreview';
public constructor(
private readonly engine: MarkdownEngine
) { }
public async execute(document: vscode.Uri, textContent: string): Promise<string> {
return this.engine.renderText(document, textContent);
}
}

View File

@@ -59,6 +59,8 @@ export function activate(context: vscode.ExtensionContext) {
commandManager.register(new commands.OnPreviewStyleLoadErrorCommand());
commandManager.register(new commands.OpenDocumentLinkCommand(engine));
commandManager.register(new commands.ToggleLockCommand(previewManager));
// {{SQL CARBON EDIT}}
commandManager.register(new commands.ShowNotebookPreview(engine));
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
logger.updateConfiguration();

View File

@@ -86,6 +86,12 @@ export class MarkdownEngine {
return { text, offset };
}
// {{SQL CARBON EDIT}}
public async renderText(document: vscode.Uri, text: string): Promise<string> {
const engine = await this.getEngine(document);
return engine.render(text);
}
public async render(document: vscode.Uri, stripFrontmatter: boolean, text: string): Promise<string> {
let offset = 0;
if (stripFrontmatter) {

View File

@@ -18,7 +18,7 @@
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json"
},
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.8",
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.10",
"opener": "^1.4.3",
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"vscode-extension-telemetry": "^0.0.15"
@@ -285,6 +285,10 @@
{
"displayName": "Windows Authentication",
"name": "Integrated"
},
{
"displayName": "Azure Active Directory - Universal with MFA support",
"name": "AzureMFA"
}
],
"isRequired": true,
@@ -345,7 +349,7 @@
"specialValueType": null,
"isIdentity": false,
"name": "asynchronousProcessing",
"displayName": "Asynchronous processing enabled",
"displayName": "Asynchronous processing",
"description": "When true, enables usage of the Asynchronous functionality in the .Net Framework Data Provider",
"groupName": "Initialization",
"valueType": "boolean",
@@ -387,7 +391,7 @@
"specialValueType": null,
"isIdentity": false,
"name": "columnEncryptionSetting",
"displayName": "Column encryption setting",
"displayName": "Column encryption",
"description": "Default column encryption setting for all the commands on the connection",
"groupName": "Security",
"valueType": "category",

View File

@@ -163,6 +163,7 @@
"\tFROM INFORMATION_SCHEMA.ROUTINES",
"WHERE SPECIFIC_SCHEMA = N'${2:dbo}'",
"\tAND SPECIFIC_NAME = N'${1:StoredProcedureName}'",
"\tAND ROUTINE_TYPE = N'PROCEDURE'"
")",
"DROP PROCEDURE ${2:dbo}.${1:StoredProcedureName}",
"GO",

View File

@@ -1,6 +1,6 @@
{
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "1.5.0-alpha.52",
"version": "1.5.0-alpha.63",
"downloadFileNames": {
"Windows_86": "win-x86-netcoreapp2.2.zip",
"Windows_64": "win-x64-netcoreapp2.2.zip",

View File

@@ -291,3 +291,60 @@ export namespace DeleteAgentJobScheduleRequest {
}
// ------------------------------- < Agent Management > ------------------------------------
// ------------------------------- < DacFx > ------------------------------------
export enum TaskExecutionMode {
execute = 0,
script = 1,
executeAndScript = 2,
}
export interface ExportParams {
databaseName: string;
packageFilePath: string;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export interface ImportParams {
packageFilePath: string;
databaseName: string;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export interface ExtractParams {
databaseName: string;
packageFilePath: string;
applicationName: string;
applicationVersion: string;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export interface DeployParams {
packageFilePath: string;
databaseName: string;
upgradeExisting: boolean;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export namespace ExportRequest {
export const type = new RequestType<ExportParams, sqlops.DacFxResult, void, void>('dacfx/export');
}
export namespace ImportRequest {
export const type = new RequestType<ImportParams, sqlops.DacFxResult, void, void>('dacfx/import');
}
export namespace ExtractRequest {
export const type = new RequestType<ExtractParams, sqlops.DacFxResult, void, void>('dacfx/extract');
}
export namespace DeployRequest {
export const type = new RequestType<DeployParams, sqlops.DacFxResult, void, void>('dacfx/deploy');
}
// ------------------------------- < DacFx > ------------------------------------

View File

@@ -8,7 +8,7 @@ import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
import { Disposable } from 'vscode';
import { Telemetry } from './telemetry';
import * as contracts from './contracts';
import * as contracts from './contracts';
import * as sqlops from 'sqlops';
import * as Utils from './utils';
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
@@ -28,6 +28,94 @@ export class TelemetryFeature implements StaticFeature {
}
}
export class DacFxServicesFeature extends SqlOpsFeature<undefined> {
private static readonly messageTypes: RPCMessageType[] = [
contracts.ExportRequest.type,
contracts.ImportRequest.type,
contracts.ExtractRequest.type,
contracts.DeployRequest.type
];
constructor(client: SqlOpsDataClient) {
super(client, DacFxServicesFeature.messageTypes);
}
public fillClientCapabilities(capabilities: ClientCapabilities): void {
}
public initialize(capabilities: ServerCapabilities): void {
this.register(this.messages, {
id: UUID.generateUuid(),
registerOptions: undefined
});
}
protected registerProvider(options: undefined): Disposable {
const client = this._client;
let self = this;
let exportBacpac = (databaseName: string, packageFilePath: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> => {
let params: contracts.ExportParams = { databaseName: databaseName, packageFilePath: packageFilePath, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.ExportRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.ExportRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let importBacpac = (packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> => {
let params: contracts.ImportParams = { packageFilePath: packageFilePath, databaseName: databaseName, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.ImportRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.ImportRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let extractDacpac = (databaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> => {
let params: contracts.ExtractParams = { databaseName: databaseName, packageFilePath: packageFilePath, applicationName: applicationName, applicationVersion: applicationVersion, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.ExtractRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.ExtractRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let deployDacpac = (packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> => {
let params: contracts.DeployParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, upgradeExisting: upgradeExisting, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.DeployRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.DeployRequest.type, e);
return Promise.resolve(undefined);
}
);
};
return sqlops.dataprotocol.registerDacFxServicesProvider({
providerId: client.providerId,
exportBacpac,
importBacpac,
extractDacpac,
deployDacpac
});
}
}
export class AgentServicesFeature extends SqlOpsFeature<undefined> {
private static readonly messagesTypes: RPCMessageType[] = [
contracts.AgentJobsRequest.type,
@@ -229,7 +317,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
};
// Alert management methods
let getAlerts = (ownerUri: string): Thenable<sqlops.AgentAlertsResult> => {
let getAlerts = (ownerUri: string): Thenable<sqlops.AgentAlertsResult> => {
let params: contracts.AgentAlertsParams = {
ownerUri: ownerUri
};
@@ -299,7 +387,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
};
// Operator management methods
let getOperators = (ownerUri: string): Thenable<sqlops.AgentOperatorsResult> => {
let getOperators = (ownerUri: string): Thenable<sqlops.AgentOperatorsResult> => {
let params: contracts.AgentOperatorsParams = {
ownerUri: ownerUri
};
@@ -369,7 +457,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
};
// Proxy management methods
let getProxies = (ownerUri: string): Thenable<sqlops.AgentProxiesResult> => {
let getProxies = (ownerUri: string): Thenable<sqlops.AgentProxiesResult> => {
let params: contracts.AgentProxiesParams = {
ownerUri: ownerUri
};
@@ -439,7 +527,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
};
// Agent Credential Method
let getCredentials = (ownerUri: string): Thenable<sqlops.GetCredentialsResult> => {
let getCredentials = (ownerUri: string): Thenable<sqlops.GetCredentialsResult> => {
let params: contracts.GetCredentialsParams = {
ownerUri: ownerUri
};
@@ -455,7 +543,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
// Job Schedule management methods
let getJobSchedules = (ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> => {
let getJobSchedules = (ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> => {
let params: contracts.AgentJobScheduleParams = {
ownerUri: ownerUri
};

View File

@@ -16,7 +16,7 @@ import { CredentialStore } from './credentialstore/credentialstore';
import { AzureResourceProvider } from './resourceProvider/resourceProvider';
import * as Utils from './utils';
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
import { TelemetryFeature, AgentServicesFeature } from './features';
import { TelemetryFeature, AgentServicesFeature, DacFxServicesFeature } from './features';
const baseConfig = require('./config.json');
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
@@ -55,7 +55,8 @@ export async function activate(context: vscode.ExtensionContext) {
// we only want to add new features
...SqlOpsDataClient.defaultFeatures,
TelemetryFeature,
AgentServicesFeature
AgentServicesFeature,
DacFxServicesFeature,
],
outputChannel: new CustomOutputChannel()
};

View File

@@ -36,7 +36,7 @@ buffer-alloc-unsafe@^1.1.0:
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
buffer-alloc@^1.1.0:
buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
@@ -75,19 +75,26 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.8":
version "0.2.8"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/3ec3ec3fa63a8dae958c18a85b91fec74c50aec5"
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.10":
version "0.2.10"
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/4de3f7caf0eba54159911b977ddb4f5d7c0a9ca8"
dependencies:
vscode-languageclient "3.5.1"
debug@3.1.0, debug@^3.1.0:
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
@@ -161,9 +168,9 @@ end-of-stream@^1.0.0:
once "^1.4.0"
es6-promise@^4.0.3:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
version "4.2.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
es6-promisify@^5.0.0:
version "5.0.0"
@@ -213,9 +220,9 @@ get-stream@^2.2.0:
pinkie-promise "^2.0.0"
graceful-fs@^4.1.10:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
"graceful-readlink@>= 1.0.0":
version "1.0.1"
@@ -287,6 +294,11 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -300,9 +312,9 @@ once@^1.4.0:
wrappy "1"
opener@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
version "1.5.1"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
os-tmpdir@~1.0.2:
version "1.0.2"
@@ -367,9 +379,9 @@ seek-bzip@^1.0.5:
commander "~2.8.1"
semver@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
version "0.1.5"
@@ -397,16 +409,16 @@ strip-dirs@^2.0.0:
is-natural-number "^4.0.1"
tar-stream@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==
version "1.6.2"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
dependencies:
bl "^1.0.0"
buffer-alloc "^1.1.0"
buffer-alloc "^1.2.0"
end-of-stream "^1.0.0"
fs-constants "^1.0.0"
readable-stream "^2.3.0"
to-buffer "^1.1.0"
to-buffer "^1.1.1"
xtend "^4.0.0"
through@^2.3.6:
@@ -421,15 +433,15 @@ tmp@^0.0.33:
dependencies:
os-tmpdir "~1.0.2"
to-buffer@^1.1.0:
to-buffer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
unbzip2-stream@^1.0.9:
version "1.2.5"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
integrity sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==
version "1.3.1"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==
dependencies:
buffer "^3.0.1"
through "^2.3.6"

View File

@@ -0,0 +1,17 @@
# Notebook extension for Azure Data Studio
Welcome to the Notebook extension for Azure Data Studio! This extension supports core notebook functionality including configuration settings, actions such as New / Open Notebook, and more.
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Privacy Statement
The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement) describes the privacy statement of this software.
## License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [Source EULA](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt).

View File

@@ -0,0 +1,71 @@
{
"name": "notebook",
"displayName": "%displayName%",
"description": "%description%",
"version": "0.1.0",
"publisher": "Microsoft",
"engines": {
"vscode": "*",
"sqlops": "*"
},
"main": "./out/extension",
"activationEvents": [
"*"
],
"contributes": {
"configuration": {
"type": "object",
"title": "%notebook.configuration.title%",
"properties": {
"notebook.enabled": {
"type": "boolean",
"default": true,
"description": "%notebook.enabled.description%"
}
}
},
"commands": [
{
"command": "notebook.command.new",
"title": "%notebook.command.new%",
"icon": {
"dark": "resources/dark/new_notebook_inverse.svg",
"light": "resources/light/new_notebook.svg"
}
},
{
"command": "notebook.command.open",
"title": "%notebook.command.open%",
"icon": {
"dark": "resources/dark/open_notebook_inverse.svg",
"light": "resources/light/open_notebook.svg"
}
}
],
"menus": {
"commandPalette": [
{
"command": "notebook.command.new",
"when": "config.notebook.enabled"
},
{
"command": "notebook.command.open",
"when": "config.notebook.enabled"
}
]
},
"keybindings": [
{
"command": "notebook.command.new",
"key": "Ctrl+Shift+N",
"when": "config.notebook.enabled"
}
]
},
"dependencies": {
"vscode-nls": "^4.0.0"
},
"devDependencies": {
"@types/node": "8.0.33"
}
}

View File

@@ -0,0 +1,8 @@
{
"displayName": "Notebook Core Extensions",
"description": "Defines the Data-procotol based Notebook contribution and many Notebook commands and contributions.",
"notebook.configuration.title": "Notebook configuration",
"notebook.enabled.description": "Enable viewing notebook files using built-in notebook editor.",
"notebook.command.new": "New Notebook",
"notebook.command.open": "Open Notebook"
}

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#388a34;}</style></defs><title>new_notebook_inverse</title><path class="cls-1" d="M11.87,1.24V.33H9.13A3.78,3.78,0,0,0,7.92.52a3.48,3.48,0,0,0-1.07.58A3.6,3.6,0,0,0,5.78.52,3.78,3.78,0,0,0,4.57.33H1.83v.91H0V13.1H9.67v-.91H7a4,4,0,0,1,.47-.39A2.39,2.39,0,0,1,8,11.52a2.2,2.2,0,0,1,.53-.18,2.93,2.93,0,0,1,.61-.06h2.74V2.15h.91V9h.91V1.24Zm-9.13,0H4.57a3,3,0,0,1,1,.17,2.58,2.58,0,0,1,.85.49v8.93a3.94,3.94,0,0,0-.88-.35,3.73,3.73,0,0,0-.94-.12H2.74Zm-1.82,11v-10h.91v9.13H4.57a2.93,2.93,0,0,1,.61.06,2.55,2.55,0,0,1,.53.18,2.68,2.68,0,0,1,.49.28,3.29,3.29,0,0,1,.46.39Zm8.21-1.83a3.73,3.73,0,0,0-.94.12,4.22,4.22,0,0,0-.89.35V1.9a2.74,2.74,0,0,1,.86-.49,2.91,2.91,0,0,1,1-.17H11v9.12ZM12.87,10v2.2h-2.2v.91h3V10Z"/><polygon class="cls-2" points="16 12.19 16 13.13 13.8 13.13 13.8 15.33 12.87 15.33 12.87 13.13 10.67 13.13 10.67 12.19 12.87 12.19 12.87 9.99 13.8 9.99 13.8 12.19 16 12.19"/><path class="cls-2" d="M13.8,12.19V10h-.93v2.2h-2.2v.94h2.2v2.2h.93v-2.2H16v-.94Z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#0095d7;}</style></defs><title>open_notebook_inverse</title><path class="cls-1" d="M12.55,4.21l-.08-.11h-.56l-.69.06a1.54,1.54,0,0,0-.23.29v8.69H9.18a3.32,3.32,0,0,0-.93.13,3.34,3.34,0,0,0-.87.34V4.76a2.88,2.88,0,0,1,.43-.31A5.58,5.58,0,0,1,8.29,3.3a2.63,2.63,0,0,0-.3.09A3.62,3.62,0,0,0,6.93,4a3.68,3.68,0,0,0-1.07-.57A3.58,3.58,0,0,0,4.67,3.2H2v.9H.15V15.85H13.72V5.48ZM2.86,4.1H4.67a2.61,2.61,0,0,1,1,.17,2.32,2.32,0,0,1,.86.49v8.85a3.27,3.27,0,0,0-.88-.34,3.22,3.22,0,0,0-.93-.13H2.86ZM1,15V5H2v9H4.67a3.94,3.94,0,0,1,.61.06,3.2,3.2,0,0,1,.52.18,4.19,4.19,0,0,1,.49.29,2.28,2.28,0,0,1,.45.39ZM12.8,15H7.11a2.7,2.7,0,0,1,.47-.39A2.83,2.83,0,0,1,8,14.28a3.42,3.42,0,0,1,.54-.18A3.81,3.81,0,0,1,9.18,14h2.73V5h.89Z"/><polygon class="cls-2" points="13.2 3.56 13.2 3.58 13.19 3.57 13.2 3.56"/><path class="cls-2" d="M13.19,3.57h0v0Z"/><polygon class="cls-2" points="13.2 3.56 13.2 3.58 13.19 3.57 13.2 3.56"/><polygon class="cls-2" points="14.21 1.65 14.19 1.65 14.19 1.63 14.21 1.65"/><path class="cls-2" d="M15.91,2.1,14.2,3.81l-.38.38-.62-.61v0l1-1H12.79a3.35,3.35,0,0,0-1.09.26h0a3.94,3.94,0,0,0-.86.52l-.24.21s0,0,0,0a3.3,3.3,0,0,0-.51.67,3.1,3.1,0,0,0-.26.47A3.41,3.41,0,0,0,9.5,6.11H8.6a4.68,4.68,0,0,1,.16-1.19A4.74,4.74,0,0,1,9,4.26a2.21,2.21,0,0,1,.2-.41,4.66,4.66,0,0,1,.36-.51c.1-.13.22-.26.34-.39a4.14,4.14,0,0,1,.66-.53,1.19,1.19,0,0,1,.23-.16,2.79,2.79,0,0,1,.34-.18l.31-.13.42-.14a4.32,4.32,0,0,1,1.19-.16h1.15l-1-1L13.82,0Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#388a34;}</style></defs><title>new_notebook</title><path d="M11.86,1.24V.33H9.13A3.78,3.78,0,0,0,7.91.52a3.48,3.48,0,0,0-1.07.58A3.6,3.6,0,0,0,5.78.52,3.78,3.78,0,0,0,4.57.33H1.83v.91H0V13.1H9.66v-.91H7a4,4,0,0,1,.47-.39A2.39,2.39,0,0,1,8,11.52a2.2,2.2,0,0,1,.53-.18,2.93,2.93,0,0,1,.61-.06h2.74V2.15h.91V9h.91V1.24Zm-9.13,0H4.57a3,3,0,0,1,1,.17,2.58,2.58,0,0,1,.85.49v8.93a3.94,3.94,0,0,0-.88-.35,3.73,3.73,0,0,0-.94-.12H2.73Zm-1.82,11v-10h.91v9.13H4.57a2.93,2.93,0,0,1,.61.06,2.55,2.55,0,0,1,.53.18,2.68,2.68,0,0,1,.49.28,3.29,3.29,0,0,1,.46.39Zm8.21-1.83a3.73,3.73,0,0,0-.94.12,4.22,4.22,0,0,0-.89.35V1.9a2.74,2.74,0,0,1,.86-.49,2.91,2.91,0,0,1,1-.17h1.82v9.12ZM12.86,10v2.2h-2.2v.91h3V10Z"/><polygon class="cls-1" points="15.99 12.19 15.99 13.13 13.79 13.13 13.79 15.33 12.87 15.33 12.87 13.13 10.66 13.13 10.66 12.19 12.87 12.19 12.87 9.99 13.79 9.99 13.79 12.19 15.99 12.19"/><path class="cls-1" d="M13.79,12.19V10h-.93v2.2h-2.2v.94h2.2v2.2h.93v-2.2H16v-.94Z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#00539c;}</style></defs><title>open_notebook</title><path d="M12.4,4.21l-.08-.11h-.56l-.69.06a1.54,1.54,0,0,0-.23.29v8.69H9a3.32,3.32,0,0,0-.93.13,3.34,3.34,0,0,0-.87.34V4.76a2.88,2.88,0,0,1,.43-.31A5.58,5.58,0,0,1,8.14,3.3a2.63,2.63,0,0,0-.3.09A3.62,3.62,0,0,0,6.78,4a3.68,3.68,0,0,0-1.07-.57A3.58,3.58,0,0,0,4.52,3.2H1.81v.9H0V15.85H13.57V5.48ZM2.71,4.1H4.52a2.61,2.61,0,0,1,1,.17,2.32,2.32,0,0,1,.86.49v8.85a3.27,3.27,0,0,0-.88-.34,3.22,3.22,0,0,0-.93-.13H2.71ZM.9,15V5h.91v9H4.52a3.94,3.94,0,0,1,.61.06,3.2,3.2,0,0,1,.52.18,4.19,4.19,0,0,1,.49.29,2.28,2.28,0,0,1,.45.39Zm11.75,0H7a2.7,2.7,0,0,1,.47-.39,2.83,2.83,0,0,1,.47-.29,3.42,3.42,0,0,1,.54-.18A3.81,3.81,0,0,1,9,14h2.73V5h.89Z"/><polygon class="cls-1" points="13.05 3.56 13.05 3.58 13.04 3.57 13.05 3.56"/><path class="cls-1" d="M13,3.57h0v0Z"/><polygon class="cls-1" points="13.05 3.56 13.05 3.58 13.04 3.57 13.05 3.56"/><polygon class="cls-1" points="14.06 1.65 14.04 1.65 14.04 1.63 14.06 1.65"/><path class="cls-1" d="M15.76,2.1,14,3.81l-.38.38L13,3.58v0l1-1H12.64a3.35,3.35,0,0,0-1.09.26h0a3.94,3.94,0,0,0-.86.52l-.24.21s0,0,0,0a3.3,3.3,0,0,0-.51.67,3.1,3.1,0,0,0-.26.47,3.41,3.41,0,0,0-.27,1.39h-.9a4.68,4.68,0,0,1,.16-1.19,4.74,4.74,0,0,1,.25-.66,2.21,2.21,0,0,1,.2-.41,4.66,4.66,0,0,1,.36-.51c.1-.13.22-.26.34-.39a4.14,4.14,0,0,1,.66-.53,1.19,1.19,0,0,1,.23-.16A2.79,2.79,0,0,1,11,2.08l.31-.13.42-.14a4.32,4.32,0,0,1,1.19-.16h1.15l-1-1L13.67,0Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
let counter = 0;
export function activate(extensionContext: vscode.ExtensionContext) {
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.new', () => {
let title = `Untitled-${counter++}`;
let untitledUri = vscode.Uri.parse(`untitled:${title}`);
sqlops.nb.showNotebookDocument(untitledUri).then(success => {
}, (err: Error) => {
vscode.window.showErrorMessage(err.message);
});
}));
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.open', () => {
openNotebook();
}));
}
async function openNotebook(): Promise<void> {
try {
let filter = {};
// TODO support querying valid notebook file types
filter[localize('notebookFiles', 'Notebooks')] = ['ipynb'];
let file = await vscode.window.showOpenDialog({
filters: filter
});
if (file) {
let doc = await vscode.workspace.openTextDocument(file[0]);
vscode.window.showTextDocument(doc);
}
} catch (err) {
vscode.window.showErrorMessage(err);
}
}
// this method is called when your extension is deactivated
export function deactivate() {
}

View File

@@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/sql/sqlops.d.ts'/>
/// <reference path='../../../../src/sql/sqlops.proposed.d.ts'/>
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference types='@types/node'/>

View File

@@ -0,0 +1,22 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"typeRoots": [
"./node_modules/@types"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
}

View File

@@ -0,0 +1,13 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@8.0.33":
version "8.0.33"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd"
integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A==
vscode-nls@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==

View File

@@ -12,12 +12,10 @@ import { CreateSessionData } from '../data/createSessionData';
const localize = nls.loadMessageBundle();
export class CreateSessionDialog {
// Top level
private readonly DialogTitle: string = localize('createSessionDialog.newSession', 'New Session');
private readonly CancelButtonText: string = localize('createSessionDialog.cancel', 'Cancel');
private readonly CreateButtonText: string = localize('createSessionDialog.create', 'Create');
private readonly DialogTitleText: string = localize('createSessionDialog.title', 'Create New Profiler Session');
private readonly CreateButtonText: string = localize('createSessionDialog.create', 'Start');
private readonly DialogTitleText: string = localize('createSessionDialog.title', 'Start New Profiler Session');
// UI Components
private dialog: sqlops.window.modelviewdialog.Dialog;
@@ -25,23 +23,28 @@ export class CreateSessionDialog {
private sessionNameBox: sqlops.InputBoxComponent;
private model: CreateSessionData;
private readonly _providerType: string;
private _onSuccess: vscode.EventEmitter<CreateSessionData> = new vscode.EventEmitter<CreateSessionData>();
public readonly onSuccess: vscode.Event<CreateSessionData> = this._onSuccess.event;
constructor(ownerUri: string, templates: Array<sqlops.ProfilerSessionTemplate>) {
constructor(ownerUri: string, providerType: string, templates: Array<sqlops.ProfilerSessionTemplate>) {
if (typeof (templates) === 'undefined' || templates === null) {
throw new Error(localize('createSessionDialog.templatesInvalid', "Invalid templates list, cannot open dialog"));
}
if (typeof (ownerUri) === 'undefined' || ownerUri === null) {
throw new Error(localize('createSessionDialog.dialogOwnerInvalid', "Invalid dialog owner, cannot open dialog"));
}
if (typeof (providerType) === 'undefined' || providerType === null) {
throw new Error(localize('createSessionDialog.invalidProviderType', "Invalid provider type, cannot open dialog"));
}
this._providerType = providerType;
this.model = new CreateSessionData(ownerUri, templates);
}
public async showDialog(): Promise<void> {
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitleText);
this.initializeContent();
this.dialog.okButton.onClick(() => this.execute());
this.dialog.cancelButton.onClick(() => { });
@@ -65,6 +68,10 @@ export class CreateSessionDialog {
value: ''
}).component();
this.templatesBox.onValueChanged(() => {
this.updateSessionName();
});
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
components: [{
@@ -76,13 +83,14 @@ export class CreateSessionDialog {
title: localize('createSessionDialog.enterSessionName', "Enter session name:")
}],
title: this.DialogTitleText
title: ''
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
if (this.model.templates) {
this.templatesBox.values = this.model.getTemplateNames();
this.updateSessionName();
}
this.sessionNameBox.onTextChanged(() => {
@@ -96,9 +104,14 @@ export class CreateSessionDialog {
});
}
private updateSessionName() {
if (this.templatesBox.value) {
this.sessionNameBox.value = `ADS_${this.templatesBox.value.toString()}`
}
}
private async execute(): Promise<void> {
let currentConnection = await sqlops.connection.getCurrentConnection();
let profilerService = sqlops.dataprotocol.getProvider<sqlops.ProfilerProvider>(currentConnection.providerName, sqlops.DataProviderType.ProfilerProvider);
let profilerService = sqlops.dataprotocol.getProvider<sqlops.ProfilerProvider>(this._providerType, sqlops.DataProviderType.ProfilerProvider);
let name = this.sessionNameBox.value;
let selected = this.templatesBox.value.toString();

View File

@@ -29,8 +29,8 @@ export class MainController {
}
public activate(): void {
vscode.commands.registerCommand('profiler.openCreateSessionDialog', (ownerUri: string, templates: Array<sqlops.ProfilerSessionTemplate>) => {
let dialog = new CreateSessionDialog(ownerUri, templates);
vscode.commands.registerCommand('profiler.openCreateSessionDialog', (ownerUri: string, providerType: string, templates: Array<sqlops.ProfilerSessionTemplate>) => {
let dialog = new CreateSessionDialog(ownerUri, providerType, templates);
dialog.showDialog();
});
}

View File

@@ -2,7 +2,7 @@
"name": "profiler",
"displayName": "SQL Server Profiler",
"description": "SQL Server Profiler for Azure Data Studio",
"version": "0.3.0",
"version": "0.6.0",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
@@ -26,11 +26,9 @@
"Microsoft.mssql"
],
"contributes": {
"commands": [
{
"commands": [{
"command": "profiler.newProfiler",
"title": "New Profiler",
"title": "Launch Profiler",
"category": "Profiler"
},
{
@@ -49,6 +47,25 @@
"category": "Profiler"
}
],
"menus": {
"commandPalette": [{
"command": "profiler.start",
"when": "False"
},
{
"command": "profiler.stop",
"when": "False"
}, {
"command": "profiler.openCreateSessionDialog",
"when": "False"
}
],
"objectExplorer/item/context": [{
"command": "profiler.newProfiler",
"when": "connectionProvider == MSSQL && nodeType && nodeType == Server",
"group": "profiler"
}]
},
"outputChannels": [
"sqlprofiler"
]
@@ -59,4 +76,4 @@
"devDependencies": {
"vscode": "1.0.1"
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -67,7 +67,8 @@
"panel.background": "#212121",
"panel.border": "#515151",
"panelTitle.activeForeground": "#ffffff",
"panelTitle.inactiveForeground": "#888888"
"panelTitle.inactiveForeground": "#888888",
"panelTitle.activeBorder": "#026dc8"
},
"tokenColors": [
{

View File

@@ -77,7 +77,8 @@
"panel.background": "#ffffff",
"panel.border": "#c8c8c8",
"panelTitle.activeForeground": "#212121",
"panelTitle.inactiveForeground": "#757575"
"panelTitle.inactiveForeground": "#757575",
"panelTitle.activeBorder": "#026dc8"
},
"tokenColors": [
{

View File

@@ -1,6 +1,6 @@
{
"name": "azuredatastudio",
"version": "1.2.4",
"version": "1.3.9",
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
"author": {
"name": "Microsoft Corporation"
@@ -37,8 +37,10 @@
"@angular/router": "~4.1.3",
"@angular/upgrade": "~4.1.3",
"@types/chart.js": "^2.7.31",
"@types/htmlparser2": "^3.7.31",
"angular2-grid": "2.0.6",
"angular2-slickgrid": "github:Microsoft/angular2-slickgrid#1.4.6",
"ansi_up": "^3.0.0",
"applicationinsights": "0.18.0",
"chart.js": "^2.6.0",
"fast-plist": "0.1.2",
@@ -64,8 +66,9 @@
"pretty-data": "^0.40.0",
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
"sanitize-html": "^1.19.1",
"semver": "^5.5.0",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.28",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.29",
"spdlog": "0.7.1",
"sudo-prompt": "8.2.0",
"svg.js": "^2.2.5",
@@ -85,7 +88,9 @@
"@types/keytar": "4.0.1",
"@types/minimist": "1.2.0",
"@types/mocha": "2.2.39",
"@types/sanitize-html": "^1.18.2",
"@types/semver": "5.3.30",
"@types/should": "^13.0.0",
"@types/sinon": "1.16.34",
"@types/winreg": "^1.2.30",
"asar": "^0.14.0",
@@ -98,12 +103,12 @@
"documentdb": "^1.5.1",
"electron-mksnapshot": "~1.7.0",
"eslint": "^3.4.0",
"event-stream": "^3.1.7",
"event-stream": "3.3.4",
"express": "^4.13.1",
"glob": "^5.0.13",
"gulp": "^3.9.1",
"gulp-atom-electron": "^1.16.1",
"gulp-azure-storage": "^0.7.0",
"gulp-atom-electron": "^1.19.2",
"gulp-azure-storage": "^0.8.2",
"gulp-bom": "^1.0.0",
"gulp-buffer": "0.0.2",
"gulp-cli": "^2.0.1",
@@ -116,7 +121,7 @@
"gulp-json-editor": "^2.2.1",
"gulp-mocha": "^2.1.3",
"gulp-plumber": "^1.2.0",
"gulp-remote-src": "^0.4.0",
"gulp-remote-src": "^0.4.4",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.4",
"gulp-shell": "^0.5.2",
@@ -125,7 +130,7 @@
"gulp-tslint": "^8.1.2",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.6",
"gulp-vinyl-zip": "^1.2.2",
"gulp-vinyl-zip": "^2.1.2",
"husky": "^0.13.1",
"innosetup-compiler": "^5.5.60",
"is": "^3.1.0",
@@ -144,8 +149,10 @@
"queue": "3.0.6",
"remap-istanbul": "^0.6.4",
"rimraf": "^2.2.8",
"should": "^13.2.3",
"sinon": "^1.17.2",
"source-map": "^0.4.4",
"temp-write": "^3.4.0",
"tslint": "^5.9.1",
"typemoq": "^0.3.2",
"typescript": "2.9.2",
@@ -170,6 +177,7 @@
"windows-process-tree": "0.2.2"
},
"resolutions": {
"rc": "1.2.8"
"rc": "1.2.8",
"event-stream": "3.3.4"
}
}

View File

@@ -42,7 +42,8 @@
"Microsoft.server-report",
"Microsoft.sql-vnext",
"Microsoft.whoisactive",
"Redgate.sql-search"
"Redgate.sql-search",
"IDERA.sqldm-performance-insights"
],
"extensionsGallery": {
"serviceUrl": "https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json"

View File

@@ -611,7 +611,7 @@
</body></file>
<file original="src/sql/parts/connection/common/connectionActions" source-language="en" datatype="plaintext"><body>
<trans-unit id="ClearRecentlyUsedLabel">
<source xml:lang="en">Clear Recent Connections List</source>
<source xml:lang="en">Clear List</source>
</trans-unit>
<trans-unit id="ClearedRecentConnections">
<source xml:lang="en">Recent connections list cleared</source>
@@ -1039,10 +1039,10 @@
<source xml:lang="en">Connection</source>
</trans-unit>
<trans-unit id="recentConnectionTitle">
<source xml:lang="en">Recent connections</source>
<source xml:lang="en">Recent Connections</source>
</trans-unit>
<trans-unit id="savedConnectionTitle">
<source xml:lang="en">Saved connections</source>
<source xml:lang="en">Saved Connections</source>
</trans-unit>
<trans-unit id="connectType">
<source xml:lang="en">Connection type</source>
@@ -1520,9 +1520,6 @@
</trans-unit>
</body></file>
<file original="src/sql/parts/profiler/contrib/profilerActions" source-language="en" datatype="plaintext"><body>
<trans-unit id="profiler.connect">
<source xml:lang="en">Connect</source>
</trans-unit>
<trans-unit id="profilerAction.disconnect">
<source xml:lang="en">Disconnect</source>
</trans-unit>
@@ -1533,16 +1530,13 @@
<source xml:lang="en">Start</source>
</trans-unit>
<trans-unit id="create">
<source xml:lang="en">Create</source>
</trans-unit>
<trans-unit id="profiler.capture">
<source xml:lang="en">Pause Capture</source>
<source xml:lang="en">New Session</source>
</trans-unit>
<trans-unit id="profilerAction.resumeCapture">
<source xml:lang="en">Resume Capture</source>
<source xml:lang="en">Resume</source>
</trans-unit>
<trans-unit id="profilerAction.pauseCapture">
<source xml:lang="en">Pause Capture</source>
<source xml:lang="en">Pause</source>
</trans-unit>
<trans-unit id="profilerStop.stop">
<source xml:lang="en">Stop</source>
@@ -1550,9 +1544,6 @@
<trans-unit id="profiler.clear">
<source xml:lang="en">Clear Data</source>
</trans-unit>
<trans-unit id="profiler.autoscrollOn">
<source xml:lang="en">Auto Scroll: On</source>
</trans-unit>
<trans-unit id="profilerAction.autoscrollOn">
<source xml:lang="en">Auto Scroll: On</source>
</trans-unit>
@@ -1572,7 +1563,7 @@
<source xml:lang="en">Find Previous String</source>
</trans-unit>
<trans-unit id="profilerAction.newProfiler">
<source xml:lang="en">New Profiler</source>
<source xml:lang="en">Launch Profiler</source>
</trans-unit>
</body></file>
<file original="src/sql/base/browser/ui/selectBox/selectBox" source-language="en" datatype="plaintext"><body>
@@ -1644,7 +1635,7 @@
</body></file>
<file original="src/sql/parts/connection/connectionDialog/advancedPropertiesController" source-language="en" datatype="plaintext"><body>
<trans-unit id="connectionAdvancedProperties">
<source xml:lang="en">Advanced properties</source>
<source xml:lang="en">Advanced Properties</source>
</trans-unit>
<trans-unit id="advancedProperties.discard">
<source xml:lang="en">Discard</source>

View File

@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file original="extensions/profiler/client\out/dialogs/profilerCreateSessionDialog" source-language="en" datatype="plaintext"><body>
<trans-unit id="createSessionDialog.newSession">
<source xml:lang="en">New Session</source>
</trans-unit>
<trans-unit id="createSessionDialog.cancel">
<source xml:lang="en">Cancel</source>
</trans-unit>

View File

@@ -12,12 +12,18 @@ set CODE=".build\electron\%NAMESHORT%"
rem TFS Builds
if not "%BUILD_BUILDID%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha %*
if not "%ADD_REPORTER%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha --reporter mocha-junit-reporter %*
)
if "%ADD_REPORTER%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha %*
)
)
rem Otherwise
if "%BUILD_BUILDID%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha --reporter dot %*
%CODE% .\node_modules\mocha\bin\_mocha --reporter mocha-junit-reporter %*
)
popd

View File

@@ -1,7 +1,7 @@
#!/bin/bash
if [[ "$OSTYPE" == "darwin"* ]]; then
if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
ROOT=$(dirname $(dirname $(realpath "$0")))
@@ -14,7 +14,7 @@ fi
cd $ROOT
if [[ "$OSTYPE" == "darwin"* ]]; then
if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then
NAME=`node -p "require('./product.json').nameLong"`
CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron"
else
@@ -30,7 +30,7 @@ node build/lib/electron.js || ./node_modules/.bin/gulp electron
# Unit Tests
export ELECTRON_RUN_AS_NODE=1
if [[ "$OSTYPE" == "darwin"* ]]; then
if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then
cd $ROOT ; ulimit -n 4096 ; \
"$CODE" \
node_modules/mocha/bin/_mocha "$@"

View File

@@ -12,9 +12,10 @@ import * as types from 'vs/base/common/types';
import * as sqlops from 'sqlops';
export function appendRow(container: Builder, label: string, labelClass: string, cellContainerClass: string): Builder {
export function appendRow(container: Builder, label: string, labelClass: string, cellContainerClass: string, rowContainerClass?: string): Builder {
let cellContainer: Builder;
container.element('tr', {}, (rowContainer) => {
let rowAttributes = rowContainerClass ? { class: rowContainerClass } : {};
container.element('tr', rowAttributes, (rowContainer) => {
rowContainer.element('td', { class: labelClass }, (labelCellContainer) => {
labelCellContainer.div({}, (labelContainer) => {
labelContainer.text(label);

View File

@@ -56,6 +56,7 @@
.modal .modal-title {
font-size: 15px;
font-weight: 600;
}
.modal .modal-title-icon {
@@ -147,7 +148,7 @@
}
.modal .footer-button {
margin-right: 5px;
margin-left: 5px;
}
.modal .right-footer .footer-button:last-of-type {
@@ -235,8 +236,8 @@
.modal.flyout-dialog .dialog-message-detail {
margin-top: 5px;
white-space: normal;
-webkit-user-select: text;
white-space: pre-wrap;
user-select: text;
font-size: 11px;
}

View File

@@ -20,11 +20,34 @@
}
.optionsDialog-options-groups {
padding: 15px;
height: calc(100% - 150px);
margin-top: 10px;
flex: 1 1;
overflow-y: auto;
}
.optionsDialog-options-groups {
margin: 10px 0px;
flex: 1 1;
overflow-y: auto;
}
.vs .optionsDialog-options-groups {
box-shadow: 0 1px 4px 1px rgba(220, 220, 220, 0.71);
}
.vs-dark .optionsDialog-options-groups {
box-shadow: 0 4px 5px 0px rgba(0, 0, 0, 0.71);
}
.optionsDialog-options-groups .split-view-view .header {
padding-left: 28px !important;
background-position-x: 8px !important;
}
.optionsDialog-options-groups .split-view-view .body {
padding-left: 5px !important;
}
.backButtonIcon {
content: url('back.svg');
width: 20px;
@@ -33,21 +56,42 @@
cursor: pointer;
}
.vs-dark.monaco-shell .backButtonIcon {
.hc-black .backButtonIcon,
.vs-dark .backButtonIcon {
content: url('back_inverse.svg');
}
.optionsDialog-description {
padding: 15px;
overflow-y: auto;
height: 90px;
margin: 15px;
overflow-y: auto;
}
.optionsDialog-description .modal-title {
background-repeat: no-repeat;
background-position: 2px center;
padding-left: 25px;
background-size: 16px;
}
.vs .optionsDialog-description .modal-title {
background-image: url('info_notification.svg')
}
.vs-dark .optionsDialog-description .modal-title,
.hc-black .optionsDialog-description .modal-title {
background-image: url('info_notification_inverse.svg')
}
.optionsDialog-options {
height: calc(100% - 30px);
height: 100%;
display: flex;
flex-direction: column;
}
.optionsDialog-description-content {
padding: 10px;
padding-top: 10px;
padding-left: 25px;
}
.optionsDialog-table{

View File

@@ -72,8 +72,8 @@ const defaultOptions: IModalOptions = {
};
export abstract class Modal extends Disposable implements IThemable {
private _messageElement: HTMLElement;
protected _useDefaultMessageBoxLocation: boolean = true;
protected _messageElement: HTMLElement;
private _messageIcon: HTMLElement;
private _messageSeverity: Builder;
private _messageSummary: Builder;
@@ -253,7 +253,9 @@ export abstract class Modal extends Disposable implements IThemable {
this._messageElement = this._modalMessageSection.getHTMLElement();
this.updateElementVisibility(this._messageElement, false);
parts.push(this._messageElement);
if (this._useDefaultMessageBoxLocation) {
parts.push(this._messageElement);
}
}
// This modal body section refers to the body of of the dialog

View File

@@ -125,7 +125,7 @@ export class OptionsDialog extends Modal {
});
let builder = new Builder(this._body);
builder.div({ class: 'Connection-divider' }, (dividerContainer) => {
builder.div({}, (dividerContainer) => {
this._dividerBuilder = dividerContainer;
});

View File

@@ -46,9 +46,9 @@ panel {
}
.tabbedPanel .tabList .tab .tabLabel {
text-transform: uppercase;
font-size: 13px;
font-size: 14px;
padding-bottom: 4px;
font-weight: 600;
}
.tabbedPanel.vertical .tabList .tab .tabLabel {

View File

@@ -36,7 +36,6 @@ export interface IPanelTab {
interface IInternalPanelTab extends IPanelTab {
header: HTMLElement;
label: HTMLElement;
dispose(): void;
}
const defaultOptions: IPanelOptions = {
@@ -143,8 +142,6 @@ export class TabbedPanel extends Disposable implements IThemable {
this.tabList.appendChild(tabHeaderElement);
tab.header = tabHeaderElement;
tab.label = tabLabel;
tab.dispose = () => { };
this._register(tab);
}
public showTab(id: PanelTabIdentifier): void {

View File

@@ -19,6 +19,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
.tabbedPanel > .title .tabList .tab .tabLabel.active {
color: ${titleActive};
border-bottom-color: ${titleActiveBorder};
border-bottom-width: 2px;
}
.tabbedPanel > .title .tabList .tab-header.active {

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