mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-28 02:51:37 -05:00
Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84009f65ec | ||
|
|
191648df0a | ||
|
|
1265a56ff4 | ||
|
|
2171d44922 | ||
|
|
812f315e69 | ||
|
|
d48258a0fb | ||
|
|
8ec78f67af | ||
|
|
0ac0175bb1 | ||
|
|
f39007cd2d | ||
|
|
348b03327e | ||
|
|
2349aa4df8 | ||
|
|
6497bbcc38 | ||
|
|
a93a173183 | ||
|
|
a1abca26df | ||
|
|
42e55dd2dd | ||
|
|
ca3146d38f | ||
|
|
7f6cd514a5 | ||
|
|
88e24e92b5 | ||
|
|
8b447e361f | ||
|
|
a92dd2d4e4 | ||
|
|
852ec44567 | ||
|
|
b6e32cdeb4 | ||
|
|
4bd264d9be | ||
|
|
4a4b8574d0 | ||
|
|
ded073edd9 | ||
|
|
568f95e7a3 | ||
|
|
5adcabc8de | ||
|
|
e3bce7172c | ||
|
|
96fb618390 | ||
|
|
2d4fdcb661 | ||
|
|
7a84cff5b4 | ||
|
|
2af627b704 | ||
|
|
77fdf18686 | ||
|
|
944a77fe42 | ||
|
|
049678b32e | ||
|
|
3325e4d854 | ||
|
|
1e90e88d4b | ||
|
|
8aeb33c98c | ||
|
|
3b08721835 | ||
|
|
5a30878599 | ||
|
|
c8a8935db0 | ||
|
|
ec196f57bb | ||
|
|
f7809ec3a7 | ||
|
|
71d3ec3616 | ||
|
|
4a7cf8d870 | ||
|
|
4bf8836c0a | ||
|
|
1ca36ee29c | ||
|
|
3446ff88cf | ||
|
|
de5a91a13f | ||
|
|
814cd73019 | ||
|
|
c21611661b | ||
|
|
8f817ce689 | ||
|
|
971b5111e7 | ||
|
|
07069a64ae | ||
|
|
6acea51f12 | ||
|
|
7aa2dab307 | ||
|
|
3091be8f67 | ||
|
|
487531cc52 | ||
|
|
58bfcb4273 | ||
|
|
8d8be27f22 | ||
|
|
27a978cba5 | ||
|
|
71b4e6afa4 | ||
|
|
e1f3b19c0c | ||
|
|
649c2aa5a6 | ||
|
|
cac8cc99e1 | ||
|
|
cb162b16f2 | ||
|
|
86e54ce145 | ||
|
|
efd809971f | ||
|
|
38ae14cc4d | ||
|
|
c7e33a90fe | ||
|
|
5add835750 | ||
|
|
734c614cba | ||
|
|
f6b347fa62 | ||
|
|
08d2f3125e | ||
|
|
385c48dcad | ||
|
|
0926057bfe | ||
|
|
6912e3893e | ||
|
|
d3052657df | ||
|
|
a5ca4d8edf | ||
|
|
afb1ebebd5 | ||
|
|
a04a9eb5ad | ||
|
|
027badd21f | ||
|
|
1affc760e6 | ||
|
|
3ca72b7398 | ||
|
|
702dbddd78 | ||
|
|
8fbecc0227 | ||
|
|
421271acfa | ||
|
|
98af76b3ac | ||
|
|
3952fdbe2d | ||
|
|
bc13beaa85 |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,6 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please search existing issues to avoid creating duplicates. -->
|
<!-- Please search existing issues to avoid creating duplicates. -->
|
||||||
|
|||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal 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.
|
||||||
@@ -9,20 +9,21 @@
|
|||||||
"@types/mime": "0.0.29",
|
"@types/mime": "0.0.29",
|
||||||
"@types/minimatch": "^3.0.3",
|
"@types/minimatch": "^3.0.3",
|
||||||
"@types/node": "8.0.33",
|
"@types/node": "8.0.33",
|
||||||
"@types/xml2js": "0.0.33",
|
|
||||||
"@types/request": "^2.47.0",
|
"@types/request": "^2.47.0",
|
||||||
|
"@types/xml2js": "0.0.33",
|
||||||
"azure-storage": "^2.1.0",
|
"azure-storage": "^2.1.0",
|
||||||
"decompress": "^4.2.0",
|
"decompress": "^4.2.0",
|
||||||
|
"del": "^3.0.0",
|
||||||
"documentdb": "1.13.0",
|
"documentdb": "1.13.0",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
|
||||||
"fs-extra-promise": "^1.0.1",
|
"fs-extra-promise": "^1.0.1",
|
||||||
|
"github-releases": "^0.4.1",
|
||||||
"mime": "^1.3.4",
|
"mime": "^1.3.4",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
"request": "^2.85.0",
|
||||||
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"vscode": "^1.0.1",
|
"vscode": "^1.0.1",
|
||||||
"xml2js": "^0.4.17",
|
"xml2js": "^0.4.17"
|
||||||
"github-releases": "^0.4.1",
|
|
||||||
"request": "^2.85.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "tsc -p tsconfig.build.json",
|
"compile": "tsc -p tsconfig.build.json",
|
||||||
@@ -30,4 +31,4 @@
|
|||||||
"postinstall": "npm run compile",
|
"postinstall": "npm run compile",
|
||||||
"npmCheckJs": "tsc --noEmit"
|
"npmCheckJs": "tsc --noEmit"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,17 +91,17 @@ Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong
|
|||||||
#else
|
#else
|
||||||
#define SoftwareClassesRootKey "HKLM"
|
#define SoftwareClassesRootKey "HKLM"
|
||||||
#endif
|
#endif
|
||||||
Root: HKCR; Subkey: "{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
|
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#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: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#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\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: "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: {#SoftwareClassesRootKey}; 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: {#SoftwareClassesRootKey}; 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: {#SoftwareClassesRootKey}; 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: {#SoftwareClassesRootKey}; 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: {#SoftwareClassesRootKey}; 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\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
|
||||||
; Environment
|
; Environment
|
||||||
#if "user" == InstallTarget
|
#if "user" == InstallTarget
|
||||||
#define EnvironmentRootKey "HKCU"
|
#define EnvironmentRootKey "HKCU"
|
||||||
|
|||||||
@@ -571,6 +571,18 @@ deep-assign@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-obj "^1.0.0"
|
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:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
@@ -942,6 +954,29 @@ glob@^5.0.3:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.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:
|
glogg@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
|
resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
|
||||||
@@ -1313,6 +1348,25 @@ is-obj@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||||
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
|
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:
|
is-posix-bracket@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
|
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
|
||||||
@@ -1778,6 +1832,11 @@ os-tmpdir@~1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
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:
|
parse-glob@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
|
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
|
||||||
@@ -1798,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"
|
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
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:
|
pause-stream@0.0.11:
|
||||||
version "0.0.11"
|
version "0.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
|
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
|
||||||
@@ -1820,7 +1884,7 @@ performance-now@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||||
|
|
||||||
pify@^2.3.0:
|
pify@^2.0.0, pify@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||||
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
||||||
@@ -2118,7 +2182,7 @@ requires-port@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||||
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
|
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
|
||||||
|
|
||||||
rimraf@2:
|
rimraf@2, rimraf@^2.2.8:
|
||||||
version "2.6.2"
|
version "2.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
|
||||||
integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
|
integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "agent",
|
"name": "agent",
|
||||||
"displayName": "SQL Server Agent",
|
"displayName": "SQL Server Agent",
|
||||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||||
"version": "0.35.1",
|
"version": "0.35.2",
|
||||||
"publisher": "Microsoft",
|
"publisher": "Microsoft",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class AlertData implements IAgentDialogData {
|
|||||||
this.eventDescriptionKeyword = alertInfo.eventDescriptionKeyword;
|
this.eventDescriptionKeyword = alertInfo.eventDescriptionKeyword;
|
||||||
this.eventSource = alertInfo.eventSource;
|
this.eventSource = alertInfo.eventSource;
|
||||||
this.hasNotification = alertInfo.hasNotification;
|
this.hasNotification = alertInfo.hasNotification;
|
||||||
this.includeEventDescription = alertInfo.includeEventDescription.toString();
|
this.includeEventDescription = alertInfo.includeEventDescription ? alertInfo.includeEventDescription.toString() : null;
|
||||||
this.isEnabled = alertInfo.isEnabled;
|
this.isEnabled = alertInfo.isEnabled;
|
||||||
this.jobId = alertInfo.jobId;
|
this.jobId = alertInfo.jobId;
|
||||||
this.lastOccurrenceDate = alertInfo.lastOccurrenceDate;
|
this.lastOccurrenceDate = alertInfo.lastOccurrenceDate;
|
||||||
@@ -82,7 +82,7 @@ export class AlertData implements IAgentDialogData {
|
|||||||
this.databaseName = alertInfo.databaseName;
|
this.databaseName = alertInfo.databaseName;
|
||||||
this.countResetDate = alertInfo.countResetDate;
|
this.countResetDate = alertInfo.countResetDate;
|
||||||
this.categoryName = alertInfo.categoryName;
|
this.categoryName = alertInfo.categoryName;
|
||||||
this.alertType = alertInfo.alertType.toString();
|
this.alertType = alertInfo.alertType ? alertInfo.alertType.toString() : null;
|
||||||
this.wmiEventNamespace = alertInfo.wmiEventNamespace;
|
this.wmiEventNamespace = alertInfo.wmiEventNamespace;
|
||||||
this.wmiEventQuery = alertInfo.wmiEventQuery;
|
this.wmiEventQuery = alertInfo.wmiEventQuery;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class JobData implements IAgentDialogData {
|
|||||||
public jobSchedules: sqlops.AgentJobScheduleInfo[];
|
public jobSchedules: sqlops.AgentJobScheduleInfo[];
|
||||||
public alerts: sqlops.AgentAlertInfo[];
|
public alerts: sqlops.AgentAlertInfo[];
|
||||||
public jobId: string;
|
public jobId: string;
|
||||||
|
public startStepId: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
ownerUri: string,
|
ownerUri: string,
|
||||||
@@ -60,10 +61,11 @@ export class JobData implements IAgentDialogData {
|
|||||||
this.category = jobInfo.category;
|
this.category = jobInfo.category;
|
||||||
this.description = jobInfo.description;
|
this.description = jobInfo.description;
|
||||||
this.enabled = jobInfo.enabled;
|
this.enabled = jobInfo.enabled;
|
||||||
this.jobSteps = jobInfo.JobSteps;
|
this.jobSteps = jobInfo.jobSteps;
|
||||||
this.jobSchedules = jobInfo.JobSchedules;
|
this.jobSchedules = jobInfo.jobSchedules;
|
||||||
this.alerts = jobInfo.Alerts;
|
this.alerts = jobInfo.alerts;
|
||||||
this.jobId = jobInfo.jobId;
|
this.jobId = jobInfo.jobId;
|
||||||
|
this.startStepId = jobInfo.startStepId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,17 +143,17 @@ export class JobData implements IAgentDialogData {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
owner: this.owner,
|
owner: this.owner,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
EmailLevel: this.emailLevel,
|
emailLevel: this.emailLevel,
|
||||||
PageLevel: this.pageLevel,
|
pageLevel: this.pageLevel,
|
||||||
EventLogLevel: this.eventLogLevel,
|
eventLogLevel: this.eventLogLevel,
|
||||||
DeleteLevel: this.deleteLevel,
|
deleteLevel: this.deleteLevel,
|
||||||
OperatorToEmail: this.operatorToEmail,
|
operatorToEmail: this.operatorToEmail,
|
||||||
OperatorToPage: this.operatorToPage,
|
operatorToPage: this.operatorToPage,
|
||||||
enabled: this.enabled,
|
enabled: this.enabled,
|
||||||
category: this.category,
|
category: this.category,
|
||||||
Alerts: this.alerts,
|
alerts: this.alerts,
|
||||||
JobSchedules: this.jobSchedules,
|
jobSchedules: this.jobSchedules,
|
||||||
JobSteps: this.jobSteps,
|
jobSteps: this.jobSteps,
|
||||||
// The properties below are not collected from UI
|
// The properties below are not collected from UI
|
||||||
// We could consider using a seperate class for create job request
|
// 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
|
categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS
|
||||||
lastRun: '',
|
lastRun: '',
|
||||||
nextRun: '',
|
nextRun: '',
|
||||||
jobId: this.jobId
|
jobId: this.jobId,
|
||||||
|
startStepId: this.startStepId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +123,7 @@ export class JobStepData implements IAgentDialogData {
|
|||||||
stepData.retryInterval = jobStepInfo.retryInterval,
|
stepData.retryInterval = jobStepInfo.retryInterval,
|
||||||
stepData.proxyName = jobStepInfo.proxyName;
|
stepData.proxyName = jobStepInfo.proxyName;
|
||||||
stepData.dialogMode = AgentDialogMode.EDIT;
|
stepData.dialogMode = AgentDialogMode.EDIT;
|
||||||
|
stepData.viaJobDialog = true;
|
||||||
return stepData;
|
return stepData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export abstract class AgentDialog<T extends IAgentDialogData> {
|
|||||||
public readonly onSuccess: vscode.Event<T> = this._onSuccess.event;
|
public readonly onSuccess: vscode.Event<T> = this._onSuccess.event;
|
||||||
public dialog: sqlops.window.modelviewdialog.Dialog;
|
public dialog: sqlops.window.modelviewdialog.Dialog;
|
||||||
|
|
||||||
|
// Dialog Name for Telemetry
|
||||||
|
public dialogName: string;
|
||||||
|
|
||||||
constructor(public ownerUri: string, public model: T, public title: 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);
|
protected abstract async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog);
|
||||||
|
|
||||||
public async openDialog() {
|
public async openDialog(dialogName?: string) {
|
||||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.title);
|
let event = dialogName ? dialogName : null;
|
||||||
|
this.dialog = sqlops.window.modelviewdialog.createDialog(this.title, event);
|
||||||
|
|
||||||
await this.model.initialize();
|
await this.model.initialize();
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
|||||||
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
|
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
|
||||||
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
|
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
|
||||||
|
|
||||||
|
// Event Name strings
|
||||||
|
private readonly NewAlertDialog = 'NewAlertDialogOpen';
|
||||||
|
private readonly EditAlertDialog = 'EditAlertDialogOpened';
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
private responseTab: 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 delayMinutesTextBox: sqlops.InputBoxComponent;
|
||||||
private delaySecondsTextBox: sqlops.InputBoxComponent;
|
private delaySecondsTextBox: sqlops.InputBoxComponent;
|
||||||
|
|
||||||
|
private isEdit: boolean = false;
|
||||||
private databases: string[];
|
private databases: string[];
|
||||||
private jobModel: JobData;
|
private jobModel: JobData;
|
||||||
public jobId: string;
|
public jobId: string;
|
||||||
@@ -166,6 +171,8 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
|||||||
this.jobModel = jobModel;
|
this.jobModel = jobModel;
|
||||||
this.jobId = this.jobId ? this.jobId : this.jobModel.jobId;
|
this.jobId = this.jobId ? this.jobId : this.jobModel.jobId;
|
||||||
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
|
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) {
|
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||||
|
|||||||
@@ -42,11 +42,12 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type');
|
private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type');
|
||||||
private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success');
|
private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success');
|
||||||
private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure');
|
private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure');
|
||||||
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New...');
|
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New Step');
|
||||||
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit');
|
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit Step');
|
||||||
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete');
|
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete Step');
|
||||||
private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up');
|
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
|
// Notifications tab strings
|
||||||
private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes');
|
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 AlertEnabledLabelString: string = localize('jobDialog.alertEnabledLabel', 'Enabled');
|
||||||
private readonly AlertTypeLabelString: string = localize('jobDialog.alertTypeLabel', 'Type');
|
private readonly AlertTypeLabelString: string = localize('jobDialog.alertTypeLabel', 'Type');
|
||||||
|
|
||||||
|
// Event Name strings
|
||||||
|
private readonly NewJobDialogEvent: string = 'NewJobDialogOpened';
|
||||||
|
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
private stepsTab: 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 eventLogConditionDropdown: sqlops.DropDownComponent;
|
||||||
private deleteJobCheckBox: sqlops.CheckBoxComponent;
|
private deleteJobCheckBox: sqlops.CheckBoxComponent;
|
||||||
private deleteJobConditionDropdown: sqlops.DropDownComponent;
|
private deleteJobConditionDropdown: sqlops.DropDownComponent;
|
||||||
|
private startStepDropdown: sqlops.DropDownComponent;
|
||||||
|
|
||||||
// Schedule tab controls
|
// Schedule tab controls
|
||||||
private schedulesTable: sqlops.TableComponent;
|
private schedulesTable: sqlops.TableComponent;
|
||||||
@@ -115,6 +121,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
private steps: sqlops.AgentJobStepInfo[];
|
private steps: sqlops.AgentJobStepInfo[];
|
||||||
private schedules: sqlops.AgentJobScheduleInfo[];
|
private schedules: sqlops.AgentJobScheduleInfo[];
|
||||||
private alerts: sqlops.AgentAlertInfo[] = [];
|
private alerts: sqlops.AgentAlertInfo[] = [];
|
||||||
|
private startStepDropdownValues: sqlops.CategoryValue[] = [];
|
||||||
|
|
||||||
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
|
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
|
||||||
super(
|
super(
|
||||||
@@ -125,6 +132,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
this.schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
|
this.schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
|
||||||
this.alerts = this.model.alerts ? this.model.alerts : [];
|
this.alerts = this.model.alerts ? this.model.alerts : [];
|
||||||
this.isEdit = jobInfo ? true : false;
|
this.isEdit = jobInfo ? true : false;
|
||||||
|
this.dialogName = this.isEdit ? this.EditJobDialogEvent : this.NewJobDialogEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async initializeDialog() {
|
protected async initializeDialog() {
|
||||||
@@ -218,19 +226,26 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
this.StepsTable_FailureColumnString
|
this.StepsTable_FailureColumnString
|
||||||
],
|
],
|
||||||
data: data,
|
data: data,
|
||||||
height: 750
|
height: 650
|
||||||
}).component();
|
}).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()
|
this.moveStepUpButton = view.modelBuilder.button()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
label: this.MoveStepUpButtonString,
|
label: this.MoveStepUpButtonString,
|
||||||
width: 80
|
width: 120
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.moveStepDownButton = view.modelBuilder.button()
|
this.moveStepDownButton = view.modelBuilder.button()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
label: this.MoveStepDownButtonString,
|
label: this.MoveStepDownButtonString,
|
||||||
width: 80
|
width: 120
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.moveStepUpButton.enabled = false;
|
this.moveStepUpButton.enabled = false;
|
||||||
@@ -238,7 +253,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
|
|
||||||
this.newStepButton = view.modelBuilder.button().withProperties({
|
this.newStepButton = view.modelBuilder.button().withProperties({
|
||||||
label: this.NewStepButtonString,
|
label: this.NewStepButtonString,
|
||||||
width: 80
|
width: 140
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true);
|
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);
|
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
|
||||||
this.steps.push(stepInfo);
|
this.steps.push(stepInfo);
|
||||||
this.stepsTable.data = this.convertStepsToData(this.steps);
|
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)=>{
|
this.newStepButton.onDidClick((e)=>{
|
||||||
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
|
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({
|
this.editStepButton = view.modelBuilder.button().withProperties({
|
||||||
label: this.EditStepButtonString,
|
label: this.EditStepButtonString,
|
||||||
width: 80
|
width: 140
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.deleteStepButton = view.modelBuilder.button().withProperties({
|
this.deleteStepButton = view.modelBuilder.button().withProperties({
|
||||||
label: this.DeleteStepButtonString,
|
label: this.DeleteStepButtonString,
|
||||||
width: 80
|
width: 140
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.stepsTable.enabled = false;
|
this.stepsTable.enabled = false;
|
||||||
this.editStepButton.enabled = false;
|
this.editStepButton.enabled = false;
|
||||||
this.deleteStepButton.enabled = false;
|
this.deleteStepButton.enabled = false;
|
||||||
|
|
||||||
this.stepsTable.onRowSelected(() => {
|
this.moveStepUpButton.onDidClick(() => {
|
||||||
// only let edit or delete steps if there's
|
let rowNumber = this.stepsTable.selectedRows[0];
|
||||||
// one step selection
|
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) {
|
if (this.stepsTable.selectedRows.length === 1) {
|
||||||
let rowNumber = this.stepsTable.selectedRows[0];
|
let rowNumber = this.stepsTable.selectedRows[0];
|
||||||
let stepData = this.model.jobSteps[rowNumber];
|
let stepData = this.model.jobSteps[rowNumber];
|
||||||
this.deleteStepButton.enabled = true;
|
let editStepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
|
||||||
this.editStepButton.enabled = true;
|
editStepDialog.onSuccess((step) => {
|
||||||
this.editStepButton.onDidClick(() => {
|
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
|
||||||
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
|
for (let i = 0; i < this.steps.length; i++) {
|
||||||
stepDialog.openDialog();
|
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) => {
|
editStepDialog.openDialog();
|
||||||
let steps = this.model.jobSteps ? this.model.jobSteps : [];
|
}
|
||||||
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
|
});
|
||||||
if (result && result.success) {
|
|
||||||
delete steps[rowNumber];
|
this.deleteStepButton.onDidClick(() => {
|
||||||
let data = this.convertStepsToData(steps);
|
if (this.stepsTable.selectedRows.length === 1) {
|
||||||
this.stepsTable.data = data;
|
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()
|
this.stepsTable.onRowSelected((row) => {
|
||||||
.withFormItems([{
|
// 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,
|
component: this.stepsTable,
|
||||||
title: this.JobStepsTopLabelString,
|
title: this.JobStepsTopLabelString
|
||||||
actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton]
|
},
|
||||||
}]).withLayout({ width: '100%' }).component();
|
{
|
||||||
|
component: stepMoveContainer,
|
||||||
|
title: this.StartStepDropdownString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: stepsDialogContainer,
|
||||||
|
title: ''
|
||||||
|
}
|
||||||
|
]).withLayout({ width: '100%' }).component();
|
||||||
await view.initializeModel(formModel);
|
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.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
|
||||||
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
|
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
|
||||||
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
|
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
|
||||||
|
this.model.startStepId = +this.getDropdownValue(this.startStepDropdown);
|
||||||
if (!this.model.jobSteps) {
|
if (!this.model.jobSteps) {
|
||||||
this.model.jobSteps = [];
|
this.model.jobSteps = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
|||||||
private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success');
|
private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success');
|
||||||
private readonly QuitJobReportingFailure: string = localize('jobStepDialog.quitJobFailure', 'Quit the job reporting failure');
|
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
|
// UI Components
|
||||||
|
|
||||||
// Dialogs
|
// Dialogs
|
||||||
@@ -131,6 +134,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
|||||||
this.jobModel = jobModel;
|
this.jobModel = jobModel;
|
||||||
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
|
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
this.dialogName = this.isEdit ? this.EditStepDialog : this.NewStepDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeUIComponents() {
|
private initializeUIComponents() {
|
||||||
@@ -519,6 +523,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
|||||||
this.model.failureAction = this.failureActionDropdown.value as string;
|
this.model.failureAction = this.failureActionDropdown.value as string;
|
||||||
this.model.outputFileName = this.outputFileNameBox.value;
|
this.model.outputFileName = this.outputFileNameBox.value;
|
||||||
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
|
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
|
||||||
|
this.model.command = this.commandTextBox.value ? this.commandTextBox.value : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initializeDialog() {
|
public async initializeDialog() {
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
|||||||
private static readonly AlertEmailColumnLabel: string = localize('createOperator.AlertEmailColumnLabel', 'E-mail');
|
private static readonly AlertEmailColumnLabel: string = localize('createOperator.AlertEmailColumnLabel', 'E-mail');
|
||||||
private static readonly AlertPagerColumnLabel: string = localize('createOperator.AlertPagerColumnLabel', 'Pager');
|
private static readonly AlertPagerColumnLabel: string = localize('createOperator.AlertPagerColumnLabel', 'Pager');
|
||||||
|
|
||||||
|
// Event strings
|
||||||
|
private readonly NewOperatorDialog = 'NewOperatorDialogOpened';
|
||||||
|
private readonly EditOperatorDialog = 'EditOperatorDialogOpened';
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
|
private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
@@ -68,12 +72,15 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
|||||||
|
|
||||||
// Notification tab controls
|
// Notification tab controls
|
||||||
private alertsTable: sqlops.TableComponent;
|
private alertsTable: sqlops.TableComponent;
|
||||||
|
private isEdit: boolean = false;
|
||||||
|
|
||||||
constructor(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo = undefined) {
|
constructor(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo = undefined) {
|
||||||
super(
|
super(
|
||||||
ownerUri,
|
ownerUri,
|
||||||
new OperatorData(ownerUri, operatorInfo),
|
new OperatorData(ownerUri, operatorInfo),
|
||||||
operatorInfo ? OperatorDialog.EditDialogTitle : OperatorDialog.CreateDialogTitle);
|
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) {
|
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
|
|||||||
private static readonly PowerShellLabel: string = localize('createProxy.PowerShell', 'PowerShell');
|
private static readonly PowerShellLabel: string = localize('createProxy.PowerShell', 'PowerShell');
|
||||||
private static readonly SubSystemHeadingLabel: string = localize('createProxy.subSystemHeading', 'Active to the following subsytems');
|
private static readonly SubSystemHeadingLabel: string = localize('createProxy.subSystemHeading', 'Active to the following subsytems');
|
||||||
|
|
||||||
|
private readonly NewProxyDialog = 'NewProxyDialogOpened';
|
||||||
|
private readonly EditProxyDialog = 'EditProxyDialogOpened';
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
|
|
||||||
@@ -56,6 +59,7 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
|
|||||||
private powershellCheckBox: sqlops.CheckBoxComponent;
|
private powershellCheckBox: sqlops.CheckBoxComponent;
|
||||||
|
|
||||||
private credentials: sqlops.CredentialInfo[];
|
private credentials: sqlops.CredentialInfo[];
|
||||||
|
private isEdit: boolean = false;
|
||||||
|
|
||||||
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
|
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
|
||||||
super(
|
super(
|
||||||
@@ -63,6 +67,8 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
|
|||||||
new ProxyData(ownerUri, proxyInfo),
|
new ProxyData(ownerUri, proxyInfo),
|
||||||
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
|
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
|
this.isEdit = proxyInfo ? true : false;
|
||||||
|
this.dialogName = this.isEdit ? this.EditProxyDialog : this.NewProxyDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ export class MainController {
|
|||||||
public activate(): void {
|
public activate(): void {
|
||||||
vscode.commands.registerCommand('agent.openJobDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo) => {
|
vscode.commands.registerCommand('agent.openJobDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo) => {
|
||||||
let dialog = new JobDialog(ownerUri, jobInfo);
|
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) => {
|
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: sqlops.AgentJobInfo, jobStepInfo: sqlops.AgentJobStepInfo) => {
|
||||||
AgentUtils.getAgentService().then((agentService) => {
|
AgentUtils.getAgentService().then((agentService) => {
|
||||||
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
|
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
|
||||||
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
|
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) => {
|
vscode.commands.registerCommand('agent.openPickScheduleDialog', (ownerUri: string, jobName: string) => {
|
||||||
@@ -57,17 +57,16 @@ export class MainController {
|
|||||||
AgentUtils.getAgentService().then((agentService) => {
|
AgentUtils.getAgentService().then((agentService) => {
|
||||||
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
|
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
|
||||||
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
|
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) => {
|
vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => {
|
||||||
let dialog = new OperatorDialog(ownerUri, operatorInfo);
|
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[]) => {
|
vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo, credentials: sqlops.CredentialInfo[]) => {
|
||||||
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
|
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
|
||||||
dialog.openDialog();
|
dialog.dialogName ? dialog.openDialog(dialog.dialogName) : dialog.openDialog();
|
||||||
MainController.showNotYetImplemented();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,22 +223,16 @@ export default class TokenCache implements adal.TokenCache {
|
|||||||
return this.getOrCreateEncryptionParams()
|
return this.getOrCreateEncryptionParams()
|
||||||
.then(encryptionParams => {
|
.then(encryptionParams => {
|
||||||
try {
|
try {
|
||||||
let cacheCipher = fs.readFileSync(self._cacheSerializationPath, TokenCache.FsOptions);
|
return self.decryptCache('utf8', encryptionParams);
|
||||||
|
|
||||||
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;
|
|
||||||
} catch (e) {
|
} 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 => {
|
.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[] {
|
private removeFromCache(cache: adal.TokenResponse[], entries: adal.TokenResponse[]): adal.TokenResponse[] {
|
||||||
entries.forEach((entry: adal.TokenResponse) => {
|
entries.forEach((entry: adal.TokenResponse) => {
|
||||||
// Check to see if the entry exists
|
// Check to see if the entry exists
|
||||||
@@ -274,7 +284,7 @@ export default class TokenCache implements adal.TokenCache {
|
|||||||
let cacheJson = JSON.stringify(cache);
|
let cacheJson = JSON.stringify(cache);
|
||||||
|
|
||||||
let cipher = crypto.createCipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
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');
|
cacheCipher += cipher.final('hex');
|
||||||
|
|
||||||
fs.writeFileSync(self._cacheSerializationPath, cacheCipher, TokenCache.FsOptions);
|
fs.writeFileSync(self._cacheSerializationPath, cacheCipher, TokenCache.FsOptions);
|
||||||
|
|||||||
@@ -1,9 +1,50 @@
|
|||||||
# Microsoft SQL Server Import for Azure Data Studio
|
# 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" />
|
<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
|
## License
|
||||||
|
|
||||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
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.
|
> 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
|
## Code of Conduct
|
||||||
|
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "import",
|
"name": "import",
|
||||||
"displayName": "SQL Server Import",
|
"displayName": "SQL Server Import",
|
||||||
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
|
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
|
||||||
"version": "0.4.2",
|
"version": "0.5.0",
|
||||||
"publisher": "Microsoft",
|
"publisher": "Microsoft",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.7",
|
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.10",
|
||||||
"opener": "^1.4.3",
|
"opener": "^1.4.3",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"vscode-extension-telemetry": "0.0.18",
|
"vscode-extension-telemetry": "0.0.18",
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export class DataTierApplicationWizard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async deploy() {
|
private async deploy() {
|
||||||
let service = await DataTierApplicationWizard.getService();
|
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
|
||||||
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
|
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);
|
let result = await service.deployDacpac(this.model.filePath, this.model.database, this.model.upgradeExisting, ownerUri, sqlops.TaskExecutionMode.execute);
|
||||||
@@ -213,7 +213,7 @@ export class DataTierApplicationWizard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async extract() {
|
private async extract() {
|
||||||
let service = await DataTierApplicationWizard.getService();
|
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
|
||||||
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
|
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);
|
let result = await service.extractDacpac(this.model.database, this.model.filePath, this.model.database, this.model.version, ownerUri, sqlops.TaskExecutionMode.execute);
|
||||||
@@ -224,7 +224,7 @@ export class DataTierApplicationWizard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async export() {
|
private async export() {
|
||||||
let service = await DataTierApplicationWizard.getService();
|
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
|
||||||
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
|
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);
|
let result = await service.exportBacpac(this.model.database, this.model.filePath, ownerUri, sqlops.TaskExecutionMode.execute);
|
||||||
@@ -235,7 +235,7 @@ export class DataTierApplicationWizard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async import() {
|
private async import() {
|
||||||
let service = await DataTierApplicationWizard.getService();
|
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
|
||||||
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
|
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);
|
let result = await service.importBacpac(this.model.filePath, this.model.database, ownerUri, sqlops.TaskExecutionMode.execute);
|
||||||
@@ -245,9 +245,8 @@ export class DataTierApplicationWizard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getService(): Promise<sqlops.DacFxServicesProvider> {
|
private static async getService(providerName: string): Promise<sqlops.DacFxServicesProvider> {
|
||||||
let currentConnection = await sqlops.connection.getCurrentConnection();
|
let service = sqlops.dataprotocol.getProvider<sqlops.DacFxServicesProvider>(providerName, sqlops.DataProviderType.DacFxServicesProvider);
|
||||||
let service = sqlops.dataprotocol.getProvider<sqlops.DacFxServicesProvider>(currentConnection.providerName, sqlops.DataProviderType.DacFxServicesProvider);
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class DeployConfigPage extends DacFxConfigPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<boolean> {
|
async start(): Promise<boolean> {
|
||||||
let serverComponent = await this.createServerDropdown(true);
|
let serverComponent = await this.createServerDropdown(true);
|
||||||
let fileBrowserComponent = await this.createFileBrowser();
|
let fileBrowserComponent = await this.createFileBrowser();
|
||||||
this.databaseComponent = await this.createDatabaseTextBox();
|
this.databaseComponent = await this.createDatabaseTextBox();
|
||||||
this.databaseComponent.title = localize('dacFx.databaseNameTextBox', 'Database Name');
|
this.databaseComponent.title = localize('dacFx.databaseNameTextBox', 'Database Name');
|
||||||
@@ -131,7 +131,7 @@ export class DeployConfigPage extends DacFxConfigPage {
|
|||||||
this.model.database = this.databaseTextBox.value;
|
this.model.database = this.databaseTextBox.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize with upgrade existing true
|
//Initialize with upgrade existing true
|
||||||
upgradeRadioButton.checked = true;
|
upgradeRadioButton.checked = true;
|
||||||
this.model.upgradeExisting = true;
|
this.model.upgradeExisting = true;
|
||||||
|
|
||||||
@@ -149,10 +149,10 @@ export class DeployConfigPage extends DacFxConfigPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async createDeployDatabaseDropdown(): Promise<sqlops.FormComponent> {
|
protected async createDeployDatabaseDropdown(): Promise<sqlops.FormComponent> {
|
||||||
this.databaseDropdown = this.view.modelBuilder.dropDown().withProperties({
|
this.databaseDropdown = this.view.modelBuilder.dropDown().withProperties({
|
||||||
required: true
|
required: true
|
||||||
}).component();
|
}).component();
|
||||||
// Handle database changes
|
//Handle database changes
|
||||||
this.databaseDropdown.onValueChanged(async () => {
|
this.databaseDropdown.onValueChanged(async () => {
|
||||||
this.model.database = (<sqlops.CategoryValue>this.databaseDropdown.value).name;
|
this.model.database = (<sqlops.CategoryValue>this.databaseDropdown.value).name;
|
||||||
});
|
});
|
||||||
@@ -172,7 +172,8 @@ export class DeployConfigPage extends DacFxConfigPage {
|
|||||||
}
|
}
|
||||||
let values = await this.getDatabaseValues();
|
let values = await this.getDatabaseValues();
|
||||||
|
|
||||||
if (this.model.database === undefined) {
|
//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.model.database = values[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { DacFxDataModel } from '../api/models';
|
import { DacFxDataModel } from '../api/models';
|
||||||
import { DataTierApplicationWizard, Operation } from '../DataTierApplicationWizard';
|
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
|
||||||
import { BasePage } from '../api/basePage';
|
import { BasePage } from '../api/basePage';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ agent-base@4, agent-base@^4.1.0:
|
|||||||
|
|
||||||
applicationinsights@1.0.1:
|
applicationinsights@1.0.1:
|
||||||
version "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=
|
integrity sha1-U0Rrgw/o1dYZ7uKieLMdPSUDCSc=
|
||||||
dependencies:
|
dependencies:
|
||||||
diagnostic-channel "0.2.0"
|
diagnostic-channel "0.2.0"
|
||||||
@@ -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"
|
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||||
|
|
||||||
buffer-alloc@^1.1.0:
|
buffer-alloc@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
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"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||||
|
|
||||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.7":
|
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.10":
|
||||||
version "0.2.6"
|
version "0.2.10"
|
||||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/85653d8b305af8aef334728d71f07bdc240dfcb7"
|
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/4de3f7caf0eba54159911b977ddb4f5d7c0a9ca8"
|
||||||
dependencies:
|
dependencies:
|
||||||
vscode-languageclient "3.5.1"
|
vscode-languageclient "3.5.1"
|
||||||
|
|
||||||
debug@3.1.0, debug@^3.1.0:
|
debug@3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
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:
|
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
||||||
@@ -143,12 +150,12 @@ decompress@^4.2.0:
|
|||||||
|
|
||||||
diagnostic-channel-publishers@0.2.1:
|
diagnostic-channel-publishers@0.2.1:
|
||||||
version "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=
|
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
|
||||||
|
|
||||||
diagnostic-channel@0.2.0:
|
diagnostic-channel@0.2.0:
|
||||||
version "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=
|
integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
|
||||||
dependencies:
|
dependencies:
|
||||||
semver "^5.3.0"
|
semver "^5.3.0"
|
||||||
@@ -161,9 +168,9 @@ end-of-stream@^1.0.0:
|
|||||||
once "^1.4.0"
|
once "^1.4.0"
|
||||||
|
|
||||||
es6-promise@^4.0.3:
|
es6-promise@^4.0.3:
|
||||||
version "4.2.4"
|
version "4.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
|
||||||
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
|
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
|
||||||
|
|
||||||
es6-promisify@^5.0.0:
|
es6-promisify@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
@@ -213,9 +220,9 @@ get-stream@^2.2.0:
|
|||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
|
|
||||||
graceful-fs@^4.1.10:
|
graceful-fs@^4.1.10:
|
||||||
version "4.1.11"
|
version "4.1.15"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||||
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
|
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||||
|
|
||||||
"graceful-readlink@>= 1.0.0":
|
"graceful-readlink@>= 1.0.0":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@@ -287,6 +294,11 @@ ms@2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
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:
|
object-assign@^4.0.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
@@ -300,9 +312,9 @@ once@^1.4.0:
|
|||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
opener@^1.4.3:
|
opener@^1.4.3:
|
||||||
version "1.4.3"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
|
||||||
integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
|
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
|
||||||
|
|
||||||
os-tmpdir@~1.0.2:
|
os-tmpdir@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -368,7 +380,7 @@ seek-bzip@^1.0.5:
|
|||||||
|
|
||||||
semver@^5.3.0:
|
semver@^5.3.0:
|
||||||
version "5.6.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==
|
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
|
||||||
|
|
||||||
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
||||||
@@ -397,16 +409,16 @@ strip-dirs@^2.0.0:
|
|||||||
is-natural-number "^4.0.1"
|
is-natural-number "^4.0.1"
|
||||||
|
|
||||||
tar-stream@^1.5.2:
|
tar-stream@^1.5.2:
|
||||||
version "1.6.1"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
|
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
|
||||||
integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==
|
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
bl "^1.0.0"
|
bl "^1.0.0"
|
||||||
buffer-alloc "^1.1.0"
|
buffer-alloc "^1.2.0"
|
||||||
end-of-stream "^1.0.0"
|
end-of-stream "^1.0.0"
|
||||||
fs-constants "^1.0.0"
|
fs-constants "^1.0.0"
|
||||||
readable-stream "^2.3.0"
|
readable-stream "^2.3.0"
|
||||||
to-buffer "^1.1.0"
|
to-buffer "^1.1.1"
|
||||||
xtend "^4.0.0"
|
xtend "^4.0.0"
|
||||||
|
|
||||||
through@^2.3.6:
|
through@^2.3.6:
|
||||||
@@ -421,15 +433,15 @@ tmp@^0.0.33:
|
|||||||
dependencies:
|
dependencies:
|
||||||
os-tmpdir "~1.0.2"
|
os-tmpdir "~1.0.2"
|
||||||
|
|
||||||
to-buffer@^1.1.0:
|
to-buffer@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
||||||
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||||
|
|
||||||
unbzip2-stream@^1.0.9:
|
unbzip2-stream@^1.0.9:
|
||||||
version "1.2.5"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
|
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
|
||||||
integrity sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==
|
integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer "^3.0.1"
|
buffer "^3.0.1"
|
||||||
through "^2.3.6"
|
through "^2.3.6"
|
||||||
@@ -441,7 +453,7 @@ util-deprecate@~1.0.1:
|
|||||||
|
|
||||||
vscode-extension-telemetry@0.0.18:
|
vscode-extension-telemetry@0.0.18:
|
||||||
version "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==
|
integrity sha512-Vw3Sr+dZwl+c6PlsUwrTtCOJkgrmvS3OUVDQGcmpXWAgq9xGq6as0K4pUx+aGqTjzLAESmWSrs6HlJm6J6Khcg==
|
||||||
dependencies:
|
dependencies:
|
||||||
applicationinsights "1.0.1"
|
applicationinsights "1.0.1"
|
||||||
@@ -472,9 +484,9 @@ vscode-languageserver-types@3.5.0:
|
|||||||
integrity sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=
|
integrity sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=
|
||||||
|
|
||||||
vscode-nls@^3.2.1:
|
vscode-nls@^3.2.1:
|
||||||
version "3.2.4"
|
version "3.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.5.tgz#25520c1955108036dec607c85e00a522f247f1a4"
|
||||||
integrity sha512-FTjdqa4jDDoBjJqr36O8lmmZf/55kQ2w4ZY/+GL6K92fq765BqO3aYw21atnXUno/P04V5DWagNl4ybDIndJsw==
|
integrity sha512-ITtoh3V4AkWXMmp3TB97vsMaHRgHhsSFPsUdzlueSL+dRZbSNTZeOmdQv60kjCV306ghPxhDeoNUEm3+EZMuyw==
|
||||||
|
|
||||||
wrappy@1:
|
wrappy@1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -496,5 +508,5 @@ yauzl@^2.4.2:
|
|||||||
|
|
||||||
zone.js@0.7.6:
|
zone.js@0.7.6:
|
||||||
version "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=
|
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json"
|
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.9",
|
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.10",
|
||||||
"opener": "^1.4.3",
|
"opener": "^1.4.3",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"vscode-extension-telemetry": "^0.0.15"
|
"vscode-extension-telemetry": "^0.0.15"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||||
"version": "1.5.0-alpha.59",
|
"version": "1.5.0-alpha.63",
|
||||||
"downloadFileNames": {
|
"downloadFileNames": {
|
||||||
"Windows_86": "win-x86-netcoreapp2.2.zip",
|
"Windows_86": "win-x86-netcoreapp2.2.zip",
|
||||||
"Windows_64": "win-x64-netcoreapp2.2.zip",
|
"Windows_64": "win-x64-netcoreapp2.2.zip",
|
||||||
|
|||||||
@@ -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"
|
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||||
|
|
||||||
buffer-alloc@^1.1.0:
|
buffer-alloc@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
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"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||||
|
|
||||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.9":
|
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.10":
|
||||||
version "0.2.9"
|
version "0.2.10"
|
||||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/0a3c0f22940d1c67bb567171508ccb1169c6313a"
|
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/4de3f7caf0eba54159911b977ddb4f5d7c0a9ca8"
|
||||||
dependencies:
|
dependencies:
|
||||||
vscode-languageclient "3.5.1"
|
vscode-languageclient "3.5.1"
|
||||||
|
|
||||||
debug@3.1.0, debug@^3.1.0:
|
debug@3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
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:
|
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
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"
|
once "^1.4.0"
|
||||||
|
|
||||||
es6-promise@^4.0.3:
|
es6-promise@^4.0.3:
|
||||||
version "4.2.4"
|
version "4.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
|
||||||
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
|
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
|
||||||
|
|
||||||
es6-promisify@^5.0.0:
|
es6-promisify@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
@@ -213,9 +220,9 @@ get-stream@^2.2.0:
|
|||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
|
|
||||||
graceful-fs@^4.1.10:
|
graceful-fs@^4.1.10:
|
||||||
version "4.1.11"
|
version "4.1.15"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||||
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
|
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||||
|
|
||||||
"graceful-readlink@>= 1.0.0":
|
"graceful-readlink@>= 1.0.0":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@@ -287,6 +294,11 @@ ms@2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
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:
|
object-assign@^4.0.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
@@ -300,9 +312,9 @@ once@^1.4.0:
|
|||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
opener@^1.4.3:
|
opener@^1.4.3:
|
||||||
version "1.4.3"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
|
||||||
integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
|
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
|
||||||
|
|
||||||
os-tmpdir@~1.0.2:
|
os-tmpdir@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -367,9 +379,9 @@ seek-bzip@^1.0.5:
|
|||||||
commander "~2.8.1"
|
commander "~2.8.1"
|
||||||
|
|
||||||
semver@^5.3.0:
|
semver@^5.3.0:
|
||||||
version "5.5.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
|
||||||
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
|
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
|
||||||
|
|
||||||
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
||||||
version "0.1.5"
|
version "0.1.5"
|
||||||
@@ -397,16 +409,16 @@ strip-dirs@^2.0.0:
|
|||||||
is-natural-number "^4.0.1"
|
is-natural-number "^4.0.1"
|
||||||
|
|
||||||
tar-stream@^1.5.2:
|
tar-stream@^1.5.2:
|
||||||
version "1.6.1"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
|
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
|
||||||
integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==
|
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
bl "^1.0.0"
|
bl "^1.0.0"
|
||||||
buffer-alloc "^1.1.0"
|
buffer-alloc "^1.2.0"
|
||||||
end-of-stream "^1.0.0"
|
end-of-stream "^1.0.0"
|
||||||
fs-constants "^1.0.0"
|
fs-constants "^1.0.0"
|
||||||
readable-stream "^2.3.0"
|
readable-stream "^2.3.0"
|
||||||
to-buffer "^1.1.0"
|
to-buffer "^1.1.1"
|
||||||
xtend "^4.0.0"
|
xtend "^4.0.0"
|
||||||
|
|
||||||
through@^2.3.6:
|
through@^2.3.6:
|
||||||
@@ -421,15 +433,15 @@ tmp@^0.0.33:
|
|||||||
dependencies:
|
dependencies:
|
||||||
os-tmpdir "~1.0.2"
|
os-tmpdir "~1.0.2"
|
||||||
|
|
||||||
to-buffer@^1.1.0:
|
to-buffer@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
||||||
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||||
|
|
||||||
unbzip2-stream@^1.0.9:
|
unbzip2-stream@^1.0.9:
|
||||||
version "1.2.5"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
|
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
|
||||||
integrity sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==
|
integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer "^3.0.1"
|
buffer "^3.0.1"
|
||||||
through "^2.3.6"
|
through "^2.3.6"
|
||||||
|
|||||||
17
extensions/notebook/README.md
Normal file
17
extensions/notebook/README.md
Normal 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).
|
||||||
71
extensions/notebook/package.json
Normal file
71
extensions/notebook/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
extensions/notebook/package.nls.json
Normal file
8
extensions/notebook/package.nls.json
Normal 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"
|
||||||
|
}
|
||||||
1
extensions/notebook/resources/dark/new_notebook_inverse.svg
Executable file
1
extensions/notebook/resources/dark/new_notebook_inverse.svg
Executable 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 |
1
extensions/notebook/resources/dark/open_notebook_inverse.svg
Executable file
1
extensions/notebook/resources/dark/open_notebook_inverse.svg
Executable 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 |
1
extensions/notebook/resources/light/new_notebook.svg
Executable file
1
extensions/notebook/resources/light/new_notebook.svg
Executable 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 |
1
extensions/notebook/resources/light/open_notebook.svg
Executable file
1
extensions/notebook/resources/light/open_notebook.svg
Executable 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 |
50
extensions/notebook/src/extension.ts
Normal file
50
extensions/notebook/src/extension.ts
Normal 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() {
|
||||||
|
}
|
||||||
9
extensions/notebook/src/typings/refs.d.ts
vendored
Normal file
9
extensions/notebook/src/typings/refs.d.ts
vendored
Normal 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'/>
|
||||||
22
extensions/notebook/tsconfig.json
Normal file
22
extensions/notebook/tsconfig.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
13
extensions/notebook/yarn.lock
Normal file
13
extensions/notebook/yarn.lock
Normal 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==
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "profiler",
|
"name": "profiler",
|
||||||
"displayName": "SQL Server Profiler",
|
"displayName": "SQL Server Profiler",
|
||||||
"description": "SQL Server Profiler for Azure Data Studio",
|
"description": "SQL Server Profiler for Azure Data Studio",
|
||||||
"version": "0.5.1",
|
"version": "0.6.0",
|
||||||
"publisher": "Microsoft",
|
"publisher": "Microsoft",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||||
@@ -26,8 +26,7 @@
|
|||||||
"Microsoft.mssql"
|
"Microsoft.mssql"
|
||||||
],
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [{
|
||||||
{
|
|
||||||
"command": "profiler.newProfiler",
|
"command": "profiler.newProfiler",
|
||||||
"title": "Launch Profiler",
|
"title": "Launch Profiler",
|
||||||
"category": "Profiler"
|
"category": "Profiler"
|
||||||
@@ -49,13 +48,23 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
"objectExplorer/item/context": [
|
"commandPalette": [{
|
||||||
|
"command": "profiler.start",
|
||||||
|
"when": "False"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "profiler.newProfiler",
|
"command": "profiler.stop",
|
||||||
"when": "connectionProvider == MSSQL && nodeType && nodeType == Server",
|
"when": "False"
|
||||||
"group": "profiler"
|
}, {
|
||||||
|
"command": "profiler.openCreateSessionDialog",
|
||||||
|
"when": "False"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"objectExplorer/item/context": [{
|
||||||
|
"command": "profiler.newProfiler",
|
||||||
|
"when": "connectionProvider == MSSQL && nodeType && nodeType == Server",
|
||||||
|
"group": "profiler"
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
"outputChannels": [
|
"outputChannels": [
|
||||||
"sqlprofiler"
|
"sqlprofiler"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "azuredatastudio",
|
"name": "azuredatastudio",
|
||||||
"version": "1.3.4",
|
"version": "1.3.8",
|
||||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"rxjs": "5.4.0",
|
"rxjs": "5.4.0",
|
||||||
"sanitize-html": "^1.19.1",
|
"sanitize-html": "^1.19.1",
|
||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.28",
|
"slickgrid": "github:anthonydresser/SlickGrid#2.3.29",
|
||||||
"spdlog": "0.7.1",
|
"spdlog": "0.7.1",
|
||||||
"sudo-prompt": "8.2.0",
|
"sudo-prompt": "8.2.0",
|
||||||
"svg.js": "^2.2.5",
|
"svg.js": "^2.2.5",
|
||||||
@@ -90,6 +90,7 @@
|
|||||||
"@types/mocha": "2.2.39",
|
"@types/mocha": "2.2.39",
|
||||||
"@types/sanitize-html": "^1.18.2",
|
"@types/sanitize-html": "^1.18.2",
|
||||||
"@types/semver": "5.3.30",
|
"@types/semver": "5.3.30",
|
||||||
|
"@types/should": "^13.0.0",
|
||||||
"@types/sinon": "1.16.34",
|
"@types/sinon": "1.16.34",
|
||||||
"@types/winreg": "^1.2.30",
|
"@types/winreg": "^1.2.30",
|
||||||
"asar": "^0.14.0",
|
"asar": "^0.14.0",
|
||||||
@@ -148,8 +149,10 @@
|
|||||||
"queue": "3.0.6",
|
"queue": "3.0.6",
|
||||||
"remap-istanbul": "^0.6.4",
|
"remap-istanbul": "^0.6.4",
|
||||||
"rimraf": "^2.2.8",
|
"rimraf": "^2.2.8",
|
||||||
|
"should": "^13.2.3",
|
||||||
"sinon": "^1.17.2",
|
"sinon": "^1.17.2",
|
||||||
"source-map": "^0.4.4",
|
"source-map": "^0.4.4",
|
||||||
|
"temp-write": "^3.4.0",
|
||||||
"tslint": "^5.9.1",
|
"tslint": "^5.9.1",
|
||||||
"typemoq": "^0.3.2",
|
"typemoq": "^0.3.2",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
@@ -174,6 +177,7 @@
|
|||||||
"windows-process-tree": "0.2.2"
|
"windows-process-tree": "0.2.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"rc": "1.2.8"
|
"rc": "1.2.8",
|
||||||
|
"event-stream": "3.3.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,87 +4,72 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces';
|
import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces';
|
||||||
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
|
|
||||||
export interface IObservableCollection<T> {
|
export interface IObservableCollection<T> {
|
||||||
getLength(): number;
|
getLength(): number;
|
||||||
at(index: number): T;
|
at(index: number): T;
|
||||||
getRange(start: number, end: number): T[];
|
getRange(start: number, end: number): T[];
|
||||||
setCollectionChangedCallback(callback: (change: CollectionChange, startIndex: number, count: number) => void): void;
|
setCollectionChangedCallback(callback: (startIndex: number, count: number) => void): void;
|
||||||
|
setLength(number): void;
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGridDataRow {
|
class DataWindow<T> {
|
||||||
row?: number;
|
private _data: T[];
|
||||||
values: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum CollectionChange {
|
|
||||||
ItemsReplaced
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoadCancellationToken {
|
|
||||||
isCancelled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataWindow<TData> {
|
|
||||||
private _data: TData[];
|
|
||||||
private _length: number = 0;
|
private _length: number = 0;
|
||||||
private _offsetFromDataSource: number = -1;
|
private _offsetFromDataSource: number = -1;
|
||||||
|
|
||||||
private lastLoadCancellationToken: LoadCancellationToken;
|
private cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private loadFunction: (offset: number, count: number) => Thenable<TData[]>,
|
private loadFunction: (offset: number, count: number) => Thenable<T[]>,
|
||||||
private placeholderItemGenerator: (index: number) => TData,
|
private placeholderItemGenerator: (index: number) => T,
|
||||||
private loadCompleteCallback: (start: number, end: number) => void
|
private loadCompleteCallback: (start: number, end: number) => void
|
||||||
) {
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._data = undefined;
|
this._data = undefined;
|
||||||
this.loadFunction = undefined;
|
this.loadFunction = undefined;
|
||||||
this.placeholderItemGenerator = undefined;
|
this.placeholderItemGenerator = undefined;
|
||||||
this.loadCompleteCallback = undefined;
|
this.loadCompleteCallback = undefined;
|
||||||
if (this.lastLoadCancellationToken) {
|
this.cancellationToken.cancel();
|
||||||
this.lastLoadCancellationToken.isCancelled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStartIndex(): number {
|
public getStartIndex(): number {
|
||||||
return this._offsetFromDataSource;
|
return this._offsetFromDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
getEndIndex(): number {
|
public getEndIndex(): number {
|
||||||
return this._offsetFromDataSource + this._length;
|
return this._offsetFromDataSource + this._length;
|
||||||
}
|
}
|
||||||
|
|
||||||
contains(dataSourceIndex: number): boolean {
|
public contains(dataSourceIndex: number): boolean {
|
||||||
return dataSourceIndex >= this.getStartIndex() && dataSourceIndex < this.getEndIndex();
|
return dataSourceIndex >= this.getStartIndex() && dataSourceIndex < this.getEndIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
getItem(index: number): TData {
|
public getItem(index: number): T {
|
||||||
if (!this._data) {
|
if (!this._data) {
|
||||||
return this.placeholderItemGenerator(index);
|
return this.placeholderItemGenerator(index);
|
||||||
}
|
}
|
||||||
return this._data[index - this._offsetFromDataSource];
|
return this._data[index - this._offsetFromDataSource];
|
||||||
}
|
}
|
||||||
|
|
||||||
positionWindow(offset: number, length: number): void {
|
public positionWindow(offset: number, length: number): void {
|
||||||
this._offsetFromDataSource = offset;
|
this._offsetFromDataSource = offset;
|
||||||
this._length = length;
|
this._length = length;
|
||||||
this._data = undefined;
|
this._data = undefined;
|
||||||
|
|
||||||
if (this.lastLoadCancellationToken) {
|
this.cancellationToken.cancel();
|
||||||
this.lastLoadCancellationToken.isCancelled = true;
|
this.cancellationToken = new CancellationTokenSource();
|
||||||
}
|
const currentCancellation = this.cancellationToken;
|
||||||
|
|
||||||
if (length === 0) {
|
if (length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastLoadCancellationToken = new LoadCancellationToken();
|
|
||||||
this.loadFunction(offset, length).then(data => {
|
this.loadFunction(offset, length).then(data => {
|
||||||
if (!this.lastLoadCancellationToken.isCancelled) {
|
if (!currentCancellation.token.isCancellationRequested) {
|
||||||
this._data = data;
|
this._data = data;
|
||||||
this.loadCompleteCallback(this._offsetFromDataSource, this._offsetFromDataSource + this._length);
|
this.loadCompleteCallback(this._offsetFromDataSource, this._offsetFromDataSource + this._length);
|
||||||
}
|
}
|
||||||
@@ -92,34 +77,28 @@ class DataWindow<TData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VirtualizedCollection<TData> implements IObservableCollection<TData> {
|
export class VirtualizedCollection<T extends Slick.SlickData> implements IObservableCollection<T> {
|
||||||
|
private _bufferWindowBefore: DataWindow<T>;
|
||||||
|
private _window: DataWindow<T>;
|
||||||
|
private _bufferWindowAfter: DataWindow<T>;
|
||||||
|
|
||||||
private _length: number;
|
private collectionChangedCallback: (startIndex: number, count: number) => void;
|
||||||
private _windowSize: number;
|
|
||||||
private _bufferWindowBefore: DataWindow<TData>;
|
|
||||||
private _window: DataWindow<TData>;
|
|
||||||
private _bufferWindowAfter: DataWindow<TData>;
|
|
||||||
|
|
||||||
private collectionChangedCallback: (change: CollectionChange, startIndex: number, count: number) => void;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
windowSize: number,
|
private readonly windowSize: number,
|
||||||
length: number,
|
private placeHolderGenerator: (index: number) => T,
|
||||||
loadFn: (offset: number, count: number) => Thenable<TData[]>,
|
private length: number,
|
||||||
private _placeHolderGenerator: (index: number) => TData
|
loadFn: (offset: number, count: number) => Thenable<T[]>
|
||||||
) {
|
) {
|
||||||
this._windowSize = windowSize;
|
|
||||||
this._length = length;
|
|
||||||
|
|
||||||
let loadCompleteCallback = (start: number, end: number) => {
|
let loadCompleteCallback = (start: number, end: number) => {
|
||||||
if (this.collectionChangedCallback) {
|
if (this.collectionChangedCallback) {
|
||||||
this.collectionChangedCallback(CollectionChange.ItemsReplaced, start, end - start);
|
this.collectionChangedCallback(start, end - start);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this._bufferWindowBefore = new DataWindow(loadFn, _placeHolderGenerator, loadCompleteCallback);
|
this._bufferWindowBefore = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback);
|
||||||
this._window = new DataWindow(loadFn, _placeHolderGenerator, loadCompleteCallback);
|
this._window = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback);
|
||||||
this._bufferWindowAfter = new DataWindow(loadFn, _placeHolderGenerator, loadCompleteCallback);
|
this._bufferWindowAfter = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
@@ -128,19 +107,23 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
this._window.dispose();
|
this._window.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
setCollectionChangedCallback(callback: (change: CollectionChange, startIndex: number, count: number) => void): void {
|
public setCollectionChangedCallback(callback: (startIndex: number, count: number) => void): void {
|
||||||
this.collectionChangedCallback = callback;
|
this.collectionChangedCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLength(): number {
|
public getLength(): number {
|
||||||
return this._length;
|
return this.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
at(index: number): TData {
|
setLength(number: any): void {
|
||||||
|
this.length = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public at(index: number): T {
|
||||||
return this.getRange(index, index + 1)[0];
|
return this.getRange(index, index + 1)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
getRange(start: number, end: number): TData[] {
|
public getRange(start: number, end: number): T[] {
|
||||||
|
|
||||||
// current data may contain placeholders
|
// current data may contain placeholders
|
||||||
let currentData = this.getRangeFromCurrent(start, end);
|
let currentData = this.getRangeFromCurrent(start, end);
|
||||||
@@ -155,7 +138,7 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
this._bufferWindowAfter = this._window;
|
this._bufferWindowAfter = this._window;
|
||||||
this._window = this._bufferWindowBefore;
|
this._window = this._bufferWindowBefore;
|
||||||
this._bufferWindowBefore = windowToRecycle;
|
this._bufferWindowBefore = windowToRecycle;
|
||||||
let newWindowOffset = Math.max(0, this._window.getStartIndex() - this._windowSize);
|
let newWindowOffset = Math.max(0, this._window.getStartIndex() - this.windowSize);
|
||||||
|
|
||||||
this._bufferWindowBefore.positionWindow(newWindowOffset, this._window.getStartIndex() - newWindowOffset);
|
this._bufferWindowBefore.positionWindow(newWindowOffset, this._window.getStartIndex() - newWindowOffset);
|
||||||
} else if (start >= this._bufferWindowAfter.getStartIndex()) {
|
} else if (start >= this._bufferWindowAfter.getStartIndex()) {
|
||||||
@@ -164,8 +147,8 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
this._bufferWindowBefore = this._window;
|
this._bufferWindowBefore = this._window;
|
||||||
this._window = this._bufferWindowAfter;
|
this._window = this._bufferWindowAfter;
|
||||||
this._bufferWindowAfter = windowToRecycle;
|
this._bufferWindowAfter = windowToRecycle;
|
||||||
let newWindowOffset = Math.min(this._window.getStartIndex() + this._windowSize, this._length);
|
let newWindowOffset = Math.min(this._window.getStartIndex() + this.windowSize, this.length);
|
||||||
let newWindowLength = Math.min(this._length - newWindowOffset, this._windowSize);
|
let newWindowLength = Math.min(this.length - newWindowOffset, this.windowSize);
|
||||||
|
|
||||||
this._bufferWindowAfter.positionWindow(newWindowOffset, newWindowLength);
|
this._bufferWindowAfter.positionWindow(newWindowOffset, newWindowLength);
|
||||||
}
|
}
|
||||||
@@ -173,7 +156,7 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
return currentData;
|
return currentData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRangeFromCurrent(start: number, end: number): TData[] {
|
private getRangeFromCurrent(start: number, end: number): T[] {
|
||||||
let currentData = [];
|
let currentData = [];
|
||||||
for (let i = 0; i < end - start; i++) {
|
for (let i = 0; i < end - start; i++) {
|
||||||
currentData.push(this.getDataFromCurrent(start + i));
|
currentData.push(this.getDataFromCurrent(start + i));
|
||||||
@@ -182,7 +165,7 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
return currentData;
|
return currentData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDataFromCurrent(index: number): TData {
|
private getDataFromCurrent(index: number): T {
|
||||||
if (this._bufferWindowBefore.contains(index)) {
|
if (this._bufferWindowBefore.contains(index)) {
|
||||||
return this._bufferWindowBefore.getItem(index);
|
return this._bufferWindowBefore.getItem(index);
|
||||||
} else if (this._bufferWindowAfter.contains(index)) {
|
} else if (this._bufferWindowAfter.contains(index)) {
|
||||||
@@ -191,39 +174,47 @@ export class VirtualizedCollection<TData> implements IObservableCollection<TData
|
|||||||
return this._window.getItem(index);
|
return this._window.getItem(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._placeHolderGenerator(index);
|
return this.placeHolderGenerator(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetWindowsAroundIndex(index: number): void {
|
private resetWindowsAroundIndex(index: number): void {
|
||||||
|
|
||||||
let bufferWindowBeforeStart = Math.max(0, index - this._windowSize * 1.5);
|
let bufferWindowBeforeStart = Math.max(0, index - this.windowSize * 1.5);
|
||||||
let bufferWindowBeforeEnd = Math.max(0, index - this._windowSize / 2);
|
let bufferWindowBeforeEnd = Math.max(0, index - this.windowSize / 2);
|
||||||
this._bufferWindowBefore.positionWindow(bufferWindowBeforeStart, bufferWindowBeforeEnd - bufferWindowBeforeStart);
|
this._bufferWindowBefore.positionWindow(bufferWindowBeforeStart, bufferWindowBeforeEnd - bufferWindowBeforeStart);
|
||||||
|
|
||||||
let mainWindowStart = bufferWindowBeforeEnd;
|
let mainWindowStart = bufferWindowBeforeEnd;
|
||||||
let mainWindowEnd = Math.min(mainWindowStart + this._windowSize, this._length);
|
let mainWindowEnd = Math.min(mainWindowStart + this.windowSize, this.length);
|
||||||
this._window.positionWindow(mainWindowStart, mainWindowEnd - mainWindowStart);
|
this._window.positionWindow(mainWindowStart, mainWindowEnd - mainWindowStart);
|
||||||
|
|
||||||
let bufferWindowAfterStart = mainWindowEnd;
|
let bufferWindowAfterStart = mainWindowEnd;
|
||||||
let bufferWindowAfterEnd = Math.min(bufferWindowAfterStart + this._windowSize, this._length);
|
let bufferWindowAfterEnd = Math.min(bufferWindowAfterStart + this.windowSize, this.length);
|
||||||
this._bufferWindowAfter.positionWindow(bufferWindowAfterStart, bufferWindowAfterEnd - bufferWindowAfterStart);
|
this._bufferWindowAfter.positionWindow(bufferWindowAfterStart, bufferWindowAfterEnd - bufferWindowAfterStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AsyncDataProvider<TData extends IGridDataRow> implements IDisposableDataProvider<TData> {
|
export class AsyncDataProvider<T extends Slick.SlickData> implements IDisposableDataProvider<T> {
|
||||||
|
|
||||||
constructor(private dataRows: IObservableCollection<TData>) { }
|
constructor(public dataRows: IObservableCollection<T>) { }
|
||||||
|
|
||||||
public getLength(): number {
|
public getLength(): number {
|
||||||
return this.dataRows ? this.dataRows.getLength() : 0;
|
return this.dataRows.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getItem(index: number): TData {
|
public getItem(index: number): T {
|
||||||
return !this.dataRows ? undefined : this.dataRows.at(index);
|
return this.dataRows.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRange(start: number, end: number): TData[] {
|
public getRange(start: number, end: number): T[] {
|
||||||
return !this.dataRows ? undefined : this.dataRows.getRange(start, end);
|
return this.dataRows.getRange(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set length(length: number) {
|
||||||
|
this.dataRows.setLength(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get length(): number {
|
||||||
|
return this.dataRows.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { range } from 'vs/base/common/arrays';
|
|
||||||
|
|
||||||
export interface IRowNumberColumnOptions {
|
export interface IRowNumberColumnOptions {
|
||||||
numberOfRows: number;
|
numberOfRows: number;
|
||||||
cssClass?: string;
|
cssClass?: string;
|
||||||
@@ -17,7 +15,7 @@ const sizePerDigit = 15;
|
|||||||
export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
||||||
private handler = new Slick.EventHandler();
|
private handler = new Slick.EventHandler();
|
||||||
private grid: Slick.Grid<T>;
|
private grid: Slick.Grid<T>;
|
||||||
|
private currentColumnWidth: number;
|
||||||
|
|
||||||
constructor(private options: IRowNumberColumnOptions) {
|
constructor(private options: IRowNumberColumnOptions) {
|
||||||
}
|
}
|
||||||
@@ -52,16 +50,22 @@ export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateRowCount(rowNum: number) {
|
||||||
|
this.options.numberOfRows = rowNum;
|
||||||
|
let columnWidth = Math.max(this.options.numberOfRows.toString().length * sizePerDigit, 22);
|
||||||
|
if (columnWidth !== this.currentColumnWidth) {
|
||||||
|
this.grid.setColumnWidths([this.getColumnDefinition()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getColumnDefinition(): Slick.Column<T> {
|
public getColumnDefinition(): Slick.Column<T> {
|
||||||
// that smallest we can make it is 22 due to padding and margins in the cells
|
// that smallest we can make it is 22 due to padding and margins in the cells
|
||||||
let columnWidth = Math.max(this.options.numberOfRows.toString().length * sizePerDigit, 22);
|
this.currentColumnWidth = Math.max(this.options.numberOfRows.toString().length * sizePerDigit, 22);
|
||||||
return {
|
return {
|
||||||
id: 'rowNumber',
|
id: 'rowNumber',
|
||||||
name: '',
|
name: '',
|
||||||
field: 'rowNumber',
|
field: 'rowNumber',
|
||||||
width: columnWidth,
|
width: this.currentColumnWidth,
|
||||||
minWidth: columnWidth,
|
|
||||||
maxWidth: columnWidth,
|
|
||||||
resizable: false,
|
resizable: false,
|
||||||
cssClass: this.options.cssClass,
|
cssClass: this.options.cssClass,
|
||||||
focusable: false,
|
focusable: false,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
|
|||||||
this._onRowCountChange.fire();
|
this._onRowCountChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
find(exp: string): Thenable<IFindPosition> {
|
find(exp: string, maxMatches: number = 0): Thenable<IFindPosition> {
|
||||||
if (!this._findFn) {
|
if (!this._findFn) {
|
||||||
return TPromise.wrapError(new Error('no find function provided'));
|
return TPromise.wrapError(new Error('no find function provided'));
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,8 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
|
|||||||
this._onFindCountChange.fire(this._findArray.length);
|
this._onFindCountChange.fire(this._findArray.length);
|
||||||
if (exp) {
|
if (exp) {
|
||||||
this._findObs = Observable.create((observer: Observer<IFindPosition>) => {
|
this._findObs = Observable.create((observer: Observer<IFindPosition>) => {
|
||||||
this._data.forEach((item, i) => {
|
for (let i = 0; i < this._data.length; i++) {
|
||||||
|
let item = this._data[i];
|
||||||
let result = this._findFn(item, exp);
|
let result = this._findFn(item, exp);
|
||||||
if (result) {
|
if (result) {
|
||||||
result.forEach(pos => {
|
result.forEach(pos => {
|
||||||
@@ -96,8 +97,11 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
|
|||||||
observer.next(index);
|
observer.next(index);
|
||||||
this._onFindCountChange.fire(this._findArray.length);
|
this._onFindCountChange.fire(this._findArray.length);
|
||||||
});
|
});
|
||||||
|
if (maxMatches > 0 && this._findArray.length > maxMatches) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
return this._findObs.take(1).toPromise().then(() => {
|
return this._findObs.take(1).toPromise().then(() => {
|
||||||
return this._findArray[this._findIndex];
|
return this._findArray[this._findIndex];
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export const NewQuery = 'NewQuery';
|
|||||||
export const FirewallRuleRequested = 'FirewallRuleCreated';
|
export const FirewallRuleRequested = 'FirewallRuleCreated';
|
||||||
export const DashboardNavigated = 'DashboardNavigated';
|
export const DashboardNavigated = 'DashboardNavigated';
|
||||||
|
|
||||||
|
|
||||||
// Telemetry Properties
|
// Telemetry Properties
|
||||||
|
|
||||||
// Modal Dialogs:
|
// Modal Dialogs:
|
||||||
@@ -42,3 +41,21 @@ export const Accounts = 'Accounts';
|
|||||||
export const FireWallRule = 'FirewallRule';
|
export const FireWallRule = 'FirewallRule';
|
||||||
export const AutoOAuth = 'AutoOAuth';
|
export const AutoOAuth = 'AutoOAuth';
|
||||||
export const AddNewDashboardTab = 'AddNewDashboardTab';
|
export const AddNewDashboardTab = 'AddNewDashboardTab';
|
||||||
|
|
||||||
|
// SQL Agent Events:
|
||||||
|
|
||||||
|
// Views
|
||||||
|
export const JobsView = 'JobsViewOpened';
|
||||||
|
export const JobHistoryView = 'JobHistoryViewOpened';
|
||||||
|
export const JobStepsView = 'JobStepsViewOpened';
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
export const RunAgentJob = 'RunAgentJob';
|
||||||
|
export const StopAgentJob = 'StopAgentJob';
|
||||||
|
export const DeleteAgentJob = 'DeleteAgentJob';
|
||||||
|
export const DeleteAgentJobStep = 'DeleteAgentJobStep';
|
||||||
|
export const DeleteAgentAlert = 'DeleteAgentAlert';
|
||||||
|
export const DeleteAgentOperator = 'DeleteAgentOperator';
|
||||||
|
export const DeleteAgentProxy = 'DeleteAgentProxy';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,31 +4,10 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
import * as crypto from 'crypto';
|
|
||||||
import * as os from 'os';
|
|
||||||
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
import { warn } from 'sql/base/common/log';
|
import { warn } from 'sql/base/common/log';
|
||||||
|
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
|
||||||
|
|
||||||
// Generate a unique, deterministic ID for the current user of the extension
|
|
||||||
export function generateUserId(): Promise<string> {
|
|
||||||
return new Promise<string>(resolve => {
|
|
||||||
try {
|
|
||||||
getmac.getMac((error, macAddress) => {
|
|
||||||
if (!error) {
|
|
||||||
resolve(crypto.createHash('sha256').update(macAddress + os.homedir(), 'utf8').digest('hex'));
|
|
||||||
} else {
|
|
||||||
resolve(generateUuid()); // fallback
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
resolve(generateUuid()); // fallback
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConnectionTelemetryData extends ITelemetryData {
|
export interface IConnectionTelemetryData extends ITelemetryData {
|
||||||
provider?: string;
|
provider?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export class CommandLineService implements ICommandLineProcessing {
|
|||||||
// prompt the user for a new connection on startup if no profiles are registered
|
// prompt the user for a new connection on startup if no profiles are registered
|
||||||
this._connectionManagementService.showConnectionDialog();
|
this._connectionManagementService.showConnectionDialog();
|
||||||
} else if (this._connectionProfile) {
|
} else if (this._connectionProfile) {
|
||||||
this._connectionManagementService.connectIfNotConnected(this._connectionProfile, 'connection')
|
this._connectionManagementService.connectIfNotConnected(this._connectionProfile, 'connection', true)
|
||||||
.then(result => TaskUtilities.newQuery(this._connectionProfile,
|
.then(result => TaskUtilities.newQuery(this._connectionProfile,
|
||||||
this._connectionManagementService,
|
this._connectionManagementService,
|
||||||
this._queryEditorService,
|
this._queryEditorService,
|
||||||
|
|||||||
@@ -5,9 +5,8 @@
|
|||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
|
||||||
import { EditorInput, IEditorInput } from 'vs/workbench/common/editor';
|
import { EditorInput, IEditorInput } from 'vs/workbench/common/editor';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||||
import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput';
|
import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
@@ -17,8 +16,9 @@ import { QueryInput } from 'sql/parts/query/common/queryInput';
|
|||||||
import { IQueryEditorOptions } from 'sql/parts/query/common/queryEditorService';
|
import { IQueryEditorOptions } from 'sql/parts/query/common/queryEditorService';
|
||||||
import { QueryPlanInput } from 'sql/parts/queryPlan/queryPlanInput';
|
import { QueryPlanInput } from 'sql/parts/queryPlan/queryPlanInput';
|
||||||
import { NotebookInput, NotebookInputModel, NotebookInputValidator } from 'sql/parts/notebook/notebookInput';
|
import { NotebookInput, NotebookInputModel, NotebookInputValidator } from 'sql/parts/notebook/notebookInput';
|
||||||
import { Extensions, INotebookProviderRegistry } from 'sql/services/notebook/notebookRegistry';
|
import { DEFAULT_NOTEBOOK_PROVIDER, INotebookService } from 'sql/services/notebook/notebookService';
|
||||||
import { DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
import { getProviderForFileName } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ export const untitledFilePrefix = 'SQLQuery';
|
|||||||
|
|
||||||
// mode identifier for SQL mode
|
// mode identifier for SQL mode
|
||||||
export const sqlModeId = 'sql';
|
export const sqlModeId = 'sql';
|
||||||
|
export const notebookModeId = 'notebook';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the specified input is supported by one our custom input types, and if so convert it
|
* Checks if the specified input is supported by one our custom input types, and if so convert it
|
||||||
@@ -58,20 +59,20 @@ export function convertEditorInput(input: EditorInput, options: IQueryEditorOpti
|
|||||||
|
|
||||||
//Notebook
|
//Notebook
|
||||||
let notebookValidator = instantiationService.createInstance(NotebookInputValidator);
|
let notebookValidator = instantiationService.createInstance(NotebookInputValidator);
|
||||||
uri = getNotebookEditorUri(input);
|
uri = getNotebookEditorUri(input, instantiationService);
|
||||||
if(uri && notebookValidator.isNotebookEnabled()){
|
if (uri && notebookValidator.isNotebookEnabled()) {
|
||||||
//TODO: We need to pass in notebook data either through notebook input or notebook service
|
return withService<INotebookService, NotebookInput>(instantiationService, INotebookService, notebookService => {
|
||||||
let fileName: string = 'untitled';
|
let fileName: string = 'untitled';
|
||||||
let providerId: string = DEFAULT_NOTEBOOK_PROVIDER;
|
let providerId: string = DEFAULT_NOTEBOOK_PROVIDER;
|
||||||
if (input) {
|
if (input) {
|
||||||
fileName = input.getName();
|
fileName = input.getName();
|
||||||
providerId = getProviderForFileName(fileName);
|
providerId = getProviderForFileName(fileName, notebookService);
|
||||||
}
|
}
|
||||||
let notebookInputModel = new NotebookInputModel(uri, undefined, false, undefined);
|
let notebookInputModel = new NotebookInputModel(uri, undefined, false, undefined);
|
||||||
notebookInputModel.providerId = providerId;
|
notebookInputModel.providerId = providerId;
|
||||||
//TO DO: Second parameter has to be the content.
|
let notebookInput: NotebookInput = instantiationService.createInstance(NotebookInput, fileName, notebookInputModel);
|
||||||
let notebookInput: NotebookInput = instantiationService.createInstance(NotebookInput, fileName, notebookInputModel);
|
return notebookInput;
|
||||||
return notebookInput;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
@@ -96,6 +97,13 @@ export function getSupportedInputResource(input: IEditorInput): URI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input instanceof ResourceEditorInput) {
|
||||||
|
let resourceCast: ResourceEditorInput = <ResourceEditorInput>input;
|
||||||
|
if (resourceCast) {
|
||||||
|
return resourceCast.getResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,46 +161,51 @@ function getQueryPlanEditorUri(input: EditorInput): URI {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If input is a supported notebook editor file (.ipynb), return it's URI. Otherwise return undefined.
|
* If input is a supported notebook editor file (.ipynb), return it's URI. Otherwise return undefined.
|
||||||
* @param input The EditorInput to get the URI of.
|
* @param input The EditorInput to get the URI of.
|
||||||
*/
|
*/
|
||||||
function getNotebookEditorUri(input: EditorInput): URI {
|
function getNotebookEditorUri(input: EditorInput, instantiationService: IInstantiationService): URI {
|
||||||
if (!input || !input.getName()) {
|
if (!input || !input.getName()) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If this editor is not already of type notebook input
|
// If this editor is not already of type notebook input
|
||||||
if (!(input instanceof NotebookInput)) {
|
if (!(input instanceof NotebookInput)) {
|
||||||
let uri: URI = getSupportedInputResource(input);
|
let uri: URI = getSupportedInputResource(input);
|
||||||
if (uri) {
|
if (uri) {
|
||||||
if (hasFileExtension(getNotebookFileExtensions(), input, false)) {
|
if (hasFileExtension(getNotebookFileExtensions(instantiationService), input, false) || hasNotebookFileMode(input)) {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotebookFileExtensions() {
|
function getNotebookFileExtensions(instantiationService: IInstantiationService): string[] {
|
||||||
let notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
return withService<INotebookService, string[]>(instantiationService, INotebookService, notebookService => {
|
||||||
return notebookRegistry.getSupportedFileExtensions();
|
return notebookService.getSupportedFileExtensions();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProviderForFileName(fileName: string) {
|
/**
|
||||||
let fileExt = path.extname(fileName);
|
* Checks whether the given EditorInput is set to either undefined or notebook mode
|
||||||
if (fileExt && fileExt.startsWith('.')) {
|
* @param input The EditorInput to check the mode of
|
||||||
fileExt = fileExt.slice(1,fileExt.length);
|
*/
|
||||||
let notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
function hasNotebookFileMode(input: EditorInput): boolean {
|
||||||
return notebookRegistry.getProviderForFileType(fileExt);
|
if (input instanceof UntitledEditorInput) {
|
||||||
|
let untitledCast: UntitledEditorInput = <UntitledEditorInput>input;
|
||||||
|
return (untitledCast && untitledCast.getModeId() === notebookModeId);
|
||||||
}
|
}
|
||||||
return DEFAULT_NOTEBOOK_PROVIDER;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withService<TService, TResult>(instantiationService: IInstantiationService, serviceId: ServiceIdentifier<TService>, action: (service: TService) => TResult, ): TResult {
|
||||||
|
return instantiationService.invokeFunction(accessor => {
|
||||||
|
let service = accessor.get(serviceId);
|
||||||
|
return action(service);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the given EditorInput is set to either undefined or sql mode
|
* Checks whether the given EditorInput is set to either undefined or sql mode
|
||||||
@@ -229,3 +242,17 @@ function hasFileExtension(extensions: string[], input: EditorInput, checkUntitle
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns file mode - notebookModeId or sqlModeId
|
||||||
|
export function getFileMode(instantiationService: IInstantiationService, resource: URI): string {
|
||||||
|
if (!resource) {
|
||||||
|
return sqlModeId;
|
||||||
|
}
|
||||||
|
return withService<INotebookService, string>(instantiationService, INotebookService, notebookService => {
|
||||||
|
for (const editor of notebookService.listNotebookEditors()) {
|
||||||
|
if (editor.notebookParams.notebookUri === resource) {
|
||||||
|
return notebookModeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sqlModeId;
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -121,7 +121,7 @@ export interface IConnectionManagementService {
|
|||||||
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
||||||
* The purpose is connection by default
|
* The purpose is connection by default
|
||||||
*/
|
*/
|
||||||
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string>;
|
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection', saveConnection?: boolean): Promise<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the successful connection to MRU and send the connection error back to the connection handler for failed connections
|
* Adds the successful connection to MRU and send the connection error back to the connection handler for failed connections
|
||||||
|
|||||||
@@ -380,14 +380,14 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
|||||||
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
||||||
* The purpose is connection by default
|
* The purpose is connection by default
|
||||||
*/
|
*/
|
||||||
public connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string> {
|
public connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection', saveConnection: boolean = false): Promise<string> {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
let ownerUri: string = Utils.generateUri(connection, purpose);
|
let ownerUri: string = Utils.generateUri(connection, purpose);
|
||||||
if (this._connectionStatusManager.isConnected(ownerUri)) {
|
if (this._connectionStatusManager.isConnected(ownerUri)) {
|
||||||
resolve(this._connectionStatusManager.getOriginalOwnerUri(ownerUri));
|
resolve(this._connectionStatusManager.getOriginalOwnerUri(ownerUri));
|
||||||
} else {
|
} else {
|
||||||
const options: IConnectionCompletionOptions = {
|
const options: IConnectionCompletionOptions = {
|
||||||
saveTheConnection: false,
|
saveTheConnection: saveConnection,
|
||||||
showConnectionDialogOnError: true,
|
showConnectionDialogOnError: true,
|
||||||
showDashboard: purpose === 'dashboard',
|
showDashboard: purpose === 'dashboard',
|
||||||
params: undefined,
|
params: undefined,
|
||||||
@@ -769,8 +769,19 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let tokens = await this._accountManagementService.getSecurityToken(account, AzureResource.Sql);
|
let tokensByTenant = await this._accountManagementService.getSecurityToken(account, AzureResource.Sql);
|
||||||
connection.options['azureAccountToken'] = Object.values(tokens)[0].token;
|
let token: string;
|
||||||
|
let tenantId = connection.azureTenantId;
|
||||||
|
if (tenantId && tokensByTenant[tenantId]) {
|
||||||
|
token = tokensByTenant[tenantId].token;
|
||||||
|
} else {
|
||||||
|
let tokens = Object.values(tokensByTenant);
|
||||||
|
if (tokens.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token = Object.values(tokensByTenant)[0].token;
|
||||||
|
}
|
||||||
|
connection.options['azureAccountToken'] = token;
|
||||||
connection.options['password'] = '';
|
connection.options['password'] = '';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
|||||||
this.savePassword = model.savePassword;
|
this.savePassword = model.savePassword;
|
||||||
this.saveProfile = model.saveProfile;
|
this.saveProfile = model.saveProfile;
|
||||||
this._id = model.id;
|
this._id = model.id;
|
||||||
|
this.azureTenantId = model.azureTenantId;
|
||||||
} else {
|
} else {
|
||||||
//Default for a new connection
|
//Default for a new connection
|
||||||
this.savePassword = false;
|
this.savePassword = false;
|
||||||
@@ -84,6 +85,14 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
|||||||
this._id = value;
|
this._id = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get azureTenantId(): string {
|
||||||
|
return this.options['azureTenantId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public set azureTenantId(value: string) {
|
||||||
|
this.options['azureTenantId'] = value;
|
||||||
|
}
|
||||||
|
|
||||||
public get groupFullName(): string {
|
public get groupFullName(): string {
|
||||||
return this._groupName;
|
return this._groupName;
|
||||||
}
|
}
|
||||||
@@ -159,7 +168,8 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
|||||||
userName: this.userName,
|
userName: this.userName,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
saveProfile: this.saveProfile,
|
saveProfile: this.saveProfile,
|
||||||
id: this.id
|
id: this.id,
|
||||||
|
azureTenantId: this.azureTenantId
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -52,9 +52,11 @@ export class ConnectionWidget {
|
|||||||
private _password: string;
|
private _password: string;
|
||||||
private _rememberPasswordCheckBox: Checkbox;
|
private _rememberPasswordCheckBox: Checkbox;
|
||||||
private _azureAccountDropdown: SelectBox;
|
private _azureAccountDropdown: SelectBox;
|
||||||
|
private _azureTenantDropdown: SelectBox;
|
||||||
private _refreshCredentialsLinkBuilder: Builder;
|
private _refreshCredentialsLinkBuilder: Builder;
|
||||||
private _addAzureAccountMessage: string = localize('connectionWidget.AddAzureAccount', 'Add an account...');
|
private _addAzureAccountMessage: string = localize('connectionWidget.AddAzureAccount', 'Add an account...');
|
||||||
private readonly _azureProviderId = 'azurePublicCloud';
|
private readonly _azureProviderId = 'azurePublicCloud';
|
||||||
|
private _azureTenantId: string;
|
||||||
private _azureAccountList: sqlops.Account[];
|
private _azureAccountList: sqlops.Account[];
|
||||||
private _advancedButton: Button;
|
private _advancedButton: Button;
|
||||||
private _callbacks: IConnectionComponentCallbacks;
|
private _callbacks: IConnectionComponentCallbacks;
|
||||||
@@ -215,6 +217,12 @@ export class ConnectionWidget {
|
|||||||
let refreshCredentialsBuilder = DialogHelper.appendRow(this._tableContainer, '', 'connection-label', 'connection-input', 'azure-account-row refresh-credentials-link');
|
let refreshCredentialsBuilder = DialogHelper.appendRow(this._tableContainer, '', 'connection-label', 'connection-input', 'azure-account-row refresh-credentials-link');
|
||||||
this._refreshCredentialsLinkBuilder = refreshCredentialsBuilder.a({ href: '#' }).text(localize('connectionWidget.refreshAzureCredentials', 'Refresh account credentials'));
|
this._refreshCredentialsLinkBuilder = refreshCredentialsBuilder.a({ href: '#' }).text(localize('connectionWidget.refreshAzureCredentials', 'Refresh account credentials'));
|
||||||
|
|
||||||
|
// Azure tenant picker
|
||||||
|
let tenantLabel = localize('connection.azureTenantDropdownLabel', 'Azure AD tenant');
|
||||||
|
let tenantDropdownBuilder = DialogHelper.appendRow(this._tableContainer, tenantLabel, 'connection-label', 'connection-input', 'azure-account-row azure-tenant-row');
|
||||||
|
this._azureTenantDropdown = new SelectBox([], undefined, this._contextViewService, tenantDropdownBuilder.getContainer(), { ariaLabel: tenantLabel });
|
||||||
|
DialogHelper.appendInputSelectBox(tenantDropdownBuilder, this._azureTenantDropdown);
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName];
|
let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName];
|
||||||
let databaseNameBuilder = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input');
|
let databaseNameBuilder = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input');
|
||||||
@@ -308,6 +316,13 @@ export class ConnectionWidget {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._azureTenantDropdown) {
|
||||||
|
this._toDispose.push(styler.attachSelectBoxStyler(this._azureTenantDropdown, this._themeService));
|
||||||
|
this._toDispose.push(this._azureTenantDropdown.onDidSelect((selectInfo) => {
|
||||||
|
this.onAzureTenantSelected(selectInfo.index);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (this._refreshCredentialsLinkBuilder) {
|
if (this._refreshCredentialsLinkBuilder) {
|
||||||
this._toDispose.push(this._refreshCredentialsLinkBuilder.on(DOM.EventType.CLICK, async () => {
|
this._toDispose.push(this._refreshCredentialsLinkBuilder.on(DOM.EventType.CLICK, async () => {
|
||||||
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||||
@@ -426,7 +441,7 @@ export class ConnectionWidget {
|
|||||||
accountDropdownOptions.push(this._addAzureAccountMessage);
|
accountDropdownOptions.push(this._addAzureAccountMessage);
|
||||||
this._azureAccountDropdown.setOptions(accountDropdownOptions);
|
this._azureAccountDropdown.setOptions(accountDropdownOptions);
|
||||||
this._azureAccountDropdown.selectWithOptionName(oldSelection);
|
this._azureAccountDropdown.selectWithOptionName(oldSelection);
|
||||||
this.updateRefreshCredentialsLink();
|
await this.onAzureAccountSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateRefreshCredentialsLink(): Promise<void> {
|
private async updateRefreshCredentialsLink(): Promise<void> {
|
||||||
@@ -441,7 +456,6 @@ export class ConnectionWidget {
|
|||||||
private async onAzureAccountSelected(): Promise<void> {
|
private async onAzureAccountSelected(): Promise<void> {
|
||||||
// Reset the dropdown's validation message if the old selection was not valid but the new one is
|
// Reset the dropdown's validation message if the old selection was not valid but the new one is
|
||||||
this.validateAzureAccountSelection(false);
|
this.validateAzureAccountSelection(false);
|
||||||
this._refreshCredentialsLinkBuilder.display('none');
|
|
||||||
|
|
||||||
// Open the add account dialog if needed, then select the added account
|
// Open the add account dialog if needed, then select the added account
|
||||||
if (this._azureAccountDropdown.value === this._addAzureAccountMessage) {
|
if (this._azureAccountDropdown.value === this._addAzureAccountMessage) {
|
||||||
@@ -461,6 +475,35 @@ export class ConnectionWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updateRefreshCredentialsLink();
|
this.updateRefreshCredentialsLink();
|
||||||
|
|
||||||
|
// Display the tenant select box if needed
|
||||||
|
const hideTenantsClassName = 'hide-azure-tenants';
|
||||||
|
let selectedAccount = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||||
|
if (selectedAccount && selectedAccount.properties.tenants && selectedAccount.properties.tenants.length > 1) {
|
||||||
|
// There are multiple tenants available so let the user select one
|
||||||
|
let options = selectedAccount.properties.tenants.map(tenant => tenant.displayName);
|
||||||
|
this._azureTenantDropdown.setOptions(options);
|
||||||
|
this._tableContainer.getContainer().classList.remove(hideTenantsClassName);
|
||||||
|
this.onAzureTenantSelected(0);
|
||||||
|
} else {
|
||||||
|
if (selectedAccount && selectedAccount.properties.tenants && selectedAccount.properties.tenants.length === 1) {
|
||||||
|
this._azureTenantId = selectedAccount.properties.tenants[0].id;
|
||||||
|
} else {
|
||||||
|
this._azureTenantId = undefined;
|
||||||
|
}
|
||||||
|
this._tableContainer.getContainer().classList.add(hideTenantsClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onAzureTenantSelected(tenantIndex: number): void {
|
||||||
|
this._azureTenantId = undefined;
|
||||||
|
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||||
|
if (account && account.properties.tenants) {
|
||||||
|
let tenant = account.properties.tenants[tenantIndex];
|
||||||
|
if (tenant) {
|
||||||
|
this._azureTenantId = tenant.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private serverNameChanged(serverName: string) {
|
private serverNameChanged(serverName: string) {
|
||||||
@@ -518,6 +561,7 @@ export class ConnectionWidget {
|
|||||||
this._passwordInputBox.value = connectionInfo.password ? Constants.passwordChars : '';
|
this._passwordInputBox.value = connectionInfo.password ? Constants.passwordChars : '';
|
||||||
this._password = this.getModelValue(connectionInfo.password);
|
this._password = this.getModelValue(connectionInfo.password);
|
||||||
this._saveProfile = connectionInfo.saveProfile;
|
this._saveProfile = connectionInfo.saveProfile;
|
||||||
|
this._azureTenantId = connectionInfo.azureTenantId;
|
||||||
let groupName: string;
|
let groupName: string;
|
||||||
if (this._saveProfile) {
|
if (this._saveProfile) {
|
||||||
if (!connectionInfo.groupFullName) {
|
if (!connectionInfo.groupFullName) {
|
||||||
@@ -545,6 +589,26 @@ export class ConnectionWidget {
|
|||||||
|
|
||||||
if (this._authTypeSelectBox) {
|
if (this._authTypeSelectBox) {
|
||||||
this.onAuthTypeSelected(this._authTypeSelectBox.value);
|
this.onAuthTypeSelected(this._authTypeSelectBox.value);
|
||||||
|
} else {
|
||||||
|
let tableContainerElement = this._tableContainer.getContainer();
|
||||||
|
tableContainerElement.classList.remove('hide-username-password');
|
||||||
|
tableContainerElement.classList.add('hide-azure-accounts');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authType === AuthenticationType.AzureMFA) {
|
||||||
|
this.fillInAzureAccountOptions().then(async () => {
|
||||||
|
this._azureAccountDropdown.selectWithOptionName(this.getModelValue(connectionInfo.userName));
|
||||||
|
await this.onAzureAccountSelected();
|
||||||
|
let tenantId = connectionInfo.azureTenantId;
|
||||||
|
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||||
|
if (account && account.properties.tenants.length > 1) {
|
||||||
|
let tenant = account.properties.tenants.find(tenant => tenant.id === tenantId);
|
||||||
|
if (tenant) {
|
||||||
|
this._azureTenantDropdown.selectWithOptionName(tenant.displayName);
|
||||||
|
}
|
||||||
|
this.onAzureTenantSelected(this._azureTenantDropdown.values.indexOf(this._azureTenantDropdown.value));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable connect button if -
|
// Disable connect button if -
|
||||||
@@ -712,6 +776,9 @@ export class ConnectionWidget {
|
|||||||
model.saveProfile = true;
|
model.saveProfile = true;
|
||||||
model.groupId = this.findGroupId(model.groupFullName);
|
model.groupId = this.findGroupId(model.groupFullName);
|
||||||
}
|
}
|
||||||
|
if (this.authType === AuthenticationType.AzureMFA) {
|
||||||
|
model.azureTenantId = this._azureTenantId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return validInputs;
|
return validInputs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,10 +105,12 @@
|
|||||||
background: url('clear-search-results.svg');
|
background: url('clear-search-results.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
.vs-dark .search-action.clear-search-results,
|
.vs-dark .search-action.clear-search-results,
|
||||||
.hc-black .search-action.clear-search-results {
|
.hc-black .search-action.clear-search-results {
|
||||||
background: url('clear-search-results-dark.svg');
|
background: url('clear-search-results-dark.svg');
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
.connection-details-title {
|
.connection-details-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -128,3 +130,7 @@
|
|||||||
.hide-refresh-link .azure-account-row.refresh-credentials-link {
|
.hide-refresh-link .azure-account-row.refresh-credentials-link {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-azure-tenants .azure-tenant-row {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -168,8 +168,7 @@ export const DashboardModule = (params, selector: string, instantiationService:
|
|||||||
if (e instanceof NavigationEnd) {
|
if (e instanceof NavigationEnd) {
|
||||||
this.navigations++;
|
this.navigations++;
|
||||||
TelemetryUtils.addTelemetry(this.telemetryService, TelemetryKeys.DashboardNavigated, {
|
TelemetryUtils.addTelemetry(this.telemetryService, TelemetryKeys.DashboardNavigated, {
|
||||||
numberOfNavigations: this.navigations,
|
numberOfNavigations: this.navigations
|
||||||
routeUrl: e.url
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { $ } from 'vs/base/browser/dom';
|
|
||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
|
|
||||||
export class DBCellValue {
|
export class DBCellValue {
|
||||||
@@ -41,20 +40,24 @@ export function hyperLinkFormatter(row: number, cell: any, value: any, columnDef
|
|||||||
*/
|
*/
|
||||||
export function textFormatter(row: number, cell: any, value: any, columnDef: any, dataContext: any): string {
|
export function textFormatter(row: number, cell: any, value: any, columnDef: any, dataContext: any): string {
|
||||||
let cellClasses = 'grid-cell-value-container';
|
let cellClasses = 'grid-cell-value-container';
|
||||||
let valueToDisplay: string = '';
|
let valueToDisplay = '';
|
||||||
|
let titleValue = '';
|
||||||
|
|
||||||
if (DBCellValue.isDBCellValue(value)) {
|
if (DBCellValue.isDBCellValue(value)) {
|
||||||
valueToDisplay = 'NULL';
|
valueToDisplay = 'NULL';
|
||||||
if (!value.isNull) {
|
if (!value.isNull) {
|
||||||
valueToDisplay = escape(value.displayValue.replace(/(\r\n|\n|\r)/g, ' '));
|
valueToDisplay = value.displayValue.replace(/(\r\n|\n|\r)/g, ' ');
|
||||||
|
valueToDisplay = escape(valueToDisplay.length > 250 ? valueToDisplay.slice(0, 250) + '...' : valueToDisplay);
|
||||||
|
titleValue = value.displayValue;
|
||||||
} else {
|
} else {
|
||||||
cellClasses += ' missing-value';
|
cellClasses += ' missing-value';
|
||||||
}
|
}
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
valueToDisplay = escape(value);
|
valueToDisplay = escape(value.length > 250 ? value.slice(0, 250) + '...' : value);
|
||||||
|
titleValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<span title="${valueToDisplay}" class="${cellClasses}">${valueToDisplay}</span>`;
|
return `<span title="${titleValue}" class="${cellClasses}">${valueToDisplay}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The following code is a rewrite over the both formatter function using dom builder
|
/** The following code is a rewrite over the both formatter function using dom builder
|
||||||
|
|||||||
@@ -343,6 +343,9 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
handleResultSet(self: EditDataComponent, event: any): void {
|
handleResultSet(self: EditDataComponent, event: any): void {
|
||||||
// Clone the data before altering it to avoid impacting other subscribers
|
// Clone the data before altering it to avoid impacting other subscribers
|
||||||
let resultSet = Object.assign({}, event.data);
|
let resultSet = Object.assign({}, event.data);
|
||||||
|
if (!resultSet.complete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add an extra 'new row'
|
// Add an extra 'new row'
|
||||||
resultSet.rowCount++;
|
resultSet.rowCount++;
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import { AlertsViewComponent } from 'sql/parts/jobManagement/views/alertsView.co
|
|||||||
import { OperatorsViewComponent } from 'sql/parts/jobManagement/views/operatorsView.component';
|
import { OperatorsViewComponent } from 'sql/parts/jobManagement/views/operatorsView.component';
|
||||||
import { ProxiesViewComponent } from 'sql/parts/jobManagement/views/proxiesView.component';
|
import { ProxiesViewComponent } from 'sql/parts/jobManagement/views/proxiesView.component';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||||
|
import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||||
|
|
||||||
export enum JobActions {
|
export enum JobActions {
|
||||||
Run = 'run',
|
Run = 'run',
|
||||||
@@ -80,7 +83,8 @@ export class RunJobAction extends Action {
|
|||||||
constructor(
|
constructor(
|
||||||
@INotificationService private notificationService: INotificationService,
|
@INotificationService private notificationService: INotificationService,
|
||||||
@IJobManagementService private jobManagementService: IJobManagementService,
|
@IJobManagementService private jobManagementService: IJobManagementService,
|
||||||
@IInstantiationService private instantationService: IInstantiationService
|
@IInstantiationService private instantationService: IInstantiationService,
|
||||||
|
@ITelemetryService private telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(RunJobAction.ID, RunJobAction.LABEL, 'runJobIcon');
|
super(RunJobAction.ID, RunJobAction.LABEL, 'runJobIcon');
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,7 @@ export class RunJobAction extends Action {
|
|||||||
let jobName = context.agentJobInfo.name;
|
let jobName = context.agentJobInfo.name;
|
||||||
let ownerUri = context.ownerUri;
|
let ownerUri = context.ownerUri;
|
||||||
let refreshAction = this.instantationService.createInstance(JobsRefreshAction);
|
let refreshAction = this.instantationService.createInstance(JobsRefreshAction);
|
||||||
|
this.telemetryService.publicLog(TelemetryKeys.RunAgentJob);
|
||||||
return new TPromise<boolean>((resolve, reject) => {
|
return new TPromise<boolean>((resolve, reject) => {
|
||||||
this.jobManagementService.jobAction(ownerUri, jobName, JobActions.Run).then(result => {
|
this.jobManagementService.jobAction(ownerUri, jobName, JobActions.Run).then(result => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -118,7 +123,8 @@ export class StopJobAction extends Action {
|
|||||||
constructor(
|
constructor(
|
||||||
@INotificationService private notificationService: INotificationService,
|
@INotificationService private notificationService: INotificationService,
|
||||||
@IJobManagementService private jobManagementService: IJobManagementService,
|
@IJobManagementService private jobManagementService: IJobManagementService,
|
||||||
@IInstantiationService private instantationService: IInstantiationService
|
@IInstantiationService private instantationService: IInstantiationService,
|
||||||
|
@ITelemetryService private telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(StopJobAction.ID, StopJobAction.LABEL, 'stopJobIcon');
|
super(StopJobAction.ID, StopJobAction.LABEL, 'stopJobIcon');
|
||||||
}
|
}
|
||||||
@@ -127,6 +133,7 @@ export class StopJobAction extends Action {
|
|||||||
let jobName = context.agentJobInfo.name;
|
let jobName = context.agentJobInfo.name;
|
||||||
let ownerUri = context.ownerUri;
|
let ownerUri = context.ownerUri;
|
||||||
let refreshAction = this.instantationService.createInstance(JobsRefreshAction);
|
let refreshAction = this.instantationService.createInstance(JobsRefreshAction);
|
||||||
|
this.telemetryService.publicLog(TelemetryKeys.StopAgentJob);
|
||||||
return new TPromise<boolean>((resolve, reject) => {
|
return new TPromise<boolean>((resolve, reject) => {
|
||||||
this.jobManagementService.jobAction(ownerUri, jobName, JobActions.Stop).then(result => {
|
this.jobManagementService.jobAction(ownerUri, jobName, JobActions.Stop).then(result => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -174,7 +181,8 @@ export class DeleteJobAction extends Action {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IJobManagementService private _jobService: IJobManagementService
|
@IJobManagementService private _jobService: IJobManagementService,
|
||||||
|
@ITelemetryService private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(DeleteJobAction.ID, DeleteJobAction.LABEL);
|
super(DeleteJobAction.ID, DeleteJobAction.LABEL);
|
||||||
}
|
}
|
||||||
@@ -188,6 +196,7 @@ export class DeleteJobAction extends Action {
|
|||||||
[{
|
[{
|
||||||
label: DeleteJobAction.LABEL,
|
label: DeleteJobAction.LABEL,
|
||||||
run: () => {
|
run: () => {
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentJob);
|
||||||
self._jobService.deleteJob(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
self._jobService.deleteJob(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
||||||
if (!result || !result.success) {
|
if (!result || !result.success) {
|
||||||
let errorMessage = nls.localize("jobaction.failedToDeleteJob", "Could not delete job '{0}'.\nError: {1}",
|
let errorMessage = nls.localize("jobaction.failedToDeleteJob", "Could not delete job '{0}'.\nError: {1}",
|
||||||
@@ -234,7 +243,8 @@ export class DeleteStepAction extends Action {
|
|||||||
constructor(
|
constructor(
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IJobManagementService private _jobService: IJobManagementService,
|
@IJobManagementService private _jobService: IJobManagementService,
|
||||||
@IInstantiationService private instantationService: IInstantiationService
|
@IInstantiationService private instantationService: IInstantiationService,
|
||||||
|
@ITelemetryService private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(DeleteStepAction.ID, DeleteStepAction.LABEL);
|
super(DeleteStepAction.ID, DeleteStepAction.LABEL);
|
||||||
}
|
}
|
||||||
@@ -249,6 +259,7 @@ export class DeleteStepAction extends Action {
|
|||||||
[{
|
[{
|
||||||
label: DeleteStepAction.LABEL,
|
label: DeleteStepAction.LABEL,
|
||||||
run: () => {
|
run: () => {
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentJobStep);
|
||||||
self._jobService.deleteJobStep(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
self._jobService.deleteJobStep(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
||||||
if (!result || !result.success) {
|
if (!result || !result.success) {
|
||||||
let errorMessage = nls.localize("jobaction.failedToDeleteStep", "Could not delete step '{0}'.\nError: {1}",
|
let errorMessage = nls.localize("jobaction.failedToDeleteStep", "Could not delete step '{0}'.\nError: {1}",
|
||||||
@@ -318,7 +329,8 @@ export class DeleteAlertAction extends Action {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IJobManagementService private _jobService: IJobManagementService
|
@IJobManagementService private _jobService: IJobManagementService,
|
||||||
|
@ITelemetryService private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(DeleteAlertAction.ID, DeleteAlertAction.LABEL);
|
super(DeleteAlertAction.ID, DeleteAlertAction.LABEL);
|
||||||
}
|
}
|
||||||
@@ -332,6 +344,7 @@ export class DeleteAlertAction extends Action {
|
|||||||
[{
|
[{
|
||||||
label: DeleteAlertAction.LABEL,
|
label: DeleteAlertAction.LABEL,
|
||||||
run: () => {
|
run: () => {
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentAlert);
|
||||||
self._jobService.deleteAlert(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
self._jobService.deleteAlert(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
||||||
if (!result || !result.success) {
|
if (!result || !result.success) {
|
||||||
let errorMessage = nls.localize("jobaction.failedToDeleteAlert", "Could not delete alert '{0}'.\nError: {1}",
|
let errorMessage = nls.localize("jobaction.failedToDeleteAlert", "Could not delete alert '{0}'.\nError: {1}",
|
||||||
@@ -397,7 +410,8 @@ export class DeleteOperatorAction extends Action {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IJobManagementService private _jobService: IJobManagementService
|
@IJobManagementService private _jobService: IJobManagementService,
|
||||||
|
@ITelemetryService private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(DeleteOperatorAction.ID, DeleteOperatorAction.LABEL);
|
super(DeleteOperatorAction.ID, DeleteOperatorAction.LABEL);
|
||||||
}
|
}
|
||||||
@@ -411,6 +425,7 @@ export class DeleteOperatorAction extends Action {
|
|||||||
[{
|
[{
|
||||||
label: DeleteOperatorAction.LABEL,
|
label: DeleteOperatorAction.LABEL,
|
||||||
run: () => {
|
run: () => {
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentOperator);
|
||||||
self._jobService.deleteOperator(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
self._jobService.deleteOperator(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
||||||
if (!result || !result.success) {
|
if (!result || !result.success) {
|
||||||
let errorMessage = nls.localize("jobaction.failedToDeleteOperator", "Could not delete operator '{0}'.\nError: {1}",
|
let errorMessage = nls.localize("jobaction.failedToDeleteOperator", "Could not delete operator '{0}'.\nError: {1}",
|
||||||
@@ -477,7 +492,8 @@ export class DeleteProxyAction extends Action {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IJobManagementService private _jobService: IJobManagementService
|
@IJobManagementService private _jobService: IJobManagementService,
|
||||||
|
@ITelemetryService private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(DeleteProxyAction.ID, DeleteProxyAction.LABEL);
|
super(DeleteProxyAction.ID, DeleteProxyAction.LABEL);
|
||||||
}
|
}
|
||||||
@@ -491,6 +507,7 @@ export class DeleteProxyAction extends Action {
|
|||||||
[{
|
[{
|
||||||
label: DeleteProxyAction.LABEL,
|
label: DeleteProxyAction.LABEL,
|
||||||
run: () => {
|
run: () => {
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentProxy);
|
||||||
self._jobService.deleteProxy(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
self._jobService.deleteProxy(actionInfo.ownerUri, actionInfo.targetObject).then(result => {
|
||||||
if (!result || !result.success) {
|
if (!result || !result.success) {
|
||||||
let errorMessage = nls.localize("jobaction.failedToDeleteProxy", "Could not delete proxy '{0}'.\nError: {1}",
|
let errorMessage = nls.localize("jobaction.failedToDeleteProxy", "Could not delete proxy '{0}'.\nError: {1}",
|
||||||
|
|||||||
@@ -304,14 +304,6 @@ table.jobprevruns > tbody {
|
|||||||
background-image: url('refresh_inverse.svg');
|
background-image: url('refresh_inverse.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
jobsview-component .agent-actionbar-container {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agent-actionbar-container .monaco-action-bar > ul.actions-container > li.action-item {
|
.agent-actionbar-container .monaco-action-bar > ul.actions-container > li.action-item {
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
@@ -414,4 +406,11 @@ jobsview-component .jobview-grid .slick-cell.error-row {
|
|||||||
#proxiesDiv .proxyview-proxynameindicatordisabled {
|
#proxiesDiv .proxyview-proxynameindicatordisabled {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
background: red;
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jobsDiv jobsview-component .monaco-toolbar.carbon-taskbar,
|
||||||
|
#operatorsDiv joboperatorsview-component .monaco-toolbar.carbon-taskbar,
|
||||||
|
#alertsDiv jobalertsview-component .monaco-toolbar.carbon-taskbar,
|
||||||
|
#proxiesDiv jobproxiesview-component .monaco-toolbar.carbon-taskbar {
|
||||||
|
margin: 10px 0px 10px 0px;
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
<!-- Job History details -->
|
<!-- Job History details -->
|
||||||
<div class='history-details'>
|
<div class='history-details'>
|
||||||
<!-- Previous run list -->
|
<!-- Previous run list -->
|
||||||
<div class="prev-run-list-container" style="min-width: 275px; height: 75vh">
|
<div class="prev-run-list-container" style="min-width: 250px">
|
||||||
<table *ngIf="_showPreviousRuns === true">
|
<table *ngIf="_showPreviousRuns === true">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="date-column">
|
<td class="date-column">
|
||||||
@@ -89,7 +89,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h3 *ngIf="_showPreviousRuns === false" style="text-align: center">No Previous Runs Available</h3>
|
<h3 *ngIf="_showPreviousRuns === false" style="text-align: center">No Previous Runs Available</h3>
|
||||||
<div #table class="step-table prev-run-list" style="position: relative; height: 100%; width: 100%"></div>
|
<div class="step-table prev-run-list" style="position: relative; width: 100%">
|
||||||
|
<div #table style="position: absolute; width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Job Steps -->
|
<!-- Job Steps -->
|
||||||
<div class="job-steps" id="job-steps">
|
<div class="job-steps" id="job-steps">
|
||||||
@@ -154,7 +156,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div #jobsteps style="height: 100%">
|
<div #jobsteps *ngIf="showSteps === true" style="flex: 1 1 auto; position: relative">
|
||||||
<jobstepsview-component *ngIf="showSteps === true"></jobstepsview-component>
|
<jobstepsview-component *ngIf="showSteps === true"></jobstepsview-component>
|
||||||
</div>
|
</div>
|
||||||
<h3 *ngIf="showSteps === false">No Steps Available</h3>
|
<h3 *ngIf="showSteps === false">No Steps Available</h3>
|
||||||
|
|||||||
@@ -23,13 +23,14 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
|
|||||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
|
||||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { JobManagementView } from 'sql/parts/jobManagement/views/jobManagementView';
|
import { JobManagementView } from 'sql/parts/jobManagement/views/jobManagementView';
|
||||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||||
|
|
||||||
export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
|
export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
|
||||||
|
|
||||||
@@ -64,7 +65,6 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
|||||||
private _agentJobInfo: sqlops.AgentJobInfo;
|
private _agentJobInfo: sqlops.AgentJobInfo;
|
||||||
private _noJobsAvailable: boolean = false;
|
private _noJobsAvailable: boolean = false;
|
||||||
|
|
||||||
private static readonly INITIAL_TREE_HEIGHT: number = 780;
|
|
||||||
private static readonly HEADING_HEIGHT: number = 24;
|
private static readonly HEADING_HEIGHT: number = 24;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -77,7 +77,8 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
|||||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||||
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
|
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
|
||||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||||
@Inject(IDashboardService) dashboardService: IDashboardService
|
@Inject(IDashboardService) dashboardService: IDashboardService,
|
||||||
|
@Inject(ITelemetryService) private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||||
this._treeController = new JobHistoryController();
|
this._treeController = new JobHistoryController();
|
||||||
@@ -141,9 +142,9 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
|||||||
renderer: this._treeRenderer
|
renderer: this._treeRenderer
|
||||||
}, {verticalScrollMode: ScrollbarVisibility.Visible});
|
}, {verticalScrollMode: ScrollbarVisibility.Visible});
|
||||||
this._register(attachListStyler(this._tree, this.themeService));
|
this._register(attachListStyler(this._tree, this.themeService));
|
||||||
this._tree.layout(JobHistoryComponent.INITIAL_TREE_HEIGHT);
|
this._tree.layout(dom.getContentHeight(this._tableContainer.nativeElement));
|
||||||
this.initActionBar();
|
this.initActionBar();
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.JobHistoryView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadHistory() {
|
private loadHistory() {
|
||||||
@@ -293,6 +294,7 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
|||||||
if (historyDetails && statusBar) {
|
if (historyDetails && statusBar) {
|
||||||
let historyBottom = historyDetails.getBoundingClientRect().bottom;
|
let historyBottom = historyDetails.getBoundingClientRect().bottom;
|
||||||
let statusTop = statusBar.getBoundingClientRect().top;
|
let statusTop = statusBar.getBoundingClientRect().top;
|
||||||
|
|
||||||
let height: number = statusTop - historyBottom - JobHistoryComponent.HEADING_HEIGHT;
|
let height: number = statusTop - historyBottom - JobHistoryComponent.HEADING_HEIGHT;
|
||||||
|
|
||||||
if (this._table) {
|
if (this._table) {
|
||||||
@@ -302,14 +304,7 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._tree) {
|
if (this._tree) {
|
||||||
this._tree.layout(height);
|
this._tree.layout(dom.getContentHeight(this._tableContainer.nativeElement));
|
||||||
}
|
|
||||||
|
|
||||||
if (this._jobStepsView) {
|
|
||||||
let element = this._jobStepsView.nativeElement as HTMLElement;
|
|
||||||
if (element) {
|
|
||||||
element.style.height = height + 'px';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
.all-jobs {
|
.all-jobs {
|
||||||
display: inline;
|
display: inline;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.overview-container .overview-tab .resultsViewCollapsible {
|
.overview-container .overview-tab .resultsViewCollapsible {
|
||||||
@@ -177,17 +176,17 @@ table.step-list tr.step-row td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.history-details {
|
.history-details {
|
||||||
height: 100%;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-details > .job-steps {
|
.history-details > .job-steps {
|
||||||
display: block;
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
border-left: 3px solid #f4f4f4;
|
border-left: 3px solid #f4f4f4;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
height: 100%;
|
flex-direction: column;
|
||||||
width: 90%;
|
width: 100%;
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs-dark .history-details > .job-steps {
|
.vs-dark .history-details > .job-steps {
|
||||||
@@ -241,13 +240,22 @@ table.step-list tr.step-row td {
|
|||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.steps-tree .monaco-tree .monaco-tree-row {
|
.step-table {
|
||||||
white-space: normal;
|
flex: 1 1 auto;
|
||||||
min-height: 40px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobhistory-component .jobhistory-heading-container {
|
.prev-run-list-container {
|
||||||
display: -webkit-box;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobhistory-component {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobhistory-component > .jobhistory-heading-container {
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobhistory-component > .jobhistory-heading-container > .icon.in-progress {
|
jobhistory-component > .jobhistory-heading-container > .icon.in-progress {
|
||||||
@@ -257,14 +265,22 @@ jobhistory-component > .jobhistory-heading-container > .icon.in-progress {
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
jobhistory-component > .agent-actionbar-container {
|
||||||
border-top: 3px solid #f4f4f4;
|
border-top: 3px solid #f4f4f4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs-dark jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
.vs-dark jobhistory-component > .agent-actionbar-container {
|
||||||
border-top: 3px solid #444444;
|
border-top: 3px solid #444444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hc-black jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
.hc-black jobhistory-component > .agent-actionbar-container {
|
||||||
border-top: 3px solid #2b56f2;
|
border-top: 3px solid #2b56f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobhistory-component .step-table.prev-run-list .monaco-tree-wrapper .monaco-tree-row {
|
||||||
|
width: 96%;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobhistory-component .agent-actionbar-container > .monaco-toolbar.carbon-taskbar {
|
||||||
|
margin: 10px 0px 5px 0px;
|
||||||
|
}
|
||||||
@@ -22,4 +22,6 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class='steps-tree' #table style="height: 100%; width: 100%"></div>
|
<div class='steps-tree' style="flex: 1 1 auto; position: relative">
|
||||||
|
<div #table style="position: absolute; height: 100%; width: 100%" ></div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import 'vs/css!./jobStepsView';
|
import 'vs/css!./jobStepsView';
|
||||||
|
|
||||||
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Injectable, AfterContentChecked } from '@angular/core';
|
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Injectable, AfterContentChecked } from '@angular/core';
|
||||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||||
@@ -20,7 +21,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||||
import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||||
|
|
||||||
export const JOBSTEPSVIEW_SELECTOR: string = 'jobstepsview-component';
|
export const JOBSTEPSVIEW_SELECTOR: string = 'jobstepsview-component';
|
||||||
|
|
||||||
@@ -36,7 +38,6 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
private _treeDataSource = new JobStepsViewDataSource();
|
private _treeDataSource = new JobStepsViewDataSource();
|
||||||
private _treeRenderer = new JobStepsViewRenderer();
|
private _treeRenderer = new JobStepsViewRenderer();
|
||||||
private _treeFilter = new JobStepsViewFilter();
|
private _treeFilter = new JobStepsViewFilter();
|
||||||
private _pageSize = 1024;
|
|
||||||
|
|
||||||
@ViewChild('table') private _tableContainer: ElementRef;
|
@ViewChild('table') private _tableContainer: ElementRef;
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||||
@Inject(IDashboardService) dashboardService: IDashboardService
|
@Inject(IDashboardService) dashboardService: IDashboardService,
|
||||||
|
@Inject(ITelemetryService) private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||||
}
|
}
|
||||||
@@ -57,17 +59,8 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
ngAfterContentChecked() {
|
ngAfterContentChecked() {
|
||||||
if (this._jobHistoryComponent.stepRows.length > 0) {
|
if (this._jobHistoryComponent.stepRows.length > 0) {
|
||||||
this._treeDataSource.data = this._jobHistoryComponent.stepRows;
|
this._treeDataSource.data = this._jobHistoryComponent.stepRows;
|
||||||
if (!this._tree) {
|
|
||||||
this._tree = new Tree(this._tableContainer.nativeElement, {
|
|
||||||
controller: this._treeController,
|
|
||||||
dataSource: this._treeDataSource,
|
|
||||||
filter: this._treeFilter,
|
|
||||||
renderer: this._treeRenderer
|
|
||||||
}, { verticalScrollMode: ScrollbarVisibility.Visible });
|
|
||||||
this._register(attachListStyler(this._tree, this.themeService));
|
|
||||||
}
|
|
||||||
this._tree.layout(this._pageSize);
|
|
||||||
this._tree.setInput(new JobStepsViewModel());
|
this._tree.setInput(new JobStepsViewModel());
|
||||||
|
this.layout();
|
||||||
$('jobstepsview-component .steps-tree .monaco-tree').attr('tabIndex', '-1');
|
$('jobstepsview-component .steps-tree .monaco-tree').attr('tabIndex', '-1');
|
||||||
$('jobstepsview-component .steps-tree .monaco-tree-row').attr('tabIndex', '0');
|
$('jobstepsview-component .steps-tree .monaco-tree-row').attr('tabIndex', '0');
|
||||||
}
|
}
|
||||||
@@ -79,14 +72,20 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
dataSource: this._treeDataSource,
|
dataSource: this._treeDataSource,
|
||||||
filter: this._treeFilter,
|
filter: this._treeFilter,
|
||||||
renderer: this._treeRenderer
|
renderer: this._treeRenderer
|
||||||
}, {verticalScrollMode: ScrollbarVisibility.Visible});
|
}, {verticalScrollMode: ScrollbarVisibility.Visible, horizontalScrollMode: ScrollbarVisibility.Visible });
|
||||||
|
this.layout();
|
||||||
this._register(attachListStyler(this._tree, this.themeService));
|
this._register(attachListStyler(this._tree, this.themeService));
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.JobStepsView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onFirstVisible() {
|
public onFirstVisible() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout() {
|
public layout() {
|
||||||
|
if (this._tree) {
|
||||||
|
let treeheight = dom.getContentHeight(this._tableContainer.nativeElement);
|
||||||
|
this._tree.layout(treeheight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,5 +78,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
jobstepsview-component {
|
jobstepsview-component {
|
||||||
padding-top: 10px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobstepsview-component .steps-tree .monaco-tree-wrapper .monaco-tree-row {
|
||||||
|
width: 99.2%;
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { $ } from 'vs/base/browser/builder';
|
||||||
import * as tree from 'vs/base/parts/tree/browser/tree';
|
import * as tree from 'vs/base/parts/tree/browser/tree';
|
||||||
import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
|
import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
|
||||||
import { Promise, TPromise } from 'vs/base/common/winjs.base';
|
import { Promise, TPromise } from 'vs/base/common/winjs.base';
|
||||||
@@ -86,7 +87,7 @@ export class JobStepsViewRenderer implements tree.IRenderer {
|
|||||||
private _statusIcon: HTMLElement;
|
private _statusIcon: HTMLElement;
|
||||||
|
|
||||||
public getHeight(tree: tree.ITree, element: JobStepsViewRow): number {
|
public getHeight(tree: tree.ITree, element: JobStepsViewRow): number {
|
||||||
return 22 * Math.ceil(element.message.length/JobManagementUtilities.jobMessageLength);
|
return 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTemplateId(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): string {
|
public getTemplateId(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): string {
|
||||||
@@ -118,6 +119,7 @@ export class JobStepsViewRenderer implements tree.IRenderer {
|
|||||||
let stepMessageCol: HTMLElement = DOM.$('div');
|
let stepMessageCol: HTMLElement = DOM.$('div');
|
||||||
stepMessageCol.className = 'tree-message-col';
|
stepMessageCol.className = 'tree-message-col';
|
||||||
stepMessageCol.innerText = element.message;
|
stepMessageCol.innerText = element.message;
|
||||||
|
$(templateData.label).empty();
|
||||||
templateData.label.appendChild(stepIdCol);
|
templateData.label.appendChild(stepIdCol);
|
||||||
templateData.label.appendChild(stepNameCol);
|
templateData.label.appendChild(stepNameCol);
|
||||||
templateData.label.appendChild(stepMessageCol);
|
templateData.label.appendChild(stepMessageCol);
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import { IDashboardService } from 'sql/services/dashboard/common/dashboardServic
|
|||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { tableBackground, cellBackground, cellBorderColor } from 'sql/common/theme/colors';
|
import { tableBackground, cellBackground, cellBorderColor } from 'sql/common/theme/colors';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||||
|
|
||||||
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||||
export const ROW_HEIGHT: number = 45;
|
export const ROW_HEIGHT: number = 45;
|
||||||
@@ -106,7 +108,8 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||||
@Inject(IDashboardService) _dashboardService: IDashboardService
|
@Inject(IDashboardService) _dashboardService: IDashboardService,
|
||||||
|
@Inject(ITelemetryService) private _telemetryService: ITelemetryService
|
||||||
) {
|
) {
|
||||||
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||||
this._didTabChange = false;
|
this._didTabChange = false;
|
||||||
@@ -127,6 +130,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
this._visibilityElement = this._gridEl;
|
this._visibilityElement = this._gridEl;
|
||||||
this._parentComponent = this._agentViewComponent;
|
this._parentComponent = this._agentViewComponent;
|
||||||
this._register(this._themeService.onDidColorThemeChange(e => this.updateTheme(e)));
|
this._register(this._themeService.onDidColorThemeChange(e => this.updateTheme(e)));
|
||||||
|
this._telemetryService.publicLog(TelemetryKeys.JobsView);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -587,7 +591,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
|
|
||||||
private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
||||||
const self = this;
|
const self = this;
|
||||||
jobs.forEach(async (job) => {
|
await Promise.all(jobs.map(async (job) => {
|
||||||
await this._jobManagementService.getJobHistory(ownerUri, job.jobId, job.name).then(async(result) => {
|
await this._jobManagementService.getJobHistory(ownerUri, job.jobId, job.name).then(async(result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
self.jobSteps[job.jobId] = result.steps ? result.steps : [];
|
self.jobSteps[job.jobId] = result.steps ? result.steps : [];
|
||||||
@@ -618,32 +622,23 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
|
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
|
||||||
let chartHeights = this.getChartHeights(jobHistories);
|
let chartHeights = this.getChartHeights(jobHistories);
|
||||||
let runCharts = [];
|
let runCharts = [];
|
||||||
for (let i = 0; i < jobHistories.length; i++) {
|
for (let i = 0; i < chartHeights.length; i++) {
|
||||||
let runGraph = $(`table#${jobId}.jobprevruns > tbody > tr > td > div.bar${i}`);
|
let runGraph = $(`table#${jobId}.jobprevruns > tbody > tr > td > div.bar${i}`);
|
||||||
if (jobHistories && jobHistories.length > 0) {
|
runGraph.css('height', chartHeights[i]);
|
||||||
runGraph.css('height', chartHeights[i]);
|
let bgColor = jobHistories[i].runStatus === 0 ? 'red' : 'green';
|
||||||
let bgColor = jobHistories[i].runStatus === 0 ? 'red' : 'green';
|
runGraph.css('background', bgColor);
|
||||||
runGraph.css('background', bgColor);
|
runGraph.hover((e) => {
|
||||||
runGraph.hover((e) => {
|
let currentTarget = e.currentTarget;
|
||||||
let currentTarget = e.currentTarget;
|
currentTarget.title = jobHistories[i].runDuration;
|
||||||
currentTarget.title = jobHistories[i].runDuration;
|
});
|
||||||
});
|
if (runGraph.get(0)) {
|
||||||
if (runGraph.get(0)) {
|
runCharts.push(runGraph.get(0).outerHTML);
|
||||||
runCharts.push(runGraph.get(0).outerHTML);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
runGraph.css('height', '5px');
|
|
||||||
runGraph.css('background', 'red');
|
|
||||||
runGraph.hover((e) => {
|
|
||||||
let currentTarget = e.currentTarget;
|
|
||||||
currentTarget.title = 'Job not run.';
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (runCharts.length > 0) {
|
if (runCharts.length > 0) {
|
||||||
@@ -654,7 +649,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
// chart height normalization logic
|
// chart height normalization logic
|
||||||
private getChartHeights(jobHistories: sqlops.AgentJobHistoryInfo[]): string[] {
|
private getChartHeights(jobHistories: sqlops.AgentJobHistoryInfo[]): string[] {
|
||||||
if (!jobHistories || jobHistories.length === 0) {
|
if (!jobHistories || jobHistories.length === 0) {
|
||||||
return ['5px', '5px', '5px', '5px', '5px'];
|
return [];
|
||||||
}
|
}
|
||||||
let maxDuration: number = 0;
|
let maxDuration: number = 0;
|
||||||
jobHistories.forEach(history => {
|
jobHistories.forEach(history => {
|
||||||
@@ -933,19 +928,19 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe
|
|||||||
// add steps
|
// add steps
|
||||||
if (this.jobSteps && this.jobSteps[jobId]) {
|
if (this.jobSteps && this.jobSteps[jobId]) {
|
||||||
let steps = this.jobSteps[jobId];
|
let steps = this.jobSteps[jobId];
|
||||||
job[0].JobSteps = steps;
|
job[0].jobSteps = steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add schedules
|
// add schedules
|
||||||
if (this.jobSchedules && this.jobSchedules[jobId]) {
|
if (this.jobSchedules && this.jobSchedules[jobId]) {
|
||||||
let schedules = this.jobSchedules[jobId];
|
let schedules = this.jobSchedules[jobId];
|
||||||
job[0].JobSchedules = schedules;
|
job[0].jobSchedules = schedules;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add alerts
|
// add alerts
|
||||||
if (this.jobAlerts && this.jobAlerts[jobId]) {
|
if (this.jobAlerts && this.jobAlerts[jobId]) {
|
||||||
let alerts = this.jobAlerts[jobId];
|
let alerts = this.jobAlerts[jobId];
|
||||||
job[0].Alerts = alerts;
|
job[0].alerts = alerts;
|
||||||
}
|
}
|
||||||
return job && job.length > 0 ? job[0] : undefined;
|
return job && job.length > 0 ? job[0] : undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,32 @@
|
|||||||
<span *ngIf="hasStatus" class="card-status">
|
<span *ngIf="hasStatus" class="card-status">
|
||||||
<div class="status-content" [style.backgroundColor]="statusColor"></div>
|
<div class="status-content" [style.backgroundColor]="statusColor"></div>
|
||||||
</span>
|
</span>
|
||||||
|
<span *ngIf="showRadioButton" class="selection-indicator-container">
|
||||||
<ng-container *ngIf="isVerticalButton">
|
<div *ngIf="showAsSelected" class="selection-indicator"></div>
|
||||||
<div class="card-vertical-button">
|
</span>
|
||||||
<div *ngIf="iconPath" class="iconContainer">
|
<ng-container *ngIf="isVerticalButton">
|
||||||
<div [class]="iconClass" [style.maxWidth]="iconWidth" [style.maxHeight]="iconHeight"></div>
|
<div class="card-vertical-button">
|
||||||
</div>
|
<div *ngIf="iconPath" class="iconContainer">
|
||||||
<h4 class="card-label">{{label}}</h4>
|
<div [class]="iconClass" [style.maxWidth]="iconWidth" [style.maxHeight]="iconHeight"></div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
<h4 class="card-label">{{label}}</h4>
|
||||||
|
</div>
|
||||||
<ng-container *ngIf="isDetailsCard">
|
</ng-container>
|
||||||
<div class="card-content">
|
|
||||||
<h4 class="card-label">{{label}}</h4>
|
|
||||||
<p class="card-value">{{value}}</p>
|
|
||||||
<span *ngIf="actions">
|
|
||||||
<table class="model-table">
|
|
||||||
<tr *ngFor="let action of actions">
|
|
||||||
<td class="table-row">{{action.label}}</td>
|
|
||||||
<td *ngIf="action.actionTitle" class="table-row">
|
|
||||||
<a class="pointer prominent" (click)="onDidActionClick(action)">{{action.actionTitle}}</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
|
<ng-container *ngIf="isDetailsCard">
|
||||||
|
<div class="card-content">
|
||||||
|
<h4 class="card-label">{{label}}</h4>
|
||||||
|
<p class="card-value">{{value}}</p>
|
||||||
|
<span *ngIf="actions">
|
||||||
|
<table class="model-table">
|
||||||
|
<tr *ngFor="let action of actions">
|
||||||
|
<td class="table-row">{{action.label}}</td>
|
||||||
|
<td *ngIf="action.actionTitle" class="table-row">
|
||||||
|
<a class="pointer prominent" (click)="onDidActionClick(action)">{{action.actionTitle}}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +29,7 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
|
|||||||
|
|
||||||
private backgroundColor: string;
|
private backgroundColor: string;
|
||||||
|
|
||||||
constructor( @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||||
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
||||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||||
) {
|
) {
|
||||||
@@ -130,6 +130,14 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
|
|||||||
return this.cardType === 'VerticalButton';
|
return this.cardType === 'VerticalButton';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get showRadioButton():boolean{
|
||||||
|
return this.selectable && (this.selected || this._hasFocus)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get showAsSelected(): boolean {
|
||||||
|
return this.selectable && this.selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public get actions(): ActionDescriptor[] {
|
public get actions(): ActionDescriptor[] {
|
||||||
return this.getPropertyOrDefault<CardProperties, ActionDescriptor[]>((props) => props.actions, []);
|
return this.getPropertyOrDefault<CardProperties, ActionDescriptor[]>((props) => props.actions, []);
|
||||||
@@ -156,6 +164,7 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
|
|||||||
|
|
||||||
private updateTheme(theme: IColorTheme) {
|
private updateTheme(theme: IColorTheme) {
|
||||||
this.backgroundColor = theme.getColor(colors.editorBackground, true).toString();
|
this.backgroundColor = theme.getColor(colors.editorBackground, true).toString();
|
||||||
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDidActionClick(action: ActionDescriptor): void {
|
private onDidActionClick(action: ActionDescriptor): void {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
.model-card {
|
.model-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -7,23 +6,18 @@
|
|||||||
margin: 15px;
|
margin: 15px;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
box-shadow: rgba(120, 120, 120, 0.75) 0px 0px 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-card.selected {
|
.model-card.selected {
|
||||||
border-color: darkblue
|
border-color: rgb(0, 120, 215);
|
||||||
}
|
box-shadow: rgba(0, 120, 215, 0.75) 0px 0px 6px;
|
||||||
|
|
||||||
.vs-dark .monaco-workbench .model-card.selected,
|
|
||||||
.hc-black .monaco-workbench .model-card.selected {
|
|
||||||
border-color: darkblue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-card.unselected {
|
.model-card.unselected {
|
||||||
border-color: rgb(214, 214, 214);
|
border-color: rgb(214, 214, 214);
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,21 +96,43 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-card .selection-indicator-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: white;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: rgb(0, 120, 215);
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-card .selection-indicator {
|
||||||
|
margin: 4px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgb(0, 120, 215);
|
||||||
|
}
|
||||||
|
|
||||||
.model-card .model-table {
|
.model-card .model-table {
|
||||||
border-spacing: 5px;
|
border-spacing: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-table .table-row {
|
.model-table .table-row {
|
||||||
width: auto;
|
width: auto;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-table .table-cell {
|
.model-table .table-cell {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-table a {
|
.model-table a {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: underline
|
text-decoration: underline
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,20 @@ export class QueryTextEditor extends BaseTextEditor {
|
|||||||
if (!this._config) {
|
if (!this._config) {
|
||||||
this._config = new Configuration(undefined, editorWidget.getDomNode());
|
this._config = new Configuration(undefined, editorWidget.getDomNode());
|
||||||
}
|
}
|
||||||
let editorHeightUsingLines = this._config.editor.lineHeight * editorWidget.getModel().getLineCount();
|
let editorWidgetModel = editorWidget.getModel();
|
||||||
|
let lineCount = editorWidgetModel.getLineCount();
|
||||||
|
// Need to also keep track of lines that wrap; if we just keep into account line count, then the editor's height would not be
|
||||||
|
// tall enough and we would need to show a scrollbar. Unfortunately, it looks like there isn't any metadata saved in a ICodeEditor
|
||||||
|
// around max column length for an editor (which we could leverage to see if we need to loop through every line to determine
|
||||||
|
// number of lines that wrap). Finally, viewportColumn is calculated on editor resizing automatically; we can use it to ensure
|
||||||
|
// that the viewportColumn will always be greater than any character's column in an editor.
|
||||||
|
let numberWrappedLines = 0;
|
||||||
|
for (let line = 1; line <= lineCount; line++) {
|
||||||
|
if (editorWidgetModel.getLineMaxColumn(line) >= this._config.editor.layoutInfo.viewportColumn - 1) {
|
||||||
|
numberWrappedLines += Math.ceil(editorWidgetModel.getLineMaxColumn(line) / this._config.editor.layoutInfo.viewportColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let editorHeightUsingLines = this._config.editor.lineHeight * (lineCount + numberWrappedLines);
|
||||||
let editorHeightUsingMinHeight = Math.max(editorHeightUsingLines, this._minHeight);
|
let editorHeightUsingMinHeight = Math.max(editorHeightUsingLines, this._minHeight);
|
||||||
this.setHeight(editorHeightUsingMinHeight);
|
this.setHeight(editorHeightUsingMinHeight);
|
||||||
}
|
}
|
||||||
|
|||||||
127
src/sql/parts/notebook/cellToggleMoreActions.ts
Normal file
127
src/sql/parts/notebook/cellToggleMoreActions.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ElementRef } from '@angular/core';
|
||||||
|
|
||||||
|
import { nb } from 'sqlops';
|
||||||
|
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { Action } from 'vs/base/common/actions';
|
||||||
|
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
|
import { getErrorMessage } from 'vs/base/common/errors';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import { CellContext, CellActionBase } from 'sql/parts/notebook/cellViews/codeActions';
|
||||||
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
||||||
|
import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
|
import { CellModel } from 'sql/parts/notebook/models/cell';
|
||||||
|
|
||||||
|
export class CellToggleMoreActions {
|
||||||
|
private _actions: Action[] = [];
|
||||||
|
private _moreActions: ActionBar;
|
||||||
|
constructor(
|
||||||
|
@IInstantiationService private instantiationService: IInstantiationService) {
|
||||||
|
this._actions.push(
|
||||||
|
instantiationService.createInstance(DeleteCellAction, 'delete', localize('delete', 'Delete')),
|
||||||
|
instantiationService.createInstance(AddCellFromContextAction,'codeBefore', localize('codeBefore', 'Insert Code before'), CellTypes.Code, false),
|
||||||
|
instantiationService.createInstance(AddCellFromContextAction, 'codeAfter', localize('codeAfter', 'Insert Code after'), CellTypes.Code, true),
|
||||||
|
instantiationService.createInstance(AddCellFromContextAction, 'markdownBefore', localize('markdownBefore', 'Insert Markdown before'), CellTypes.Markdown, false),
|
||||||
|
instantiationService.createInstance(AddCellFromContextAction, 'markdownAfter', localize('markdownAfter', 'Insert Markdown after'), CellTypes.Markdown, true),
|
||||||
|
instantiationService.createInstance(ClearCellOutputAction, 'clear', localize('clear', 'Clear output'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggle(showIcon: boolean, elementRef: ElementRef, model: NotebookModel, cellModel: ICellModel) {
|
||||||
|
let context = new CellContext(model,cellModel);
|
||||||
|
let moreActionsElement = <HTMLElement>elementRef.nativeElement;
|
||||||
|
if (showIcon) {
|
||||||
|
if (moreActionsElement.childNodes.length > 0) {
|
||||||
|
moreActionsElement.removeChild(moreActionsElement.childNodes[0]);
|
||||||
|
}
|
||||||
|
this._moreActions = new ActionBar(moreActionsElement, { orientation: ActionsOrientation.VERTICAL });
|
||||||
|
this._moreActions.context = { target: moreActionsElement };
|
||||||
|
this._moreActions.push(this.instantiationService.createInstance(ToggleMoreWidgetAction, this._actions, context), { icon: showIcon, label: false });
|
||||||
|
}
|
||||||
|
else if (moreActionsElement.childNodes.length > 0) {
|
||||||
|
moreActionsElement.removeChild(moreActionsElement.childNodes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AddCellFromContextAction extends CellActionBase {
|
||||||
|
constructor(
|
||||||
|
id: string, label: string, private cellType: CellType, private isAfter: boolean,
|
||||||
|
@INotificationService notificationService: INotificationService
|
||||||
|
) {
|
||||||
|
super(id, label, undefined, notificationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
runCellAction(context: CellContext): Promise<void> {
|
||||||
|
try {
|
||||||
|
let model = context.model;
|
||||||
|
let index = model.cells.findIndex((cell) => cell.id === context.cell.id);
|
||||||
|
if (index !== undefined && this.isAfter) {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
model.addCell(this.cellType, index);
|
||||||
|
} catch (error) {
|
||||||
|
let message = getErrorMessage(error);
|
||||||
|
|
||||||
|
this.notificationService.notify({
|
||||||
|
severity: Severity.Error,
|
||||||
|
message: message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DeleteCellAction extends CellActionBase {
|
||||||
|
constructor(id: string, label: string,
|
||||||
|
@INotificationService notificationService: INotificationService
|
||||||
|
) {
|
||||||
|
super(id, label, undefined, notificationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
runCellAction(context: CellContext): Promise<void> {
|
||||||
|
try {
|
||||||
|
context.model.deleteCell(context.cell);
|
||||||
|
} catch (error) {
|
||||||
|
let message = getErrorMessage(error);
|
||||||
|
|
||||||
|
this.notificationService.notify({
|
||||||
|
severity: Severity.Error,
|
||||||
|
message: message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClearCellOutputAction extends CellActionBase {
|
||||||
|
constructor(id: string, label: string,
|
||||||
|
@INotificationService notificationService: INotificationService
|
||||||
|
) {
|
||||||
|
super(id, label, undefined, notificationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
runCellAction(context: CellContext): Promise<void> {
|
||||||
|
try {
|
||||||
|
(context.model.activeCell as CellModel).clearOutputs();
|
||||||
|
} catch (error) {
|
||||||
|
let message = getErrorMessage(error);
|
||||||
|
|
||||||
|
this.notificationService.notify({
|
||||||
|
severity: Severity.Error,
|
||||||
|
message: message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,6 +9,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div #editor class="editor" style="flex: 1 1 auto; overflow: hidden;">
|
<div #editor class="editor" style="flex: 1 1 auto; overflow: hidden;">
|
||||||
</div>
|
</div>
|
||||||
<div #moreactions class="toolbar" style="flex: 0 0 auto; display: flex; flex-flow:column; width: 20px; min-height: 20px; max-height: 20px; padding-top: 10px; orientation: portrait">
|
<div #moreactions class="moreActions" style="flex: 0 0 auto; display: flex; flex-flow:column;width: 20px; min-height: 20px; max-height: 20px; padding-top: 0px; orientation: portrait">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,16 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import 'vs/css!./code';
|
import 'vs/css!./code';
|
||||||
|
|
||||||
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
|
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
|
||||||
|
|
||||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||||
import { QueryTextEditor } from 'sql/parts/modelComponents/queryTextEditor';
|
import { QueryTextEditor } from 'sql/parts/modelComponents/queryTextEditor';
|
||||||
|
import { CellToggleMoreActions } from 'sql/parts/notebook/cellToggleMoreActions';
|
||||||
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
|
import { RunCellAction, CellContext } from 'sql/parts/notebook/cellViews/codeActions';
|
||||||
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
|
||||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import * as themeColors from 'vs/workbench/common/theme';
|
import * as themeColors from 'vs/workbench/common/theme';
|
||||||
@@ -19,20 +24,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { Action } from 'vs/base/common/actions';
|
|
||||||
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
|
||||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
|
||||||
import { RunCellAction, CellContext, NotebookCellToggleMoreActon } from 'sql/parts/notebook/cellViews/codeActions';
|
|
||||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
|
||||||
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
|
||||||
import { CellTypes } from 'sql/parts/notebook/models/contracts';
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
export const CODE_SELECTOR: string = 'code-component';
|
export const CODE_SELECTOR: string = 'code-component';
|
||||||
@@ -66,7 +62,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
private _uri: string;
|
private _uri: string;
|
||||||
private _model: NotebookModel;
|
private _model: NotebookModel;
|
||||||
private _activeCellId: string;
|
private _activeCellId: string;
|
||||||
private _toggleMoreActions: NotebookCellToggleMoreActon;
|
private _cellToggleMoreActions: CellToggleMoreActions;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||||
@@ -80,6 +76,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
@Inject(INotificationService) private notificationService: INotificationService,
|
@Inject(INotificationService) private notificationService: INotificationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this._cellToggleMoreActions = this._instantiationService.createInstance(CellToggleMoreActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -90,20 +87,20 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
this._toggleMoreActions = new NotebookCellToggleMoreActon(
|
|
||||||
this._instantiationService,
|
|
||||||
this.contextMenuService,
|
|
||||||
this.notificationService,
|
|
||||||
this.moreActionsElementRef,
|
|
||||||
this.model);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
|
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
|
||||||
this.updateLanguageMode();
|
this.updateLanguageMode();
|
||||||
this.updateModel();
|
this.updateModel();
|
||||||
if (this._toggleMoreActions) {
|
for (let propName in changes) {
|
||||||
this._toggleMoreActions.onChange(this.cellModel, changes);
|
if (propName === 'activeCellId') {
|
||||||
|
let changedProp = changes[propName];
|
||||||
|
if (this.cellModel.id === changedProp.currentValue) {
|
||||||
|
this._cellToggleMoreActions.toggle(true, this.moreActionsElementRef, this.model, this.cellModel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._cellToggleMoreActions.toggle(false, this.moreActionsElementRef, this.model, this.cellModel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +189,8 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
let toolbarEl = <HTMLElement>this.toolbarElement.nativeElement;
|
let toolbarEl = <HTMLElement>this.toolbarElement.nativeElement;
|
||||||
toolbarEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
toolbarEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
|
|
||||||
let moreactionsEl = <HTMLElement>this.moreActionsElementRef.nativeElement;
|
let moreActionsEl = <HTMLElement>this.moreActionsElementRef.nativeElement;
|
||||||
moreactionsEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
moreActionsEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ code-component .carbon-taskbar .icon {
|
|||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code-component .action-label.icon.toggle-more {
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
code-component .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container
|
code-component .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,20 +5,13 @@
|
|||||||
|
|
||||||
import { nb } from 'sqlops';
|
import { nb } from 'sqlops';
|
||||||
|
|
||||||
import { ElementRef, SimpleChange } from '@angular/core';
|
|
||||||
|
|
||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
|
||||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
|
||||||
|
|
||||||
import { CellType, CellTypes } from 'sql/parts/notebook/models/contracts';
|
|
||||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||||
import { ICellModel, FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel, FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { ToggleableAction } from 'sql/parts/notebook/notebookActions';
|
import { ToggleableAction } from 'sql/parts/notebook/notebookActions';
|
||||||
|
|
||||||
@@ -47,7 +40,7 @@ export class CellContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class CellActionBase extends Action {
|
export abstract class CellActionBase extends Action {
|
||||||
|
|
||||||
constructor(id: string, label: string, icon: string, protected notificationService: INotificationService) {
|
constructor(id: string, label: string, icon: string, protected notificationService: INotificationService) {
|
||||||
super(id, label, icon);
|
super(id, label, icon);
|
||||||
@@ -142,100 +135,3 @@ export class RunCellAction extends ToggleableAction {
|
|||||||
return clientSession.kernel;
|
return clientSession.kernel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AddCellAction extends CellActionBase {
|
|
||||||
constructor(
|
|
||||||
id: string, label: string, private cellType: CellType, private isAfter: boolean,
|
|
||||||
@INotificationService notificationService: INotificationService
|
|
||||||
) {
|
|
||||||
super(id, label, undefined, notificationService);
|
|
||||||
}
|
|
||||||
|
|
||||||
runCellAction(context: CellContext): Promise<void> {
|
|
||||||
try {
|
|
||||||
let model = context.model;
|
|
||||||
let index = model.cells.findIndex((cell) => cell.id === context.cell.id);
|
|
||||||
if (index !== undefined && this.isAfter) {
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
model.addCell(this.cellType, index);
|
|
||||||
} catch (error) {
|
|
||||||
let message = getErrorMessage(error);
|
|
||||||
|
|
||||||
this.notificationService.notify({
|
|
||||||
severity: Severity.Error,
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DeleteCellAction extends CellActionBase {
|
|
||||||
constructor(id: string, label: string,
|
|
||||||
@INotificationService notificationService: INotificationService
|
|
||||||
) {
|
|
||||||
super(id, label, undefined, notificationService);
|
|
||||||
}
|
|
||||||
|
|
||||||
runCellAction(context: CellContext): Promise<void> {
|
|
||||||
try {
|
|
||||||
context.model.deleteCell(context.cell);
|
|
||||||
} catch (error) {
|
|
||||||
let message = getErrorMessage(error);
|
|
||||||
|
|
||||||
this.notificationService.notify({
|
|
||||||
severity: Severity.Error,
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookCellToggleMoreActon {
|
|
||||||
private _actions: Action[] = [];
|
|
||||||
private _moreActions: ActionBar;
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private _instantiationService: IInstantiationService,
|
|
||||||
private contextMenuService: IContextMenuService,
|
|
||||||
private notificationService: INotificationService,
|
|
||||||
private moreActionElementRef: ElementRef,
|
|
||||||
private model: NotebookModel
|
|
||||||
) {
|
|
||||||
this._actions.push(
|
|
||||||
this._instantiationService.createInstance(AddCellAction, 'codeBefore', localize('codeBefore', 'Insert Code before'), CellTypes.Code, false, this.notificationService),
|
|
||||||
this._instantiationService.createInstance(AddCellAction, 'codeBefore', localize('codeAfter', 'Insert Code after'), CellTypes.Code, true, this.notificationService),
|
|
||||||
this._instantiationService.createInstance(AddCellAction, 'markdownBefore', localize('markdownBefore', 'Insert Markdown before'), CellTypes.Markdown, false, this.notificationService),
|
|
||||||
this._instantiationService.createInstance(AddCellAction, 'markdownAfter', localize('markdownAfter', 'Insert Markdown after'), CellTypes.Markdown, true, this.notificationService),
|
|
||||||
this._instantiationService.createInstance(DeleteCellAction, 'delete', localize('delete', 'Delete'), this.notificationService)
|
|
||||||
);
|
|
||||||
let moreActionsElement = <HTMLElement>this.moreActionElementRef.nativeElement;
|
|
||||||
this._moreActions = new ActionBar(moreActionsElement, { orientation: ActionsOrientation.VERTICAL });
|
|
||||||
this._moreActions.context = { target: moreActionsElement };
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle(showIcon: boolean): void {
|
|
||||||
if (showIcon) {
|
|
||||||
this._moreActions.push(this._instantiationService.createInstance(ToggleMoreWidgetAction, this._actions, this.model, this.contextMenuService), { icon: showIcon, label: false });
|
|
||||||
} else if (this._moreActions) {
|
|
||||||
this._moreActions.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public onChange(cellModel: ICellModel, changes: { [propKey: string]: SimpleChange }): void {
|
|
||||||
for (let propName in changes) {
|
|
||||||
if (propName === 'activeCellId') {
|
|
||||||
let changedProp = changes[propName];
|
|
||||||
if (cellModel.id === changedProp.currentValue) {
|
|
||||||
this.toggle(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.toggle(false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="notebook-code" style="flex: 0 0 auto;">
|
<div class="notebook-code" style="flex: 0 0 auto;">
|
||||||
<code-component [cellModel]="cellModel" [model]="model" [activeCellId]="activeCellId"></code-component>
|
<code-component [cellModel]="cellModel" [model]="model" [activeCellId]="activeCellId"></code-component>
|
||||||
</div>
|
</div>
|
||||||
<div #codeCellOutput class="notebook-output" style="flex: 0 0 auto;">
|
<div style="flex: 0 0 auto; width: 100%; height: 100%; display: block">
|
||||||
<output-area-component *ngIf="cellModel.outputs && cellModel.outputs.length > 0" [cellModel]="cellModel">
|
<output-area-component *ngIf="cellModel.outputs && cellModel.outputs.length > 0" [cellModel]="cellModel">
|
||||||
</output-area-component>
|
</output-area-component>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,15 +2,10 @@
|
|||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import 'vs/css!./codeCell';
|
|
||||||
|
|
||||||
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, SimpleChange, OnChanges } from '@angular/core';
|
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, SimpleChange, OnChanges } from '@angular/core';
|
||||||
|
|
||||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
import { CellView } from 'sql/parts/notebook/cellViews/interfaces';
|
import { CellView } from 'sql/parts/notebook/cellViews/interfaces';
|
||||||
|
|
||||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
|
||||||
import * as themeColors from 'vs/workbench/common/theme';
|
|
||||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
|
||||||
@@ -21,9 +16,9 @@ export const CODE_SELECTOR: string = 'code-cell-component';
|
|||||||
selector: CODE_SELECTOR,
|
selector: CODE_SELECTOR,
|
||||||
templateUrl: decodeURI(require.toUrl('./codeCell.component.html'))
|
templateUrl: decodeURI(require.toUrl('./codeCell.component.html'))
|
||||||
})
|
})
|
||||||
|
|
||||||
export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
||||||
@ViewChild('codeCellOutput', { read: ElementRef }) private outputPreview: ElementRef;
|
@ViewChild('codeCellOutput', { read: ElementRef }) private outputPreview: ElementRef;
|
||||||
|
|
||||||
@Input() cellModel: ICellModel;
|
@Input() cellModel: ICellModel;
|
||||||
@Input() set model(value: NotebookModel) {
|
@Input() set model(value: NotebookModel) {
|
||||||
this._model = value;
|
this._model = value;
|
||||||
@@ -37,14 +32,11 @@ export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
|
||||||
this.updateTheme(this.themeService.getColorTheme());
|
|
||||||
if (this.cellModel) {
|
if (this.cellModel) {
|
||||||
this.cellModel.onOutputsChanged(() => {
|
this.cellModel.onOutputsChanged(() => {
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
@@ -74,10 +66,4 @@ export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
public layout() {
|
public layout() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateTheme(theme: IColorTheme): void {
|
|
||||||
let outputElement = <HTMLElement>this.outputPreview.nativeElement;
|
|
||||||
outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
-->
|
-->
|
||||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||||
<div style="flex: 0 0 auto;">
|
<div #outputarea class="notebook-output" style="flex: 0 0 auto;">
|
||||||
<output-component *ngFor="let output of cellModel.outputs" [cellOutput]="output" [trustedMode] = "cellModel.trustedMode" >
|
<output-component *ngFor="let output of cellModel.outputs" [cellOutput]="output" [trustedMode] = "cellModel.trustedMode" >
|
||||||
</output-component>
|
</output-component>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import 'vs/css!./code';
|
import 'vs/css!./code';
|
||||||
import { OnInit, Component, Input, Inject, forwardRef, ChangeDetectorRef } from '@angular/core';
|
import 'vs/css!./outputArea';
|
||||||
|
import { OnInit, Component, Input, Inject, ElementRef, ViewChild, forwardRef, ChangeDetectorRef } from '@angular/core';
|
||||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import * as themeColors from 'vs/workbench/common/theme';
|
||||||
|
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
|
|
||||||
export const OUTPUT_AREA_SELECTOR: string = 'output-area-component';
|
export const OUTPUT_AREA_SELECTOR: string = 'output-area-component';
|
||||||
|
|
||||||
@@ -14,20 +17,30 @@ export const OUTPUT_AREA_SELECTOR: string = 'output-area-component';
|
|||||||
templateUrl: decodeURI(require.toUrl('./outputArea.component.html'))
|
templateUrl: decodeURI(require.toUrl('./outputArea.component.html'))
|
||||||
})
|
})
|
||||||
export class OutputAreaComponent extends AngularDisposable implements OnInit {
|
export class OutputAreaComponent extends AngularDisposable implements OnInit {
|
||||||
|
@ViewChild('outputarea', { read: ElementRef }) private outputArea: ElementRef;
|
||||||
@Input() cellModel: ICellModel;
|
@Input() cellModel: ICellModel;
|
||||||
|
|
||||||
private readonly _minimumHeight = 30;
|
private readonly _minimumHeight = 30;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
ngOnInit(): void {
|
|
||||||
|
ngOnInit() {
|
||||||
|
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||||
|
this.updateTheme(this.themeService.getColorTheme());
|
||||||
if (this.cellModel) {
|
if (this.cellModel) {
|
||||||
this.cellModel.onOutputsChanged(() => {
|
this.cellModel.onOutputsChanged(() => {
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateTheme(theme: IColorTheme): void {
|
||||||
|
let outputElement = <HTMLElement>this.outputArea.nativeElement;
|
||||||
|
outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
output-area-component {
|
||||||
code-cell-component {
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
code-cell-component .notebook-output {
|
output-area-component .notebook-output {
|
||||||
border-top-width: 1px;
|
border-top-width: 1px;
|
||||||
border-top-style: solid;
|
border-top-style: solid;
|
||||||
user-select: initial;
|
user-select: initial;
|
||||||
|
padding: 5px 20px 0px;
|
||||||
|
box-shadow: rgba(120, 120, 120, 0.75) 0px -2px 1px -2px;
|
||||||
}
|
}
|
||||||
@@ -5,9 +5,15 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
-->
|
-->
|
||||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||||
|
<loading-spinner [loading]="isLoading"></loading-spinner>
|
||||||
<div class="notebook-text" style="flex: 0 0 auto;">
|
<div class="notebook-text" style="flex: 0 0 auto;">
|
||||||
<code-component *ngIf="isEditMode" [cellModel]="cellModel" (onContentChanged)="handleContentChanged()" [activeCellId]="activeCellId" [hideVerticalToolbar]=1></code-component>
|
<code-component *ngIf="isEditMode" [cellModel]="cellModel" (onContentChanged)="handleContentChanged()" [model]="model" [activeCellId]="activeCellId" [hideVerticalToolbar]=true>
|
||||||
|
</code-component>
|
||||||
</div>
|
</div>
|
||||||
<div #preview class="notebook-preview" style="flex: 0 0 auto;" (dblclick)="toggleEditMode()">
|
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: row">
|
||||||
|
<div #preview class ="notebook-preview" style="flex: 1 1 auto; user-select: initial;" (dblclick)="toggleEditMode()">
|
||||||
|
</div>
|
||||||
|
<div #moreactions class="moreActions" style="flex: 0 0 auto; display: flex; flex-flow:column;width: 20px; min-height: 20px; max-height: 20px; padding-top: 0px; orientation: portrait">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,15 +6,21 @@ import 'vs/css!./textCell';
|
|||||||
|
|
||||||
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, OnChanges, SimpleChange } from '@angular/core';
|
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, OnChanges, SimpleChange } from '@angular/core';
|
||||||
|
|
||||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
import { localize } from 'vs/nls';
|
||||||
import { CellView } from 'sql/parts/notebook/cellViews/interfaces';
|
|
||||||
|
|
||||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import * as themeColors from 'vs/workbench/common/theme';
|
import * as themeColors from 'vs/workbench/common/theme';
|
||||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import URI from 'vs/base/common/uri';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
import { CellView } from 'sql/parts/notebook/cellViews/interfaces';
|
||||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { ISanitizer, defaultSanitizer } from 'sql/parts/notebook/outputs/sanitizer';
|
import { ISanitizer, defaultSanitizer } from 'sql/parts/notebook/outputs/sanitizer';
|
||||||
import { localize } from 'vs/nls';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
import { CellToggleMoreActions } from 'sql/parts/notebook/cellToggleMoreActions';
|
||||||
|
|
||||||
export const TEXT_SELECTOR: string = 'text-cell-component';
|
export const TEXT_SELECTOR: string = 'text-cell-component';
|
||||||
|
|
||||||
@@ -24,34 +30,39 @@ export const TEXT_SELECTOR: string = 'text-cell-component';
|
|||||||
})
|
})
|
||||||
export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||||
@ViewChild('preview', { read: ElementRef }) private output: ElementRef;
|
@ViewChild('preview', { read: ElementRef }) private output: ElementRef;
|
||||||
|
@ViewChild('moreactions', { read: ElementRef }) private moreActionsElementRef: ElementRef;
|
||||||
@Input() cellModel: ICellModel;
|
@Input() cellModel: ICellModel;
|
||||||
|
|
||||||
|
@Input() set model(value: NotebookModel) {
|
||||||
|
this._model = value;
|
||||||
|
}
|
||||||
|
|
||||||
@Input() set activeCellId(value: string) {
|
@Input() set activeCellId(value: string) {
|
||||||
this._activeCellId = value;
|
this._activeCellId = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _content: string;
|
private _content: string;
|
||||||
private isEditMode: boolean;
|
private isEditMode: boolean;
|
||||||
private _sanitizer: ISanitizer;
|
private _sanitizer: ISanitizer;
|
||||||
|
private _model: NotebookModel;
|
||||||
private _activeCellId: string;
|
private _activeCellId: string;
|
||||||
|
private readonly _onDidClickLink = this._register(new Emitter<URI>());
|
||||||
|
public readonly onDidClickLink = this._onDidClickLink.event;
|
||||||
|
protected isLoading: boolean;
|
||||||
|
private _cellToggleMoreActions: CellToggleMoreActions;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||||
|
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
|
||||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||||
@Inject(ICommandService) private _commandService: ICommandService
|
@Inject(ICommandService) private _commandService: ICommandService,
|
||||||
|
@Inject(IOpenerService) private readonly openerService: IOpenerService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.isEditMode = false;
|
this.isEditMode = false;
|
||||||
}
|
this.isLoading = true;
|
||||||
|
this._cellToggleMoreActions = this._instantiationService.createInstance(CellToggleMoreActions);
|
||||||
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
|
|
||||||
this.updatePreview();
|
|
||||||
for (let propName in changes) {
|
|
||||||
if (propName === 'activeCellId') {
|
|
||||||
let changedProp = changes[propName];
|
|
||||||
this._activeCellId = changedProp.currentValue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Gets sanitizer from ISanitizer interface
|
//Gets sanitizer from ISanitizer interface
|
||||||
@@ -62,17 +73,47 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
return this._sanitizer = defaultSanitizer;
|
return this._sanitizer = defaultSanitizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get model(): NotebookModel {
|
||||||
|
return this._model;
|
||||||
|
}
|
||||||
|
|
||||||
get activeCellId(): string {
|
get activeCellId(): string {
|
||||||
return this._activeCellId;
|
return this._activeCellId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setLoading(isLoading: boolean): void {
|
||||||
|
this.isLoading = isLoading;
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.updatePreview();
|
||||||
|
this.setLoading(false);
|
||||||
|
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||||
|
this.updateTheme(this.themeService.getColorTheme());
|
||||||
|
this.cellModel.onOutputsChanged(e => {
|
||||||
|
this.updatePreview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
|
||||||
|
for (let propName in changes) {
|
||||||
|
if (propName === 'activeCellId') {
|
||||||
|
let changedProp = changes[propName];
|
||||||
|
this._activeCellId = changedProp.currentValue;
|
||||||
|
this.toggleEditMode(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the preview of markdown component with latest changes
|
* Updates the preview of markdown component with latest changes
|
||||||
* If content is empty and in non-edit mode, default it to 'Double-click to edit'
|
* If content is empty and in non-edit mode, default it to 'Double-click to edit'
|
||||||
* Sanitizes the data to be shown in markdown cell
|
* Sanitizes the data to be shown in markdown cell
|
||||||
*/
|
*/
|
||||||
private updatePreview() {
|
private updatePreview() {
|
||||||
if (this._content !== this.cellModel.source) {
|
if (this._content !== this.cellModel.source || this.cellModel.source.length === 0) {
|
||||||
if (!this.cellModel.source && !this.isEditMode) {
|
if (!this.cellModel.source && !this.isEditMode) {
|
||||||
(<HTMLElement>this.output.nativeElement).innerHTML = localize('doubleClickEdit', 'Double-click to edit');
|
(<HTMLElement>this.output.nativeElement).innerHTML = localize('doubleClickEdit', 'Double-click to edit');
|
||||||
} else {
|
} else {
|
||||||
@@ -94,14 +135,6 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.updatePreview();
|
|
||||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
|
||||||
this.updateTheme(this.themeService.getColorTheme());
|
|
||||||
this.cellModel.onOutputsChanged(e => {
|
|
||||||
this.updatePreview();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: implement layout
|
// Todo: implement layout
|
||||||
public layout() {
|
public layout() {
|
||||||
@@ -110,14 +143,23 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
private updateTheme(theme: IColorTheme): void {
|
private updateTheme(theme: IColorTheme): void {
|
||||||
let outputElement = <HTMLElement>this.output.nativeElement;
|
let outputElement = <HTMLElement>this.output.nativeElement;
|
||||||
outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
|
|
||||||
|
let moreActionsEl = <HTMLElement>this.moreActionsElementRef.nativeElement;
|
||||||
|
moreActionsEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleContentChanged(): void {
|
public handleContentChanged(): void {
|
||||||
this.updatePreview();
|
this.updatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleEditMode(): void {
|
public toggleEditMode(editMode?: boolean): void {
|
||||||
this.isEditMode = !this.isEditMode;
|
this.isEditMode = editMode !== undefined? editMode : !this.isEditMode;
|
||||||
|
if (!this.isEditMode && this.cellModel.id === this._activeCellId) {
|
||||||
|
this._cellToggleMoreActions.toggle(true, this.moreActionsElementRef, this.model, this.cellModel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._cellToggleMoreActions.toggle(false, this.moreActionsElementRef, this.model, this.cellModel);
|
||||||
|
}
|
||||||
this.updatePreview();
|
this.updatePreview();
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ text-cell-component .notebook-preview {
|
|||||||
border-top-width: 1px;
|
border-top-width: 1px;
|
||||||
border-top-style: solid;
|
border-top-style: solid;
|
||||||
user-select: initial;
|
user-select: initial;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
1
src/sql/parts/notebook/media/dark/save_inverse.svg
Normal file
1
src/sql/parts/notebook/media/dark/save_inverse.svg
Normal 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;}</style></defs><title>save_inverse</title><path class="cls-1" d="M14,1a1,1,0,0,1,.39.08,1,1,0,0,1,.53.53A1,1,0,0,1,15,2V15H2.79L1,13.2V2a1,1,0,0,1,.08-.39,1,1,0,0,1,.53-.53A1,1,0,0,1,2,1Zm0,1H13V8H3V2H2V12.79L3.2,14H4V10h7v4h3ZM4,7h8V2H4Zm6,4H5v3H6V12H7v2h3Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
src/sql/parts/notebook/media/light/save.svg
Normal file
1
src/sql/parts/notebook/media/light/save.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>save</title><path d="M14,1a1,1,0,0,1,.39.08,1,1,0,0,1,.53.53A1,1,0,0,1,15,2V15H2.79L1,13.2V2a1,1,0,0,1,.08-.39,1,1,0,0,1,.53-.53A1,1,0,0,1,2,1Zm0,1H13V8H3V2H2V12.79L3.2,14H4V10h7v4h3ZM4,7h8V2H4Zm6,4H5v3H6V12H7v2h3Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
@@ -14,6 +14,7 @@ import { ICellModelOptions, IModelFactory, FutureInternal } from './modelInterfa
|
|||||||
import * as notebookUtils from '../notebookUtils';
|
import * as notebookUtils from '../notebookUtils';
|
||||||
import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
|
||||||
let modelId = 0;
|
let modelId = 0;
|
||||||
|
|
||||||
@@ -34,18 +35,18 @@ export class CellModel implements ICellModel {
|
|||||||
private _active: boolean;
|
private _active: boolean;
|
||||||
private _cellUri: URI;
|
private _cellUri: URI;
|
||||||
|
|
||||||
constructor(private factory: IModelFactory, cellData?: nb.ICell, private _options?: ICellModelOptions) {
|
constructor(private factory: IModelFactory, cellData?: nb.ICellContents, private _options?: ICellModelOptions) {
|
||||||
this.id = `${modelId++}`;
|
this.id = `${modelId++}`;
|
||||||
CellModel.CreateLanguageMappings();
|
CellModel.CreateLanguageMappings();
|
||||||
// Do nothing for now
|
|
||||||
if (cellData) {
|
if (cellData) {
|
||||||
|
// Read in contents if available
|
||||||
this.fromJSON(cellData);
|
this.fromJSON(cellData);
|
||||||
} else {
|
} else {
|
||||||
this._cellType = CellTypes.Code;
|
this._cellType = CellTypes.Code;
|
||||||
this._source = '';
|
this._source = '';
|
||||||
}
|
}
|
||||||
this._isEditMode = this._cellType !== CellTypes.Markdown;
|
this._isEditMode = this._cellType !== CellTypes.Markdown;
|
||||||
this.setDefaultLanguage();
|
this.ensureDefaultLanguage();
|
||||||
if (_options && _options.isTrusted) {
|
if (_options && _options.isTrusted) {
|
||||||
this._isTrusted = true;
|
this._isTrusted = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -222,18 +223,48 @@ export class CellModel implements ICellModel {
|
|||||||
if (output) {
|
if (output) {
|
||||||
// deletes transient node in the serialized JSON
|
// deletes transient node in the serialized JSON
|
||||||
delete output['transient'];
|
delete output['transient'];
|
||||||
this._outputs.push(output);
|
this._outputs.push(this.rewriteOutputUrls(output));
|
||||||
this.fireOutputsChanged();
|
this.fireOutputsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private rewriteOutputUrls(output: nb.ICellOutput): nb.ICellOutput {
|
||||||
|
// Only rewrite if this is coming back during execution, not when loading from disk.
|
||||||
|
// A good approximation is that the model has a future (needed for execution)
|
||||||
|
if (this.future) {
|
||||||
|
try {
|
||||||
|
let result = output as nb.IDisplayResult;
|
||||||
|
if (result && result.data && result.data['text/html']) {
|
||||||
|
let nbm = (this as CellModel).options.notebook as NotebookModel;
|
||||||
|
if (nbm.hadoopConnection) {
|
||||||
|
let host = nbm.hadoopConnection.host;
|
||||||
|
let html = result.data['text/html'];
|
||||||
|
html = html.replace(/(https?:\/\/mssql-master.*\/proxy)(.*)/g, function (a, b, c) {
|
||||||
|
let ret = '';
|
||||||
|
if (b !== '') {
|
||||||
|
ret = 'https://' + host + ':30443/gateway/default/yarn/proxy';
|
||||||
|
}
|
||||||
|
if (c !== '') {
|
||||||
|
ret = ret + c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
(<nb.IDisplayResult>output).data['text/html'] = html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
private getDisplayId(msg: nb.IIOPubMessage): string | undefined {
|
private getDisplayId(msg: nb.IIOPubMessage): string | undefined {
|
||||||
let transient = (msg.content.transient || {});
|
let transient = (msg.content.transient || {});
|
||||||
return transient['display_id'] as string;
|
return transient['display_id'] as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): nb.ICell {
|
public toJSON(): nb.ICellContents {
|
||||||
let cellJson: Partial<nb.ICell> = {
|
let cellJson: Partial<nb.ICellContents> = {
|
||||||
cell_type: this._cellType,
|
cell_type: this._cellType,
|
||||||
source: this._source,
|
source: this._source,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -244,16 +275,16 @@ export class CellModel implements ICellModel {
|
|||||||
cellJson.outputs = this._outputs;
|
cellJson.outputs = this._outputs;
|
||||||
cellJson.execution_count = 1; // TODO: keep track of actual execution count
|
cellJson.execution_count = 1; // TODO: keep track of actual execution count
|
||||||
}
|
}
|
||||||
return cellJson as nb.ICell;
|
return cellJson as nb.ICellContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public fromJSON(cell: nb.ICell): void {
|
public fromJSON(cell: nb.ICellContents): void {
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._cellType = cell.cell_type;
|
this._cellType = cell.cell_type;
|
||||||
this._source = Array.isArray(cell.source) ? cell.source.join('') : cell.source;
|
this._source = Array.isArray(cell.source) ? cell.source.join('') : cell.source;
|
||||||
this._language = (cell.metadata && cell.metadata.language) ? cell.metadata.language : 'python';
|
this.setLanguageFromContents(cell);
|
||||||
if (cell.outputs) {
|
if (cell.outputs) {
|
||||||
for (let output of cell.outputs) {
|
for (let output of cell.outputs) {
|
||||||
// For now, we're assuming it's OK to save these as-is with no modification
|
// For now, we're assuming it's OK to save these as-is with no modification
|
||||||
@@ -262,6 +293,15 @@ export class CellModel implements ICellModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setLanguageFromContents(cell: nb.ICellContents): void {
|
||||||
|
if (cell.cell_type === CellTypes.Markdown) {
|
||||||
|
this._language = 'markdown';
|
||||||
|
} else if (cell.metadata && cell.metadata.language) {
|
||||||
|
this._language = cell.metadata.language;
|
||||||
|
}
|
||||||
|
// else skip, we set default language anyhow
|
||||||
|
}
|
||||||
|
|
||||||
private addOutput(output: nb.ICellOutput) {
|
private addOutput(output: nb.ICellOutput) {
|
||||||
this._normalize(output);
|
this._normalize(output);
|
||||||
this._outputs.push(output);
|
this._outputs.push(output);
|
||||||
@@ -296,8 +336,32 @@ export class CellModel implements ICellModel {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setDefaultLanguage(): void {
|
/**
|
||||||
this._language = 'python';
|
* Ensures there is a default language set, if none was already defined.
|
||||||
|
* Will read information from the overall Notebook (passed as options to the model), or
|
||||||
|
* if all else fails default back to python.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private ensureDefaultLanguage(): void {
|
||||||
|
// See if language is already set / is known based on cell type
|
||||||
|
if (this.hasLanguage()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._cellType === CellTypes.Markdown) {
|
||||||
|
this._language = 'markdown';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try set it based on overall Notebook language
|
||||||
|
this.trySetLanguageFromLangInfo();
|
||||||
|
|
||||||
|
// fallback to python
|
||||||
|
if (!this._language) {
|
||||||
|
this._language = 'python';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private trySetLanguageFromLangInfo() {
|
||||||
// In languageInfo, set the language to the "name" property
|
// In languageInfo, set the language to the "name" property
|
||||||
// If the "name" property isn't defined, check the "mimeType" property
|
// If the "name" property isn't defined, check the "mimeType" property
|
||||||
// Otherwise, default to python as the language
|
// Otherwise, default to python as the language
|
||||||
@@ -307,16 +371,25 @@ export class CellModel implements ICellModel {
|
|||||||
// check the LanguageMapping to determine if a mapping is necessary (example 'pyspark' -> 'python')
|
// check the LanguageMapping to determine if a mapping is necessary (example 'pyspark' -> 'python')
|
||||||
if (CellModel.LanguageMapping[languageInfo.name]) {
|
if (CellModel.LanguageMapping[languageInfo.name]) {
|
||||||
this._language = CellModel.LanguageMapping[languageInfo.name];
|
this._language = CellModel.LanguageMapping[languageInfo.name];
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this._language = languageInfo.name;
|
this._language = languageInfo.name;
|
||||||
}
|
}
|
||||||
} else if (languageInfo.mimetype) {
|
}
|
||||||
|
else if (languageInfo.mimetype) {
|
||||||
this._language = languageInfo.mimetype;
|
this._language = languageInfo.mimetype;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mimeTypePrefix = 'x-';
|
|
||||||
if (this._language.includes(mimeTypePrefix)) {
|
if (this._language) {
|
||||||
this._language = this._language.replace(mimeTypePrefix, '');
|
let mimeTypePrefix = 'x-';
|
||||||
|
if (this._language.includes(mimeTypePrefix)) {
|
||||||
|
this._language = this._language.replace(mimeTypePrefix, '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private hasLanguage(): boolean {
|
||||||
|
return !!this._language;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { ClientSession } from './clientSession';
|
|||||||
|
|
||||||
export class ModelFactory implements IModelFactory {
|
export class ModelFactory implements IModelFactory {
|
||||||
|
|
||||||
public createCell(cell: nb.ICell, options: ICellModelOptions): ICellModel {
|
public createCell(cell: nb.ICellContents, options: ICellModelOptions): ICellModel {
|
||||||
return new CellModel(this, cell, options);
|
return new CellModel(this, cell, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { INotebookManager } from 'sql/services/notebook/notebookService';
|
|||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
||||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||||
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
export interface IClientSessionOptions {
|
export interface IClientSessionOptions {
|
||||||
notebookUri: URI;
|
notebookUri: URI;
|
||||||
@@ -287,6 +288,12 @@ export interface INotebookModel {
|
|||||||
*/
|
*/
|
||||||
readonly contexts: IDefaultConnection | undefined;
|
readonly contexts: IDefaultConnection | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event fired on first initialization of the cells and
|
||||||
|
* on subsequent change events
|
||||||
|
*/
|
||||||
|
readonly contentChanged: Event<NotebookContentChange>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The trusted mode of the Notebook
|
* The trusted mode of the Notebook
|
||||||
*/
|
*/
|
||||||
@@ -328,6 +335,37 @@ export interface INotebookModel {
|
|||||||
* Notifies the notebook of a change in the cell
|
* Notifies the notebook of a change in the cell
|
||||||
*/
|
*/
|
||||||
onCellChange(cell: ICellModel, change: NotebookChangeType): void;
|
onCellChange(cell: ICellModel, change: NotebookChangeType): void;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push edit operations, basically editing the model. This is the preferred way of
|
||||||
|
* editing the model. Long-term, this will ensure edit operations can be added to the undo stack
|
||||||
|
* @param edits The edit operations to perform
|
||||||
|
*/
|
||||||
|
pushEditOperations(edits: ISingleNotebookEditOperation[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotebookContentChange {
|
||||||
|
/**
|
||||||
|
* The type of change that occurred
|
||||||
|
*/
|
||||||
|
changeType: NotebookChangeType;
|
||||||
|
/**
|
||||||
|
* Optional cells that were changed
|
||||||
|
*/
|
||||||
|
cells?: ICellModel | ICellModel[];
|
||||||
|
/**
|
||||||
|
* Optional index of the change, indicating the cell at which an insert or
|
||||||
|
* delete occurred
|
||||||
|
*/
|
||||||
|
cellIndex?: number;
|
||||||
|
/**
|
||||||
|
* Optional value indicating if the notebook is in a dirty or clean state after this change
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof NotebookContentChange
|
||||||
|
*/
|
||||||
|
isDirty?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICellModelOptions {
|
export interface ICellModelOptions {
|
||||||
@@ -348,7 +386,7 @@ export interface ICellModel {
|
|||||||
readonly onOutputsChanged: Event<ReadonlyArray<nb.ICellOutput>>;
|
readonly onOutputsChanged: Event<ReadonlyArray<nb.ICellOutput>>;
|
||||||
setFuture(future: FutureInternal): void;
|
setFuture(future: FutureInternal): void;
|
||||||
equals(cellModel: ICellModel): boolean;
|
equals(cellModel: ICellModel): boolean;
|
||||||
toJSON(): nb.ICell;
|
toJSON(): nb.ICellContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FutureInternal extends nb.IFuture {
|
export interface FutureInternal extends nb.IFuture {
|
||||||
@@ -357,7 +395,7 @@ export interface FutureInternal extends nb.IFuture {
|
|||||||
|
|
||||||
export interface IModelFactory {
|
export interface IModelFactory {
|
||||||
|
|
||||||
createCell(cell: nb.ICell, options: ICellModelOptions): ICellModel;
|
createCell(cell: nb.ICellContents, options: ICellModelOptions): ICellModel;
|
||||||
createClientSession(options: IClientSessionOptions): IClientSession;
|
createClientSession(options: IClientSessionOptions): IClientSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
import { CellModel } from './cell';
|
import { CellModel } from './cell';
|
||||||
import { IClientSession, INotebookModel, IDefaultConnection, INotebookModelOptions, ICellModel, notebookConstants } from './modelInterfaces';
|
import { IClientSession, INotebookModel, IDefaultConnection, INotebookModelOptions, ICellModel, notebookConstants, NotebookContentChange } from './modelInterfaces';
|
||||||
import { NotebookChangeType, CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
import { NotebookChangeType, CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { nbversion } from '../notebookConstants';
|
import { nbversion } from '../notebookConstants';
|
||||||
import * as notebookUtils from '../notebookUtils';
|
import * as notebookUtils from '../notebookUtils';
|
||||||
@@ -22,6 +22,8 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
|||||||
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
||||||
import { INotification, Severity } from 'vs/platform/notification/common/notification';
|
import { INotification, Severity } from 'vs/platform/notification/common/notification';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import URI from 'vs/base/common/uri';
|
||||||
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to control whether a message in a dialog/wizard is displayed as an error,
|
* Used to control whether a message in a dialog/wizard is displayed as an error,
|
||||||
@@ -37,28 +39,6 @@ export class ErrorInfo {
|
|||||||
constructor(public readonly message: string, public readonly severity: MessageLevel) {
|
constructor(public readonly message: string, public readonly severity: MessageLevel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface NotebookContentChange {
|
|
||||||
/**
|
|
||||||
* What was the change that occurred?
|
|
||||||
*/
|
|
||||||
changeType: NotebookChangeType;
|
|
||||||
/**
|
|
||||||
* Optional cells that were changed
|
|
||||||
*/
|
|
||||||
cells?: ICellModel | ICellModel[];
|
|
||||||
/**
|
|
||||||
* Optional index of the change, indicating the cell at which an insert or
|
|
||||||
* delete occurred
|
|
||||||
*/
|
|
||||||
cellIndex?: number;
|
|
||||||
/**
|
|
||||||
* Optional value indicating if the notebook is in a dirty or clean state after this change
|
|
||||||
*
|
|
||||||
* @type {boolean}
|
|
||||||
* @memberof NotebookContentChange
|
|
||||||
*/
|
|
||||||
isDirty?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookModel extends Disposable implements INotebookModel {
|
export class NotebookModel extends Disposable implements INotebookModel {
|
||||||
private _contextsChangedEmitter = new Emitter<void>();
|
private _contextsChangedEmitter = new Emitter<void>();
|
||||||
@@ -96,6 +76,13 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
return this.notebookOptions.notebookManager;
|
return this.notebookOptions.notebookManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get notebookUri() : URI {
|
||||||
|
return this.notebookOptions.notebookUri;
|
||||||
|
}
|
||||||
|
public set notebookUri(value : URI) {
|
||||||
|
this.notebookOptions.notebookUri = value;
|
||||||
|
}
|
||||||
|
|
||||||
public get hasServerManager(): boolean {
|
public get hasServerManager(): boolean {
|
||||||
// If the service has a server manager, then we can show the start button
|
// If the service has a server manager, then we can show the start button
|
||||||
return !!this.notebookManager.serverManager;
|
return !!this.notebookManager.serverManager;
|
||||||
@@ -237,7 +224,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createCell(cellType: CellType): ICellModel {
|
private createCell(cellType: CellType): ICellModel {
|
||||||
let singleCell: nb.ICell = {
|
let singleCell: nb.ICellContents = {
|
||||||
cell_type: cellType,
|
cell_type: cellType,
|
||||||
source: '',
|
source: '',
|
||||||
metadata: {},
|
metadata: {},
|
||||||
@@ -263,6 +250,25 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pushEditOperations(edits: ISingleNotebookEditOperation[]): void {
|
||||||
|
if (this.inErrorState || !this._cells) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let edit of edits) {
|
||||||
|
let newCells: ICellModel[] = [];
|
||||||
|
if (edit.cell) {
|
||||||
|
// TODO: should we validate and complete required missing parameters?
|
||||||
|
let contents: nb.ICellContents = edit.cell as nb.ICellContents;
|
||||||
|
newCells.push(this.notebookOptions.factory.createCell(contents, { notebook: this, isTrusted: this._trustedMode }));
|
||||||
|
}
|
||||||
|
this._cells.splice(edit.range.start, edit.range.end - edit.range.start, ...newCells);
|
||||||
|
this._contentChangedEmitter.fire({
|
||||||
|
changeType: NotebookChangeType.CellsAdded
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public get activeCell(): ICellModel {
|
public get activeCell(): ICellModel {
|
||||||
return this._activeCell;
|
return this._activeCell;
|
||||||
}
|
}
|
||||||
@@ -281,9 +287,14 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
notebookManager: this.notebookManager,
|
notebookManager: this.notebookManager,
|
||||||
notificationService: this.notebookOptions.notificationService
|
notificationService: this.notebookOptions.notificationService
|
||||||
});
|
});
|
||||||
let id: string = this.connectionProfile ? this.connectionProfile.id : undefined;
|
let profile = this.connectionProfile as IConnectionProfile;
|
||||||
|
|
||||||
|
if (this.isValidKnoxConnection(profile)) {
|
||||||
|
this._hadoopConnection = new NotebookConnection(this.connectionProfile);
|
||||||
|
} else {
|
||||||
|
this._hadoopConnection = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
this._hadoopConnection = this.connectionProfile ? new NotebookConnection(this.connectionProfile) : undefined;
|
|
||||||
this._clientSession.initialize(this._hadoopConnection);
|
this._clientSession.initialize(this._hadoopConnection);
|
||||||
this._sessionLoadFinished = this._clientSession.ready.then(async () => {
|
this._sessionLoadFinished = this._clientSession.ready.then(async () => {
|
||||||
if (this._clientSession.isInErrorState) {
|
if (this._clientSession.isInErrorState) {
|
||||||
@@ -389,7 +400,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
|
|
||||||
// Get default language if saved in notebook file
|
// Get default language if saved in notebook file
|
||||||
// Otherwise, default to python
|
// Otherwise, default to python
|
||||||
private getDefaultLanguageInfo(notebook: nb.INotebook): nb.ILanguageInfo {
|
private getDefaultLanguageInfo(notebook: nb.INotebookContents): nb.ILanguageInfo {
|
||||||
return notebook!.metadata!.language_info || {
|
return notebook!.metadata!.language_info || {
|
||||||
name: 'python',
|
name: 'python',
|
||||||
version: '',
|
version: '',
|
||||||
@@ -398,7 +409,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get default kernel info if saved in notebook file
|
// Get default kernel info if saved in notebook file
|
||||||
private getSavedKernelInfo(notebook: nb.INotebook): nb.IKernelInfo {
|
private getSavedKernelInfo(notebook: nb.INotebookContents): nb.IKernelInfo {
|
||||||
return notebook!.metadata!.kernelspec;
|
return notebook!.metadata!.kernelspec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,8 +501,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
/**
|
/**
|
||||||
* Serialize the model to JSON.
|
* Serialize the model to JSON.
|
||||||
*/
|
*/
|
||||||
toJSON(): nb.INotebook {
|
toJSON(): nb.INotebookContents {
|
||||||
let cells: nb.ICell[] = this.cells.map(c => c.toJSON());
|
let cells: nb.ICellContents[] = this.cells.map(c => c.toJSON());
|
||||||
let metadata = Object.create(null) as nb.INotebookMetadata;
|
let metadata = Object.create(null) as nb.INotebookMetadata;
|
||||||
// TODO update language and kernel when these change
|
// TODO update language and kernel when these change
|
||||||
metadata.kernelspec = this._savedKernelInfo;
|
metadata.kernelspec = this._savedKernelInfo;
|
||||||
|
|||||||
@@ -140,12 +140,19 @@ export class SparkMagicContexts {
|
|||||||
* @param savedKernelInfo kernel info loaded from
|
* @param savedKernelInfo kernel info loaded from
|
||||||
*/
|
*/
|
||||||
public static getDefaultKernel(specs: nb.IAllKernels, connectionInfo: IConnectionProfile, savedKernelInfo: nb.IKernelInfo, notificationService: INotificationService): nb.IKernelSpec {
|
public static getDefaultKernel(specs: nb.IAllKernels, connectionInfo: IConnectionProfile, savedKernelInfo: nb.IKernelInfo, notificationService: INotificationService): nb.IKernelSpec {
|
||||||
let defaultKernel = specs.kernels.find((kernel) => kernel.name === specs.defaultKernel);
|
let foundSavedKernelInSpecs;
|
||||||
|
let defaultKernel;
|
||||||
|
if (specs) {
|
||||||
|
defaultKernel = specs.kernels.find((kernel) => kernel.name === specs.defaultKernel);
|
||||||
|
if (savedKernelInfo) {
|
||||||
|
foundSavedKernelInSpecs = specs.kernels.find((kernel) => kernel.name === savedKernelInfo.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
let profile = connectionInfo as IConnectionProfile;
|
let profile = connectionInfo as IConnectionProfile;
|
||||||
if (specs && connectionInfo && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
if (specs && connectionInfo && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
||||||
// set default kernel to default spark kernel if profile exists
|
// set default kernel to default spark kernel if profile exists
|
||||||
// otherwise, set default to kernel info loaded from existing file
|
// otherwise, set default to kernel info loaded from existing file
|
||||||
defaultKernel = !savedKernelInfo ? specs.kernels.find((spec) => spec.name === notebookConstants.defaultSparkKernel) : savedKernelInfo;
|
defaultKernel = !foundSavedKernelInSpecs ? specs.kernels.find((spec) => spec.name === notebookConstants.defaultSparkKernel) : foundSavedKernelInSpecs;
|
||||||
} else {
|
} else {
|
||||||
// Handle kernels
|
// Handle kernels
|
||||||
if (savedKernelInfo && savedKernelInfo.name.toLowerCase().indexOf('spark') > -1) {
|
if (savedKernelInfo && savedKernelInfo.name.toLowerCase().indexOf('spark') > -1) {
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
-->
|
-->
|
||||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||||
<div #toolbar class="editor-toolbar actionbar-container" style="flex: 0 0 auto; display: flex; flex-flow: row; width: 100%; align-items: center; height: 36px">
|
<div #toolbar class="editor-toolbar actionbar-container" style="flex: 0 0 auto; display: flex; flex-flow: row; width: 100%; align-items: center;">
|
||||||
</div>
|
</div>
|
||||||
<div class="scrollable" style="flex: 1 1 auto; position: relative">
|
<div class="scrollable" style="flex: 1 1 auto; position: relative" (click)="unselectActiveCell()">
|
||||||
<loading-spinner [loading]="isLoading"></loading-spinner>
|
<loading-spinner [loading]="isLoading"></loading-spinner>
|
||||||
<div class="notebook-cell" *ngFor="let cell of cells" (click)="selectCell(cell)" [class.active]="cell.active" (keydown)="onKeyDown($event)">
|
<div class="notebook-cell" *ngFor="let cell of cells" (click)="selectCell(cell, $event)" [class.active]="cell.active">
|
||||||
<code-cell-component *ngIf="cell.cellType === 'code'" [cellModel]="cell" [model]="model" [activeCellId]="activeCellId">
|
<code-cell-component *ngIf="cell.cellType === 'code'" [cellModel]="cell" [model]="model" [activeCellId]="activeCellId">
|
||||||
</code-cell-component>
|
</code-cell-component>
|
||||||
<text-cell-component *ngIf="cell.cellType === 'markdown'" [cellModel]="cell" [activeCellId]="activeCellId">
|
<text-cell-component *ngIf="cell.cellType === 'markdown'" [cellModel]="cell" [model]="model" [activeCellId]="activeCellId">
|
||||||
</text-cell-component>
|
</text-cell-component>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,34 +5,50 @@
|
|||||||
|
|
||||||
import './notebookStyles';
|
import './notebookStyles';
|
||||||
|
|
||||||
import { nb } from 'sqlops';
|
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnDestroy } from '@angular/core';
|
||||||
|
|
||||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild } from '@angular/core';
|
|
||||||
|
|
||||||
import URI from 'vs/base/common/uri';
|
|
||||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import * as themeColors from 'vs/workbench/common/theme';
|
import * as themeColors from 'vs/workbench/common/theme';
|
||||||
import { INotificationService, INotification } from 'vs/platform/notification/common/notification';
|
import { INotificationService, INotification, Severity } from 'vs/platform/notification/common/notification';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||||
|
import { IAction, Action, IActionItem } from 'vs/base/common/actions';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
|
import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import URI from 'vs/base/common/uri';
|
||||||
|
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||||
|
import * as paths from 'vs/base/common/paths';
|
||||||
|
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||||
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||||
|
import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions';
|
||||||
|
|
||||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||||
|
import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
import { ICellModel, IModelFactory, notebookConstants, INotebookModel, NotebookContentChange } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { ICellModel, IModelFactory } from 'sql/parts/notebook/models/modelInterfaces';
|
|
||||||
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
||||||
import { INotebookService, INotebookParams, INotebookManager } from 'sql/services/notebook/notebookService';
|
import { INotebookService, INotebookParams, INotebookManager, INotebookEditor, DEFAULT_NOTEBOOK_FILETYPE, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
||||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||||
import { NotebookModel, ErrorInfo, MessageLevel, NotebookContentChange } from 'sql/parts/notebook/models/notebookModel';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
||||||
import * as notebookUtils from './notebookUtils';
|
import * as notebookUtils from 'sql/parts/notebook/notebookUtils';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
||||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||||
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction } from 'sql/parts/notebook/notebookActions';
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
||||||
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
|
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||||
|
|
||||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||||
|
|
||||||
@@ -41,7 +57,7 @@ export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
|||||||
selector: NOTEBOOK_SELECTOR,
|
selector: NOTEBOOK_SELECTOR,
|
||||||
templateUrl: decodeURI(require.toUrl('./notebook.component.html'))
|
templateUrl: decodeURI(require.toUrl('./notebook.component.html'))
|
||||||
})
|
})
|
||||||
export class NotebookComponent extends AngularDisposable implements OnInit {
|
export class NotebookComponent extends AngularDisposable implements OnInit, OnDestroy, INotebookEditor {
|
||||||
@ViewChild('toolbar', { read: ElementRef }) private toolbar: ElementRef;
|
@ViewChild('toolbar', { read: ElementRef }) private toolbar: ElementRef;
|
||||||
private _model: NotebookModel;
|
private _model: NotebookModel;
|
||||||
private _isInErrorState: boolean = false;
|
private _isInErrorState: boolean = false;
|
||||||
@@ -62,26 +78,61 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||||
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
|
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
|
||||||
|
@Inject(IObjectExplorerService) private objectExplorerService: IObjectExplorerService,
|
||||||
|
@Inject(IEditorService) private editorService: IEditorService,
|
||||||
@Inject(INotificationService) private notificationService: INotificationService,
|
@Inject(INotificationService) private notificationService: INotificationService,
|
||||||
@Inject(INotebookService) private notebookService: INotebookService,
|
@Inject(INotebookService) private notebookService: INotebookService,
|
||||||
@Inject(IBootstrapParams) private notebookParams: INotebookParams,
|
@Inject(IBootstrapParams) private _notebookParams: INotebookParams,
|
||||||
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
||||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||||
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService
|
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService,
|
||||||
|
@Inject(IContextKeyService) private contextKeyService: IContextKeyService,
|
||||||
|
@Inject(IMenuService) private menuService: IMenuService,
|
||||||
|
@Inject(IKeybindingService) private keybindingService: IKeybindingService,
|
||||||
|
@Inject(IHistoryService) private historyService: IHistoryService,
|
||||||
|
@Inject(IWindowService) private windowService: IWindowService,
|
||||||
|
@Inject(IViewletService) private viewletService: IViewletService,
|
||||||
|
@Inject(IUntitledEditorService) private untitledEditorService: IUntitledEditorService,
|
||||||
|
@Inject(IEditorGroupsService) private editorGroupService: IEditorGroupsService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.profile = this.notebookParams!.profile;
|
this.updateProfile();
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateProfile(): void {
|
||||||
|
this.profile = this.notebookParams!.profile;
|
||||||
|
if (!this.profile) {
|
||||||
|
// use global connection if possible
|
||||||
|
let profile = TaskUtilities.getCurrentGlobalConnection(this.objectExplorerService, this.connectionManagementService, this.editorService);
|
||||||
|
// TODO use generic method to match kernel with valid connection that's compatible. For now, we only have 1
|
||||||
|
if (profile && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
||||||
|
this.profile = profile;
|
||||||
|
} else {
|
||||||
|
// if not, try 1st active connection that matches our filter
|
||||||
|
let profiles = this.connectionManagementService.getActiveConnections([notebookConstants.hadoopKnoxProviderName]);
|
||||||
|
if (profiles && profiles.length > 0) {
|
||||||
|
this.profile = profiles[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||||
this.updateTheme(this.themeService.getColorTheme());
|
this.updateTheme(this.themeService.getColorTheme());
|
||||||
|
this.notebookService.addNotebookEditor(this);
|
||||||
this.initActionBar();
|
this.initActionBar();
|
||||||
this.doLoad();
|
this.doLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.notebookService) {
|
||||||
|
this.notebookService.removeNotebookEditor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public get model(): NotebookModel {
|
public get model(): NotebookModel {
|
||||||
return this._model;
|
return this._model;
|
||||||
}
|
}
|
||||||
@@ -94,7 +145,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
return this._modelRegisteredDeferred.promise;
|
return this._modelRegisteredDeferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get cells(): ReadonlyArray<ICellModel> {
|
public get cells(): ICellModel[] {
|
||||||
return this._model ? this._model.cells : [];
|
return this._model ? this._model.cells : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +154,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
toolbarEl.style.borderBottomColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
toolbarEl.style.borderBottomColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public selectCell(cell: ICellModel) {
|
public selectCell(cell: ICellModel, event?: Event) {
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
if (cell !== this._activeCell) {
|
if (cell !== this._activeCell) {
|
||||||
if (this._activeCell) {
|
if (this._activeCell) {
|
||||||
this._activeCell.active = false;
|
this._activeCell.active = false;
|
||||||
@@ -116,6 +170,16 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unselectActiveCell() {
|
||||||
|
if (this._activeCell) {
|
||||||
|
this._activeCell.active = false;
|
||||||
|
}
|
||||||
|
this._activeCell = null;
|
||||||
|
this._model.activeCell = null;
|
||||||
|
this._activeCellId = null;
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
// Add cell based on cell type
|
// Add cell based on cell type
|
||||||
public addCell(cellType: CellType)
|
public addCell(cellType: CellType)
|
||||||
{
|
{
|
||||||
@@ -171,16 +235,17 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async loadModel(): Promise<void> {
|
private async loadModel(): Promise<void> {
|
||||||
this.notebookManager = await this.notebookService.getOrCreateNotebookManager(this.notebookParams.providerId, this.notebookParams.notebookUri);
|
await this.awaitNonDefaultProvider();
|
||||||
|
this.notebookManager = await this.notebookService.getOrCreateNotebookManager(this._notebookParams.providerId, this._notebookParams.notebookUri);
|
||||||
let model = new NotebookModel({
|
let model = new NotebookModel({
|
||||||
factory: this.modelFactory,
|
factory: this.modelFactory,
|
||||||
notebookUri: this.notebookParams.notebookUri,
|
notebookUri: this._notebookParams.notebookUri,
|
||||||
connectionService: this.connectionManagementService,
|
connectionService: this.connectionManagementService,
|
||||||
notificationService: this.notificationService,
|
notificationService: this.notificationService,
|
||||||
notebookManager: this.notebookManager
|
notebookManager: this.notebookManager
|
||||||
}, false, this.profile);
|
}, false, this.profile);
|
||||||
model.onError((errInfo: INotification) => this.handleModelError(errInfo));
|
model.onError((errInfo: INotification) => this.handleModelError(errInfo));
|
||||||
await model.requestModelLoad(this.notebookParams.isTrusted);
|
await model.requestModelLoad(this._notebookParams.isTrusted);
|
||||||
model.contentChanged((change) => this.handleContentChanged(change));
|
model.contentChanged((change) => this.handleContentChanged(change));
|
||||||
this._model = model;
|
this._model = model;
|
||||||
this.updateToolbarComponents(this._model.trustedMode);
|
this.updateToolbarComponents(this._model.trustedMode);
|
||||||
@@ -190,6 +255,34 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async awaitNonDefaultProvider(): Promise<void> {
|
||||||
|
// Wait on registration for now. Long-term would be good to cache and refresh
|
||||||
|
await this.notebookService.registrationComplete;
|
||||||
|
// Refresh the provider if we had been using default
|
||||||
|
if (DEFAULT_NOTEBOOK_PROVIDER === this._notebookParams.providerId) {
|
||||||
|
this._notebookParams.providerId = notebookUtils.getProviderForFileName(this._notebookParams.notebookUri.fsPath, this.notebookService);
|
||||||
|
}
|
||||||
|
if (DEFAULT_NOTEBOOK_PROVIDER === this._notebookParams.providerId) {
|
||||||
|
// If it's still the default, warn them they should install an extension
|
||||||
|
this.notificationService.prompt(Severity.Warning,
|
||||||
|
localize('noKernelInstalled', 'Please install the SQL Server 2019 extension to run cells'),
|
||||||
|
[{
|
||||||
|
label: localize('installSql2019Extension', 'Install Extension'),
|
||||||
|
run: () => this.openExtensionGallery()
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async openExtensionGallery(): Promise<void> {
|
||||||
|
try {
|
||||||
|
let viewlet = await this.viewletService.openViewlet(VIEWLET_ID, true) as IExtensionsViewlet;
|
||||||
|
viewlet.search('sql-vnext');
|
||||||
|
viewlet.focus();
|
||||||
|
} catch (error) {
|
||||||
|
this.notificationService.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Updates toolbar components
|
// Updates toolbar components
|
||||||
private updateToolbarComponents(isTrusted: boolean)
|
private updateToolbarComponents(isTrusted: boolean)
|
||||||
{
|
{
|
||||||
@@ -201,10 +294,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get modelFactory(): IModelFactory {
|
private get modelFactory(): IModelFactory {
|
||||||
if (!this.notebookParams.modelFactory) {
|
if (!this._notebookParams.modelFactory) {
|
||||||
this.notebookParams.modelFactory = new ModelFactory();
|
this._notebookParams.modelFactory = new ModelFactory();
|
||||||
}
|
}
|
||||||
return this.notebookParams.modelFactory;
|
return this._notebookParams.modelFactory;
|
||||||
}
|
}
|
||||||
private handleModelError(notification: INotification): void {
|
private handleModelError(notification: INotification): void {
|
||||||
this.notificationService.notify(notification);
|
this.notificationService.notify(notification);
|
||||||
@@ -239,9 +332,6 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
attachTodropdwon.render(attachToContainer);
|
attachTodropdwon.render(attachToContainer);
|
||||||
attachSelectBoxStyler(attachTodropdwon, this.themeService);
|
attachSelectBoxStyler(attachTodropdwon, this.themeService);
|
||||||
|
|
||||||
let attachToInfoText = document.createElement('div');
|
|
||||||
attachToInfoText.className = 'notebook-info-label';
|
|
||||||
attachToInfoText.innerText = 'Attach To: ';
|
|
||||||
|
|
||||||
let addCodeCellButton = new AddCellAction('notebook.AddCodeCell', localize('code', 'Code'), 'notebook-button icon-add');
|
let addCodeCellButton = new AddCellAction('notebook.AddCodeCell', localize('code', 'Code'), 'notebook-button icon-add');
|
||||||
addCodeCellButton.cellType = CellTypes.Code;
|
addCodeCellButton.cellType = CellTypes.Code;
|
||||||
@@ -252,21 +342,115 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
this._trustedAction = this.instantiationService.createInstance(TrustedAction, 'notebook.Trusted');
|
this._trustedAction = this.instantiationService.createInstance(TrustedAction, 'notebook.Trusted');
|
||||||
this._trustedAction.enabled = false;
|
this._trustedAction.enabled = false;
|
||||||
|
|
||||||
|
let saveNotebookButton = this.instantiationService.createInstance(SaveNotebookAction, 'notebook.SaveNotebook', localize('save', 'Save'), 'notebook-button icon-save');
|
||||||
|
|
||||||
|
// Get all of the menu contributions that use the ID 'notebook/toolbar'.
|
||||||
|
// Then, find all groups (currently we don't leverage the contributed
|
||||||
|
// groups functionality for the notebook toolbar), and fill in the 'primary'
|
||||||
|
// array with items that don't list a group. Finally, add any actions from
|
||||||
|
// the primary array to the end of the toolbar.
|
||||||
|
const notebookBarMenu = this.menuService.createMenu(MenuId.NotebookToolbar, this.contextKeyService);
|
||||||
|
let groups = notebookBarMenu.getActions({ arg: null, shouldForwardArgs: true });
|
||||||
|
let primary: IAction[] = [];
|
||||||
|
let secondary: IAction[] = [];
|
||||||
|
fillInActions(groups, {primary, secondary}, false, (group: string) => group === undefined);
|
||||||
|
|
||||||
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
||||||
this._actionBar = new Taskbar(taskbar, this.contextMenuService);
|
this._actionBar = new Taskbar(taskbar, this.contextMenuService, { actionItemProvider: action => this.actionItemProvider(action as Action)});
|
||||||
this._actionBar.context = this;
|
this._actionBar.context = this;
|
||||||
this._actionBar.setContent([
|
this._actionBar.setContent([
|
||||||
{ element: kernelContainer },
|
{ element: kernelContainer },
|
||||||
{ element: attachToContainer },
|
{ element: attachToContainer },
|
||||||
{ action: addCodeCellButton},
|
{ action: addCodeCellButton },
|
||||||
{ action: addTextCellButton},
|
{ action: addTextCellButton },
|
||||||
{ action: this._trustedAction}
|
{ action: saveNotebookButton },
|
||||||
|
{ action: this._trustedAction }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Primary actions are categorized as those that are added to the 'horizontal' group.
|
||||||
|
// For the vertical toolbar, we can do the same thing and instead use the 'vertical' group.
|
||||||
|
for (let action of primary) {
|
||||||
|
this._actionBar.addAction(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets file path from recent workspace in local
|
||||||
|
private getLastActiveFilePath(untitledResource: URI): string {
|
||||||
|
let fileName = untitledResource.path + '.' + DEFAULT_NOTEBOOK_FILETYPE.toLocaleLowerCase();
|
||||||
|
|
||||||
|
let lastActiveFile = this.historyService.getLastActiveFile();
|
||||||
|
if (lastActiveFile) {
|
||||||
|
return URI.file(paths.join(paths.dirname(lastActiveFile.fsPath), fileName)).fsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastActiveFolder = this.historyService.getLastActiveWorkspaceRoot('file');
|
||||||
|
if (lastActiveFolder) {
|
||||||
|
return URI.file(paths.join(lastActiveFolder.fsPath, fileName)).fsPath;
|
||||||
|
}
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
promptForPath(defaultPath: string): TPromise<string> {
|
||||||
|
return this.windowService.showSaveDialog({
|
||||||
|
defaultPath: defaultPath,
|
||||||
|
filters: [{ name: localize('notebookFile', 'Notebook'), extensions: ['ipynb']}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point to save notebook
|
||||||
public async save(): Promise<boolean> {
|
public async save(): Promise<boolean> {
|
||||||
|
let self = this;
|
||||||
|
let notebookUri = this.notebookParams.notebookUri;
|
||||||
|
if (notebookUri.scheme === Schemas.untitled) {
|
||||||
|
let dialogPath = this.getLastActiveFilePath(notebookUri);
|
||||||
|
return this.promptForPath(dialogPath).then(path => {
|
||||||
|
if (path) {
|
||||||
|
let target = URI.file(path);
|
||||||
|
let resource = self._model.notebookUri;
|
||||||
|
self._model.notebookUri = target;
|
||||||
|
this.saveNotebook().then(result => {
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
return this.replaceUntitledNotebookEditor(resource, target);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false; // User clicks cancel
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return await this.saveNotebook();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces untitled notebook editor with the saved file name
|
||||||
|
private async replaceUntitledNotebookEditor(resource: URI, target: URI): Promise<boolean> {
|
||||||
|
let encodingOfSource = this.untitledEditorService.getEncoding(resource);
|
||||||
|
const replacement: IResourceInput = {
|
||||||
|
resource: target,
|
||||||
|
encoding: encodingOfSource,
|
||||||
|
options: {
|
||||||
|
pinned: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TPromise.join(this.editorGroupService.groups.map(g =>
|
||||||
|
this.editorService.replaceEditors([{
|
||||||
|
editor: { resource },
|
||||||
|
replacement
|
||||||
|
}], g))).then(() => {
|
||||||
|
this.notebookService.renameNotebookEditor(resource, target, this);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async saveNotebook(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
let saved = await this._model.saveModel();
|
let saved = await this._model.saveModel();
|
||||||
|
if (saved) {
|
||||||
|
this.setDirty(false);
|
||||||
|
}
|
||||||
return saved;
|
return saved;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.notificationService.error(localize('saveFailed', 'Failed to save notebook: {0}', notebookUtils.getErrorMessage(err)));
|
this.notificationService.error(localize('saveFailed', 'Failed to save notebook: {0}', notebookUtils.getErrorMessage(err)));
|
||||||
@@ -275,11 +459,50 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setDirty(isDirty: boolean): void {
|
private setDirty(isDirty: boolean): void {
|
||||||
// TODO reenable handling of isDirty
|
if(this._notebookParams.input){
|
||||||
// if (this.editor) {
|
this._notebookParams.input.setDirty(isDirty);
|
||||||
// this.editor.isDirty = isDirty;
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private actionItemProvider(action: Action): IActionItem {
|
||||||
|
// Check extensions to create ActionItem; otherwise, return undefined
|
||||||
|
// This is similar behavior that exists in MenuItemActionItem
|
||||||
|
if (action instanceof MenuItemAction) {
|
||||||
|
return new LabeledMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService, 'notebook-button');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get notebookParams(): INotebookParams {
|
||||||
|
return this._notebookParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string {
|
||||||
|
return this._notebookParams.notebookUri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get modelReady(): Promise<INotebookModel> {
|
||||||
|
return this._modelReadyDeferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
isActive(): boolean {
|
||||||
|
return this.editorService.activeEditor === this.notebookParams.input;
|
||||||
|
}
|
||||||
|
|
||||||
|
isVisible(): boolean {
|
||||||
|
let notebookEditor = this.notebookParams.input;
|
||||||
|
return this.editorService.visibleEditors.some(e => e === notebookEditor);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirty(): boolean {
|
||||||
|
return this.notebookParams.input.isDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
executeEdits(edits: ISingleNotebookEditOperation[]): boolean {
|
||||||
|
if (!edits || edits.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this._model.pushEditOperations(edits);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,50 +4,10 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
|
||||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
|
||||||
import { Action } from 'vs/base/common/actions';
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import URI from 'vs/base/common/uri';
|
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
|
|
||||||
import { NotebookInput, NotebookInputModel, notebooksEnabledCondition } from 'sql/parts/notebook/notebookInput';
|
import { NotebookInput } from 'sql/parts/notebook/notebookInput';
|
||||||
import { NotebookEditor } from 'sql/parts/notebook/notebookEditor';
|
import { NotebookEditor } from 'sql/parts/notebook/notebookEditor';
|
||||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
|
||||||
|
|
||||||
|
|
||||||
let counter = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* todo: Will remove this code.
|
|
||||||
* This is the entry point to open the new Notebook
|
|
||||||
*/
|
|
||||||
export class NewNotebookAction extends Action {
|
|
||||||
|
|
||||||
public static ID = 'workbench.action.newnotebook';
|
|
||||||
public static LABEL = localize('workbench.action.newnotebook.description', 'New Notebook');
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
id: string,
|
|
||||||
label: string,
|
|
||||||
@IEditorService private _editorService: IEditorService,
|
|
||||||
@IInstantiationService private _instantiationService: IInstantiationService
|
|
||||||
) {
|
|
||||||
super(id, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
public run(): TPromise<void> {
|
|
||||||
let title = `Untitled-${counter++}`;
|
|
||||||
let untitledUri = URI.from({ scheme: Schemas.untitled, path: title });
|
|
||||||
let model = new NotebookInputModel(untitledUri, undefined, false, undefined);
|
|
||||||
let input = this._instantiationService.createInstance(NotebookInput, title, model);
|
|
||||||
return this._editorService.openEditor(input, { pinned: true }).then(() => undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Model View editor registration
|
// Model View editor registration
|
||||||
const viewModelEditorDescriptor = new EditorDescriptor(
|
const viewModelEditorDescriptor = new EditorDescriptor(
|
||||||
@@ -58,31 +18,3 @@ const viewModelEditorDescriptor = new EditorDescriptor(
|
|||||||
|
|
||||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||||
.registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(NotebookInput)]);
|
.registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(NotebookInput)]);
|
||||||
|
|
||||||
// Feature flag for built-in Notebooks. Will be removed in the future.
|
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration);
|
|
||||||
configurationRegistry.registerConfiguration({
|
|
||||||
'id': 'notebook',
|
|
||||||
'title': 'Notebook',
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'notebook.enabled': {
|
|
||||||
'type': 'boolean',
|
|
||||||
'default': false,
|
|
||||||
'description': localize('notebook.enabledDescription', 'Enable viewing notebook files using built-in notebook editor.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// this is the entry point to open the new Notebook
|
|
||||||
CommandsRegistry.registerCommand(NewNotebookAction.ID, serviceAccessor => {
|
|
||||||
serviceAccessor.get(IInstantiationService).createInstance(NewNotebookAction, NewNotebookAction.ID, NewNotebookAction.LABEL).run();
|
|
||||||
});
|
|
||||||
|
|
||||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
|
||||||
command: {
|
|
||||||
id: NewNotebookAction.ID,
|
|
||||||
title:NewNotebookAction.LABEL,
|
|
||||||
},
|
|
||||||
when: notebooksEnabledCondition
|
|
||||||
});
|
|
||||||
@@ -31,9 +31,13 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
background-size: 11px;
|
background-size: 13px;
|
||||||
margin-right: 0.3em;
|
margin-right: 0.3em;
|
||||||
font-size: 11px;
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notebookEditor .monaco-select-box {
|
||||||
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notebookEditor .notebook-button.icon-add{
|
.notebookEditor .notebook-button.icon-add{
|
||||||
@@ -61,4 +65,18 @@
|
|||||||
.vs-dark .notebookEditor .notebook-button.icon-notTrusted,
|
.vs-dark .notebookEditor .notebook-button.icon-notTrusted,
|
||||||
.hc-black .notebookEditor .notebook-button.icon-notTrusted{
|
.hc-black .notebookEditor .notebook-button.icon-notTrusted{
|
||||||
background-image: url("./media/dark/nottrusted_inverse.svg");
|
background-image: url("./media/dark/nottrusted_inverse.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.notebookEditor .notebook-button.icon-save{
|
||||||
|
background-image: url("./media/light/save.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .notebookEditor .notebook-button.icon-save,
|
||||||
|
.hc-black .notebookEditor .notebook-button.icon-save{
|
||||||
|
background-image: url("./media/dark/save_inverse.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.moreActions .action-label.icon.toggle-more {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
|||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
||||||
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
import { noKernel } from 'sql/services/notebook/sessionManager';
|
||||||
|
|
||||||
const msgLoading = localize('loading', 'Loading kernels...');
|
const msgLoading = localize('loading', 'Loading kernels...');
|
||||||
const kernelLabel: string = localize('Kernel', 'Kernel: ');
|
const kernelLabel: string = localize('Kernel', 'Kernel: ');
|
||||||
@@ -25,7 +26,7 @@ const attachToLabel: string = localize('AttachTo', 'Attach to: ');
|
|||||||
const msgLoadingContexts = localize('loadingContexts', 'Loading contexts...');
|
const msgLoadingContexts = localize('loadingContexts', 'Loading contexts...');
|
||||||
const msgAddNewConnection = localize('addNewConnection', 'Add new connection');
|
const msgAddNewConnection = localize('addNewConnection', 'Add new connection');
|
||||||
const msgSelectConnection = localize('selectConnection', 'Select connection');
|
const msgSelectConnection = localize('selectConnection', 'Select connection');
|
||||||
const msgConnectionNotApplicable = localize('connectionNotSupported', 'n/a');
|
const msgLocalHost = localize('localhost', 'Localhost');
|
||||||
|
|
||||||
// Action to add a cell to notebook based on cell type(code/markdown).
|
// Action to add a cell to notebook based on cell type(code/markdown).
|
||||||
export class AddCellAction extends Action {
|
export class AddCellAction extends Action {
|
||||||
@@ -48,6 +49,26 @@ export class AddCellAction extends Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SaveNotebookAction extends Action {
|
||||||
|
private static readonly notebookSavedMsg = localize('notebookSavedMsg', 'Notebook saved successfully.');
|
||||||
|
private static readonly notebookFailedSaveMsg = localize('notebookFailedSaveMsg', 'Failed to save Notebook.');
|
||||||
|
constructor(
|
||||||
|
id: string, label: string, cssClass: string,
|
||||||
|
@INotificationService private _notificationService: INotificationService
|
||||||
|
) {
|
||||||
|
super(id, label, cssClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(context: NotebookComponent): TPromise<boolean> {
|
||||||
|
const actions: INotificationActions = { primary: [] };
|
||||||
|
let saved = await context.save();
|
||||||
|
if (saved) {
|
||||||
|
this._notificationService.notify({ severity: Severity.Info, message: SaveNotebookAction.notebookSavedMsg, actions });
|
||||||
|
}
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IToggleableState {
|
export interface IToggleableState {
|
||||||
baseClass?: string;
|
baseClass?: string;
|
||||||
shouldToggleTooltip?: boolean;
|
shouldToggleTooltip?: boolean;
|
||||||
@@ -215,9 +236,8 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
|
|
||||||
// Load "Attach To" dropdown with the values corresponding to Kernel dropdown
|
// Load "Attach To" dropdown with the values corresponding to Kernel dropdown
|
||||||
public async loadAttachToDropdown(model: INotebookModel, currentKernel: string): Promise<void> {
|
public async loadAttachToDropdown(model: INotebookModel, currentKernel: string): Promise<void> {
|
||||||
if (currentKernel === notebookConstants.python3) {
|
if (currentKernel === notebookConstants.python3 || currentKernel === noKernel) {
|
||||||
this.setOptions([msgConnectionNotApplicable]);
|
this.setOptions([msgLocalHost]);
|
||||||
this.disable();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let hadoopConnections = this.getHadoopConnections(model);
|
let hadoopConnections = this.getHadoopConnections(model);
|
||||||
@@ -292,6 +312,7 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
attachToConnections = attachToConnections.filter(val => val !== msgSelectConnection);
|
attachToConnections = attachToConnections.filter(val => val !== msgSelectConnection);
|
||||||
|
|
||||||
let index = attachToConnections.findIndex((connection => connection === connectedServer));
|
let index = attachToConnections.findIndex((connection => connection === connectedServer));
|
||||||
|
this.setOptions([]);
|
||||||
this.setOptions(attachToConnections);
|
this.setOptions(attachToConnections);
|
||||||
if (!index || index < 0 || index >= attachToConnections.length) {
|
if (!index || index < 0 || index >= attachToConnections.length) {
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export class NotebookEditor extends BaseEditor {
|
|||||||
input.hasBootstrapped = true;
|
input.hasBootstrapped = true;
|
||||||
let params: INotebookParams = {
|
let params: INotebookParams = {
|
||||||
notebookUri: input.notebookUri,
|
notebookUri: input.notebookUri,
|
||||||
|
input: input,
|
||||||
providerId: input.providerId ? input.providerId : DEFAULT_NOTEBOOK_PROVIDER,
|
providerId: input.providerId ? input.providerId : DEFAULT_NOTEBOOK_PROVIDER,
|
||||||
isTrusted: input.isTrusted
|
isTrusted: input.isTrusted
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { EditorInput, EditorModel, ConfirmResult } from 'vs/workbench/common/edi
|
|||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import * as resources from 'vs/base/common/resources';
|
||||||
|
|
||||||
import { INotebookService } from 'sql/services/notebook/notebookService';
|
import { INotebookService } from 'sql/services/notebook/notebookService';
|
||||||
|
|
||||||
@@ -88,15 +89,6 @@ export class NotebookInput extends EditorInput {
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire());
|
this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire());
|
||||||
this.onDispose(() => {
|
|
||||||
if (this.notebookService) {
|
|
||||||
this.notebookService.handleNotebookClosed(this.notebookUri);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public get title(): string {
|
|
||||||
return this._title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookUri(): URI {
|
public get notebookUri(): URI {
|
||||||
@@ -116,6 +108,10 @@ export class NotebookInput extends EditorInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getName(): string {
|
public getName(): string {
|
||||||
|
if (!this._title) {
|
||||||
|
this._title = resources.basenameOrAuthority(this._model.notebookUri);
|
||||||
|
}
|
||||||
|
|
||||||
return this._title;
|
return this._title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,4 +169,28 @@ export class NotebookInput extends EditorInput {
|
|||||||
save(): TPromise<boolean> {
|
save(): TPromise<boolean> {
|
||||||
return this._model.save();
|
return this._model.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets active editor with dirty value.
|
||||||
|
* @param isDirty boolean value to set editor dirty
|
||||||
|
*/
|
||||||
|
setDirty(isDirty: boolean): void {
|
||||||
|
this._model.setDirty(isDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public matches(otherInput: any): boolean {
|
||||||
|
if (super.matches(otherInput) === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherInput instanceof NotebookInput) {
|
||||||
|
const otherNotebookEditorInput = <NotebookInput>otherInput;
|
||||||
|
|
||||||
|
// Compare by resource
|
||||||
|
return otherNotebookEditorInput.notebookUri.toString() === this.notebookUri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,8 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||||||
collector.addRule(`
|
collector.addRule(`
|
||||||
.notebookEditor .notebook-cell.active {
|
.notebookEditor .notebook-cell.active {
|
||||||
border-color: ${activeBorder};
|
border-color: ${activeBorder};
|
||||||
border-width: 2px;
|
border-width: 1px;
|
||||||
|
box-shadow: 0px 4px 6px 0px rgba(0,0,0,0.14);
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import * as path from 'path';
|
||||||
import { nb } from 'sqlops';
|
import { nb } from 'sqlops';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { IOutputChannel } from 'vs/workbench/parts/output/common/output';
|
import { IOutputChannel } from 'vs/workbench/parts/output/common/output';
|
||||||
|
import { DEFAULT_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_FILETYPE, INotebookService } from 'sql/services/notebook/notebookService';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,3 +38,22 @@ export async function mkDir(dirPath: string, outputChannel?: IOutputChannel): Pr
|
|||||||
await pfs.mkdirp(dirPath);
|
await pfs.mkdirp(dirPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProviderForFileName(fileName: string, notebookService: INotebookService): string {
|
||||||
|
let fileExt = path.extname(fileName);
|
||||||
|
let provider: string;
|
||||||
|
// First try to get provider for actual file type
|
||||||
|
if (fileExt && fileExt.startsWith('.')) {
|
||||||
|
fileExt = fileExt.slice(1,fileExt.length);
|
||||||
|
provider = notebookService.getProviderForFileType(fileExt);
|
||||||
|
}
|
||||||
|
// Fallback to provider for default file type (assume this is a global handler)
|
||||||
|
if (!provider) {
|
||||||
|
provider = notebookService.getProviderForFileType(DEFAULT_NOTEBOOK_FILETYPE);
|
||||||
|
}
|
||||||
|
// Finally if all else fails, use the built-in handler
|
||||||
|
if (!provider) {
|
||||||
|
provider = DEFAULT_NOTEBOOK_PROVIDER;
|
||||||
|
}
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||||
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IConnectionManagementService, IConnectionDialogService} from 'sql/parts/connection/common/connectionManagement';
|
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
||||||
import { IObjectExplorerService } from '../../objectExplorer/common/objectExplorerService';
|
import { IObjectExplorerService } from '../../objectExplorer/common/objectExplorerService';
|
||||||
import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput';
|
import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
@@ -55,10 +55,10 @@ CommandsRegistry.registerCommand({
|
|||||||
|
|
||||||
let promise;
|
let promise;
|
||||||
if (connectionProfile) {
|
if (connectionProfile) {
|
||||||
promise = connectionService.connectIfNotConnected(connectionProfile);
|
promise = connectionService.connectIfNotConnected(connectionProfile, 'connection', true);
|
||||||
} else {
|
} else {
|
||||||
// if still no luck, we will open the Connection dialog and let user connect to a server
|
// if still no luck, we will open the Connection dialog and let user connect to a server
|
||||||
promise = connectionDialogService.openDialogAndWait(connectionService, { connectionType: 1, providers: [mssqlProviderName] }).then((profile) => {
|
promise = connectionDialogService.openDialogAndWait(connectionService, { connectionType: 0, showDashboard: false, providers: [mssqlProviderName] }).then((profile) => {
|
||||||
connectionProfile = profile as ConnectionProfile;
|
connectionProfile = profile as ConnectionProfile;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { Widget } from 'vs/base/browser/ui/widget';
|
|||||||
import { Sash, IHorizontalSashLayoutProvider, ISashEvent, Orientation } from 'vs/base/browser/ui/sash/sash';
|
import { Sash, IHorizontalSashLayoutProvider, ISashEvent, Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
import { IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||||
import { FIND_IDS, MATCHES_LIMIT, CONTEXT_FIND_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
|
import { FIND_IDS, CONTEXT_FIND_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
|
||||||
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
||||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ITheme, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
import { ITheme, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
@@ -36,7 +36,7 @@ const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find");
|
|||||||
const NLS_PREVIOUS_MATCH_BTN_LABEL = nls.localize('label.previousMatchButton', "Previous match");
|
const NLS_PREVIOUS_MATCH_BTN_LABEL = nls.localize('label.previousMatchButton', "Previous match");
|
||||||
const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next match");
|
const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next match");
|
||||||
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
|
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
|
||||||
const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Only the first 999 results are highlighted, but all find operations work on the entire text.");
|
const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Your search returned a large number of results, only the first 999 matches will be highlighted.");
|
||||||
const NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', "{0} of {1}");
|
const NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', "{0} of {1}");
|
||||||
const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
|
const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
|
||||||
|
|
||||||
@@ -46,6 +46,8 @@ const FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;
|
|||||||
|
|
||||||
let MAX_MATCHES_COUNT_WIDTH = 69;
|
let MAX_MATCHES_COUNT_WIDTH = 69;
|
||||||
|
|
||||||
|
export const PROFILER_MAX_MATCHES = 999;
|
||||||
|
|
||||||
export const ACTION_IDS = {
|
export const ACTION_IDS = {
|
||||||
FIND_NEXT: 'findNext',
|
FIND_NEXT: 'findNext',
|
||||||
FIND_PREVIOUS: 'findPrev'
|
FIND_PREVIOUS: 'findPrev'
|
||||||
@@ -86,6 +88,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
|
|
||||||
private _resizeSash: Sash;
|
private _resizeSash: Sash;
|
||||||
|
|
||||||
|
private searchTimeoutHandle: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
tableController: ITableController,
|
tableController: ITableController,
|
||||||
state: FindReplaceState,
|
state: FindReplaceState,
|
||||||
@@ -213,7 +217,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
|
|
||||||
private _updateMatchesCount(): void {
|
private _updateMatchesCount(): void {
|
||||||
this._matchesCount.style.minWidth = MAX_MATCHES_COUNT_WIDTH + 'px';
|
this._matchesCount.style.minWidth = MAX_MATCHES_COUNT_WIDTH + 'px';
|
||||||
if (this._state.matchesCount >= MATCHES_LIMIT) {
|
if (this._state.matchesCount >= PROFILER_MAX_MATCHES) {
|
||||||
this._matchesCount.title = NLS_MATCHES_COUNT_LIMIT_TITLE;
|
this._matchesCount.title = NLS_MATCHES_COUNT_LIMIT_TITLE;
|
||||||
} else {
|
} else {
|
||||||
this._matchesCount.title = '';
|
this._matchesCount.title = '';
|
||||||
@@ -227,8 +231,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
let label: string;
|
let label: string;
|
||||||
if (this._state.matchesCount > 0) {
|
if (this._state.matchesCount > 0) {
|
||||||
let matchesCount: string = String(this._state.matchesCount);
|
let matchesCount: string = String(this._state.matchesCount);
|
||||||
if (this._state.matchesCount >= MATCHES_LIMIT) {
|
if (this._state.matchesCount >= PROFILER_MAX_MATCHES) {
|
||||||
matchesCount += '+';
|
matchesCount = PROFILER_MAX_MATCHES + '+';
|
||||||
}
|
}
|
||||||
let matchesPosition: string = String(this._state.matchesPosition);
|
let matchesPosition: string = String(this._state.matchesPosition);
|
||||||
if (matchesPosition === '0') {
|
if (matchesPosition === '0') {
|
||||||
@@ -308,8 +312,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
// ----- Public
|
// ----- Public
|
||||||
|
|
||||||
public focusFindInput(): void {
|
public focusFindInput(): void {
|
||||||
this._findInput.select();
|
|
||||||
// Edge browser requires focus() in addition to select()
|
|
||||||
this._findInput.focus();
|
this._findInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +405,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._findInput.setWholeWords(!!this._state.wholeWord);
|
this._findInput.setWholeWords(!!this._state.wholeWord);
|
||||||
this._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e)));
|
this._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e)));
|
||||||
this._register(this._findInput.onInput(() => {
|
this._register(this._findInput.onInput(() => {
|
||||||
this._state.change({ searchString: this._findInput.getValue() }, true);
|
let self = this;
|
||||||
|
if (self.searchTimeoutHandle) {
|
||||||
|
clearTimeout(self.searchTimeoutHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchTimeoutHandle = setTimeout(function () {
|
||||||
|
self._state.change({ searchString: self._findInput.getValue() }, true);
|
||||||
|
}, 300);
|
||||||
}));
|
}));
|
||||||
this._register(this._findInput.onDidOptionChange(() => {
|
this._register(this._findInput.onDidOptionChange(() => {
|
||||||
this._state.change({
|
this._state.change({
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user