mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-21 18:47:00 -05:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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.7",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,36 +9,27 @@ 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 {
|
|
||||||
row?: number;
|
|
||||||
values: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum CollectionChange {
|
|
||||||
ItemsReplaced
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoadCancellationToken {
|
class LoadCancellationToken {
|
||||||
isCancelled: boolean;
|
isCancelled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataWindow<TData> {
|
class DataWindow<T> {
|
||||||
private _data: TData[];
|
private _data: T[];
|
||||||
private _length: number = 0;
|
private _length: number = 0;
|
||||||
private _offsetFromDataSource: number = -1;
|
private _offsetFromDataSource: number = -1;
|
||||||
|
|
||||||
private lastLoadCancellationToken: LoadCancellationToken;
|
private lastLoadCancellationToken: LoadCancellationToken;
|
||||||
|
|
||||||
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;
|
||||||
@@ -50,26 +41,26 @@ class DataWindow<TData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -92,34 +83,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 +113,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 +144,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 +153,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 +162,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 +171,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 +180,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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ 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 { Extensions, INotebookProviderRegistry } from 'sql/services/notebook/notebookRegistry';
|
||||||
import { DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
import { DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
||||||
|
import { getProviderForFileName } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
@@ -183,17 +184,6 @@ function getNotebookFileExtensions() {
|
|||||||
return notebookRegistry.getSupportedFileExtensions();
|
return notebookRegistry.getSupportedFileExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProviderForFileName(fileName: string) {
|
|
||||||
let fileExt = path.extname(fileName);
|
|
||||||
if (fileExt && fileExt.startsWith('.')) {
|
|
||||||
fileExt = fileExt.slice(1,fileExt.length);
|
|
||||||
let notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
|
||||||
return notebookRegistry.getProviderForFileType(fileExt);
|
|
||||||
}
|
|
||||||
return DEFAULT_NOTEBOOK_PROVIDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param input The EditorInput to check the mode of
|
* @param input The EditorInput to check the mode of
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,3 +128,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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}",
|
||||||
|
|||||||
@@ -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,8 +156,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div #jobsteps style="height: 100%">
|
<div #jobsteps style="flex: 1 1 auto; position: relative">
|
||||||
<jobstepsview-component *ngIf="showSteps === true"></jobstepsview-component>
|
<jobstepsview-component *ngIf="showSteps === true" style="position: absolute; height: 100%; width: 100%"></jobstepsview-component>
|
||||||
</div>
|
</div>
|
||||||
<h3 *ngIf="showSteps === false">No Steps Available</h3>
|
<h3 *ngIf="showSteps === false">No Steps Available</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
@@ -77,7 +78,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 +143,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 +295,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 +305,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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,17 +177,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 +241,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 {
|
||||||
@@ -267,4 +276,4 @@ jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.action
|
|||||||
|
|
||||||
.hc-black jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
.hc-black jobhistory-component > .agent-actionbar-container .monaco-action-bar > ul.actions-container {
|
||||||
border-top: 3px solid #2b56f2;
|
border-top: 3px solid #2b56f2;
|
||||||
}
|
}
|
||||||
@@ -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,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
jobstepsview-component {
|
jobstepsview-component {
|
||||||
padding-top: 10px;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -933,19 +937,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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="toolbar" 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>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ 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 { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
import { RunCellAction, CellContext, NotebookCellToggleMoreActon } from 'sql/parts/notebook/cellViews/codeActions';
|
import { RunCellAction, DeleteCellAction, AddCellAction, CellContext } from 'sql/parts/notebook/cellViews/codeActions';
|
||||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
||||||
import { CellTypes } from 'sql/parts/notebook/models/contracts';
|
import { CellTypes } from 'sql/parts/notebook/models/contracts';
|
||||||
@@ -59,14 +59,15 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _actionBar: Taskbar;
|
protected _actionBar: Taskbar;
|
||||||
|
protected _moreActions: ActionBar;
|
||||||
private readonly _minimumHeight = 30;
|
private readonly _minimumHeight = 30;
|
||||||
private _editor: QueryTextEditor;
|
private _editor: QueryTextEditor;
|
||||||
private _editorInput: UntitledEditorInput;
|
private _editorInput: UntitledEditorInput;
|
||||||
private _editorModel: ITextModel;
|
private _editorModel: ITextModel;
|
||||||
private _uri: string;
|
private _uri: string;
|
||||||
private _model: NotebookModel;
|
private _model: NotebookModel;
|
||||||
|
private _actions: Action[] = [];
|
||||||
private _activeCellId: string;
|
private _activeCellId: string;
|
||||||
private _toggleMoreActions: NotebookCellToggleMoreActon;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||||
@@ -80,6 +81,13 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
@Inject(INotificationService) private notificationService: INotificationService,
|
@Inject(INotificationService) private notificationService: INotificationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this._actions.push(
|
||||||
|
this._instantiationService.createInstance(AddCellAction, 'codeBefore', localize('codeBefore', 'Insert Code before'), CellTypes.Code, false),
|
||||||
|
this._instantiationService.createInstance(AddCellAction, 'codeAfter', localize('codeAfter', 'Insert Code after'), CellTypes.Code, true),
|
||||||
|
this._instantiationService.createInstance(AddCellAction, 'markdownBefore', localize('markdownBefore', 'Insert Markdown before'), CellTypes.Markdown, false),
|
||||||
|
this._instantiationService.createInstance(AddCellAction, 'markdownAfter', localize('markdownAfter', 'Insert Markdown after'), CellTypes.Markdown, true),
|
||||||
|
this._instantiationService.createInstance(DeleteCellAction, 'delete', localize('delete', 'Delete'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -90,20 +98,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.toggleMoreActions(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.toggleMoreActions(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +173,21 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toggleMoreActions(showIcon: boolean) {
|
||||||
|
let context = new CellContext(this.model, this.cellModel);
|
||||||
|
let moreActionsElement = <HTMLElement>this.moreActionsElementRef.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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private createUri(): URI {
|
private createUri(): URI {
|
||||||
let uri = URI.from({ scheme: Schemas.untitled, path: `notebook-editor-${this.cellModel.id}` });
|
let uri = URI.from({ scheme: Schemas.untitled, path: `notebook-editor-${this.cellModel.id}` });
|
||||||
@@ -192,8 +215,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
@@ -191,51 +184,4 @@ export class DeleteCellAction extends CellActionBase {
|
|||||||
}
|
}
|
||||||
return Promise.resolve();
|
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;
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
-->
|
-->
|
||||||
<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 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 #preview style="flex: 0 0 auto;" (dblclick)="toggleEditMode()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
|
|||||||
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 { localize } from 'vs/nls';
|
||||||
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
|
||||||
export const TEXT_SELECTOR: string = 'text-cell-component';
|
export const TEXT_SELECTOR: string = 'text-cell-component';
|
||||||
|
|
||||||
@@ -25,12 +26,20 @@ 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;
|
||||||
@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 _previewCssApplied: boolean = false;
|
||||||
|
private _model: NotebookModel;
|
||||||
private _activeCellId: string;
|
private _activeCellId: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -43,17 +52,6 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
this.isEditMode = false;
|
this.isEditMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
private get sanitizer(): ISanitizer {
|
private get sanitizer(): ISanitizer {
|
||||||
if (this._sanitizer) {
|
if (this._sanitizer) {
|
||||||
@@ -62,17 +60,41 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.updatePreview();
|
||||||
|
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 +116,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() {
|
||||||
@@ -113,12 +127,29 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public handleContentChanged(): void {
|
public handleContentChanged(): void {
|
||||||
|
if (!this._previewCssApplied) {
|
||||||
|
this.updatePreviewCssClass();
|
||||||
|
}
|
||||||
this.updatePreview();
|
this.updatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleEditMode(): void {
|
public toggleEditMode(editMode?: boolean): void {
|
||||||
this.isEditMode = !this.isEditMode;
|
this.isEditMode = editMode !== undefined? editMode : !this.isEditMode;
|
||||||
|
this.updatePreviewCssClass();
|
||||||
this.updatePreview();
|
this.updatePreview();
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the css class to preview 'div' based on edit mode
|
||||||
|
private updatePreviewCssClass() {
|
||||||
|
let outputElement = <HTMLElement>this.output.nativeElement;
|
||||||
|
if (this.isEditMode && this.cellModel.source) {
|
||||||
|
outputElement.className = 'notebook-preview';
|
||||||
|
this._previewCssApplied = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
outputElement.className = '';
|
||||||
|
this._previewCssApplied = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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,7 +35,7 @@ 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
|
// Do nothing for now
|
||||||
@@ -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,10 +275,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -328,6 +329,14 @@ 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 ICellModelOptions {
|
export interface ICellModelOptions {
|
||||||
@@ -348,7 +357,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 +366,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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 { 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,
|
||||||
@@ -237,7 +238,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 +264,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 +301,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 +414,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 +423,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 +515,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,9 +140,16 @@ 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 (foundSavedKernelInSpecs && 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 = !savedKernelInfo ? specs.kernels.find((spec) => spec.name === notebookConstants.defaultSparkKernel) : savedKernelInfo;
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
<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; height: 36px">
|
||||||
</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>
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import './notebookStyles';
|
|||||||
|
|
||||||
import { nb } from 'sqlops';
|
import { nb } from 'sqlops';
|
||||||
|
|
||||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild } from '@angular/core';
|
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, OnDestroy } 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 } from 'vs/platform/notification/common/notification';
|
||||||
@@ -18,12 +17,12 @@ import { localize } from 'vs/nls';
|
|||||||
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, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { ICellModel, IModelFactory } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel, IModelFactory, notebookConstants } 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 } 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, NotebookContentChange } 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 './notebookUtils';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
@@ -31,8 +30,17 @@ 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction } from 'sql/parts/notebook/notebookActions';
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
||||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
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 { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||||
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||||
|
|
||||||
@@ -41,7 +49,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 +70,56 @@ 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
|
||||||
) {
|
) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -103,7 +141,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 +157,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 +222,16 @@ 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);
|
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);
|
||||||
@@ -201,10 +252,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 +290,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 +300,44 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async save(): Promise<boolean> {
|
public async save(): 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 +346,46 @@ 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notebookEditor .notebook-button.icon-add{
|
.notebookEditor .notebook-button.icon-add{
|
||||||
@@ -61,4 +65,13 @@
|
|||||||
.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");
|
||||||
}
|
}
|
||||||
@@ -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: ');
|
||||||
@@ -26,6 +27,7 @@ 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 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 +50,28 @@ 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 });
|
||||||
|
} else {
|
||||||
|
this._notificationService.error(SaveNotebookAction.notebookFailedSaveMsg);
|
||||||
|
}
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IToggleableState {
|
export interface IToggleableState {
|
||||||
baseClass?: string;
|
baseClass?: string;
|
||||||
shouldToggleTooltip?: boolean;
|
shouldToggleTooltip?: boolean;
|
||||||
@@ -215,9 +239,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 +315,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,12 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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,15 @@
|
|||||||
|
|
||||||
'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 { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { INotebookProviderRegistry, Extensions } from 'sql/services/notebook/notebookRegistry';
|
||||||
|
import { DEFAULT_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_FILETYPE } from 'sql/services/notebook/notebookService';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,3 +40,23 @@ export async function mkDir(dirPath: string, outputChannel?: IOutputChannel): Pr
|
|||||||
await pfs.mkdirp(dirPath);
|
await pfs.mkdirp(dirPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProviderForFileName(fileName: string): string {
|
||||||
|
let fileExt = path.extname(fileName);
|
||||||
|
let provider: string;
|
||||||
|
let notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
||||||
|
// First try to get provider for actual file type
|
||||||
|
if (fileExt && fileExt.startsWith('.')) {
|
||||||
|
fileExt = fileExt.slice(1,fileExt.length);
|
||||||
|
provider = notebookRegistry.getProviderForFileType(fileExt);
|
||||||
|
}
|
||||||
|
// Fallback to provider for default file type (assume this is a global handler)
|
||||||
|
if (!provider) {
|
||||||
|
provider = notebookRegistry.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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,8 +308,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll
|
|||||||
if (p) {
|
if (p) {
|
||||||
this._profilerTable.setActiveCell(p.row, p.col);
|
this._profilerTable.setActiveCell(p.row, p.col);
|
||||||
this._updateFinderMatchState();
|
this._updateFinderMatchState();
|
||||||
|
this._finder.focusFindInput();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -557,6 +557,7 @@ export class ProfilerEditor extends BaseEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public focus() {
|
public focus() {
|
||||||
|
this._profilerEditorContextKey.set(true);
|
||||||
super.focus();
|
super.focus();
|
||||||
let savedViewState = this._savedTableViewStates.get(this.input);
|
let savedViewState = this._savedTableViewStates.get(this.input);
|
||||||
if (savedViewState) {
|
if (savedViewState) {
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
|||||||
let searchFn = (val: { [x: string]: string }, exp: string): Array<number> => {
|
let searchFn = (val: { [x: string]: string }, exp: string): Array<number> => {
|
||||||
let ret = new Array<number>();
|
let ret = new Array<number>();
|
||||||
for (let i = 0; i < this._columns.length; i++) {
|
for (let i = 0; i < this._columns.length; i++) {
|
||||||
if (val[this._columns[i]].includes(exp)) {
|
let colVal = val[this._columns[i]];
|
||||||
|
if (colVal && colVal.toLocaleLowerCase().includes(exp.toLocaleLowerCase())) {
|
||||||
ret.push(i);
|
ret.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export interface IQueryManagementService {
|
|||||||
runQueryStatement(ownerUri: string, line: number, column: number): Thenable<void>;
|
runQueryStatement(ownerUri: string, line: number, column: number): Thenable<void>;
|
||||||
runQueryString(ownerUri: string, queryString: string): Thenable<void>;
|
runQueryString(ownerUri: string, queryString: string): Thenable<void>;
|
||||||
runQueryAndReturn(ownerUri: string, queryString: string): Thenable<sqlops.SimpleExecuteResult>;
|
runQueryAndReturn(ownerUri: string, queryString: string): Thenable<sqlops.SimpleExecuteResult>;
|
||||||
parseSyntax(ownerUri:string, query: string): Thenable<sqlops.SyntaxParseResult>;
|
parseSyntax(ownerUri: string, query: string): Thenable<sqlops.SyntaxParseResult>;
|
||||||
getQueryRows(rowData: sqlops.QueryExecuteSubsetParams): Thenable<sqlops.QueryExecuteSubsetResult>;
|
getQueryRows(rowData: sqlops.QueryExecuteSubsetParams): Thenable<sqlops.QueryExecuteSubsetResult>;
|
||||||
disposeQuery(ownerUri: string): Thenable<void>;
|
disposeQuery(ownerUri: string): Thenable<void>;
|
||||||
saveResults(requestParams: sqlops.SaveResultsRequestParams): Thenable<sqlops.SaveResultRequestResult>;
|
saveResults(requestParams: sqlops.SaveResultsRequestParams): Thenable<sqlops.SaveResultRequestResult>;
|
||||||
@@ -38,7 +38,8 @@ export interface IQueryManagementService {
|
|||||||
onQueryComplete(result: sqlops.QueryExecuteCompleteNotificationResult): void;
|
onQueryComplete(result: sqlops.QueryExecuteCompleteNotificationResult): void;
|
||||||
onBatchStart(batchInfo: sqlops.QueryExecuteBatchNotificationParams): void;
|
onBatchStart(batchInfo: sqlops.QueryExecuteBatchNotificationParams): void;
|
||||||
onBatchComplete(batchInfo: sqlops.QueryExecuteBatchNotificationParams): void;
|
onBatchComplete(batchInfo: sqlops.QueryExecuteBatchNotificationParams): void;
|
||||||
onResultSetComplete(resultSetInfo: sqlops.QueryExecuteResultSetCompleteNotificationParams): void;
|
onResultSetAvailable(resultSetInfo: sqlops.QueryExecuteResultSetNotificationParams): void;
|
||||||
|
onResultSetUpdated(resultSetInfo: sqlops.QueryExecuteResultSetNotificationParams): void;
|
||||||
onMessage(message: sqlops.QueryExecuteMessageParams): void;
|
onMessage(message: sqlops.QueryExecuteMessageParams): void;
|
||||||
|
|
||||||
// Edit Data Callbacks
|
// Edit Data Callbacks
|
||||||
@@ -65,7 +66,7 @@ export interface IQueryRequestHandler {
|
|||||||
runQueryStatement(ownerUri: string, line: number, column: number): Thenable<void>;
|
runQueryStatement(ownerUri: string, line: number, column: number): Thenable<void>;
|
||||||
runQueryString(ownerUri: string, queryString: string): Thenable<void>;
|
runQueryString(ownerUri: string, queryString: string): Thenable<void>;
|
||||||
runQueryAndReturn(ownerUri: string, queryString: string): Thenable<sqlops.SimpleExecuteResult>;
|
runQueryAndReturn(ownerUri: string, queryString: string): Thenable<sqlops.SimpleExecuteResult>;
|
||||||
parseSyntax(ownerUri:string, query: string): Thenable<sqlops.SyntaxParseResult>;
|
parseSyntax(ownerUri: string, query: string): Thenable<sqlops.SyntaxParseResult>;
|
||||||
getQueryRows(rowData: sqlops.QueryExecuteSubsetParams): Thenable<sqlops.QueryExecuteSubsetResult>;
|
getQueryRows(rowData: sqlops.QueryExecuteSubsetParams): Thenable<sqlops.QueryExecuteSubsetResult>;
|
||||||
disposeQuery(ownerUri: string): Thenable<void>;
|
disposeQuery(ownerUri: string): Thenable<void>;
|
||||||
saveResults(requestParams: sqlops.SaveResultsRequestParams): Thenable<sqlops.SaveResultRequestResult>;
|
saveResults(requestParams: sqlops.SaveResultsRequestParams): Thenable<sqlops.SaveResultRequestResult>;
|
||||||
@@ -244,9 +245,15 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onResultSetComplete(resultSetInfo: sqlops.QueryExecuteResultSetCompleteNotificationParams): void {
|
public onResultSetAvailable(resultSetInfo: sqlops.QueryExecuteResultSetNotificationParams): void {
|
||||||
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleResultSetComplete(resultSetInfo);
|
runner.handleResultSetAvailable(resultSetInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onResultSetUpdated(resultSetInfo: sqlops.QueryExecuteResultSetNotificationParams): void {
|
||||||
|
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
|
runner.handleResultSetUpdated(resultSetInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import * as pretty from 'pretty-data';
|
||||||
|
|
||||||
import { attachTableStyler } from 'sql/common/theme/styler';
|
import { attachTableStyler } from 'sql/common/theme/styler';
|
||||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||||
import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView';
|
import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView';
|
||||||
@@ -12,7 +14,7 @@ import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scr
|
|||||||
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
||||||
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||||
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
||||||
import { IGridActionContext, SaveResultAction, CopyResultAction, SelectAllGridAction, MaximizeTableAction, RestoreTableAction, ChartDataAction, ShowQueryPlanAction } from 'sql/parts/query/editor/actions';
|
import { IGridActionContext, SaveResultAction, CopyResultAction, SelectAllGridAction, MaximizeTableAction, RestoreTableAction, ChartDataAction } from 'sql/parts/query/editor/actions';
|
||||||
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||||
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
@@ -20,9 +22,9 @@ import { hyperLinkFormatter, textFormatter } from 'sql/parts/grid/services/share
|
|||||||
import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
|
import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
|
||||||
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||||
import { ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/interfaces';
|
import { ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/interfaces';
|
||||||
|
import { warn } from 'sql/base/common/log';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import * as pretty from 'pretty-data';
|
|
||||||
|
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
@@ -38,7 +40,7 @@ import { $ } from 'vs/base/browser/builder';
|
|||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { Separator, ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { Separator, ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
import { Dimension, getContentWidth, isInDOM } from 'vs/base/browser/dom';
|
import { isInDOM } from 'vs/base/browser/dom';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
@@ -175,7 +177,8 @@ export class GridPanel extends ViewletPanel {
|
|||||||
this.reset();
|
this.reset();
|
||||||
this.queryRunnerDisposables = [];
|
this.queryRunnerDisposables = [];
|
||||||
this.runner = runner;
|
this.runner = runner;
|
||||||
this.queryRunnerDisposables.push(this.runner.onResultSet(e => this.onResultSet(e)));
|
this.queryRunnerDisposables.push(this.runner.onResultSet(this.onResultSet, this));
|
||||||
|
this.queryRunnerDisposables.push(this.runner.onResultSetUpdate(this.updateResultSet, this));
|
||||||
this.queryRunnerDisposables.push(this.runner.onQueryStart(() => {
|
this.queryRunnerDisposables.push(this.runner.onQueryStart(() => {
|
||||||
if (this.state) {
|
if (this.state) {
|
||||||
this.state.tableStates = [];
|
this.state.tableStates = [];
|
||||||
@@ -200,6 +203,33 @@ export class GridPanel extends ViewletPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
||||||
|
|
||||||
|
let resultsToUpdate: sqlops.ResultSetSummary[];
|
||||||
|
if (!Array.isArray(resultSet)) {
|
||||||
|
resultsToUpdate = [resultSet];
|
||||||
|
} else {
|
||||||
|
resultsToUpdate = resultSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let set of resultsToUpdate) {
|
||||||
|
let table = this.tables.find(t => t.resultSet.batchId === set.batchId && t.resultSet.id === set.id);
|
||||||
|
if (table) {
|
||||||
|
table.updateResult(set);
|
||||||
|
} else {
|
||||||
|
warn('Got result set update request for non-existant table');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maximumBodySize = this.tables.reduce((p, c) => {
|
||||||
|
return p + c.maximumSize;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
if (this.state && this.state.scrollPosition) {
|
||||||
|
this.splitView.setScrollPosition(this.state.scrollPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private addResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
private addResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
||||||
let resultsToAdd: sqlops.ResultSetSummary[];
|
let resultsToAdd: sqlops.ResultSetSummary[];
|
||||||
if (!Array.isArray(resultSet)) {
|
if (!Array.isArray(resultSet)) {
|
||||||
@@ -323,9 +353,12 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
private selectionModel = new CellSelectionModel();
|
private selectionModel = new CellSelectionModel();
|
||||||
private styles: ITableStyles;
|
private styles: ITableStyles;
|
||||||
private currentHeight: number;
|
private currentHeight: number;
|
||||||
|
private dataProvider: AsyncDataProvider<T>;
|
||||||
|
|
||||||
private columns: Slick.Column<T>[];
|
private columns: Slick.Column<T>[];
|
||||||
|
|
||||||
|
private rowNumberColumn: RowNumberColumn<T>;
|
||||||
|
|
||||||
private _onDidChange = new Emitter<number>();
|
private _onDidChange = new Emitter<number>();
|
||||||
public readonly onDidChange: Event<number> = this._onDidChange.event;
|
public readonly onDidChange: Event<number> = this._onDidChange.event;
|
||||||
|
|
||||||
@@ -335,13 +368,20 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
private _state: GridTableState;
|
private _state: GridTableState;
|
||||||
|
|
||||||
private scrolled = false;
|
private scrolled = false;
|
||||||
|
private visible = false;
|
||||||
|
|
||||||
|
public get resultSet(): sqlops.ResultSetSummary {
|
||||||
|
return this._resultSet;
|
||||||
|
}
|
||||||
|
|
||||||
// this handles if the row count is small, like 4-5 rows
|
// this handles if the row count is small, like 4-5 rows
|
||||||
private readonly maxSize = ((this.resultSet.rowCount) * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT;
|
private get maxSize(): number {
|
||||||
|
return ((this.resultSet.rowCount) * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private runner: QueryRunner,
|
private runner: QueryRunner,
|
||||||
public readonly resultSet: sqlops.ResultSetSummary,
|
private _resultSet: sqlops.ResultSetSummary,
|
||||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||||
@IInstantiationService private instantiationService: IInstantiationService,
|
@IInstantiationService private instantiationService: IInstantiationService,
|
||||||
@IEditorService private editorService: IEditorService,
|
@IEditorService private editorService: IEditorService,
|
||||||
@@ -367,7 +407,31 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onAdd() {
|
||||||
|
this.visible = true;
|
||||||
|
let collection = new VirtualizedCollection(
|
||||||
|
50,
|
||||||
|
index => this.placeholdGenerator(index),
|
||||||
|
this.resultSet.rowCount,
|
||||||
|
(offset, count) => this.loadData(offset, count)
|
||||||
|
);
|
||||||
|
collection.setCollectionChangedCallback((startIndex, count) => {
|
||||||
|
this.renderGridDataRowsRange(startIndex, count);
|
||||||
|
});
|
||||||
|
this.dataProvider.dataRows = collection;
|
||||||
|
this.table.updateRowCount();
|
||||||
|
}
|
||||||
|
|
||||||
public onRemove() {
|
public onRemove() {
|
||||||
|
this.visible = false;
|
||||||
|
let collection = new VirtualizedCollection(
|
||||||
|
50,
|
||||||
|
index => this.placeholdGenerator(index),
|
||||||
|
0,
|
||||||
|
() => TPromise.as([])
|
||||||
|
);
|
||||||
|
this.dataProvider.dataRows = collection;
|
||||||
|
this.table.updateRowCount();
|
||||||
// when we are removed slickgrid acts badly so we need to account for that
|
// when we are removed slickgrid acts badly so we need to account for that
|
||||||
this.scrolled = false;
|
this.scrolled = false;
|
||||||
}
|
}
|
||||||
@@ -379,34 +443,38 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
private build(): void {
|
private build(): void {
|
||||||
let tableContainer = document.createElement('div');
|
let tableContainer = document.createElement('div');
|
||||||
tableContainer.style.display = 'inline-block';
|
tableContainer.style.display = 'inline-block';
|
||||||
|
tableContainer.style.width = `calc(100% - ${ACTIONBAR_WIDTH}px)`;
|
||||||
|
|
||||||
this.container.appendChild(tableContainer);
|
this.container.appendChild(tableContainer);
|
||||||
|
|
||||||
let collection = new VirtualizedCollection(50, this.resultSet.rowCount,
|
let collection = new VirtualizedCollection(
|
||||||
(offset, count) => this.loadData(offset, count),
|
50,
|
||||||
index => this.placeholdGenerator(index)
|
index => this.placeholdGenerator(index),
|
||||||
|
0,
|
||||||
|
() => TPromise.as([])
|
||||||
);
|
);
|
||||||
collection.setCollectionChangedCallback((change, startIndex, count) => {
|
collection.setCollectionChangedCallback((startIndex, count) => {
|
||||||
this.renderGridDataRowsRange(startIndex, count);
|
this.renderGridDataRowsRange(startIndex, count);
|
||||||
});
|
});
|
||||||
let numberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
|
this.rowNumberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
|
||||||
let copyHandler = new CopyKeybind();
|
let copyHandler = new CopyKeybind();
|
||||||
copyHandler.onCopy(e => {
|
copyHandler.onCopy(e => {
|
||||||
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
|
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
|
||||||
});
|
});
|
||||||
this.columns.unshift(numberColumn.getColumnDefinition());
|
this.columns.unshift(this.rowNumberColumn.getColumnDefinition());
|
||||||
let tableOptions: Slick.GridOptions<T> = {
|
let tableOptions: Slick.GridOptions<T> = {
|
||||||
rowHeight: ROW_HEIGHT,
|
rowHeight: ROW_HEIGHT,
|
||||||
showRowNumber: true,
|
showRowNumber: true,
|
||||||
forceFitColumns: false,
|
forceFitColumns: false,
|
||||||
defaultColumnWidth: 120
|
defaultColumnWidth: 120
|
||||||
};
|
};
|
||||||
this.table = this._register(new Table(tableContainer, { dataProvider: new AsyncDataProvider(collection), columns: this.columns }, tableOptions));
|
this.dataProvider = new AsyncDataProvider(collection);
|
||||||
|
this.table = this._register(new Table(tableContainer, { dataProvider: this.dataProvider, columns: this.columns }, tableOptions));
|
||||||
this.table.setSelectionModel(this.selectionModel);
|
this.table.setSelectionModel(this.selectionModel);
|
||||||
this.table.registerPlugin(new MouseWheelSupport());
|
this.table.registerPlugin(new MouseWheelSupport());
|
||||||
this.table.registerPlugin(new AutoColumnSize());
|
this.table.registerPlugin(new AutoColumnSize());
|
||||||
this.table.registerPlugin(copyHandler);
|
this.table.registerPlugin(copyHandler);
|
||||||
this.table.registerPlugin(numberColumn);
|
this.table.registerPlugin(this.rowNumberColumn);
|
||||||
this.table.registerPlugin(new AdditionalKeyBindings());
|
this.table.registerPlugin(new AdditionalKeyBindings());
|
||||||
this._register(this.table.onContextMenu(this.contextMenu, this));
|
this._register(this.table.onContextMenu(this.contextMenu, this));
|
||||||
this._register(this.table.onClick(this.onTableClick, this));
|
this._register(this.table.onClick(this.onTableClick, this));
|
||||||
@@ -507,7 +575,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// If Xml fails to parse, fall back on original Xml content
|
// If Xml fails to parse, fall back on original Xml content
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let jsonContent: string = undefined;
|
let jsonContent: string = undefined;
|
||||||
try {
|
try {
|
||||||
jsonContent = JSON.parse(content);
|
jsonContent = JSON.parse(content);
|
||||||
@@ -526,6 +594,15 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateResult(resultSet: sqlops.ResultSetSummary) {
|
||||||
|
this._resultSet = resultSet;
|
||||||
|
if (this.table && this.visible) {
|
||||||
|
this.dataProvider.length = resultSet.rowCount;
|
||||||
|
this.table.updateRowCount();
|
||||||
|
}
|
||||||
|
this.rowNumberColumn.updateRowCount(resultSet.rowCount);
|
||||||
|
}
|
||||||
|
|
||||||
private generateContext(cell?: Slick.Cell): IGridActionContext {
|
private generateContext(cell?: Slick.Cell): IGridActionContext {
|
||||||
const selection = this.selectionModel.getSelectedRanges();
|
const selection = this.selectionModel.getSelectedRanges();
|
||||||
return <IGridActionContext>{
|
return <IGridActionContext>{
|
||||||
@@ -577,12 +654,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
} else {
|
} else {
|
||||||
this.currentHeight = size;
|
this.currentHeight = size;
|
||||||
}
|
}
|
||||||
this.table.layout(
|
this.table.layout(size, Orientation.VERTICAL);
|
||||||
new Dimension(
|
|
||||||
getContentWidth(this.container) - ACTIONBAR_WIDTH,
|
|
||||||
size
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get minimumSize(): number {
|
public get minimumSize(): number {
|
||||||
@@ -596,6 +668,9 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
|
|
||||||
private loadData(offset: number, count: number): Thenable<T[]> {
|
private loadData(offset: number, count: number): Thenable<T[]> {
|
||||||
return this.runner.getQueryRows(offset, count, this.resultSet.batchId, this.resultSet.id).then(response => {
|
return this.runner.getQueryRows(offset, count, this.resultSet.batchId, this.resultSet.id).then(response => {
|
||||||
|
if (!response.resultSubset) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
return response.resultSubset.rows.map(r => {
|
return response.resultSubset.rows.map(r => {
|
||||||
let dataWithSchema = {};
|
let dataWithSchema = {};
|
||||||
// skip the first column since its a number column
|
// skip the first column since its a number column
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ export class QueryResultsView extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
|
dispose(this.runnerDisposables);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,18 @@ export default class QueryRunner extends Disposable {
|
|||||||
private _echoedResultSet = echo(this._debouncedResultSet.event);
|
private _echoedResultSet = echo(this._debouncedResultSet.event);
|
||||||
public readonly onResultSet = this._echoedResultSet.event;
|
public readonly onResultSet = this._echoedResultSet.event;
|
||||||
|
|
||||||
|
private _onResultSetUpdate = this._register(new Emitter<sqlops.ResultSetSummary>());
|
||||||
|
private _debouncedResultSetUpdate = debounceEvent<sqlops.ResultSetSummary, sqlops.ResultSetSummary[]>(this._onResultSetUpdate.event, (l, e) => {
|
||||||
|
// on first run
|
||||||
|
if (types.isUndefinedOrNull(l)) {
|
||||||
|
return [e];
|
||||||
|
} else {
|
||||||
|
return l.concat(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
private _echoedResultSetUpdate = echo(this._debouncedResultSetUpdate.event);
|
||||||
|
public readonly onResultSetUpdate = this._echoedResultSetUpdate.event;
|
||||||
|
|
||||||
private _onQueryStart = this._register(new Emitter<void>());
|
private _onQueryStart = this._register(new Emitter<void>());
|
||||||
public readonly onQueryStart: Event<void> = this._onQueryStart.event;
|
public readonly onQueryStart: Event<void> = this._onQueryStart.event;
|
||||||
|
|
||||||
@@ -336,7 +348,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Handle a ResultSetComplete from the service layer
|
* Handle a ResultSetComplete from the service layer
|
||||||
*/
|
*/
|
||||||
public handleResultSetComplete(result: sqlops.QueryExecuteResultSetCompleteNotificationParams): void {
|
public handleResultSetAvailable(result: sqlops.QueryExecuteResultSetNotificationParams): void {
|
||||||
if (result && result.resultSetSummary) {
|
if (result && result.resultSetSummary) {
|
||||||
let resultSet = result.resultSetSummary;
|
let resultSet = result.resultSetSummary;
|
||||||
let batchSet: sqlops.BatchSummary;
|
let batchSet: sqlops.BatchSummary;
|
||||||
@@ -365,7 +377,9 @@ export default class QueryRunner extends Disposable {
|
|||||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (batchSet) {
|
// we will just ignore the set if we already have it
|
||||||
|
// ideally this should never happen
|
||||||
|
if (batchSet && !batchSet.resultSetSummaries[resultSet.id]) {
|
||||||
// Store the result set in the batch and emit that a result set has completed
|
// Store the result set in the batch and emit that a result set has completed
|
||||||
batchSet.resultSetSummaries[resultSet.id] = resultSet;
|
batchSet.resultSetSummaries[resultSet.id] = resultSet;
|
||||||
this._eventEmitter.emit(EventType.RESULT_SET, resultSet);
|
this._eventEmitter.emit(EventType.RESULT_SET, resultSet);
|
||||||
@@ -374,6 +388,27 @@ export default class QueryRunner extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public handleResultSetUpdated(result: sqlops.QueryExecuteResultSetNotificationParams): void {
|
||||||
|
if (result && result.resultSetSummary) {
|
||||||
|
let resultSet = result.resultSetSummary;
|
||||||
|
let batchSet: sqlops.BatchSummary;
|
||||||
|
batchSet = this.batchSets[resultSet.batchId];
|
||||||
|
// handle getting queryPlanxml if we need too
|
||||||
|
if (this.isQueryPlan) {
|
||||||
|
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||||
|
let hasShowPlan = !!result.resultSetSummary.columnInfo.find(e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||||
|
if (hasShowPlan) {
|
||||||
|
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (batchSet) {
|
||||||
|
// Store the result set in the batch and emit that a result set has completed
|
||||||
|
batchSet.resultSetSummaries[resultSet.id] = resultSet;
|
||||||
|
this._onResultSetUpdate.fire(resultSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a Mssage from the service layer
|
* Handle a Mssage from the service layer
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -249,9 +249,9 @@ export class QueryEditorService implements IQueryEditorService {
|
|||||||
QueryEditorService.editorService.openEditor(newEditorInput, options, group).then((editor) => {
|
QueryEditorService.editorService.openEditor(newEditorInput, options, group).then((editor) => {
|
||||||
resolve(QueryEditorService._onEditorOpened(editor, uri.toString(), undefined, options.pinned));
|
resolve(QueryEditorService._onEditorOpened(editor, uri.toString(), undefined, options.pinned));
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ export class CustomDialogService {
|
|||||||
|
|
||||||
constructor( @IInstantiationService private _instantiationService: IInstantiationService) { }
|
constructor( @IInstantiationService private _instantiationService: IInstantiationService) { }
|
||||||
|
|
||||||
public showDialog(dialog: Dialog, options?: IModalOptions): void {
|
public showDialog(dialog: Dialog, dialogName?: string, options?: IModalOptions): void {
|
||||||
let dialogModal = this._instantiationService.createInstance(DialogModal, dialog, 'CustomDialog', options || defaultOptions);
|
let name = dialogName ? dialogName : 'CustomDialog';
|
||||||
|
let dialogModal = this._instantiationService.createInstance(DialogModal, dialog, name, options || defaultOptions);
|
||||||
this._dialogModals.set(dialog, dialogModal);
|
this._dialogModals.set(dialog, dialogModal);
|
||||||
dialogModal.render();
|
dialogModal.render();
|
||||||
dialogModal.open();
|
dialogModal.open();
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import * as nls from 'vs/nls';
|
|
||||||
import * as platform from 'vs/platform/registry/common/platform';
|
import * as platform from 'vs/platform/registry/common/platform';
|
||||||
import * as statusbar from 'vs/workbench/browser/parts/statusbar/statusbar';
|
import * as statusbar from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||||
|
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { Memento, Scope as MementoScope } from 'vs/workbench/common/memento';
|
import { Memento, Scope as MementoScope } from 'vs/workbench/common/memento';
|
||||||
@@ -20,8 +20,8 @@ import { AccountDialogController } from 'sql/parts/accountManagement/accountDial
|
|||||||
import { AutoOAuthDialogController } from 'sql/parts/accountManagement/autoOAuthDialog/autoOAuthDialogController';
|
import { AutoOAuthDialogController } from 'sql/parts/accountManagement/autoOAuthDialog/autoOAuthDialogController';
|
||||||
import { AccountListStatusbarItem } from 'sql/parts/accountManagement/accountListStatusbar/accountListStatusbarItem';
|
import { AccountListStatusbarItem } from 'sql/parts/accountManagement/accountListStatusbar/accountListStatusbarItem';
|
||||||
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
|
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
|
||||||
import { IAccountManagementService, AzureResource } from 'sql/services/accountManagement/interfaces';
|
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
|
|
||||||
export class AccountManagementService implements IAccountManagementService {
|
export class AccountManagementService implements IAccountManagementService {
|
||||||
// CONSTANTS ///////////////////////////////////////////////////////////
|
// CONSTANTS ///////////////////////////////////////////////////////////
|
||||||
@@ -198,11 +198,6 @@ export class AccountManagementService implements IAccountManagementService {
|
|||||||
public getAccountsForProvider(providerId: string): Thenable<sqlops.Account[]> {
|
public getAccountsForProvider(providerId: string): Thenable<sqlops.Account[]> {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
// Make sure the provider exists before attempting to retrieve accounts
|
|
||||||
if (!this._providers[providerId]) {
|
|
||||||
return Promise.reject(new Error(nls.localize('accountManagementNoProvider', 'Account provider does not exist'))).then();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1) Get the accounts from the store
|
// 1) Get the accounts from the store
|
||||||
// 2) Update our local cache of accounts
|
// 2) Update our local cache of accounts
|
||||||
return this.doWithProvider(providerId, provider => {
|
return this.doWithProvider(providerId, provider => {
|
||||||
@@ -217,7 +212,7 @@ export class AccountManagementService implements IAccountManagementService {
|
|||||||
/**
|
/**
|
||||||
* Generates a security token by asking the account's provider
|
* Generates a security token by asking the account's provider
|
||||||
* @param {Account} account Account to generate security token for
|
* @param {Account} account Account to generate security token for
|
||||||
* @param {AzureResource} resource The resource to get the security token for
|
* @param {sqlops.AzureResource} resource The resource to get the security token for
|
||||||
* @return {Thenable<{}>} Promise to return the security token
|
* @return {Thenable<{}>} Promise to return the security token
|
||||||
*/
|
*/
|
||||||
public getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
|
public getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
|
||||||
@@ -389,10 +384,17 @@ export class AccountManagementService implements IAccountManagementService {
|
|||||||
|
|
||||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||||
private doWithProvider<T>(providerId: string, op: (provider: AccountProviderWithMetadata) => Thenable<T>): Thenable<T> {
|
private doWithProvider<T>(providerId: string, op: (provider: AccountProviderWithMetadata) => Thenable<T>): Thenable<T> {
|
||||||
// Make sure the provider exists before attempting to retrieve accounts
|
|
||||||
let provider = this._providers[providerId];
|
let provider = this._providers[providerId];
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return Promise.reject(new Error(nls.localize('accountManagementNoProvider', 'Account provider does not exist'))).then();
|
// If the provider doesn't already exist wait until it gets registered
|
||||||
|
let deferredPromise = new Deferred<T>();
|
||||||
|
let toDispose = this.addAccountProviderEvent(params => {
|
||||||
|
if (params.addedProvider.id === providerId) {
|
||||||
|
toDispose.dispose();
|
||||||
|
deferredPromise.resolve(op(this._providers[providerId]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return deferredPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
return op(provider);
|
return op(provider);
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ import * as pfs from 'vs/base/node/pfs';
|
|||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
|
|
||||||
import ContentManager = nb.ContentManager;
|
import ContentManager = nb.ContentManager;
|
||||||
import INotebook = nb.INotebook;
|
|
||||||
|
|
||||||
export class LocalContentManager implements ContentManager {
|
export class LocalContentManager implements ContentManager {
|
||||||
public async getNotebookContents(notebookUri: URI): Promise<INotebook> {
|
public async getNotebookContents(notebookUri: URI): Promise<nb.INotebookContents> {
|
||||||
if (!notebookUri) {
|
if (!notebookUri) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -23,10 +22,10 @@ export class LocalContentManager implements ContentManager {
|
|||||||
let path = notebookUri.fsPath;
|
let path = notebookUri.fsPath;
|
||||||
// Note: intentionally letting caller handle exceptions
|
// Note: intentionally letting caller handle exceptions
|
||||||
let notebookFileBuffer = await pfs.readFile(path);
|
let notebookFileBuffer = await pfs.readFile(path);
|
||||||
return <INotebook>json.parse(notebookFileBuffer.toString());
|
return <nb.INotebookContents>json.parse(notebookFileBuffer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async save(notebookUri: URI, notebook: INotebook): Promise<INotebook> {
|
public async save(notebookUri: URI, notebook: nb.INotebookContents): Promise<nb.INotebookContents> {
|
||||||
// Convert to JSON with pretty-print functionality
|
// Convert to JSON with pretty-print functionality
|
||||||
let contents = JSON.stringify(notebook, undefined, ' ');
|
let contents = JSON.stringify(notebook, undefined, ' ');
|
||||||
let path = notebookUri.fsPath;
|
let path = notebookUri.fsPath;
|
||||||
|
|||||||
@@ -6,21 +6,29 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||||
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
||||||
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
|
import { NotebookInput } from 'sql/parts/notebook/notebookInput';
|
||||||
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
export const SERVICE_ID = 'notebookService';
|
export const SERVICE_ID = 'notebookService';
|
||||||
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
|
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
|
||||||
|
|
||||||
export const DEFAULT_NOTEBOOK_PROVIDER = 'builtin';
|
export const DEFAULT_NOTEBOOK_PROVIDER = 'builtin';
|
||||||
|
export const DEFAULT_NOTEBOOK_FILETYPE = 'IPYNB';
|
||||||
|
|
||||||
export interface INotebookService {
|
export interface INotebookService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
onNotebookEditorAdd: Event<INotebookEditor>;
|
||||||
|
onNotebookEditorRemove: Event<INotebookEditor>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a metadata provider
|
* Register a metadata provider
|
||||||
*/
|
*/
|
||||||
@@ -40,7 +48,11 @@ export interface INotebookService {
|
|||||||
*/
|
*/
|
||||||
getOrCreateNotebookManager(providerId: string, uri: URI): Thenable<INotebookManager>;
|
getOrCreateNotebookManager(providerId: string, uri: URI): Thenable<INotebookManager>;
|
||||||
|
|
||||||
handleNotebookClosed(uri: URI): void;
|
addNotebookEditor(editor: INotebookEditor): void;
|
||||||
|
|
||||||
|
removeNotebookEditor(editor: INotebookEditor): void;
|
||||||
|
|
||||||
|
listNotebookEditors(): INotebookEditor[];
|
||||||
|
|
||||||
shutdown(): void;
|
shutdown(): void;
|
||||||
|
|
||||||
@@ -62,8 +74,19 @@ export interface INotebookManager {
|
|||||||
|
|
||||||
export interface INotebookParams extends IBootstrapParams {
|
export interface INotebookParams extends IBootstrapParams {
|
||||||
notebookUri: URI;
|
notebookUri: URI;
|
||||||
|
input: NotebookInput;
|
||||||
providerId: string;
|
providerId: string;
|
||||||
isTrusted: boolean;
|
isTrusted: boolean;
|
||||||
profile?: IConnectionProfile;
|
profile?: IConnectionProfile;
|
||||||
modelFactory?: ModelFactory;
|
modelFactory?: ModelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INotebookEditor {
|
||||||
|
readonly notebookParams: INotebookParams;
|
||||||
|
readonly id: string;
|
||||||
|
isDirty(): boolean;
|
||||||
|
isActive(): boolean;
|
||||||
|
isVisible(): boolean;
|
||||||
|
save(): Promise<boolean>;
|
||||||
|
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
|
||||||
}
|
}
|
||||||
@@ -10,20 +10,26 @@ import { localize } from 'vs/nls';
|
|||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
import { INotebookService, INotebookManager, INotebookProvider, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
import {
|
||||||
|
INotebookService, INotebookManager, INotebookProvider, DEFAULT_NOTEBOOK_PROVIDER,
|
||||||
|
DEFAULT_NOTEBOOK_FILETYPE, INotebookEditor
|
||||||
|
} from 'sql/services/notebook/notebookService';
|
||||||
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
||||||
import { standardRendererFactories } from 'sql/parts/notebook/outputs/factories';
|
import { standardRendererFactories } from 'sql/parts/notebook/outputs/factories';
|
||||||
import { LocalContentManager } from 'sql/services/notebook/localContentManager';
|
import { LocalContentManager } from 'sql/services/notebook/localContentManager';
|
||||||
import { SessionManager } from 'sql/services/notebook/sessionManager';
|
import { SessionManager } from 'sql/services/notebook/sessionManager';
|
||||||
import { Extensions, INotebookProviderRegistry } from 'sql/services/notebook/notebookRegistry';
|
import { Extensions, INotebookProviderRegistry } from 'sql/services/notebook/notebookRegistry';
|
||||||
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
|
||||||
const DEFAULT_NOTEBOOK_FILETYPE = 'IPYNB';
|
|
||||||
|
|
||||||
export class NotebookService implements INotebookService {
|
export class NotebookService implements INotebookService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
private _mimeRegistry: RenderMimeRegistry;
|
private _mimeRegistry: RenderMimeRegistry;
|
||||||
private _providers: Map<string, INotebookProvider> = new Map();
|
private _providers: Map<string, INotebookProvider> = new Map();
|
||||||
private _managers: Map<string, INotebookManager> = new Map();
|
private _managers: Map<string, INotebookManager> = new Map();
|
||||||
|
private _onNotebookEditorAdd = new Emitter<INotebookEditor>();
|
||||||
|
private _onNotebookEditorRemove = new Emitter<INotebookEditor>();
|
||||||
|
private _editors = new Map<string, INotebookEditor>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.registerDefaultProvider();
|
this.registerDefaultProvider();
|
||||||
@@ -71,8 +77,34 @@ export class NotebookService implements INotebookService {
|
|||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNotebookClosed(notebookUri: URI): void {
|
get onNotebookEditorAdd(): Event<INotebookEditor> {
|
||||||
|
return this._onNotebookEditorAdd.event;
|
||||||
|
}
|
||||||
|
get onNotebookEditorRemove(): Event<INotebookEditor> {
|
||||||
|
return this._onNotebookEditorRemove.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
addNotebookEditor(editor: INotebookEditor): void {
|
||||||
|
this._editors.set(editor.id, editor);
|
||||||
|
this._onNotebookEditorAdd.fire(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNotebookEditor(editor: INotebookEditor): void {
|
||||||
|
if (this._editors.delete(editor.id)) {
|
||||||
|
this._onNotebookEditorRemove.fire(editor);
|
||||||
|
}
|
||||||
// Remove the manager from the tracked list, and let the notebook provider know that it should update its mappings
|
// Remove the manager from the tracked list, and let the notebook provider know that it should update its mappings
|
||||||
|
this.sendNotebookCloseToProvider(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
listNotebookEditors(): INotebookEditor[] {
|
||||||
|
let editors = [];
|
||||||
|
this._editors.forEach(e => editors.push(e));
|
||||||
|
return editors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sendNotebookCloseToProvider(editor: INotebookEditor) {
|
||||||
|
let notebookUri = editor.notebookParams.notebookUri;
|
||||||
let uriString = notebookUri.toString();
|
let uriString = notebookUri.toString();
|
||||||
let manager = this._managers.get(uriString);
|
let manager = this._managers.get(uriString);
|
||||||
if (manager) {
|
if (manager) {
|
||||||
@@ -82,15 +114,20 @@ export class NotebookService implements INotebookService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||||
private doWithProvider<T>(providerId: string, op: (provider: INotebookProvider) => Thenable<T>): Thenable<T> {
|
private doWithProvider<T>(providerId: string, op: (provider: INotebookProvider) => Thenable<T>): Thenable<T> {
|
||||||
// Make sure the provider exists before attempting to retrieve accounts
|
// Make sure the provider exists before attempting to retrieve accounts
|
||||||
let provider = this._providers.get(providerId);
|
let provider: INotebookProvider;
|
||||||
|
if (this._providers.has(providerId)) {
|
||||||
|
provider = this._providers.get(providerId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
provider = this._providers.get(DEFAULT_NOTEBOOK_PROVIDER);
|
||||||
|
}
|
||||||
|
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return Promise.reject(new Error(localize('notebookServiceNoProvider', 'Notebook provider does not exist'))).then();
|
return Promise.reject(new Error(localize('notebookServiceNoProvider', 'Notebook provider does not exist'))).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
return op(provider);
|
return op(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +140,6 @@ export class NotebookService implements INotebookService {
|
|||||||
}
|
}
|
||||||
return this._mimeRegistry;
|
return this._mimeRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BuiltinProvider implements INotebookProvider {
|
export class BuiltinProvider implements INotebookProvider {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { nb } from 'sqlops';
|
|||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
import { FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
|
||||||
const noKernel: string = localize('noKernel', 'No Kernel');
|
export const noKernel: string = localize('noKernel', 'No Kernel');
|
||||||
const runNotebookDisabled = localize('runNotebookDisabled', 'Cannot run cells as no kernel has been configured');
|
const runNotebookDisabled = localize('runNotebookDisabled', 'Cannot run cells as no kernel has been configured');
|
||||||
|
|
||||||
let noKernelSpec: nb.IKernelSpec = ({
|
let noKernelSpec: nb.IKernelSpec = ({
|
||||||
@@ -24,9 +24,9 @@ export class SessionManager implements nb.SessionManager {
|
|||||||
|
|
||||||
public get specs(): nb.IAllKernels {
|
public get specs(): nb.IAllKernels {
|
||||||
let allKernels: nb.IAllKernels = {
|
let allKernels: nb.IAllKernels = {
|
||||||
defaultKernel: noKernel,
|
defaultKernel: noKernel,
|
||||||
kernels: [noKernelSpec]
|
kernels: [noKernelSpec]
|
||||||
};
|
};
|
||||||
return allKernels;
|
return allKernels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export class SessionManager implements nb.SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptySession implements nb.ISession {
|
export class EmptySession implements nb.ISession {
|
||||||
private _kernel: EmptyKernel;
|
private _kernel: EmptyKernel;
|
||||||
private _defaultKernelLoaded = false;
|
private _defaultKernelLoaded = false;
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class EmptyKernel implements nb.IKernel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyFuture implements FutureInternal {
|
export class EmptyFuture implements FutureInternal {
|
||||||
|
|
||||||
|
|
||||||
get inProgress(): boolean {
|
get inProgress(): boolean {
|
||||||
|
|||||||
26
src/sql/sqlops.d.ts
vendored
26
src/sql/sqlops.d.ts
vendored
@@ -214,6 +214,7 @@ declare module 'sqlops' {
|
|||||||
providerName: string;
|
providerName: string;
|
||||||
saveProfile: boolean;
|
saveProfile: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
|
azureTenantId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -694,7 +695,8 @@ declare module 'sqlops' {
|
|||||||
registerOnQueryComplete(handler: (result: QueryExecuteCompleteNotificationResult) => any): void;
|
registerOnQueryComplete(handler: (result: QueryExecuteCompleteNotificationResult) => any): void;
|
||||||
registerOnBatchStart(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any): void;
|
registerOnBatchStart(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any): void;
|
||||||
registerOnBatchComplete(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any): void;
|
registerOnBatchComplete(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any): void;
|
||||||
registerOnResultSetComplete(handler: (resultSetInfo: QueryExecuteResultSetCompleteNotificationParams) => any): void;
|
registerOnResultSetAvailable(handler: (resultSetInfo: QueryExecuteResultSetNotificationParams) => any): void;
|
||||||
|
registerOnResultSetUpdated(handler: (resultSetInfo: QueryExecuteResultSetNotificationParams) => any): void;
|
||||||
registerOnMessage(handler: (message: QueryExecuteMessageParams) => any): void;
|
registerOnMessage(handler: (message: QueryExecuteMessageParams) => any): void;
|
||||||
|
|
||||||
// Edit Data Requests
|
// Edit Data Requests
|
||||||
@@ -769,6 +771,7 @@ declare module 'sqlops' {
|
|||||||
batchId: number;
|
batchId: number;
|
||||||
rowCount: number;
|
rowCount: number;
|
||||||
columnInfo: IDbColumn[];
|
columnInfo: IDbColumn[];
|
||||||
|
complete: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatchSummary {
|
export interface BatchSummary {
|
||||||
@@ -837,7 +840,7 @@ declare module 'sqlops' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface QueryExecuteResultSetCompleteNotificationParams {
|
export interface QueryExecuteResultSetNotificationParams {
|
||||||
resultSetSummary: ResultSetSummary;
|
resultSetSummary: ResultSetSummary;
|
||||||
ownerUri: string;
|
ownerUri: string;
|
||||||
}
|
}
|
||||||
@@ -1297,15 +1300,16 @@ declare module 'sqlops' {
|
|||||||
lastRun: string;
|
lastRun: string;
|
||||||
nextRun: string;
|
nextRun: string;
|
||||||
jobId: string;
|
jobId: string;
|
||||||
EmailLevel: JobCompletionActionCondition;
|
startStepId: number;
|
||||||
PageLevel: JobCompletionActionCondition;
|
emailLevel: JobCompletionActionCondition;
|
||||||
EventLogLevel: JobCompletionActionCondition;
|
pageLevel: JobCompletionActionCondition;
|
||||||
DeleteLevel: JobCompletionActionCondition;
|
eventLogLevel: JobCompletionActionCondition;
|
||||||
OperatorToEmail: string;
|
deleteLevel: JobCompletionActionCondition;
|
||||||
OperatorToPage: string;
|
operatorToEmail: string;
|
||||||
JobSteps: AgentJobStepInfo[];
|
operatorToPage: string;
|
||||||
JobSchedules: AgentJobScheduleInfo[];
|
jobSteps: AgentJobStepInfo[];
|
||||||
Alerts: AgentAlertInfo[];
|
jobSchedules: AgentJobScheduleInfo[];
|
||||||
|
alerts: AgentAlertInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentJobScheduleInfo {
|
export interface AgentJobScheduleInfo {
|
||||||
|
|||||||
307
src/sql/sqlops.proposed.d.ts
vendored
307
src/sql/sqlops.proposed.d.ts
vendored
@@ -839,7 +839,7 @@ declare module 'sqlops' {
|
|||||||
* Create a dialog with the given title
|
* Create a dialog with the given title
|
||||||
* @param title The title of the dialog, displayed at the top
|
* @param title The title of the dialog, displayed at the top
|
||||||
*/
|
*/
|
||||||
export function createDialog(title: string): Dialog;
|
export function createDialog(title: string, dialogName?: string): Dialog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a dialog tab which can be included as part of the content of a dialog
|
* Create a dialog tab which can be included as part of the content of a dialog
|
||||||
@@ -951,6 +951,12 @@ declare module 'sqlops' {
|
|||||||
*/
|
*/
|
||||||
message: DialogMessage;
|
message: DialogMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the dialog name when opening
|
||||||
|
* the dialog for telemetry
|
||||||
|
*/
|
||||||
|
dialogName?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a callback that will be called when the user tries to click done. Only
|
* Register a callback that will be called when the user tries to click done. Only
|
||||||
* one callback can be registered at once, so each registration call will clear
|
* one callback can be registered at once, so each registration call will clear
|
||||||
@@ -1368,6 +1374,282 @@ declare module 'sqlops' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export namespace nb {
|
export namespace nb {
|
||||||
|
/**
|
||||||
|
* All notebook documents currently known to the system.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
export let notebookDocuments: NotebookDocument[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active Notebook editor or `undefined`. The active editor is the one
|
||||||
|
* that currently has focus or, when none has focus, the one that has changed
|
||||||
|
* input most recently.
|
||||||
|
*/
|
||||||
|
export let activeNotebookEditor: NotebookEditor | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently visible editors or an empty array.
|
||||||
|
*/
|
||||||
|
export let visibleNotebookEditors: NotebookEditor[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is emitted when a [notebook document](#NotebookDocument) is opened.
|
||||||
|
*
|
||||||
|
* To add an event listener when a visible text document is opened, use the [TextEditor](#TextEditor) events in the
|
||||||
|
* [window](#window) namespace. Note that:
|
||||||
|
*
|
||||||
|
* - The event is emitted before the [document](#NotebookDocument) is updated in the
|
||||||
|
* [active notebook editor](#nb.activeNotebookEditor)
|
||||||
|
* - When a [notebook document](#NotebookDocument) is already open (e.g.: open in another visible notebook editor) this event is not emitted
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const onDidOpenNotebookDocument: vscode.Event<NotebookDocument>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is emitted when a [notebook's](#NotebookDocument) cell contents are changed.
|
||||||
|
*/
|
||||||
|
export const onDidChangeNotebookCell: vscode.Event<NotebookCellChangeEvent>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the given document in a notebook editor. A [column](#ViewColumn) can be provided
|
||||||
|
* to control where the editor is being shown. Might change the [active editor](#nb.activeNotebookEditor).
|
||||||
|
*
|
||||||
|
* The document is denoted by an [uri](#Uri). Depending on the [scheme](#Uri.scheme) the
|
||||||
|
* following rules apply:
|
||||||
|
* `file`-scheme: Open a file on disk, will be rejected if the file does not exist or cannot be loaded.
|
||||||
|
* `untitled`-scheme: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language
|
||||||
|
* will be derived from the file name.
|
||||||
|
* For all other schemes the registered notebook providers are consulted.
|
||||||
|
*
|
||||||
|
* @param document A document to be shown.
|
||||||
|
* @param column A view column in which the [editor](#NotebookEditor) should be shown. The default is the [active](#ViewColumn.Active), other values
|
||||||
|
* are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside)
|
||||||
|
* to open the editor to the side of the currently active one.
|
||||||
|
* @param preserveFocus When `true` the editor will not take focus.
|
||||||
|
* @return A promise that resolves to a [notebook editor](#NotebookEditor).
|
||||||
|
*/
|
||||||
|
export function showNotebookDocument(uri: vscode.Uri, showOptions?: NotebookShowOptions): Thenable<NotebookEditor>;
|
||||||
|
|
||||||
|
export interface NotebookDocument {
|
||||||
|
/**
|
||||||
|
* The associated uri for this notebook document.
|
||||||
|
*
|
||||||
|
* *Note* that most documents use the `file`-scheme, which means they are files on disk. However, **not** all documents are
|
||||||
|
* saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
readonly uri: vscode.Uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file system path of the associated resource. Shorthand
|
||||||
|
* notation for [TextDocument.uri.fsPath](#TextDocument.uri). Independent of the uri scheme.
|
||||||
|
*/
|
||||||
|
readonly fileName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this document representing an untitled file which has never been saved yet. *Note* that
|
||||||
|
* this does not mean the document will be saved to disk, use [`uri.scheme`](#Uri.scheme)
|
||||||
|
* to figure out where a document will be [saved](#FileSystemProvider), e.g. `file`, `ftp` etc.
|
||||||
|
*/
|
||||||
|
readonly isUntitled: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the Notebook provider associated with this document.
|
||||||
|
*/
|
||||||
|
readonly providerId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `true` if there are unpersisted changes.
|
||||||
|
*/
|
||||||
|
readonly isDirty: boolean;
|
||||||
|
/**
|
||||||
|
* `true` if the document have been closed. A closed document isn't synchronized anymore
|
||||||
|
* and won't be re-used when the same resource is opened again.
|
||||||
|
*/
|
||||||
|
readonly isClosed: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All cells.
|
||||||
|
*/
|
||||||
|
readonly cells: NotebookCell[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the underlying file.
|
||||||
|
*
|
||||||
|
* @return A promise that will resolve to true when the file
|
||||||
|
* has been saved. If the file was not dirty or the save failed,
|
||||||
|
* will return false.
|
||||||
|
*/
|
||||||
|
save(): Thenable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure a cell range is completely contained in this document.
|
||||||
|
*
|
||||||
|
* @param range A cell range.
|
||||||
|
* @return The given range or a new, adjusted range.
|
||||||
|
*/
|
||||||
|
validateCellRange(range: CellRange): CellRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cell range represents an ordered pair of two positions in a list of cells.
|
||||||
|
* It is guaranteed that [start](#CellRange.start).isBeforeOrEqual([end](#CellRange.end))
|
||||||
|
*
|
||||||
|
* CellRange objects are __immutable__.
|
||||||
|
*/
|
||||||
|
export class CellRange {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start index. It is before or equal to [end](#CellRange.end).
|
||||||
|
*/
|
||||||
|
readonly start: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The end index. It is after or equal to [start](#CellRange.start).
|
||||||
|
*/
|
||||||
|
readonly end: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new range from two positions. If `start` is not
|
||||||
|
* before or equal to `end`, the values will be swapped.
|
||||||
|
*
|
||||||
|
* @param start A number.
|
||||||
|
* @param end A number.
|
||||||
|
*/
|
||||||
|
constructor(start: number, end: number);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotebookEditor {
|
||||||
|
/**
|
||||||
|
* The document associated with this editor. The document will be the same for the entire lifetime of this editor.
|
||||||
|
*/
|
||||||
|
readonly document: NotebookDocument;
|
||||||
|
/**
|
||||||
|
* The column in which this editor shows. Will be `undefined` in case this
|
||||||
|
* isn't one of the main editors, e.g an embedded editor, or when the editor
|
||||||
|
* column is larger than three.
|
||||||
|
*/
|
||||||
|
viewColumn?: vscode.ViewColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an edit on the document associated with this notebook editor.
|
||||||
|
*
|
||||||
|
* The given callback-function is invoked with an [edit-builder](#NotebookEditorEdit) which must
|
||||||
|
* be used to make edits. Note that the edit-builder is only valid while the
|
||||||
|
* callback executes.
|
||||||
|
*
|
||||||
|
* @param callback A function which can create edits using an [edit-builder](#NotebookEditorEdit).
|
||||||
|
* @param options The undo/redo behavior around this edit. By default, undo stops will be created before and after this edit.
|
||||||
|
* @return A promise that resolves with a value indicating if the edits could be applied.
|
||||||
|
*/
|
||||||
|
edit(callback: (editBuilder: NotebookEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotebookCell {
|
||||||
|
contents: ICellContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotebookShowOptions {
|
||||||
|
/**
|
||||||
|
* An optional view column in which the [editor](#NotebookEditor) should be shown.
|
||||||
|
* The default is the [active](#ViewColumn.Active), other values are adjusted to
|
||||||
|
* be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is
|
||||||
|
* not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) to open the
|
||||||
|
* editor to the side of the currently active one.
|
||||||
|
*/
|
||||||
|
viewColumn?: vscode.ViewColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional flag that when `true` will stop the [editor](#NotebookEditor) from taking focus.
|
||||||
|
*/
|
||||||
|
preserveFocus?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional flag that controls if an [editor](#NotebookEditor)-tab will be replaced
|
||||||
|
* with the next editor or if it will be kept.
|
||||||
|
*/
|
||||||
|
preview?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional string indicating which notebook provider to initially use
|
||||||
|
*/
|
||||||
|
providerId?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional ID indicating the initial connection to use for this editor
|
||||||
|
*/
|
||||||
|
connectionId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an event describing the change in a [notebook documents's cells](#NotebookDocument.cells).
|
||||||
|
*/
|
||||||
|
export interface NotebookCellChangeEvent {
|
||||||
|
/**
|
||||||
|
* The [notebook document](#NotebookDocument) for which the selections have changed.
|
||||||
|
*/
|
||||||
|
notebook: NotebookDocument;
|
||||||
|
/**
|
||||||
|
* The new value for the [notebook documents's cells](#NotebookDocument.cells).
|
||||||
|
*/
|
||||||
|
cell: NotebookCell[];
|
||||||
|
/**
|
||||||
|
* The [change kind](#TextEditorSelectionChangeKind) which has triggered this
|
||||||
|
* event. Can be `undefined`.
|
||||||
|
*/
|
||||||
|
kind?: vscode.TextEditorSelectionChangeKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A complex edit that will be applied in one transaction on a TextEditor.
|
||||||
|
* This holds a description of the edits and if the edits are valid (i.e. no overlapping regions, document was not changed in the meantime, etc.)
|
||||||
|
* they can be applied on a [document](#TextDocument) associated with a [text editor](#TextEditor).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export interface NotebookEditorEdit {
|
||||||
|
/**
|
||||||
|
* Replace a cell range with a new cell.
|
||||||
|
*
|
||||||
|
* @param location The range this operation should remove.
|
||||||
|
* @param value The new cell this operation should insert after removing `location`.
|
||||||
|
*/
|
||||||
|
replace(location: number | CellRange, value: ICellContents): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a cell (optionally) at a specific index. Any index outside of the length of the cells
|
||||||
|
* will result in the cell being added at the end.
|
||||||
|
*
|
||||||
|
* @param index The position where the new text should be inserted.
|
||||||
|
* @param value The new text this operation should insert.
|
||||||
|
*/
|
||||||
|
insertCell(value: ICellContents, index?: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a certain cell.
|
||||||
|
*
|
||||||
|
* @param index The index of the cell to remove.
|
||||||
|
*/
|
||||||
|
deleteCell(index: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a notebook provider. The supported file types handled by this
|
||||||
|
* provider are defined in the `package.json:
|
||||||
|
* ```json
|
||||||
|
* {
|
||||||
|
* "contributes": {
|
||||||
|
* "notebook.providers": [{
|
||||||
|
* "provider": "providername",
|
||||||
|
* "fileExtensions": ["FILEEXT"]
|
||||||
|
* }]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* @export
|
||||||
|
* @param {NotebookProvider} provider
|
||||||
|
* @returns {vscode.Disposable}
|
||||||
|
*/
|
||||||
export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable;
|
export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable;
|
||||||
|
|
||||||
export interface NotebookProvider {
|
export interface NotebookProvider {
|
||||||
@@ -1431,7 +1713,7 @@ declare module 'sqlops' {
|
|||||||
/* Reads contents from a Uri representing a local or remote notebook and returns a
|
/* Reads contents from a Uri representing a local or remote notebook and returns a
|
||||||
* JSON object containing the cells and metadata about the notebook
|
* JSON object containing the cells and metadata about the notebook
|
||||||
*/
|
*/
|
||||||
getNotebookContents(notebookUri: vscode.Uri): Thenable<INotebook>;
|
getNotebookContents(notebookUri: vscode.Uri): Thenable<INotebookContents>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a file.
|
* Save a file.
|
||||||
@@ -1443,12 +1725,19 @@ declare module 'sqlops' {
|
|||||||
* @returns A thenable which resolves with the file content model when the
|
* @returns A thenable which resolves with the file content model when the
|
||||||
* file is saved.
|
* file is saved.
|
||||||
*/
|
*/
|
||||||
save(notebookUri: vscode.Uri, notebook: INotebook): Thenable<INotebook>;
|
save(notebookUri: vscode.Uri, notebook: INotebookContents): Thenable<INotebookContents>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebook {
|
|
||||||
|
|
||||||
readonly cells: ICell[];
|
/**
|
||||||
|
* Interface defining the file format contents of a notebook, usually in a serializable
|
||||||
|
* format. This interface does not have any methods for manipulating or interacting
|
||||||
|
* with a notebook object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export interface INotebookContents {
|
||||||
|
|
||||||
|
readonly cells: ICellContents[];
|
||||||
readonly metadata: INotebookMetadata;
|
readonly metadata: INotebookMetadata;
|
||||||
readonly nbformat: number;
|
readonly nbformat: number;
|
||||||
readonly nbformat_minor: number;
|
readonly nbformat_minor: number;
|
||||||
@@ -1477,7 +1766,13 @@ declare module 'sqlops' {
|
|||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICell {
|
/**
|
||||||
|
* Interface defining the file format contents of a notebook cell, usually in a serializable
|
||||||
|
* format. This interface does not have any methods for manipulating or interacting
|
||||||
|
* with a cell object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export interface ICellContents {
|
||||||
cell_type: CellType;
|
cell_type: CellType;
|
||||||
source: string | string[];
|
source: string | string[];
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user