mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-10 04:56:56 +00:00
Compare commits
27 Commits
MPAC-2020-
...
genereated
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6870bd9b54 | ||
|
|
8aeff8fb45 | ||
|
|
ee6f635458 | ||
|
|
ad115a2cce | ||
|
|
0c255a55c8 | ||
|
|
08e84d93b5 | ||
|
|
e2895b62b4 | ||
|
|
155aacdf63 | ||
|
|
f4f2d00d7f | ||
|
|
f1812077e9 | ||
|
|
cfe9bd8303 | ||
|
|
9db8d11801 | ||
|
|
769a2e7d1c | ||
|
|
df544f88b2 | ||
|
|
acc65c9588 | ||
|
|
6860d8db1c | ||
|
|
3187756d03 | ||
|
|
0f4ff0e49f | ||
|
|
4f86015be7 | ||
|
|
46cca859e3 | ||
|
|
574fdcaf37 | ||
|
|
eab6506940 | ||
|
|
050da28d6e | ||
|
|
ffae9baca2 | ||
|
|
e491c1a042 | ||
|
|
444e25c086 | ||
|
|
99c6a7ebcc |
@@ -1,5 +1,6 @@
|
||||
**/node_modules/
|
||||
dist/
|
||||
Contracts/
|
||||
src/Api/Apis.ts
|
||||
src/AuthType.ts
|
||||
src/Bindings/BindingHandlersRegisterer.ts
|
||||
@@ -137,7 +138,6 @@ src/Explorer/Panes/AddDatabasePane.test.ts
|
||||
src/Explorer/Panes/AddDatabasePane.ts
|
||||
src/Explorer/Panes/BrowseQueriesPane.ts
|
||||
src/Explorer/Panes/CassandraAddCollectionPane.ts
|
||||
src/Explorer/Panes/ClusterLibraryPane.ts
|
||||
src/Explorer/Panes/ContextualPaneBase.ts
|
||||
src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts
|
||||
src/Explorer/Panes/DeleteCollectionConfirmationPane.ts
|
||||
@@ -145,7 +145,6 @@ src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
||||
src/Explorer/Panes/ExecuteSprocParamsPane.ts
|
||||
src/Explorer/Panes/GraphStylingPane.ts
|
||||
src/Explorer/Panes/LibraryManagePane.ts
|
||||
src/Explorer/Panes/LoadQueryPane.ts
|
||||
src/Explorer/Panes/NewVertexPane.ts
|
||||
src/Explorer/Panes/PaneComponents.ts
|
||||
@@ -331,10 +330,6 @@ src/Explorer/Controls/Directory/DirectoryListComponent.test.tsx
|
||||
src/Explorer/Controls/Directory/DirectoryListComponent.tsx
|
||||
src/Explorer/Controls/Editor/EditorReact.tsx
|
||||
src/Explorer/Controls/InputTypeahead/InputTypeaheadComponent.tsx
|
||||
src/Explorer/Controls/LibraryManagement/ClusterLibraryGrid.tsx
|
||||
src/Explorer/Controls/LibraryManagement/ClusterLibraryGridAdapter.tsx
|
||||
src/Explorer/Controls/LibraryManagement/LibraryManage.tsx
|
||||
src/Explorer/Controls/LibraryManagement/LibraryManageComponentAdapter.tsx
|
||||
src/Explorer/Controls/Notebook/NotebookTerminalComponent.test.tsx
|
||||
src/Explorer/Controls/Notebook/NotebookTerminalComponent.tsx
|
||||
src/Explorer/Controls/NotebookViewer/NotebookMetadataComponent.tsx
|
||||
|
||||
@@ -39,6 +39,7 @@ module.exports = {
|
||||
curly: "error",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"no-null/no-null": "error"
|
||||
"no-null/no-null": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# CosmosDB Explorer
|
||||
|
||||
UI for Azure Cosmos DB. Powers the [Azure Portal](https://portal.azure.com/), https://cosmos.azure.com/, and the [Cosmos DB Emulator](https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator)
|
||||
|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
- `npm install`
|
||||
@@ -87,6 +91,10 @@ Jest and Puppeteer are used for end to end production runners and are contained
|
||||
1. Copy .env.example to .env and fill in all variables
|
||||
2. Run `npm run test:e2e`
|
||||
|
||||
### Releasing
|
||||
|
||||
We generally adhear to the release strategy [documented by the Azure SDK Guidelines](https://azure.github.io/azure-sdk/policies_repobranching.html#release-branches). Most releases should happen from the master branch. If master contains commits that cannot be released, you may create a release from a `release/` or `hotfix/` branch. See linked documentation for more details.
|
||||
|
||||
# Contributing
|
||||
|
||||
Please read the [contribution guidelines](./CONTRIBUTING.md).
|
||||
|
||||
@@ -2349,9 +2349,9 @@ a:link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tabsContainer {
|
||||
.tabsManagerContainer {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
167
package-lock.json
generated
167
package-lock.json
generated
@@ -6024,6 +6024,16 @@
|
||||
"natural-compare": "^1.4.0",
|
||||
"pretty-format": "^24.9.0",
|
||||
"semver": "^6.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-validate": {
|
||||
@@ -7577,11 +7587,40 @@
|
||||
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mkdirp": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz",
|
||||
"integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.1.tgz",
|
||||
"integrity": "sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz",
|
||||
"integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
|
||||
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
@@ -8403,7 +8442,6 @@
|
||||
"graceful-fs": "^4.1.11",
|
||||
"lru-cache": "^4.1.1",
|
||||
"mississippi": "^2.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"move-concurrently": "^1.0.1",
|
||||
"promise-inflight": "^1.0.1",
|
||||
"rimraf": "^2.6.2",
|
||||
@@ -9342,6 +9380,15 @@
|
||||
"pkg-dir": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"pify": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
@@ -10656,6 +10703,14 @@
|
||||
"run-queue": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -19754,6 +19809,16 @@
|
||||
"mkdirp": "^0.5.1",
|
||||
"slash": "^2.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-validate": {
|
||||
@@ -20337,6 +20402,16 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
@@ -21287,12 +21362,9 @@
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
||||
},
|
||||
"mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
@@ -21338,6 +21410,14 @@
|
||||
"run-queue": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -21677,6 +21757,14 @@
|
||||
"tar": "^4"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -22576,6 +22664,15 @@
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -25476,6 +25573,16 @@
|
||||
"mkdirp": "^0.5.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tar-fs": {
|
||||
@@ -25833,6 +25940,14 @@
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
|
||||
@@ -26901,6 +27016,15 @@
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@@ -27012,6 +27136,15 @@
|
||||
"integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
@@ -27224,6 +27357,15 @@
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@@ -27531,6 +27673,17 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mkdirp": "^0.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"write-file-atomic": {
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
"@nteract/transform-vega": "7.0.6",
|
||||
"@octokit/rest": "17.9.2",
|
||||
"@phosphor/widgets": "1.9.3",
|
||||
"@types/mkdirp": "1.0.1",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@uifabric/react-cards": "0.109.110",
|
||||
"@uifabric/styling": "7.13.7",
|
||||
"abort-controller": "3.0.0",
|
||||
@@ -60,6 +62,7 @@
|
||||
"jquery-typeahead": "2.10.6",
|
||||
"jquery-ui-dist": "1.12.1",
|
||||
"knockout": "3.5.1",
|
||||
"mkdirp": "1.0.4",
|
||||
"monaco-editor": "0.15.6",
|
||||
"object.entries": "1.1.0",
|
||||
"office-ui-fabric-react": "7.121.10",
|
||||
@@ -147,6 +150,7 @@
|
||||
"less-vars-loader": "1.1.0",
|
||||
"mini-css-extract-plugin": "0.4.3",
|
||||
"monaco-editor-webpack-plugin": "1.7.0",
|
||||
"node-fetch": "2.6.0",
|
||||
"prettier": "1.19.1",
|
||||
"puppeteer": "4.0.0",
|
||||
"raw-loader": "0.5.1",
|
||||
@@ -187,7 +191,8 @@
|
||||
"build:contracts": "npm run compile:contracts",
|
||||
"strictEligibleFiles": "node ./strict-migration-tools/index.js",
|
||||
"autoAddStrictEligibleFiles": "node ./strict-migration-tools/autoAdd.js",
|
||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks"
|
||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
||||
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -351,6 +351,7 @@ export class HttpStatusCodes {
|
||||
public static readonly Created: number = 201;
|
||||
public static readonly Accepted: number = 202;
|
||||
public static readonly NoContent: number = 204;
|
||||
public static readonly NotModified: number = 304;
|
||||
public static readonly Unauthorized: number = 401;
|
||||
public static readonly Forbidden: number = 403;
|
||||
public static readonly NotFound: number = 404;
|
||||
|
||||
@@ -24,6 +24,7 @@ import { MessageHandler } from "./MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { OfferUtils } from "../Utils/OfferUtils";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
|
||||
export function getCommonQueryOptions(options: FeedOptions): any {
|
||||
const storedItemPerPageSetting: number = LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage);
|
||||
@@ -142,7 +143,7 @@ export abstract class DataAccessUtilityBase {
|
||||
|
||||
public executeStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: ViewModels.StoredProcedure,
|
||||
storedProcedure: StoredProcedure,
|
||||
partitionKeyValue: any,
|
||||
params: any[]
|
||||
): Q.Promise<any> {
|
||||
@@ -615,14 +616,6 @@ export abstract class DataAccessUtilityBase {
|
||||
}
|
||||
}
|
||||
|
||||
public readSubscription(subscriptionId: string, options: any): Q.Promise<DataModels.Subscription> {
|
||||
throw new Error("Read subscription not supported on this platform");
|
||||
}
|
||||
|
||||
public readSubscriptionDefaults(subscriptionId: string, quotaId: string, options: any): Q.Promise<string> {
|
||||
throw new Error("Read subscription defaults not supported on this platform");
|
||||
}
|
||||
|
||||
public queryConflicts(
|
||||
databaseId: string,
|
||||
containerId: string,
|
||||
|
||||
@@ -12,6 +12,7 @@ import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { MinimalQueryIterator, nextPage } from "./IteratorUtilities";
|
||||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
|
||||
// TODO: Log all promise resolutions and errors with verbosity levels
|
||||
export default class DocumentClientUtilityBase {
|
||||
@@ -164,7 +165,7 @@ export default class DocumentClientUtilityBase {
|
||||
|
||||
public executeStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: ViewModels.StoredProcedure,
|
||||
storedProcedure: StoredProcedure,
|
||||
partitionKeyValue: any,
|
||||
params: any[]
|
||||
): Q.Promise<any> {
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as Constants from "../Common/Constants";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { StringUtils } from "../Utils/StringUtils";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
|
||||
export default class EnvironmentUtility {
|
||||
public static getMongoBackendEndpoint(serverId: string, location: string, extensionEndpoint: string = ""): string {
|
||||
@@ -26,7 +27,7 @@ export default class EnvironmentUtility {
|
||||
return window.authType === AuthType.AAD;
|
||||
}
|
||||
|
||||
public static getCassandraBackendEndpoint(explorer: ViewModels.Explorer): string {
|
||||
public static getCassandraBackendEndpoint(explorer: Explorer): string {
|
||||
const defaultLocation: string = "default";
|
||||
const location: string = EnvironmentUtility.normalizeRegionName(explorer.databaseAccount().location);
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@ import { MessageHandler } from "./MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||
import { MinimalQueryIterator } from "./IteratorUtilities";
|
||||
|
||||
const defaultHeaders = {
|
||||
[HttpHeaders.apiType]: ApiType.MongoDB.toString(),
|
||||
@@ -23,7 +24,7 @@ const defaultHeaders = {
|
||||
[CosmosSDKConstants.HttpHeaders.Version]: "2017-11-15"
|
||||
};
|
||||
|
||||
function authHeaders(): any {
|
||||
function authHeaders() {
|
||||
if (window.authType === AuthType.EncryptedToken) {
|
||||
return { [HttpHeaders.guestAccessToken]: CosmosClient.accessToken() };
|
||||
} else {
|
||||
@@ -31,21 +32,21 @@ function authHeaders(): any {
|
||||
}
|
||||
}
|
||||
|
||||
export function queryIterator(databaseId: string, collection: Collection, query: string): any {
|
||||
export function queryIterator(databaseId: string, collection: Collection, query: string): MinimalQueryIterator {
|
||||
let continuationToken: string;
|
||||
return {
|
||||
fetchNext: () => {
|
||||
return queryDocuments(databaseId, collection, false, query).then(response => {
|
||||
continuationToken = response.continuationToken;
|
||||
const headers = {} as any;
|
||||
response.headers.forEach((value: any, key: any) => {
|
||||
const headers: { [key: string]: string | number } = {};
|
||||
response.headers.forEach((value, key) => {
|
||||
headers[key] = value;
|
||||
});
|
||||
return {
|
||||
resources: response.documents,
|
||||
headers,
|
||||
requestCharge: headers[CosmosSDKConstants.HttpHeaders.RequestCharge],
|
||||
activityId: headers[CosmosSDKConstants.HttpHeaders.ActivityId],
|
||||
requestCharge: Number(headers[CosmosSDKConstants.HttpHeaders.RequestCharge]),
|
||||
activityId: String(headers[CosmosSDKConstants.HttpHeaders.ActivityId]),
|
||||
hasMoreResults: !!continuationToken
|
||||
};
|
||||
});
|
||||
@@ -114,7 +115,8 @@ export function queryDocuments(
|
||||
headers: response.headers
|
||||
};
|
||||
}
|
||||
return errorHandling(response, "querying documents", params);
|
||||
errorHandling(response, "querying documents", params);
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -165,7 +167,7 @@ export function createDocument(
|
||||
databaseId: string,
|
||||
collection: Collection,
|
||||
partitionKeyProperty: string,
|
||||
documentContent: any
|
||||
documentContent: unknown
|
||||
): Promise<DataModels.DocumentId> {
|
||||
const databaseAccount = CosmosClient.databaseAccount();
|
||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||
@@ -204,7 +206,7 @@ export function updateDocument(
|
||||
databaseId: string,
|
||||
collection: Collection,
|
||||
documentId: ViewModels.DocumentId,
|
||||
documentContent: any
|
||||
documentContent: unknown
|
||||
): Promise<DataModels.DocumentId> {
|
||||
const databaseAccount = CosmosClient.databaseAccount();
|
||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||
@@ -228,7 +230,7 @@ export function updateDocument(
|
||||
return window
|
||||
.fetch(`${endpoint}?${queryString.stringify(params)}`, {
|
||||
method: "PUT",
|
||||
body: documentContent,
|
||||
body: JSON.stringify(documentContent),
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
...authHeaders(),
|
||||
@@ -248,7 +250,7 @@ export function deleteDocument(
|
||||
databaseId: string,
|
||||
collection: Collection,
|
||||
documentId: ViewModels.DocumentId
|
||||
): Promise<any> {
|
||||
): Promise<void> {
|
||||
const databaseAccount = CosmosClient.databaseAccount();
|
||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||
const idComponents = documentId.self.split("/");
|
||||
@@ -295,7 +297,7 @@ export function createMongoCollectionWithProxy(
|
||||
sharedThroughput: boolean,
|
||||
isSharded: boolean,
|
||||
autopilotOptions?: DataModels.RpOptions
|
||||
): Promise<any> {
|
||||
): Promise<DataModels.Collection> {
|
||||
const databaseAccount = CosmosClient.databaseAccount();
|
||||
const params: DataModels.MongoParameters = {
|
||||
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
||||
@@ -335,7 +337,7 @@ export function createMongoCollectionWithProxy(
|
||||
)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return undefined;
|
||||
return response.json();
|
||||
}
|
||||
return errorHandling(response, "creating collection", params);
|
||||
});
|
||||
@@ -352,7 +354,7 @@ export function createMongoCollectionWithARM(
|
||||
sharedThroughput: boolean,
|
||||
isSharded: boolean,
|
||||
additionalOptions?: DataModels.RpOptions
|
||||
): Promise<any> {
|
||||
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||
const databaseAccount = CosmosClient.databaseAccount();
|
||||
const params: DataModels.MongoParameters = {
|
||||
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
||||
@@ -396,7 +398,9 @@ export function getEndpoint(databaseAccount: ViewModels.DatabaseAccount): string
|
||||
return url;
|
||||
}
|
||||
|
||||
async function errorHandling(response: any, action: string, params: any): Promise<any> {
|
||||
// TODO: This function throws most of the time except on Forbidden which is a bit strange
|
||||
// It causes problems for TypeScript understanding the types
|
||||
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
||||
const errorMessage = await response.text();
|
||||
// Log the error where the user can see it
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
@@ -420,7 +424,7 @@ export async function _createMongoCollectionWithARM(
|
||||
armEndpoint: string,
|
||||
params: DataModels.MongoParameters,
|
||||
rpOptions: DataModels.RpOptions
|
||||
): Promise<any> {
|
||||
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||
const rpPayloadToCreateCollection: DataModels.MongoCreationRequest = {
|
||||
properties: {
|
||||
resource: {
|
||||
@@ -448,12 +452,13 @@ export async function _createMongoCollectionWithARM(
|
||||
}
|
||||
|
||||
try {
|
||||
await new ResourceProviderClient(armEndpoint).putAsync(
|
||||
return new ResourceProviderClient<DataModels.CreateCollectionWithRpResponse>(armEndpoint).putAsync(
|
||||
getARMCreateCollectionEndpoint(params),
|
||||
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||
rpPayloadToCreateCollection
|
||||
);
|
||||
} catch (response) {
|
||||
return errorHandling(response, "creating collection", undefined);
|
||||
errorHandling(response, "creating collection", undefined);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import * as Logger from "./Logger";
|
||||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { QueryUtils } from "../Utils/QueryUtils";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
|
||||
export class QueriesClient implements ViewModels.QueriesClient {
|
||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||
@@ -20,7 +21,7 @@ export class QueriesClient implements ViewModels.QueriesClient {
|
||||
private static readonly FetchQuery: string = "SELECT * FROM c";
|
||||
private static readonly FetchMongoQuery: string = "{}";
|
||||
|
||||
public constructor(private container: ViewModels.Explorer) {}
|
||||
public constructor(private container: Explorer) {}
|
||||
|
||||
public async setupQueriesCollection(): Promise<DataModels.Collection> {
|
||||
const queriesCollection: ViewModels.Collection = this.findQueriesCollection();
|
||||
|
||||
@@ -437,10 +437,8 @@ export interface Tenant {
|
||||
export interface AccountKeys {
|
||||
primaryMasterKey: string;
|
||||
secondaryMasterKey: string;
|
||||
properties: {
|
||||
primaryReadonlyMasterKey: string;
|
||||
secondaryReadonlyMasterKey: string;
|
||||
};
|
||||
primaryReadonlyMasterKey: string;
|
||||
secondaryReadonlyMasterKey: string;
|
||||
}
|
||||
|
||||
export interface AfecFeature {
|
||||
|
||||
@@ -1,32 +1,21 @@
|
||||
import * as DataModels from "./DataModels";
|
||||
import * as Entities from "../Explorer/Tables/Entities";
|
||||
import * as monaco from "monaco-editor";
|
||||
import DocumentClientUtilityBase from "../Common/DocumentClientUtilityBase";
|
||||
import Q from "q";
|
||||
import QueryViewModel from "../Explorer/Tables/QueryBuilder/QueryViewModel";
|
||||
import TableEntityListViewModel from "../Explorer/Tables/DataTable/TableEntityListViewModel";
|
||||
import { AccessibleVerticalList } from "../Explorer/Tree/AccessibleVerticalList";
|
||||
import { ArcadiaWorkspaceItem } from "../Explorer/Controls/Arcadia/ArcadiaMenuPicker";
|
||||
import { CassandraTableKey, CassandraTableKeys, TableDataClient } from "../Explorer/Tables/TableDataClient";
|
||||
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
|
||||
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { ExecuteSprocParam } from "../Explorer/Panes/ExecuteSprocParamsPane";
|
||||
import { GitHubClient } from "../GitHub/GitHubClient";
|
||||
import { IColumnSetting } from "../Explorer/Panes/Tables/TableColumnOptionsPane";
|
||||
import { JunoClient, IGalleryItem } from "../Juno/JunoClient";
|
||||
import { Library } from "./DataModels";
|
||||
import { MostRecentActivity } from "../Explorer/MostRecentActivity/MostRecentActivity";
|
||||
import { NotebookContentItem } from "../Explorer/Notebook/NotebookContentItem";
|
||||
import { PlatformType } from "../PlatformType";
|
||||
import { QueryMetrics } from "@azure/cosmos";
|
||||
import { SetupNotebooksPane } from "../Explorer/Panes/SetupNotebooksPane";
|
||||
import { Splitter } from "../Common/Splitter";
|
||||
import { StringInputPane } from "../Explorer/Panes/StringInputPane";
|
||||
import { TabsManager } from "../Explorer/Tabs/TabsManager";
|
||||
import { TextFieldProps } from "../Explorer/Controls/DialogReactComponent/DialogComponent";
|
||||
import { UploadDetails } from "../workers/upload/definitions";
|
||||
import { UploadItemsPaneAdapter } from "../Explorer/Panes/UploadItemsPaneAdapter";
|
||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import ConflictsTab from "../Explorer/Tabs/ConflictsTab";
|
||||
import Trigger from "../Explorer/Tree/Trigger";
|
||||
|
||||
export interface ExplorerOptions {
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
@@ -42,266 +31,12 @@ export interface NavbarButtonConfig extends CommandButtonComponentProps {}
|
||||
|
||||
export interface DatabaseAccount extends DataModels.DatabaseAccount {}
|
||||
|
||||
export interface Explorer {
|
||||
flight: ko.Observable<string>;
|
||||
handleMessage(event: MessageEvent): void;
|
||||
isRefreshingExplorer: ko.Observable<boolean>;
|
||||
|
||||
databaseAccount: ko.Observable<DatabaseAccount>;
|
||||
subscriptionType: ko.Observable<SubscriptionType>;
|
||||
quotaId: ko.Observable<string>;
|
||||
hasWriteAccess: ko.Observable<boolean>;
|
||||
|
||||
defaultExperience: ko.Observable<string>;
|
||||
isPreferredApiDocumentDB: ko.Computed<boolean>;
|
||||
isPreferredApiCassandra: ko.Computed<boolean>;
|
||||
isPreferredApiTable: ko.Computed<boolean>;
|
||||
isPreferredApiGraph: ko.Computed<boolean>;
|
||||
isPreferredApiMongoDB: ko.Computed<boolean>;
|
||||
|
||||
isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
||||
|
||||
isDatabaseNodeOrNoneSelected(): boolean;
|
||||
isDatabaseNodeSelected(): boolean;
|
||||
isNodeKindSelected(nodeKind: string): boolean;
|
||||
isNoneSelected(): boolean;
|
||||
isSelectedDatabaseShared(): boolean;
|
||||
deleteDatabaseText: ko.Observable<string>;
|
||||
deleteCollectionText: ko.Subscribable<string>; // Our code assigns to a ko.Observable, but unit test assigns to ko.Computed
|
||||
|
||||
addCollectionText: ko.Observable<string>;
|
||||
addDatabaseText: ko.Observable<string>;
|
||||
collectionTitle: ko.Observable<string>;
|
||||
collectionTreeNodeAltText: ko.Observable<string>;
|
||||
refreshTreeTitle: ko.Observable<string>;
|
||||
|
||||
isAccountReady: ko.Observable<boolean>;
|
||||
|
||||
collectionCreationDefaults: CollectionCreationDefaults;
|
||||
isEmulator: boolean;
|
||||
features: ko.Observable<any>;
|
||||
serverId: ko.Observable<string>;
|
||||
extensionEndpoint: ko.Observable<string>;
|
||||
armEndpoint: ko.Observable<string>;
|
||||
isFeatureEnabled: (feature: string) => boolean;
|
||||
isGalleryPublishEnabled: ko.Computed<boolean>;
|
||||
isGitHubPaneEnabled: ko.Observable<boolean>;
|
||||
isPublishNotebookPaneEnabled: ko.Observable<boolean>;
|
||||
isRightPanelV2Enabled: ko.Computed<boolean>;
|
||||
canExceedMaximumValue: ko.Computed<boolean>;
|
||||
hasAutoPilotV2FeatureFlag: ko.Computed<boolean>;
|
||||
isHostedDataExplorerEnabled: ko.Computed<boolean>;
|
||||
isNotificationConsoleExpanded: ko.Observable<boolean>;
|
||||
isTryCosmosDBSubscription: ko.Observable<boolean>;
|
||||
canSaveQueries: ko.Computed<boolean>;
|
||||
parentFrameDataExplorerVersion: ko.Observable<string>;
|
||||
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
notificationsClient: NotificationsClient;
|
||||
queriesClient: QueriesClient;
|
||||
tableDataClient: TableDataClient;
|
||||
splitter: Splitter;
|
||||
notificationConsoleData: ko.ObservableArray<ConsoleData>;
|
||||
|
||||
// Selection
|
||||
selectedNode: ko.Observable<TreeNode>;
|
||||
|
||||
// Tree
|
||||
databases: ko.ObservableArray<Database>;
|
||||
nonSystemDatabases: ko.Computed<Database[]>;
|
||||
selectedDatabaseId: ko.Computed<string>;
|
||||
selectedCollectionId: ko.Computed<string>;
|
||||
isLeftPaneExpanded: ko.Observable<boolean>;
|
||||
|
||||
// Resource Token
|
||||
resourceTokenDatabaseId: ko.Observable<string>;
|
||||
resourceTokenCollectionId: ko.Observable<string>;
|
||||
resourceTokenCollection: ko.Observable<CollectionBase>;
|
||||
resourceTokenPartitionKey: ko.Observable<string>;
|
||||
isAuthWithResourceToken: ko.Observable<boolean>;
|
||||
isResourceTokenCollectionNodeSelected: ko.Computed<boolean>;
|
||||
|
||||
// Tabs
|
||||
isTabsContentExpanded: ko.Observable<boolean>;
|
||||
tabsManager: TabsManager;
|
||||
|
||||
// Contextual Panes
|
||||
addDatabasePane: AddDatabasePane;
|
||||
addCollectionPane: AddCollectionPane;
|
||||
deleteCollectionConfirmationPane: DeleteCollectionConfirmationPane;
|
||||
deleteDatabaseConfirmationPane: DeleteDatabaseConfirmationPane;
|
||||
graphStylingPane: GraphStylingPane;
|
||||
addTableEntityPane: AddTableEntityPane;
|
||||
editTableEntityPane: EditTableEntityPane;
|
||||
tableColumnOptionsPane: TableColumnOptionsPane;
|
||||
querySelectPane: QuerySelectPane;
|
||||
newVertexPane: NewVertexPane;
|
||||
cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||
settingsPane: SettingsPane;
|
||||
executeSprocParamsPane: ExecuteSprocParamsPane;
|
||||
renewAdHocAccessPane: RenewAdHocAccessPane;
|
||||
uploadItemsPane: UploadItemsPane;
|
||||
uploadItemsPaneAdapter: UploadItemsPaneAdapter;
|
||||
loadQueryPane: LoadQueryPane;
|
||||
saveQueryPane: ContextualPane;
|
||||
browseQueriesPane: BrowseQueriesPane;
|
||||
uploadFilePane: UploadFilePane;
|
||||
stringInputPane: StringInputPane;
|
||||
setupNotebooksPane: SetupNotebooksPane;
|
||||
libraryManagePane: ContextualPane;
|
||||
clusterLibraryPane: ContextualPane;
|
||||
gitHubReposPane: ContextualPane;
|
||||
publishNotebookPaneAdapter: ReactAdapter;
|
||||
|
||||
// Facade
|
||||
logConsoleData(data: ConsoleData): void;
|
||||
isNodeKindSelected(nodeKind: string): boolean;
|
||||
initDataExplorerWithFrameInputs(inputs: DataExplorerInputsFrame): Q.Promise<void>;
|
||||
toggleLeftPaneExpanded(): void;
|
||||
refreshDatabaseForResourceToken(): Q.Promise<void>;
|
||||
refreshAllDatabases(isInitialLoad?: boolean): Q.Promise<any>;
|
||||
closeAllPanes(): void;
|
||||
findSelectedDatabase(): Database;
|
||||
findDatabaseWithId(databaseRid: string): Database;
|
||||
isLastDatabase(): boolean;
|
||||
isLastNonEmptyDatabase(): boolean;
|
||||
findSelectedCollection(): Collection;
|
||||
isLastCollection(): boolean;
|
||||
findSelectedStoredProcedure(): StoredProcedure;
|
||||
findSelectedUDF(): UserDefinedFunction;
|
||||
findSelectedTrigger(): Trigger;
|
||||
findCollection(rid: string): Collection;
|
||||
provideFeedbackEmail(): void;
|
||||
expandConsole: () => void;
|
||||
collapseConsole: () => void;
|
||||
generateSharedAccessData(): void;
|
||||
getPlatformType(): PlatformType;
|
||||
isConnectExplorerVisible(): boolean;
|
||||
isRunningOnNationalCloud(): boolean;
|
||||
displayConnectExplorerForm(): void;
|
||||
hideConnectExplorerForm(): void;
|
||||
displayContextSwitchPromptForConnectionString(connectionString: string): void;
|
||||
displayGuestAccessTokenRenewalPrompt(): void;
|
||||
rebindDocumentClientUtility(documentClientUtility: DocumentClientUtilityBase): void;
|
||||
renewExplorerShareAccess: (explorer: Explorer, token: string) => Q.Promise<void>;
|
||||
renewShareAccess(accessInput: string): Q.Promise<void>;
|
||||
onUpdateTabsButtons: (buttons: NavbarButtonConfig[]) => void;
|
||||
onNewCollectionClicked: () => void;
|
||||
showOkModalDialog: (title: string, msg: string) => void;
|
||||
showOkCancelModalDialog: (
|
||||
title: string,
|
||||
msg: string,
|
||||
okLabel: string,
|
||||
onOk: () => void,
|
||||
cancelLabel: string,
|
||||
onCancel: () => void
|
||||
) => void;
|
||||
showOkCancelTextFieldModalDialog: (
|
||||
title: string,
|
||||
msg: string,
|
||||
okLabel: string,
|
||||
onOk: () => void,
|
||||
cancelLabel: string,
|
||||
onCancel: () => void,
|
||||
textFiledProps: TextFieldProps,
|
||||
isPrimaryButtonDisabled?: boolean
|
||||
) => void;
|
||||
|
||||
// Analytics
|
||||
isNotebookEnabled: ko.Observable<boolean>;
|
||||
isSparkEnabled: ko.Observable<boolean>;
|
||||
isNotebooksEnabledForAccount: ko.Observable<boolean>;
|
||||
isSparkEnabledForAccount: ko.Observable<boolean>;
|
||||
hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||
openEnableSynapseLinkDialog(): void;
|
||||
isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||
notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>;
|
||||
sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
|
||||
arcadiaToken: ko.Observable<string>;
|
||||
arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||
memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||
notebookManager?: any; // This is dynamically loaded
|
||||
openNotebook(notebookContentItem: NotebookContentItem): Promise<boolean>; // True if it was opened, false otherwise
|
||||
resetNotebookWorkspace(): void;
|
||||
importAndOpen: (path: string) => Promise<boolean>;
|
||||
importAndOpenContent: (name: string, content: string) => Promise<boolean>;
|
||||
publishNotebook: (name: string, content: string) => void;
|
||||
openNotebookTerminal: (kind: TerminalKind) => void;
|
||||
openGallery: (notebookUrl?: string, galleryItem?: IGalleryItem, isFavorite?: boolean) => void;
|
||||
openNotebookViewer: (notebookUrl: string) => void;
|
||||
notebookWorkspaceManager: NotebookWorkspaceManager;
|
||||
sparkClusterManager: SparkClusterManager;
|
||||
mostRecentActivity: MostRecentActivity;
|
||||
initNotebooks: (databaseAccount: DataModels.DatabaseAccount) => Promise<void>;
|
||||
deleteCluster(): void;
|
||||
openSparkMasterTab(): Promise<void>;
|
||||
handleOpenFileAction(path: string): Promise<void>;
|
||||
|
||||
// Notebook operations
|
||||
openNotebook(notebookContentItem: NotebookContentItem): Promise<boolean>; // True if it was opened, false otherwise
|
||||
deleteNotebookFile: (item: NotebookContentItem) => Promise<void>;
|
||||
onCreateDirectory(parent: NotebookContentItem): Q.Promise<NotebookContentItem>;
|
||||
onNewNotebookClicked: (parent?: NotebookContentItem) => void;
|
||||
onUploadToNotebookServerClicked: (parent?: NotebookContentItem) => void;
|
||||
renameNotebook: (notebookFile: NotebookContentItem) => Q.Promise<NotebookContentItem>;
|
||||
readFile: (notebookFile: NotebookContentItem) => Promise<string>;
|
||||
downloadFile: (notebookFile: NotebookContentItem) => Promise<void>;
|
||||
createNotebookContentItemFile: (name: string, filepath: string) => NotebookContentItem;
|
||||
refreshContentItem(item: NotebookContentItem): Promise<void>;
|
||||
getNotebookBasePath(): string;
|
||||
|
||||
createWorkspace(): Promise<string>;
|
||||
createSparkPool(workspaceId: string): Promise<string>;
|
||||
}
|
||||
|
||||
export interface NotebookWorkspaceManager {
|
||||
getNotebookWorkspacesAsync(cosmosAccountResourceId: string): Promise<DataModels.NotebookWorkspace[]>;
|
||||
getNotebookWorkspaceAsync(
|
||||
cosmosAccountResourceId: string,
|
||||
notebookWorkspaceId: string
|
||||
): Promise<DataModels.NotebookWorkspace>;
|
||||
createNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise<void>;
|
||||
deleteNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise<void>;
|
||||
getNotebookConnectionInfoAsync(
|
||||
cosmosAccountResourceId: string,
|
||||
notebookWorkspaceId: string
|
||||
): Promise<DataModels.NotebookWorkspaceConnectionInfo>;
|
||||
startNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface KernelConnectionMetadata {
|
||||
name: string;
|
||||
configurationEndpoints: DataModels.NotebookConfigurationEndpoints;
|
||||
notebookConnectionInfo: DataModels.NotebookWorkspaceConnectionInfo;
|
||||
}
|
||||
|
||||
export interface SparkClusterManager {
|
||||
getClustersAsync(cosmosAccountResourceId: string): Promise<DataModels.SparkCluster[]>;
|
||||
getClusterAsync(cosmosAccountResourceId: string, clusterId: string): Promise<DataModels.SparkCluster>;
|
||||
createClusterAsync(cosmosAccountResourceId: string, cluster: Partial<DataModels.SparkCluster>): Promise<void>;
|
||||
updateClusterAsync(
|
||||
cosmosAccountResourceId: string,
|
||||
clusterId: string,
|
||||
sparkCluster: DataModels.SparkCluster
|
||||
): Promise<DataModels.SparkCluster>;
|
||||
deleteClusterAsync(cosmosAccountResourceId: string, clusterId: string): Promise<void>;
|
||||
getClusterConnectionInfoAsync(
|
||||
cosmosAccountResourceId: string,
|
||||
clusterId: string
|
||||
): Promise<DataModels.SparkClusterConnectionInfo>;
|
||||
getLibrariesAsync(cosmosdbResourceId: string): Promise<Library[]>;
|
||||
getLibraryAsync(cosmosdbResourceId: string, libraryName: string): Promise<Library>;
|
||||
addLibraryAsync(cosmosdbResourceId: string, libraryName: string, library: Library): Promise<void>;
|
||||
deleteLibraryAsync(cosmosdbResourceId: string, libraryName: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ArcadiaResourceManager {
|
||||
getWorkspacesAsync(arcadiaResourceId: string): Promise<DataModels.ArcadiaWorkspace[]>;
|
||||
getWorkspaceAsync(arcadiaResourceId: string, workspaceId: string): Promise<DataModels.ArcadiaWorkspace>;
|
||||
listWorkspacesAsync(subscriptionIds: string[]): Promise<DataModels.ArcadiaWorkspace[]>;
|
||||
listSparkPoolsAsync(resourceId: string): Promise<DataModels.SparkPool[]>;
|
||||
}
|
||||
|
||||
export interface TokenProvider {
|
||||
getAuthHeader(): Promise<Headers>;
|
||||
}
|
||||
@@ -505,48 +240,6 @@ export interface ConflictId {
|
||||
loadConflict(): Q.Promise<any>;
|
||||
}
|
||||
|
||||
export interface StoredProcedure extends TreeNode {
|
||||
container: Explorer;
|
||||
collection: Collection;
|
||||
rid: string;
|
||||
self: string;
|
||||
id: ko.Observable<string>;
|
||||
body: ko.Observable<string>;
|
||||
|
||||
delete(): void;
|
||||
open: () => void;
|
||||
select(): void;
|
||||
execute(params: string[], partitionKeyValue?: string): void;
|
||||
}
|
||||
|
||||
export interface UserDefinedFunction extends TreeNode {
|
||||
container: Explorer;
|
||||
collection: Collection;
|
||||
rid: string;
|
||||
self: string;
|
||||
id: ko.Observable<string>;
|
||||
body: ko.Observable<string>;
|
||||
|
||||
delete(): void;
|
||||
open: () => void;
|
||||
select(): void;
|
||||
}
|
||||
|
||||
export interface Trigger extends TreeNode {
|
||||
container: Explorer;
|
||||
collection: Collection;
|
||||
rid: string;
|
||||
self: string;
|
||||
id: ko.Observable<string>;
|
||||
body: ko.Observable<string>;
|
||||
triggerType: ko.Observable<string>;
|
||||
triggerOperation: ko.Observable<string>;
|
||||
|
||||
delete(): void;
|
||||
open: () => void;
|
||||
select(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to initialize pane
|
||||
*/
|
||||
@@ -598,78 +291,6 @@ export interface AddCollectionPaneOptions extends PaneOptions {
|
||||
databaseSelfLink?: string;
|
||||
}
|
||||
|
||||
export interface AddCollectionPane extends ContextualPane {
|
||||
collectionIdTitle: ko.Observable<string>;
|
||||
collectionWithThroughputInSharedTitle: ko.Observable<string>;
|
||||
databaseId: ko.Observable<string>;
|
||||
partitionKey: ko.Observable<string>;
|
||||
storage: ko.Observable<string>;
|
||||
throughputSinglePartition: ko.Observable<number>;
|
||||
throughputMultiPartition: ko.Observable<number>;
|
||||
|
||||
open: (databaseId?: string) => void;
|
||||
onStorageOptionsKeyDown(source: any, event: KeyboardEvent): boolean;
|
||||
onRupmOptionsKeyDown(source: any, event: KeyboardEvent): void;
|
||||
onEnableSynapseLinkButtonClicked: () => void;
|
||||
}
|
||||
|
||||
export interface AddDatabasePane extends ContextualPane {}
|
||||
|
||||
export interface DeleteDatabaseConfirmationPane extends ContextualPane {
|
||||
databaseIdConfirmation: ko.Observable<string>;
|
||||
databaseIdConfirmationText: ko.Observable<string>;
|
||||
databaseDeleteFeedback: ko.Observable<string>;
|
||||
}
|
||||
|
||||
export interface DeleteCollectionConfirmationPane extends ContextualPane {
|
||||
collectionIdConfirmation: ko.Observable<string>;
|
||||
collectionIdConfirmationText: ko.Observable<string>;
|
||||
containerDeleteFeedback: ko.Observable<string>;
|
||||
recordDeleteFeedback: ko.Observable<boolean>;
|
||||
}
|
||||
|
||||
export interface SettingsPane extends ContextualPane {
|
||||
pageOption: ko.Observable<string>;
|
||||
customItemPerPage: ko.Observable<number>;
|
||||
crossPartitionQueryEnabled: ko.Observable<boolean>;
|
||||
maxDegreeOfParallelism: ko.Observable<number>;
|
||||
shouldShowQueryPageOptions: ko.Computed<boolean>;
|
||||
|
||||
onCustomPageOptionsKeyDown(source: any, event: KeyboardEvent): boolean;
|
||||
onUnlimitedPageOptionKeyDown(source: any, event: KeyboardEvent): boolean;
|
||||
onJsonDisplayResultsKeyDown(source: any, event: KeyboardEvent): boolean;
|
||||
onGraphDisplayResultsKeyDown(source: any, event: KeyboardEvent): boolean;
|
||||
}
|
||||
|
||||
export interface ExecuteSprocParamsPane extends ContextualPane {
|
||||
params: ko.ObservableArray<ExecuteSprocParam>;
|
||||
partitionKeyValue: ko.Observable<string>;
|
||||
|
||||
addNewParam(): void;
|
||||
}
|
||||
|
||||
export interface RenewAdHocAccessPane extends ContextualPane {
|
||||
accessKey: ko.Observable<string>;
|
||||
}
|
||||
|
||||
export interface UploadItemsPane extends ContextualPane {
|
||||
selectedFilesTitle: ko.Observable<string>;
|
||||
files: ko.Observable<FileList>;
|
||||
|
||||
updateSelectedFiles(element: any, event: any): void;
|
||||
}
|
||||
|
||||
export interface LoadQueryPane extends ContextualPane {
|
||||
selectedFilesTitle: ko.Observable<string>;
|
||||
files: ko.Observable<FileList>;
|
||||
|
||||
loadQueryFromFile(file: File): Q.Promise<void>;
|
||||
}
|
||||
|
||||
export interface BrowseQueriesPane extends ContextualPane {
|
||||
loadSavedQuery: (savedQuery: DataModels.Query) => void;
|
||||
}
|
||||
|
||||
export interface UploadFilePaneOpenOptions {
|
||||
paneTitle: string;
|
||||
selectFileInputLabel: string;
|
||||
@@ -692,10 +313,6 @@ export interface StringInputPaneOpenOptions {
|
||||
defaultInput?: string;
|
||||
}
|
||||
|
||||
export interface UploadFilePane extends ContextualPane {
|
||||
openWithOptions: (options: UploadFilePaneOpenOptions) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Graph configuration
|
||||
*/
|
||||
@@ -740,41 +357,6 @@ export interface InputProperty {
|
||||
values: InputPropertyValue[];
|
||||
}
|
||||
|
||||
export interface GraphStylingPane extends ContextualPane {
|
||||
setData(graphConfigUIData: GraphConfigUiData): void;
|
||||
}
|
||||
|
||||
export interface NewVertexPane extends ContextualPane {
|
||||
setPartitionKeyProperty: (pKeyProp: string) => void;
|
||||
subscribeOnSubmitCreate: (callback: (newVertexData: NewVertexData) => void) => void;
|
||||
}
|
||||
|
||||
export interface AddTableEntityPane extends ContextualPane {
|
||||
tableViewModel: TableEntityListViewModel;
|
||||
}
|
||||
|
||||
export interface EditTableEntityPane extends ContextualPane {
|
||||
originEntity: Entities.ITableEntity;
|
||||
tableViewModel: TableEntityListViewModel;
|
||||
originalNumberOfProperties: number;
|
||||
}
|
||||
|
||||
export interface TableColumnOptionsPane extends ContextualPane {
|
||||
tableViewModel: TableEntityListViewModel;
|
||||
parameters: IColumnSetting;
|
||||
setDisplayedColumns(columnNames: string[], order: number[], visible: boolean[]): void;
|
||||
}
|
||||
|
||||
export interface QuerySelectPane extends ContextualPane {
|
||||
queryViewModel: QueryViewModel;
|
||||
}
|
||||
|
||||
export interface CassandraAddCollectionPane extends ContextualPane {
|
||||
createTableQuery: ko.Observable<string>;
|
||||
keyspaceId: ko.Observable<string>;
|
||||
userTableQuery: ko.Observable<string>;
|
||||
}
|
||||
|
||||
export interface Editable<T> extends ko.Observable<T> {
|
||||
setBaseline(baseline: T): void;
|
||||
|
||||
@@ -981,111 +563,6 @@ export interface DocumentsTab extends Tab {
|
||||
loadNextPage(): Q.Promise<any>;
|
||||
}
|
||||
|
||||
export interface ConflictsTab extends Tab {
|
||||
/* Conflicts Grid */
|
||||
selectedConflictId: ko.Observable<ConflictId>;
|
||||
selectedConflictContent: Editable<any>;
|
||||
selectedConflictCurrent: Editable<any>;
|
||||
onConflictIdClick(conflictId: ConflictId): Q.Promise<any>;
|
||||
dataContentsGridScrollHeight: ko.Observable<string>;
|
||||
accessibleDocumentList: AccessibleVerticalList;
|
||||
documentContentsGridId: string;
|
||||
|
||||
partitionKey: DataModels.PartitionKey;
|
||||
partitionKeyPropertyHeader: string;
|
||||
partitionKeyProperty: string;
|
||||
conflictIds: ko.ObservableArray<ConflictId>;
|
||||
|
||||
/* Document Editor */
|
||||
isEditorDirty: ko.Computed<boolean>;
|
||||
editorState: ko.Observable<DocumentExplorerState>;
|
||||
onValidDocumentEdit(content: any): Q.Promise<any>;
|
||||
onInvalidDocumentEdit(content: any): Q.Promise<any>;
|
||||
loadingConflictData: ko.Observable<boolean>;
|
||||
|
||||
onAcceptChangesClick(): Q.Promise<any>;
|
||||
onDiscardClick(): Q.Promise<any>;
|
||||
|
||||
initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Q.Promise<any>;
|
||||
initDocumentEditorForReplace(documentId: ConflictId, conflictContent: any, currentContent: any): Q.Promise<any>;
|
||||
initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Q.Promise<any>;
|
||||
initDocumentEditorForNoOp(conflictId: ConflictId): Q.Promise<any>;
|
||||
loadNextPage(): Q.Promise<any>;
|
||||
}
|
||||
|
||||
export interface SettingsTab extends Tab {
|
||||
/*state*/
|
||||
throughput: ko.Observable<number>;
|
||||
timeToLive: ko.Observable<string>;
|
||||
timeToLiveSeconds: ko.Observable<number>;
|
||||
geospatialVisible: ko.Computed<boolean>;
|
||||
geospatialConfigType: ko.Observable<string>;
|
||||
indexingPolicyContent: ko.Observable<DataModels.IndexingPolicy>;
|
||||
rupm: ko.Observable<string>;
|
||||
requestUnitsUsageCost: ko.Computed<string>;
|
||||
canThroughputExceedMaximumValue: ko.Computed<boolean>;
|
||||
shouldDisplayPortalUsePrompt: ko.Computed<boolean>;
|
||||
warningMessage: ko.Computed<string>;
|
||||
ttlOffFocused: ko.Observable<boolean>;
|
||||
ttlOnDefaultFocused: ko.Observable<boolean>;
|
||||
ttlOnFocused: ko.Observable<boolean>;
|
||||
indexingPolicyElementFocused: ko.Observable<boolean>;
|
||||
notificationStatusInfo: ko.Observable<string>;
|
||||
shouldShowNotificationStatusPrompt: ko.Computed<boolean>;
|
||||
shouldShowStatusBar: ko.Computed<boolean>;
|
||||
pendingNotification: ko.Observable<DataModels.Notification>;
|
||||
|
||||
conflictResolutionPolicyMode: ko.Observable<string>;
|
||||
conflictResolutionPolicyPath: ko.Observable<string>;
|
||||
conflictResolutionPolicyProcedure: ko.Observable<string>;
|
||||
|
||||
rupmVisible: ko.Computed<boolean>;
|
||||
costsVisible: ko.Computed<boolean>;
|
||||
minRUAnotationVisible: ko.Computed<boolean>;
|
||||
|
||||
/* Command Bar */
|
||||
saveSettingsButton: Button;
|
||||
discardSettingsChangesButton: Button;
|
||||
onSaveClick(): Q.Promise<any>;
|
||||
onRevertClick(): Q.Promise<any>;
|
||||
|
||||
/* Indexing Policy Editor */
|
||||
isIndexingPolicyEditorInitializing: ko.Observable<boolean>;
|
||||
indexingPolicyEditor: ko.Observable<monaco.editor.IStandaloneCodeEditor>;
|
||||
onValidIndexingPolicyEdit(content: any): Q.Promise<any>;
|
||||
onInvalidIndexingPolicyEdit(content: any): Q.Promise<any>;
|
||||
|
||||
onSaveClick(): Q.Promise<any>;
|
||||
onRevertClick(): Q.Promise<any>;
|
||||
}
|
||||
|
||||
export interface DatabaseSettingsTab extends Tab {
|
||||
/*state*/
|
||||
throughput: ko.Observable<number>;
|
||||
requestUnitsUsageCost: ko.PureComputed<string>;
|
||||
canThroughputExceedMaximumValue: ko.Computed<boolean>;
|
||||
warningMessage: ko.Computed<string>;
|
||||
notificationStatusInfo: ko.Observable<string>;
|
||||
shouldShowNotificationStatusPrompt: ko.Computed<boolean>;
|
||||
shouldShowStatusBar: ko.Computed<boolean>;
|
||||
pendingNotification: ko.Observable<DataModels.Notification>;
|
||||
|
||||
costsVisible: ko.Computed<boolean>;
|
||||
minRUAnotationVisible: ko.Computed<boolean>;
|
||||
|
||||
/* Command Bar */
|
||||
saveSettingsButton: Button;
|
||||
discardSettingsChangesButton: Button;
|
||||
onSaveClick(): Q.Promise<any>;
|
||||
onRevertClick(): Q.Promise<any>;
|
||||
|
||||
/* Errors */
|
||||
displayedError: ko.Observable<string>;
|
||||
|
||||
onSaveClick(): Q.Promise<any>;
|
||||
onRevertClick(): Q.Promise<any>;
|
||||
}
|
||||
|
||||
export interface WaitsForTemplate {
|
||||
isTemplateReady: ko.Observable<boolean>;
|
||||
}
|
||||
|
||||
@@ -123,12 +123,4 @@ describe("Component Registerer", () => {
|
||||
it("should register throughput-input component", () => {
|
||||
expect(ko.components.isRegistered("throughput-input")).toBe(true);
|
||||
});
|
||||
|
||||
it("should register library-manage-pane component", () => {
|
||||
expect(ko.components.isRegistered("library-manage-pane")).toBe(true);
|
||||
});
|
||||
|
||||
it("should register cluster-library-pane component", () => {
|
||||
expect(ko.components.isRegistered("cluster-library-pane")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,6 +78,4 @@ ko.components.register("browse-queries-pane", new PaneComponents.BrowseQueriesPa
|
||||
ko.components.register("upload-file-pane", new PaneComponents.UploadFilePaneComponent());
|
||||
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
||||
ko.components.register("setup-notebooks-pane", new PaneComponents.SetupNotebooksPaneComponent());
|
||||
ko.components.register("library-manage-pane", new PaneComponents.LibraryManagePaneComponent());
|
||||
ko.components.register("cluster-library-pane", new PaneComponents.ClusterLibraryPaneComponent());
|
||||
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
||||
|
||||
@@ -12,6 +12,10 @@ import AddTriggerIcon from "../../images/AddTrigger.svg";
|
||||
import DeleteTriggerIcon from "../../images/DeleteTrigger.svg";
|
||||
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
||||
import DeleteSprocIcon from "../../images/DeleteSproc.svg";
|
||||
import Explorer from "./Explorer";
|
||||
import UserDefinedFunction from "./Tree/UserDefinedFunction";
|
||||
import StoredProcedure from "./Tree/StoredProcedure";
|
||||
import Trigger from "./Tree/Trigger";
|
||||
|
||||
export interface CollectionContextMenuButtonParams {
|
||||
databaseId: string;
|
||||
@@ -26,7 +30,7 @@ export interface DatabaseContextMenuButtonParams {
|
||||
*/
|
||||
export class ResourceTreeContextMenuButtonFactory {
|
||||
public static createDatabaseContextMenu(
|
||||
container: ViewModels.Explorer,
|
||||
container: Explorer,
|
||||
selectedDatabase: ViewModels.Database
|
||||
): TreeNodeMenuItem[] {
|
||||
const newCollectionMenuItem: TreeNodeMenuItem = {
|
||||
@@ -44,7 +48,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
}
|
||||
|
||||
public static createCollectionContextMenuButton(
|
||||
container: ViewModels.Explorer,
|
||||
container: Explorer,
|
||||
selectedCollection: ViewModels.Collection
|
||||
): TreeNodeMenuItem[] {
|
||||
const items: TreeNodeMenuItem[] = [];
|
||||
@@ -115,8 +119,8 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
}
|
||||
|
||||
public static createStoreProcedureContextMenuItems(
|
||||
container: ViewModels.Explorer,
|
||||
storedProcedure: ViewModels.StoredProcedure
|
||||
container: Explorer,
|
||||
storedProcedure: StoredProcedure
|
||||
): TreeNodeMenuItem[] {
|
||||
if (container.isPreferredApiCassandra()) {
|
||||
return [];
|
||||
@@ -131,10 +135,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
];
|
||||
}
|
||||
|
||||
public static createTriggerContextMenuItems(
|
||||
container: ViewModels.Explorer,
|
||||
trigger: ViewModels.Trigger
|
||||
): TreeNodeMenuItem[] {
|
||||
public static createTriggerContextMenuItems(container: Explorer, trigger: Trigger): TreeNodeMenuItem[] {
|
||||
if (container.isPreferredApiCassandra()) {
|
||||
return [];
|
||||
}
|
||||
@@ -149,8 +150,8 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
}
|
||||
|
||||
public static createUserDefinedFunctionContextMenuItems(
|
||||
container: ViewModels.Explorer,
|
||||
userDefinedFunction: ViewModels.UserDefinedFunction
|
||||
container: Explorer,
|
||||
userDefinedFunction: UserDefinedFunction
|
||||
): TreeNodeMenuItem[] {
|
||||
if (container.isPreferredApiCassandra()) {
|
||||
return [];
|
||||
|
||||
@@ -23,8 +23,5 @@ interface ErrorDisplayParams {
|
||||
}
|
||||
|
||||
class ErrorDisplayViewModel {
|
||||
private params: ErrorDisplayParams;
|
||||
public constructor(params: ErrorDisplayParams) {
|
||||
this.params = params;
|
||||
}
|
||||
public constructor(public params: ErrorDisplayParams) {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import { RepoListItem } from "./GitHubReposComponent";
|
||||
@@ -9,9 +8,10 @@ import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
||||
import { IGitHubRepo } from "../../../GitHub/GitHubClient";
|
||||
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import UrlUtility from "../../../Common/UrlUtility";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export interface AddRepoComponentProps {
|
||||
container: ViewModels.Explorer;
|
||||
container: Explorer;
|
||||
getRepo: (owner: string, repo: string) => Promise<IGitHubRepo>;
|
||||
pinRepo: (item: RepoListItem) => void;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { DetailsList, IColumn, SelectionMode } from "office-ui-fabric-react/lib/DetailsList";
|
||||
import { Library } from "../../../Contracts/DataModels";
|
||||
|
||||
export interface ClusterLibraryItem extends Library {
|
||||
installed: boolean;
|
||||
}
|
||||
|
||||
export interface ClusterLibraryGridProps {
|
||||
libraryItems: ClusterLibraryItem[];
|
||||
onInstalledChanged: (libraryName: string, installed: boolean) => void;
|
||||
}
|
||||
|
||||
export function ClusterLibraryGrid(props: ClusterLibraryGridProps): JSX.Element {
|
||||
const onInstalledChanged = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const target = e.target;
|
||||
const libraryName = (target as any).dataset.name;
|
||||
const checked = (target as any).checked;
|
||||
return props.onInstalledChanged(libraryName, checked);
|
||||
};
|
||||
|
||||
const columns: IColumn[] = [
|
||||
{
|
||||
key: "name",
|
||||
name: "Name",
|
||||
fieldName: "name",
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
key: "installed",
|
||||
name: "Installed",
|
||||
minWidth: 100,
|
||||
onRender: (item: ClusterLibraryItem) => {
|
||||
return <input type="checkbox" checked={item.installed} onChange={onInstalledChanged} data-name={item.name} />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return <DetailsList columns={columns} items={props.libraryItems} selectionMode={SelectionMode.none} />;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import { ClusterLibraryGrid, ClusterLibraryGridProps } from "./ClusterLibraryGrid";
|
||||
|
||||
export class ClusterLibraryGridAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<ClusterLibraryGridProps>;
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
return <ClusterLibraryGrid {...this.parameters()} />;
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import * as React from "react";
|
||||
import DeleteIcon from "../../../../images/delete.svg";
|
||||
import { Button } from "office-ui-fabric-react/lib/Button";
|
||||
import { DetailsList, IColumn, SelectionMode } from "office-ui-fabric-react/lib/DetailsList";
|
||||
import { Library } from "../../../Contracts/DataModels";
|
||||
import { Label } from "office-ui-fabric-react/lib/Label";
|
||||
import { SparkLibrary } from "../../../Common/Constants";
|
||||
import { TextField } from "office-ui-fabric-react/lib/TextField";
|
||||
|
||||
export interface LibraryManageComponentProps {
|
||||
addProps: {
|
||||
nameProps: LibraryAddNameTextFieldProps;
|
||||
urlProps: LibraryAddUrlTextFieldProps;
|
||||
buttonProps: LibraryAddButtonProps;
|
||||
};
|
||||
gridProps: LibraryManageGridProps;
|
||||
}
|
||||
|
||||
export function LibraryManageComponent(props: LibraryManageComponentProps): JSX.Element {
|
||||
const {
|
||||
addProps: { nameProps, urlProps, buttonProps },
|
||||
gridProps
|
||||
} = props;
|
||||
return (
|
||||
<div>
|
||||
<div className="library-add-container">
|
||||
<LibraryAddNameTextField {...nameProps} />
|
||||
<LibraryAddUrlTextField {...urlProps} />
|
||||
<LibraryAddButton {...buttonProps} />
|
||||
</div>
|
||||
<div className="library-grid-container">
|
||||
<Label>All Libraries</Label>
|
||||
<LibraryManageGrid {...gridProps} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export interface LibraryManageGridProps {
|
||||
items: Library[];
|
||||
onLibraryDeleteClick: (libraryName: string) => void;
|
||||
}
|
||||
|
||||
function LibraryManageGrid(props: LibraryManageGridProps): JSX.Element {
|
||||
const columns: IColumn[] = [
|
||||
{
|
||||
key: "name",
|
||||
name: "Name",
|
||||
fieldName: "name",
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
name: "Delete",
|
||||
minWidth: 60,
|
||||
onRender: (item: Library) => {
|
||||
const onDelete = () => {
|
||||
props.onLibraryDeleteClick(item.name);
|
||||
};
|
||||
return (
|
||||
<span className="library-delete">
|
||||
<img src={DeleteIcon} alt="Delete" onClick={onDelete} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
return <DetailsList columns={columns} items={props.items} selectionMode={SelectionMode.none} />;
|
||||
}
|
||||
|
||||
export interface LibraryAddButtonProps {
|
||||
disabled: boolean;
|
||||
onLibraryAddClick: (event: React.FormEvent<any>) => void;
|
||||
}
|
||||
|
||||
function LibraryAddButton(props: LibraryAddButtonProps): JSX.Element {
|
||||
return (
|
||||
<Button text="Add" className="library-add-button" onClick={props.onLibraryAddClick} disabled={props.disabled} />
|
||||
);
|
||||
}
|
||||
|
||||
export interface LibraryAddUrlTextFieldProps {
|
||||
libraryAddress: string;
|
||||
onLibraryAddressChange: (libraryAddress: string) => void;
|
||||
onLibraryAddressValidated: (errorMessage: string, value: string) => void;
|
||||
}
|
||||
|
||||
function LibraryAddUrlTextField(props: LibraryAddUrlTextFieldProps): JSX.Element {
|
||||
const handleTextChange = (e: React.FormEvent<any>, libraryAddress: string) => {
|
||||
props.onLibraryAddressChange(libraryAddress);
|
||||
};
|
||||
const validateText = (text: string): string => {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
const libraryUrlRegex = /^(https:\/\/.+\/)(.+)\.(jar)$/gi;
|
||||
const isValidUrl = libraryUrlRegex.test(text);
|
||||
if (isValidUrl) {
|
||||
return "";
|
||||
}
|
||||
return "Need to be a valid https uri";
|
||||
};
|
||||
return (
|
||||
<TextField
|
||||
value={props.libraryAddress}
|
||||
label="Url"
|
||||
type="url"
|
||||
className="library-add-textfield"
|
||||
onChange={handleTextChange}
|
||||
onGetErrorMessage={validateText}
|
||||
onNotifyValidationResult={props.onLibraryAddressValidated}
|
||||
placeholder="https://myrepo/myjar.jar"
|
||||
autoComplete="off"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export interface LibraryAddNameTextFieldProps {
|
||||
libraryName: string;
|
||||
onLibraryNameChange: (libraryName: string) => void;
|
||||
onLibraryNameValidated: (errorMessage: string, value: string) => void;
|
||||
}
|
||||
|
||||
function LibraryAddNameTextField(props: LibraryAddNameTextFieldProps): JSX.Element {
|
||||
const handleTextChange = (e: React.FormEvent<any>, libraryName: string) => {
|
||||
props.onLibraryNameChange(libraryName);
|
||||
};
|
||||
const validateText = (text: string): string => {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
const length = text.length;
|
||||
if (length < SparkLibrary.nameMinLength || length > SparkLibrary.nameMaxLength) {
|
||||
return "Library name length need to be between 3 and 63.";
|
||||
}
|
||||
const nameRegex = /^[a-z0-9][-a-z0-9]*[a-z0-9]$/gi;
|
||||
const isValidUrl = nameRegex.test(text);
|
||||
if (isValidUrl) {
|
||||
return "";
|
||||
}
|
||||
return "Need to be a valid name. Letters, numbers and - are allowed";
|
||||
};
|
||||
return (
|
||||
<TextField
|
||||
value={props.libraryName}
|
||||
label="Name"
|
||||
type="text"
|
||||
className="library-add-textfield"
|
||||
onChange={handleTextChange}
|
||||
onGetErrorMessage={validateText}
|
||||
onNotifyValidationResult={props.onLibraryNameValidated}
|
||||
placeholder="myjar"
|
||||
autoComplete="off"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import { LibraryManageComponent, LibraryManageComponentProps } from "./LibraryManage";
|
||||
|
||||
export class LibraryManageComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<LibraryManageComponentProps>;
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
return <LibraryManageComponent {...this.parameters()} />;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { JunoClient, IGalleryItem } from "../../../Juno/JunoClient";
|
||||
import { GalleryTab, SortBy, GalleryViewerComponentProps, GalleryViewerComponent } from "./GalleryViewerComponent";
|
||||
import { NotebookViewerComponentProps, NotebookViewerComponent } from "../NotebookViewer/NotebookViewerComponent";
|
||||
import * as GalleryUtils from "../../../Utils/GalleryUtils";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export interface GalleryAndNotebookViewerComponentProps {
|
||||
container?: ViewModels.Explorer;
|
||||
container?: Explorer;
|
||||
junoClient: JunoClient;
|
||||
notebookUrl?: string;
|
||||
galleryItem?: IGalleryItem;
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
} from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import * as Logger from "../../../Common/Logger";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { IGalleryItem, JunoClient } from "../../../Juno/JunoClient";
|
||||
import * as GalleryUtils from "../../../Utils/GalleryUtils";
|
||||
import { NotificationConsoleUtils } from "../../../Utils/NotificationConsoleUtils";
|
||||
@@ -24,9 +23,10 @@ import { DialogComponent, DialogProps } from "../DialogReactComponent/DialogComp
|
||||
import { GalleryCardComponent, GalleryCardComponentProps } from "./Cards/GalleryCardComponent";
|
||||
import "./GalleryViewerComponent.less";
|
||||
import { HttpStatusCodes } from "../../../Common/Constants";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export interface GalleryViewerComponentProps {
|
||||
container?: ViewModels.Explorer;
|
||||
container?: Explorer;
|
||||
junoClient: JunoClient;
|
||||
selectedTab: GalleryTab;
|
||||
sortBy: SortBy;
|
||||
|
||||
@@ -18,9 +18,10 @@ import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookRe
|
||||
import { DialogComponent, DialogProps } from "../DialogReactComponent/DialogComponent";
|
||||
import { NotebookMetadataComponent } from "./NotebookMetadataComponent";
|
||||
import "./NotebookViewerComponent.less";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export interface NotebookViewerComponentProps {
|
||||
container?: ViewModels.Explorer;
|
||||
container?: Explorer;
|
||||
junoClient?: JunoClient;
|
||||
notebookUrl: string;
|
||||
galleryItem?: IGalleryItem;
|
||||
|
||||
@@ -217,7 +217,7 @@ export class QueriesGridComponent extends React.Component<QueriesGridComponentPr
|
||||
menuItem: any
|
||||
) => {
|
||||
if (window.confirm("Are you sure you want to delete this query?")) {
|
||||
const container: ViewModels.Explorer = window.dataExplorer;
|
||||
const container = window.dataExplorer;
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.DeleteSavedQuery, {
|
||||
databaseAccountName: container && container.databaseAccount().name,
|
||||
defaultExperience: container && container.defaultExperience(),
|
||||
|
||||
@@ -8,11 +8,12 @@ import * as React from "react";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { QueriesGridComponent, QueriesGridComponentProps } from "./QueriesGridComponent";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export class QueriesGridComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
|
||||
constructor(private container: ViewModels.Explorer) {
|
||||
constructor(private container: Explorer) {
|
||||
this.parameters = ko.observable<number>(Date.now());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Utilities for validation */
|
||||
|
||||
export const onValidateValueChange = (newValue: string, minValue?: number, maxValue?: number): number => {
|
||||
export const onValidateValueChange = (newValue: string, minValue?: number, maxValue?: number): number | undefined => {
|
||||
let numericValue = parseInt(newValue);
|
||||
if (!isNaN(numericValue) && isFinite(numericValue)) {
|
||||
if (minValue !== undefined && numericValue < minValue) {
|
||||
@@ -16,7 +16,7 @@ export const onValidateValueChange = (newValue: string, minValue?: number, maxVa
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const onIncrementValue = (newValue: string, step: number, max?: number): number => {
|
||||
export const onIncrementValue = (newValue: string, step: number, max?: number): number | undefined => {
|
||||
const numericValue = parseInt(newValue);
|
||||
if (!isNaN(numericValue) && isFinite(numericValue)) {
|
||||
const newValue = numericValue + step;
|
||||
@@ -25,7 +25,7 @@ export const onIncrementValue = (newValue: string, step: number, max?: number):
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const onDecrementValue = (newValue: string, step: number, min?: number): number => {
|
||||
export const onDecrementValue = (newValue: string, step: number, min?: number): number | undefined => {
|
||||
const numericValue = parseInt(newValue);
|
||||
if (!isNaN(numericValue) && isFinite(numericValue)) {
|
||||
const newValue = numericValue - step;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
@import "../../../../less/Common/Constants";
|
||||
|
||||
.labelWithRedAsterisk {
|
||||
line-height: 18px;
|
||||
font-size: @DefaultFontSize;
|
||||
font-family: @DataExplorerFont;
|
||||
color: @DefaultFontColor;
|
||||
}
|
||||
|
||||
.labelWithRedAsterisk::before {
|
||||
content: "* ";
|
||||
color: @SelectionHigh;
|
||||
}
|
||||
|
||||
.clusterSettingsDropdown {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { Dropdown, IDropdownOption, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { Slider, ISliderProps } from "office-ui-fabric-react/lib/Slider";
|
||||
import { Stack, IStackItemStyles, IStackStyles } from "office-ui-fabric-react/lib/Stack";
|
||||
import { TextField, ITextFieldProps } from "office-ui-fabric-react/lib/TextField";
|
||||
import { Spark } from "../../../Common/Constants";
|
||||
import { SparkCluster } from "../../../Contracts/DataModels";
|
||||
|
||||
export interface ClusterSettingsComponentProps {
|
||||
cluster: SparkCluster;
|
||||
onClusterSettingsChanged: (cluster: SparkCluster) => void;
|
||||
}
|
||||
|
||||
export class ClusterSettingsComponent extends React.Component<ClusterSettingsComponentProps, {}> {
|
||||
constructor(props: ClusterSettingsComponentProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{this.getMasterSizeDropdown()}
|
||||
{this.getWorkerSizeDropdown()}
|
||||
{this.getWorkerCountSliderInput()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private getMasterSizeDropdown(): JSX.Element {
|
||||
const driverSize: string =
|
||||
this.props.cluster && this.props.cluster.properties && this.props.cluster.properties.driverSize;
|
||||
const masterSizeOptions: IDropdownOption[] = Spark.SKUs.keys().map(sku => ({
|
||||
key: sku,
|
||||
text: Spark.SKUs.get(sku)
|
||||
}));
|
||||
const masterSizeDropdownProps: IDropdownProps = {
|
||||
label: "Master Size",
|
||||
options: masterSizeOptions,
|
||||
defaultSelectedKey: driverSize,
|
||||
onChange: this._onDriverSizeChange,
|
||||
styles: {
|
||||
root: "clusterSettingsDropdown"
|
||||
}
|
||||
};
|
||||
return <Dropdown {...masterSizeDropdownProps} />;
|
||||
}
|
||||
|
||||
private getWorkerSizeDropdown(): JSX.Element {
|
||||
const workerSize: string =
|
||||
this.props.cluster && this.props.cluster.properties && this.props.cluster.properties.workerSize;
|
||||
const workerSizeOptions: IDropdownOption[] = Spark.SKUs.keys().map(sku => ({
|
||||
key: sku,
|
||||
text: Spark.SKUs.get(sku)
|
||||
}));
|
||||
const workerSizeDropdownProps: IDropdownProps = {
|
||||
label: "Worker Size",
|
||||
options: workerSizeOptions,
|
||||
defaultSelectedKey: workerSize,
|
||||
onChange: this._onWorkerSizeChange,
|
||||
styles: {
|
||||
label: "labelWithRedAsterisk",
|
||||
root: "clusterSettingsDropdown"
|
||||
}
|
||||
};
|
||||
return <Dropdown {...workerSizeDropdownProps} />;
|
||||
}
|
||||
|
||||
private getWorkerCountSliderInput(): JSX.Element {
|
||||
const workerCount: number =
|
||||
(this.props.cluster &&
|
||||
this.props.cluster.properties &&
|
||||
this.props.cluster.properties.workerInstanceCount !== undefined &&
|
||||
this.props.cluster.properties.workerInstanceCount) ||
|
||||
0;
|
||||
const stackStyle: IStackStyles = {
|
||||
root: {
|
||||
paddingTop: 5
|
||||
}
|
||||
};
|
||||
const sliderItemStyle: IStackItemStyles = {
|
||||
root: {
|
||||
width: "100%",
|
||||
paddingRight: 20
|
||||
}
|
||||
};
|
||||
|
||||
const workerCountSliderProps: ISliderProps = {
|
||||
min: 0,
|
||||
max: Spark.MaxWorkerCount,
|
||||
step: 1,
|
||||
value: workerCount,
|
||||
showValue: false,
|
||||
onChange: this._onWorkerCountChange,
|
||||
styles: {
|
||||
root: {
|
||||
width: "100%",
|
||||
paddingRight: 20
|
||||
}
|
||||
}
|
||||
};
|
||||
const workerCountTextFieldProps: ITextFieldProps = {
|
||||
value: workerCount.toString(),
|
||||
styles: {
|
||||
fieldGroup: {
|
||||
width: 45,
|
||||
height: 25
|
||||
},
|
||||
field: {
|
||||
textAlign: "center"
|
||||
}
|
||||
},
|
||||
onChange: this._onWorkerCountTextFieldChange
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack styles={stackStyle}>
|
||||
<span className="labelWithRedAsterisk">Worker Nodes</span>
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<Slider {...workerCountSliderProps} />
|
||||
<TextField {...workerCountTextFieldProps} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
private _onDriverSizeChange = (_event: React.FormEvent, selectedOption: IDropdownOption) => {
|
||||
const newValue: string = selectedOption.key as string;
|
||||
const cluster = this.props.cluster;
|
||||
if (cluster) {
|
||||
cluster.properties.driverSize = newValue;
|
||||
this.props.onClusterSettingsChanged(cluster);
|
||||
}
|
||||
};
|
||||
|
||||
private _onWorkerSizeChange = (_event: React.FormEvent, selectedOption: IDropdownOption) => {
|
||||
const newValue: string = selectedOption.key as string;
|
||||
const cluster = this.props.cluster;
|
||||
if (cluster) {
|
||||
cluster.properties.workerSize = newValue;
|
||||
this.props.onClusterSettingsChanged(cluster);
|
||||
}
|
||||
};
|
||||
|
||||
private _onWorkerCountChange = (count: number) => {
|
||||
count = Math.min(count, Spark.MaxWorkerCount);
|
||||
const cluster = this.props.cluster;
|
||||
if (cluster) {
|
||||
cluster.properties.workerInstanceCount = count;
|
||||
this.props.onClusterSettingsChanged(cluster);
|
||||
}
|
||||
};
|
||||
|
||||
private _onWorkerCountTextFieldChange = (_event: React.FormEvent, newValue: string) => {
|
||||
const count = parseInt(newValue);
|
||||
if (!isNaN(count)) {
|
||||
this._onWorkerCountChange(count);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { ClusterSettingsComponent, ClusterSettingsComponentProps } from "./ClusterSettingsComponent";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
|
||||
export class ClusterSettingsComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<ClusterSettingsComponentProps>;
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
return <ClusterSettingsComponent {...this.parameters()} />;
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,14 @@ import * as sinon from "sinon";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Q from "q";
|
||||
import { CollectionStub, DatabaseStub, ExplorerStub } from "../OpenActionsStubs";
|
||||
import { ContainerSampleGenerator } from "./ContainerSampleGenerator";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { GremlinClient } from "../Graph/GraphExplorerComponent/GremlinClient";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
describe("ContainerSampleGenerator", () => {
|
||||
const createExplorerStub = (database: ViewModels.Database): ExplorerStub => {
|
||||
const explorerStub = new ExplorerStub();
|
||||
const createExplorerStub = (database: ViewModels.Database): Explorer => {
|
||||
const explorerStub = {} as Explorer;
|
||||
explorerStub.nonSystemDatabases = ko.computed(() => [database]);
|
||||
explorerStub.isPreferredApiGraph = ko.computed<boolean>(() => false);
|
||||
explorerStub.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
@@ -53,11 +53,11 @@ describe("ContainerSampleGenerator", () => {
|
||||
}
|
||||
]
|
||||
};
|
||||
const collection = new CollectionStub({ id: ko.observable(sampleCollectionId) });
|
||||
const database = new DatabaseStub({
|
||||
const collection = { id: ko.observable(sampleCollectionId) } as ViewModels.Collection;
|
||||
const database = {
|
||||
id: ko.observable(sampleDatabaseId),
|
||||
collections: ko.observableArray([collection])
|
||||
});
|
||||
collections: ko.observableArray<ViewModels.Collection>([collection])
|
||||
} as ViewModels.Database;
|
||||
database.findCollectionWithId = () => collection;
|
||||
|
||||
const explorerStub = createExplorerStub(database);
|
||||
@@ -98,11 +98,11 @@ describe("ContainerSampleGenerator", () => {
|
||||
"g.addV('person').property(id, '1').property('_partitionKey','pk').property('name', 'Eva').property('age', 44)"
|
||||
]
|
||||
};
|
||||
const collection = new CollectionStub({ id: ko.observable(sampleCollectionId) });
|
||||
const database = new DatabaseStub({
|
||||
const collection = { id: ko.observable(sampleCollectionId) } as ViewModels.Collection;
|
||||
const database = {
|
||||
id: ko.observable(sampleDatabaseId),
|
||||
collections: ko.observableArray([collection])
|
||||
});
|
||||
collections: ko.observableArray<ViewModels.Collection>([collection])
|
||||
} as ViewModels.Database;
|
||||
database.findCollectionWithId = () => collection;
|
||||
collection.databaseId = database.id();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsol
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { GremlinClient } from "../Graph/GraphExplorerComponent/GremlinClient";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
interface SampleDataFile extends DataModels.CreateDatabaseAndCollectionRequest {
|
||||
data: any[];
|
||||
@@ -14,12 +15,12 @@ interface SampleDataFile extends DataModels.CreateDatabaseAndCollectionRequest {
|
||||
export class ContainerSampleGenerator {
|
||||
private sampleDataFile: SampleDataFile;
|
||||
|
||||
private constructor(private container: ViewModels.Explorer) {}
|
||||
private constructor(private container: Explorer) {}
|
||||
|
||||
/**
|
||||
* Factory function to load the json data file
|
||||
*/
|
||||
public static async createSampleGeneratorAsync(container: ViewModels.Explorer): Promise<ContainerSampleGenerator> {
|
||||
public static async createSampleGeneratorAsync(container: Explorer): Promise<ContainerSampleGenerator> {
|
||||
const generator = new ContainerSampleGenerator(container);
|
||||
let dataFileContent: any;
|
||||
if (container.isPreferredApiGraph()) {
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { ExplorerStub, DatabaseStub, CollectionStub } from "../OpenActionsStubs";
|
||||
import { DataSamplesUtil } from "./DataSamplesUtil";
|
||||
import * as sinon from "sinon";
|
||||
import { ContainerSampleGenerator } from "./ContainerSampleGenerator";
|
||||
import * as ko from "knockout";
|
||||
import Explorer from "../Explorer";
|
||||
import { Database, Collection } from "../../Contracts/ViewModels";
|
||||
|
||||
describe("DataSampleUtils", () => {
|
||||
const sampleCollectionId = "sampleCollectionId";
|
||||
const sampleDatabaseId = "sampleDatabaseId";
|
||||
|
||||
it("should not create sample collection if collection already exists", async () => {
|
||||
const collection = new CollectionStub({ id: ko.observable(sampleCollectionId) });
|
||||
const database = new DatabaseStub({
|
||||
const collection = { id: ko.observable(sampleCollectionId) } as Collection;
|
||||
const database = {
|
||||
id: ko.observable(sampleDatabaseId),
|
||||
collections: ko.observableArray([collection])
|
||||
});
|
||||
const explorer = new ExplorerStub();
|
||||
collections: ko.observableArray<Collection>([collection])
|
||||
} as Database;
|
||||
const explorer = {} as Explorer;
|
||||
explorer.nonSystemDatabases = ko.computed(() => [database]);
|
||||
explorer.showOkModalDialog = () => {};
|
||||
const dataSamplesUtil = new DataSamplesUtil(explorer);
|
||||
|
||||
@@ -2,10 +2,11 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ContainerSampleGenerator } from "./ContainerSampleGenerator";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export class DataSamplesUtil {
|
||||
private static readonly DialogTitle = "Create Sample Container";
|
||||
constructor(private container: ViewModels.Explorer) {}
|
||||
constructor(private container: Explorer) {}
|
||||
|
||||
/**
|
||||
* Check if Database/Container is already there: if so, show modal to delete
|
||||
|
||||
@@ -24,7 +24,6 @@ import NewVertexPane from "./Panes/NewVertexPane";
|
||||
import NotebookV2Tab from "./Tabs/NotebookV2Tab";
|
||||
import Q from "q";
|
||||
import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
|
||||
import SparkMasterTab from "./Tabs/SparkMasterTab";
|
||||
import TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||
import TerminalTab from "./Tabs/TerminalTab";
|
||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||
@@ -36,7 +35,6 @@ import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer
|
||||
import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane";
|
||||
import { CassandraApi } from "../Api/Apis";
|
||||
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
||||
import { ClusterLibraryPane } from "./Panes/ClusterLibraryPane";
|
||||
import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import { config } from "../Config";
|
||||
import { ConsoleData, ConsoleDataType } from "./Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
@@ -52,7 +50,6 @@ import { FileSystemUtil } from "./Notebook/FileSystemUtil";
|
||||
import { handleOpenAction } from "./OpenActions";
|
||||
import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
|
||||
import { IGalleryItem } from "../Juno/JunoClient";
|
||||
import { LibraryManagePane } from "./Panes/LibraryManagePane";
|
||||
import { LoadQueryPane } from "./Panes/LoadQueryPane";
|
||||
import * as Logger from "../Common/Logger";
|
||||
import { MessageHandler } from "../Common/MessageHandler";
|
||||
@@ -72,7 +69,6 @@ import { RouteHandler } from "../RouteHandlers/RouteHandler";
|
||||
import { SaveQueryPane } from "./Panes/SaveQueryPane";
|
||||
import { SettingsPane } from "./Panes/SettingsPane";
|
||||
import { SetupNotebooksPane } from "./Panes/SetupNotebooksPane";
|
||||
import { SparkClusterManager } from "../SparkClusterManager/SparkClusterManager";
|
||||
import { SplashScreenComponentAdapter } from "./SplashScreen/SplashScreenComponentApdapter";
|
||||
import { Splitter, SplitterBounds, SplitterDirection } from "../Common/Splitter";
|
||||
import { StringInputPane } from "./Panes/StringInputPane";
|
||||
@@ -83,6 +79,9 @@ import { UploadItemsPane } from "./Panes/UploadItemsPane";
|
||||
import { UploadItemsPaneAdapter } from "./Panes/UploadItemsPaneAdapter";
|
||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
||||
import { toRawContentUri, fromContentUri } from "../Utils/GitHubUtils";
|
||||
import UserDefinedFunction from "./Tree/UserDefinedFunction";
|
||||
import StoredProcedure from "./Tree/StoredProcedure";
|
||||
import Trigger from "./Tree/Trigger";
|
||||
|
||||
BindingHandlersRegisterer.registerBindingHandlers();
|
||||
// Hold a reference to ComponentRegisterer to prevent transpiler to ignore import
|
||||
@@ -93,7 +92,7 @@ enum ShareAccessToggleState {
|
||||
Read
|
||||
}
|
||||
|
||||
export default class Explorer implements ViewModels.Explorer {
|
||||
export default class Explorer {
|
||||
public flight: ko.Observable<string> = ko.observable<string>(
|
||||
SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight
|
||||
);
|
||||
@@ -168,30 +167,28 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
public tabsManager: TabsManager;
|
||||
|
||||
// Contextual panes
|
||||
public addDatabasePane: ViewModels.AddDatabasePane;
|
||||
public addCollectionPane: ViewModels.AddCollectionPane;
|
||||
public deleteCollectionConfirmationPane: ViewModels.DeleteCollectionConfirmationPane;
|
||||
public deleteDatabaseConfirmationPane: ViewModels.DeleteDatabaseConfirmationPane;
|
||||
public graphStylingPane: ViewModels.GraphStylingPane;
|
||||
public addTableEntityPane: ViewModels.AddTableEntityPane;
|
||||
public editTableEntityPane: ViewModels.EditTableEntityPane;
|
||||
public addDatabasePane: AddDatabasePane;
|
||||
public addCollectionPane: AddCollectionPane;
|
||||
public deleteCollectionConfirmationPane: DeleteCollectionConfirmationPane;
|
||||
public deleteDatabaseConfirmationPane: DeleteDatabaseConfirmationPane;
|
||||
public graphStylingPane: GraphStylingPane;
|
||||
public addTableEntityPane: AddTableEntityPane;
|
||||
public editTableEntityPane: EditTableEntityPane;
|
||||
public tableColumnOptionsPane: TableColumnOptionsPane;
|
||||
public querySelectPane: QuerySelectPane;
|
||||
public newVertexPane: ViewModels.NewVertexPane;
|
||||
public cassandraAddCollectionPane: ViewModels.CassandraAddCollectionPane;
|
||||
public settingsPane: ViewModels.SettingsPane;
|
||||
public executeSprocParamsPane: ViewModels.ExecuteSprocParamsPane;
|
||||
public renewAdHocAccessPane: ViewModels.RenewAdHocAccessPane;
|
||||
public uploadItemsPane: ViewModels.UploadItemsPane;
|
||||
public newVertexPane: NewVertexPane;
|
||||
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||
public settingsPane: SettingsPane;
|
||||
public executeSprocParamsPane: ExecuteSprocParamsPane;
|
||||
public renewAdHocAccessPane: RenewAdHocAccessPane;
|
||||
public uploadItemsPane: UploadItemsPane;
|
||||
public uploadItemsPaneAdapter: UploadItemsPaneAdapter;
|
||||
public loadQueryPane: ViewModels.LoadQueryPane;
|
||||
public loadQueryPane: LoadQueryPane;
|
||||
public saveQueryPane: ViewModels.ContextualPane;
|
||||
public browseQueriesPane: ViewModels.BrowseQueriesPane;
|
||||
public browseQueriesPane: BrowseQueriesPane;
|
||||
public uploadFilePane: UploadFilePane;
|
||||
public stringInputPane: StringInputPane;
|
||||
public setupNotebooksPane: SetupNotebooksPane;
|
||||
public libraryManagePane: ViewModels.ContextualPane;
|
||||
public clusterLibraryPane: ViewModels.ContextualPane;
|
||||
public gitHubReposPane: ViewModels.ContextualPane;
|
||||
public publishNotebookPaneAdapter: ReactAdapter;
|
||||
|
||||
@@ -206,7 +203,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
|
||||
public shouldShowShareDialogContents: ko.Observable<boolean>;
|
||||
public shareAccessData: ko.Observable<ViewModels.AdHocAccessData>;
|
||||
public renewExplorerShareAccess: (explorer: ViewModels.Explorer, token: string) => Q.Promise<void>;
|
||||
public renewExplorerShareAccess: (explorer: Explorer, token: string) => Q.Promise<void>;
|
||||
public renewTokenError: ko.Observable<string>;
|
||||
public tokenForRenewal: ko.Observable<string>;
|
||||
public shareAccessToggleState: ko.Observable<ShareAccessToggleState>;
|
||||
@@ -220,8 +217,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
public isNotebookEnabled: ko.Observable<boolean>;
|
||||
public isNotebooksEnabledForAccount: ko.Observable<boolean>;
|
||||
public notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>;
|
||||
public notebookWorkspaceManager: ViewModels.NotebookWorkspaceManager;
|
||||
public sparkClusterManager: ViewModels.SparkClusterManager;
|
||||
public notebookWorkspaceManager: NotebookWorkspaceManager;
|
||||
public sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
|
||||
public isSparkEnabled: ko.Observable<boolean>;
|
||||
public isSparkEnabledForAccount: ko.Observable<boolean>;
|
||||
@@ -238,7 +234,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
private _isInitializingNotebooks: boolean;
|
||||
private _isInitializingSparkConnectionInfo: boolean;
|
||||
private notebookBasePath: ko.Observable<string>;
|
||||
private _arcadiaManager: ViewModels.ArcadiaResourceManager;
|
||||
private _arcadiaManager: ArcadiaResourceManager;
|
||||
private notebookToImport: {
|
||||
name: string;
|
||||
content: string;
|
||||
@@ -313,7 +309,6 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
this.isAuthWithResourceToken() ? this.refreshDatabaseForResourceToken() : this.refreshAllDatabases(true);
|
||||
RouteHandler.getInstance().initHandler();
|
||||
this.notebookWorkspaceManager = new NotebookWorkspaceManager(this.armEndpoint());
|
||||
this.sparkClusterManager = new SparkClusterManager(this.armEndpoint());
|
||||
this.arcadiaWorkspaces = ko.observableArray();
|
||||
this._arcadiaManager = new ArcadiaResourceManager(this.armEndpoint());
|
||||
this._isAfecFeatureRegistered(Constants.AfecFeatures.StorageAnalytics).then(isRegistered =>
|
||||
@@ -750,22 +745,6 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
container: this
|
||||
});
|
||||
|
||||
this.libraryManagePane = new LibraryManagePane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "libraryManagePane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
container: this
|
||||
});
|
||||
|
||||
this.clusterLibraryPane = new ClusterLibraryPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "clusterLibraryPane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
container: this
|
||||
});
|
||||
|
||||
this.tabsManager = new TabsManager();
|
||||
|
||||
this._panes = [
|
||||
@@ -1607,70 +1586,6 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
window.open(Constants.Urls.feedbackEmail, "_self");
|
||||
};
|
||||
|
||||
public async initSparkConnectionInfo(databaseAccount: DataModels.DatabaseAccount) {
|
||||
if (!databaseAccount) {
|
||||
throw new Error("No database account specified");
|
||||
}
|
||||
|
||||
if (this._isInitializingSparkConnectionInfo) {
|
||||
return;
|
||||
}
|
||||
this._isInitializingSparkConnectionInfo = true;
|
||||
|
||||
let connectionInfo: DataModels.SparkClusterConnectionInfo;
|
||||
try {
|
||||
connectionInfo = await this.sparkClusterManager.getClusterConnectionInfoAsync(databaseAccount.id, "default");
|
||||
} catch (error) {
|
||||
this._isInitializingSparkConnectionInfo = false;
|
||||
Logger.logError(error, "initSparkConnectionInfo/getClusterConnectionInfoAsync");
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to get cluster connection info: ${JSON.stringify(error)}`
|
||||
);
|
||||
throw error;
|
||||
} finally {
|
||||
// Overwrite with feature flags
|
||||
if (this.isFeatureEnabled(Constants.Features.livyEndpoint)) {
|
||||
connectionInfo = {
|
||||
userName: undefined,
|
||||
password: undefined,
|
||||
endpoints: [
|
||||
{
|
||||
kind: DataModels.SparkClusterEndpointKind.Livy,
|
||||
endpoint: this.features()[Constants.Features.livyEndpoint]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.sparkClusterConnectionInfo(connectionInfo);
|
||||
this.sparkClusterConnectionInfo.valueHasMutated();
|
||||
this._isInitializingSparkConnectionInfo = false;
|
||||
}
|
||||
|
||||
public deleteCluster() {
|
||||
if (!this.isSparkEnabled() || !this.sparkClusterManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteClusterDialogProps: DialogProps = {
|
||||
isModal: true,
|
||||
visible: true,
|
||||
title: "Delete Cluster",
|
||||
subText:
|
||||
"This will delete the default cluster associated with this account and interrupt any scheduled jobs. Proceed anyway?",
|
||||
primaryButtonText: "OK",
|
||||
secondaryButtonText: "Cancel",
|
||||
onPrimaryButtonClick: async () => {
|
||||
this._closeModalDialog();
|
||||
await this._deleteCluster();
|
||||
},
|
||||
onSecondaryButtonClick: this._closeModalDialog
|
||||
};
|
||||
this._dialogProps(deleteClusterDialogProps);
|
||||
}
|
||||
|
||||
public async getArcadiaToken(): Promise<string> {
|
||||
return new Promise<string>((resolve: (token: string) => void, reject: (error: any) => void) => {
|
||||
MessageHandler.sendCachedDataMessage<string>(MessageTypes.GetArcadiaToken, undefined /** params **/).then(
|
||||
@@ -1821,53 +1736,6 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
}
|
||||
}
|
||||
|
||||
private _deleteCluster = async () => {
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.DeleteSparkCluster, {
|
||||
databaseAccountName: this.databaseAccount() && this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
});
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
"Deleting the default spark cluster associated with this account"
|
||||
);
|
||||
try {
|
||||
await this.sparkClusterManager.deleteClusterAsync(this.databaseAccount().id, "default");
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
"Successfully deleted the default spark cluster associated with this account"
|
||||
);
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.DeleteSparkCluster,
|
||||
{
|
||||
databaseAccountName: this.databaseAccount() && this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
},
|
||||
startKey
|
||||
);
|
||||
} catch (error) {
|
||||
const errorMessage = JSON.stringify(error);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to delete default spark cluster: ${errorMessage}`
|
||||
);
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.DeleteSparkCluster,
|
||||
{
|
||||
databaseAccountName: this.databaseAccount() && this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||
error,
|
||||
errorMessage
|
||||
},
|
||||
startKey
|
||||
);
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
}
|
||||
};
|
||||
|
||||
private _resetNotebookWorkspace = async () => {
|
||||
this._closeModalDialog();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, "Resetting notebook workspace");
|
||||
@@ -2090,9 +1958,9 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
}
|
||||
|
||||
// TODO: Refactor below methods, minimize dependencies and add unit tests where necessary
|
||||
public findSelectedStoredProcedure(): ViewModels.StoredProcedure {
|
||||
public findSelectedStoredProcedure(): StoredProcedure {
|
||||
const selectedCollection: ViewModels.Collection = this.findSelectedCollection();
|
||||
return _.find(selectedCollection.storedProcedures(), (storedProcedure: ViewModels.StoredProcedure) => {
|
||||
return _.find(selectedCollection.storedProcedures(), (storedProcedure: StoredProcedure) => {
|
||||
const openedSprocTab = this.tabsManager.getTabs(
|
||||
ViewModels.CollectionTabKind.StoredProcedures,
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === storedProcedure.rid
|
||||
@@ -2104,9 +1972,9 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
});
|
||||
}
|
||||
|
||||
public findSelectedUDF(): ViewModels.UserDefinedFunction {
|
||||
public findSelectedUDF(): UserDefinedFunction {
|
||||
const selectedCollection: ViewModels.Collection = this.findSelectedCollection();
|
||||
return _.find(selectedCollection.userDefinedFunctions(), (userDefinedFunction: ViewModels.UserDefinedFunction) => {
|
||||
return _.find(selectedCollection.userDefinedFunctions(), (userDefinedFunction: UserDefinedFunction) => {
|
||||
const openedUdfTab = this.tabsManager.getTabs(
|
||||
ViewModels.CollectionTabKind.UserDefinedFunctions,
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === userDefinedFunction.rid
|
||||
@@ -2118,9 +1986,9 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
});
|
||||
}
|
||||
|
||||
public findSelectedTrigger(): ViewModels.Trigger {
|
||||
public findSelectedTrigger(): Trigger {
|
||||
const selectedCollection: ViewModels.Collection = this.findSelectedCollection();
|
||||
return _.find(selectedCollection.triggers(), (trigger: ViewModels.Trigger) => {
|
||||
return _.find(selectedCollection.triggers(), (trigger: Trigger) => {
|
||||
const openedTriggerTab = this.tabsManager.getTabs(
|
||||
ViewModels.CollectionTabKind.Triggers,
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === trigger.rid
|
||||
@@ -2835,42 +2703,6 @@ export default class Explorer implements ViewModels.Explorer {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public async openSparkMasterTab() {
|
||||
if (!this.sparkClusterConnectionInfo()) {
|
||||
await this.initSparkConnectionInfo(this.databaseAccount());
|
||||
}
|
||||
|
||||
const sparkMasterTabs: SparkMasterTab[] = this.tabsManager.getTabs(
|
||||
ViewModels.CollectionTabKind.SparkMasterTab
|
||||
) as SparkMasterTab[];
|
||||
let sparkMasterTab: SparkMasterTab = sparkMasterTabs && sparkMasterTabs[0];
|
||||
|
||||
if (sparkMasterTab) {
|
||||
this.tabsManager.activateTab(sparkMasterTab);
|
||||
} else {
|
||||
sparkMasterTab = new SparkMasterTab({
|
||||
clusterConnectionInfo: this.sparkClusterConnectionInfo(),
|
||||
tabKind: ViewModels.CollectionTabKind.SparkMasterTab,
|
||||
node: null,
|
||||
title: "Apache Spark",
|
||||
tabPath: "",
|
||||
documentClientUtility: null,
|
||||
|
||||
collection: null,
|
||||
selfLink: null,
|
||||
hashLocation: "sparkmaster",
|
||||
isActive: ko.observable(false),
|
||||
isTabsContentExpanded: ko.observable(true),
|
||||
onLoadStartKey: null,
|
||||
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
||||
container: this
|
||||
});
|
||||
|
||||
this.tabsManager.activateNewTab(sparkMasterTab);
|
||||
}
|
||||
}
|
||||
|
||||
private refreshNotebookList = async (): Promise<void> => {
|
||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||
return;
|
||||
|
||||
@@ -11,14 +11,15 @@ import { CommandBarComponentButtonFactory } from "./CommandBarComponentButtonFac
|
||||
import { CommandBar, ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { CommandBarUtil } from "./CommandBarUtil";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export class CommandBarComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
public container: ViewModels.Explorer;
|
||||
public container: Explorer;
|
||||
private tabsButtons: ViewModels.NavbarButtonConfig[];
|
||||
private isNotebookTabActive: ko.Computed<boolean>;
|
||||
|
||||
constructor(container: ViewModels.Explorer) {
|
||||
constructor(container: Explorer) {
|
||||
this.container = container;
|
||||
this.tabsButtons = [];
|
||||
this.isNotebookTabActive = ko.computed(() =>
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { CommandBarComponentButtonFactory } from "./CommandBarComponentButtonFactory";
|
||||
import { ExplorerStub } from "../../OpenActionsStubs";
|
||||
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
||||
import NotebookManager from "../../Notebook/NotebookManager";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
describe("CommandBarComponentButtonFactory tests", () => {
|
||||
let mockExplorer: ViewModels.Explorer;
|
||||
let mockExplorer: Explorer;
|
||||
|
||||
describe("Enable notebook button", () => {
|
||||
const enableNotebookBtnLabel = "Enable Notebooks (Preview)";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer = {} as Explorer;
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||
mockExplorer.isGalleryPublishEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
@@ -75,12 +76,13 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||
const openMongoShellBtnLabel = "Open Mongo Shell";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer = {} as Explorer;
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||
mockExplorer.isGalleryPublishEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
@@ -155,11 +157,12 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||
const openCassandraShellBtnLabel = "Open Cassandra Shell";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer = {} as Explorer;
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isGalleryPublishEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
@@ -236,13 +239,14 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer = {} as Explorer;
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
@@ -294,7 +298,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||
|
||||
describe("Resource token", () => {
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer = {} as Explorer;
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(true);
|
||||
mockExplorer.isPreferredApiDocumentDB = ko.computed(() => true);
|
||||
|
||||
@@ -25,11 +25,12 @@ import ResetWorkspaceIcon from "../../../../images/notebook/Notebook-reset-works
|
||||
import GitHubIcon from "../../../../images/github.svg";
|
||||
import SynapseIcon from "../../../../images/synapse-link.svg";
|
||||
import { config, Platform } from "../../../Config";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export class CommandBarComponentButtonFactory {
|
||||
private static counter: number = 0;
|
||||
|
||||
public static createStaticCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
public static createStaticCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
if (container.isAuthWithResourceToken()) {
|
||||
return CommandBarComponentButtonFactory.createStaticCommandBarButtonsForResourceToken(container);
|
||||
}
|
||||
@@ -132,7 +133,7 @@ export class CommandBarComponentButtonFactory {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static createContextCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
public static createContextCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
|
||||
if (!container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()) {
|
||||
@@ -155,7 +156,7 @@ export class CommandBarComponentButtonFactory {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static createControlCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
public static createControlCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
if (window.dataExplorerPlatform === PlatformType.Hosted) {
|
||||
return buttons;
|
||||
@@ -223,11 +224,11 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static areScriptsSupported(container: ViewModels.Explorer): boolean {
|
||||
private static areScriptsSupported(container: Explorer): boolean {
|
||||
return container.isPreferredApiDocumentDB() || container.isPreferredApiGraph();
|
||||
}
|
||||
|
||||
private static createNewCollectionGroup(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createNewCollectionGroup(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = container.addCollectionText();
|
||||
return {
|
||||
iconSrc: AddCollectionIcon,
|
||||
@@ -240,7 +241,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenSynapseLinkDialogButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenSynapseLinkDialogButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (config.platform === Platform.Emulator) {
|
||||
return null;
|
||||
}
|
||||
@@ -275,7 +276,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewDatabase(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createNewDatabase(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = container.addDatabaseText();
|
||||
return {
|
||||
iconSrc: AddDatabaseIcon,
|
||||
@@ -290,7 +291,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewSQLQueryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createNewSQLQueryButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) {
|
||||
const label = "New SQL Query";
|
||||
return {
|
||||
@@ -324,7 +325,7 @@ export class CommandBarComponentButtonFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static createScriptCommandButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
public static createScriptCommandButtons(container: Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
|
||||
const shouldEnableScriptsCommands: boolean =
|
||||
@@ -384,7 +385,7 @@ export class CommandBarComponentButtonFactory {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private static createScaleAndSettingsButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createScaleAndSettingsButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
let isShared = false;
|
||||
if (container.isDatabaseNodeSelected()) {
|
||||
isShared = container.findSelectedDatabase().isDatabaseShared();
|
||||
@@ -409,7 +410,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewNotebookButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createNewNotebookButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "New Notebook";
|
||||
return {
|
||||
iconSrc: NewNotebookIcon,
|
||||
@@ -422,7 +423,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createuploadNotebookButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createuploadNotebookButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Upload to Notebook Server";
|
||||
return {
|
||||
iconSrc: NewNotebookIcon,
|
||||
@@ -435,7 +436,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenQueryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenQueryButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Query";
|
||||
return {
|
||||
iconSrc: BrowseQueriesIcon,
|
||||
@@ -448,7 +449,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenQueryFromDiskButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenQueryFromDiskButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Query From Disk";
|
||||
return {
|
||||
iconSrc: OpenQueryFromDiskIcon,
|
||||
@@ -461,7 +462,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createEnableNotebooksButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createEnableNotebooksButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (config.platform === Platform.Emulator) {
|
||||
return null;
|
||||
}
|
||||
@@ -482,7 +483,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Terminal";
|
||||
return {
|
||||
iconSrc: CosmosTerminalIcon,
|
||||
@@ -495,7 +496,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenMongoTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenMongoTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Mongo Shell";
|
||||
const tooltip =
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
|
||||
@@ -521,7 +522,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenCassandraTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createOpenCassandraTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Cassandra Shell";
|
||||
const tooltip =
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
|
||||
@@ -547,7 +548,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createNotebookWorkspaceResetButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createNotebookWorkspaceResetButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Reset Workspace";
|
||||
return {
|
||||
iconSrc: ResetWorkspaceIcon,
|
||||
@@ -560,7 +561,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createManageGitHubAccountButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
private static createManageGitHubAccountButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
let connectedToGitHub: boolean = container.notebookManager?.gitHubOAuthService.isLoggedIn();
|
||||
const label = connectedToGitHub ? "Manage GitHub settings" : "Connect to GitHub";
|
||||
return {
|
||||
@@ -583,9 +584,7 @@ export class CommandBarComponentButtonFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private static createStaticCommandBarButtonsForResourceToken(
|
||||
container: ViewModels.Explorer
|
||||
): ViewModels.NavbarButtonConfig[] {
|
||||
private static createStaticCommandBarButtonsForResourceToken(container: Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const newSqlQueryBtn = CommandBarComponentButtonFactory.createNewSQLQueryButton(container);
|
||||
const openQueryBtn = CommandBarComponentButtonFactory.createOpenQueryButton(container);
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { NotificationConsoleComponent } from "./NotificationConsoleComponent";
|
||||
import { ConsoleData } from "./NotificationConsoleComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export class NotificationConsoleComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
public container: ViewModels.Explorer;
|
||||
public container: Explorer;
|
||||
private consoleData: ko.ObservableArray<ConsoleData>;
|
||||
|
||||
constructor(container: ViewModels.Explorer) {
|
||||
constructor(container: Explorer) {
|
||||
this.container = container;
|
||||
|
||||
this.consoleData = container.notificationConsoleData;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { StorageKey, LocalStorageUtility } from "../../Shared/StorageUtility";
|
||||
|
||||
import CollectionIcon from "../../../images/tree-collection.svg";
|
||||
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export enum Type {
|
||||
OpenCollection,
|
||||
@@ -36,7 +37,7 @@ export class MostRecentActivity {
|
||||
private static readonly schemaVersion: string = "1";
|
||||
private static itemsMaxNumber: number = 5;
|
||||
private storedData: StoredData;
|
||||
constructor(private container: ViewModels.Explorer) {
|
||||
constructor(private container: Explorer) {
|
||||
// Retrieve from local storage
|
||||
if (LocalStorageUtility.hasItem(StorageKey.MostRecentActivity)) {
|
||||
const rawData = LocalStorageUtility.getEntryString(StorageKey.MostRecentActivity);
|
||||
|
||||
@@ -131,7 +131,7 @@ export class NotebookContainerClient implements ViewModels.INotebookContainerCli
|
||||
}
|
||||
|
||||
private async recreateNotebookWorkspaceAsync(): Promise<void> {
|
||||
const explorer = window.dataExplorer as ViewModels.Explorer;
|
||||
const explorer = window.dataExplorer;
|
||||
if (!explorer || !explorer.databaseAccount() || !explorer.databaseAccount().id) {
|
||||
throw new Error("DataExplorer not initialized");
|
||||
}
|
||||
|
||||
@@ -23,9 +23,10 @@ import { DialogProps } from "../Controls/DialogReactComponent/DialogComponent";
|
||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
||||
import { PublishNotebookPaneAdapter } from "../Panes/PublishNotebookPaneAdapter";
|
||||
import { getFullName } from "../../Utils/UserUtils";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export interface NotebookManagerOptions {
|
||||
container: ViewModels.Explorer;
|
||||
container: Explorer;
|
||||
notebookBasePath: ko.Observable<string>;
|
||||
dialogProps: ko.Observable<DialogProps>;
|
||||
resourceTree: ResourceTreeAdapter;
|
||||
|
||||
@@ -1,55 +1,43 @@
|
||||
import * as ko from "knockout";
|
||||
import { handleOpenAction } from "./OpenActions";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import {
|
||||
ExplorerStub,
|
||||
DatabaseStub,
|
||||
CollectionStub,
|
||||
AddCollectionPaneStub,
|
||||
CassandraAddCollectionPane
|
||||
} from "./OpenActionsStubs";
|
||||
import { ActionContracts } from "../Contracts/ExplorerContracts";
|
||||
import Explorer from "./Explorer";
|
||||
import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
||||
import AddCollectionPane from "./Panes/AddCollectionPane";
|
||||
|
||||
describe("OpenActions", () => {
|
||||
describe("handleOpenAction", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
let database: ViewModels.Database;
|
||||
let collection: ViewModels.Collection;
|
||||
let databases: ViewModels.Database[];
|
||||
|
||||
let expandCollection: jasmine.Spy;
|
||||
let onDocumentDBDocumentsClick: jasmine.Spy;
|
||||
let onMongoDBDocumentsClick: jasmine.Spy;
|
||||
let onTableEntitiesClick: jasmine.Spy;
|
||||
let onGraphDocumentsClick: jasmine.Spy;
|
||||
let onNewQueryClick: jasmine.Spy;
|
||||
let onSettingsClick: jasmine.Spy;
|
||||
let openAddCollectionPane: jasmine.Spy;
|
||||
let openCassandraAddCollectionPane: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new ExplorerStub();
|
||||
explorer.addCollectionPane = new AddCollectionPaneStub();
|
||||
explorer.cassandraAddCollectionPane = new CassandraAddCollectionPane();
|
||||
explorer = {} as Explorer;
|
||||
explorer.addCollectionPane = {} as AddCollectionPane;
|
||||
explorer.addCollectionPane.open = jest.fn();
|
||||
explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane;
|
||||
explorer.cassandraAddCollectionPane.open = jest.fn();
|
||||
explorer.closeAllPanes = () => {};
|
||||
explorer.isConnectExplorerVisible = () => false;
|
||||
|
||||
database = new DatabaseStub({
|
||||
database = {
|
||||
id: ko.observable("db"),
|
||||
collections: ko.observableArray<ViewModels.Collection>([])
|
||||
});
|
||||
} as ViewModels.Database;
|
||||
databases = [database];
|
||||
collection = new CollectionStub({
|
||||
collection = {
|
||||
id: ko.observable("coll")
|
||||
});
|
||||
} as ViewModels.Collection;
|
||||
|
||||
expandCollection = spyOn(collection, "expandCollection");
|
||||
onDocumentDBDocumentsClick = spyOn(collection, "onDocumentDBDocumentsClick");
|
||||
onMongoDBDocumentsClick = spyOn(collection, "onMongoDBDocumentsClick");
|
||||
onTableEntitiesClick = spyOn(collection, "onTableEntitiesClick");
|
||||
onGraphDocumentsClick = spyOn(collection, "onGraphDocumentsClick");
|
||||
onNewQueryClick = spyOn(collection, "onNewQueryClick");
|
||||
onSettingsClick = spyOn(collection, "onSettingsClick");
|
||||
openAddCollectionPane = spyOn(explorer.addCollectionPane, "open");
|
||||
openCassandraAddCollectionPane = spyOn(explorer.cassandraAddCollectionPane, "open");
|
||||
collection.expandCollection = jest.fn();
|
||||
collection.onDocumentDBDocumentsClick = jest.fn();
|
||||
collection.onMongoDBDocumentsClick = jest.fn();
|
||||
collection.onTableEntitiesClick = jest.fn();
|
||||
collection.onGraphDocumentsClick = jest.fn();
|
||||
collection.onNewQueryClick = jest.fn();
|
||||
collection.onSettingsClick = jest.fn();
|
||||
});
|
||||
|
||||
describe("unknown action type", () => {
|
||||
@@ -87,7 +75,7 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
const actionHandled = handleOpenAction(action, [], explorer);
|
||||
expect(openCassandraAddCollectionPane).toHaveBeenCalled();
|
||||
expect(explorer.cassandraAddCollectionPane.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call cassandraAddCollectionPane.open", () => {
|
||||
@@ -97,7 +85,7 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
const actionHandled = handleOpenAction(action, [], explorer);
|
||||
expect(openCassandraAddCollectionPane).toHaveBeenCalled();
|
||||
expect(explorer.cassandraAddCollectionPane.open).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -109,7 +97,7 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
const actionHandled = handleOpenAction(action, [], explorer);
|
||||
expect(openAddCollectionPane).toHaveBeenCalled();
|
||||
expect(explorer.addCollectionPane.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call addCollectionPane.open", () => {
|
||||
@@ -119,7 +107,7 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
const actionHandled = handleOpenAction(action, [], explorer);
|
||||
expect(openAddCollectionPane).toHaveBeenCalled();
|
||||
expect(explorer.addCollectionPane.open).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -149,10 +137,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(expandCollection).not.toHaveBeenCalled();
|
||||
expect(collection.expandCollection).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(expandCollection).toHaveBeenCalled();
|
||||
expect(collection.expandCollection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should expand collection node when handleOpenAction is called", () => {
|
||||
@@ -164,7 +152,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(expandCollection).toHaveBeenCalled();
|
||||
expect(collection.expandCollection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("SQLDocuments tab kind", () => {
|
||||
@@ -177,10 +165,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onDocumentDBDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onDocumentDBDocumentsClick", () => {
|
||||
@@ -193,7 +181,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onDocumentDBDocumentsClick before collections are fetched", () => {
|
||||
@@ -205,10 +193,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onDocumentDBDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onDocumentDBDocumentsClick", () => {
|
||||
@@ -221,7 +209,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onDocumentDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -235,10 +223,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onMongoDBDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onMongoDBDocumentsClick", () => {
|
||||
@@ -251,7 +239,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onMongoDBDocumentsClick before collections are fetched", () => {
|
||||
@@ -263,10 +251,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onMongoDBDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onMongoDBDocumentsClick", () => {
|
||||
@@ -279,7 +267,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onMongoDBDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -293,10 +281,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onTableEntitiesClick).not.toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onTableEntitiesClick).toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onTableEntitiesClick", () => {
|
||||
@@ -309,7 +297,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onTableEntitiesClick).toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onTableEntitiesClick before collections are fetched", () => {
|
||||
@@ -322,7 +310,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onTableEntitiesClick).toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onTableEntitiesClick", () => {
|
||||
@@ -334,10 +322,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onTableEntitiesClick).not.toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onTableEntitiesClick).toHaveBeenCalled();
|
||||
expect(collection.onTableEntitiesClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -351,10 +339,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onGraphDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onGraphDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onGraphDocumentsClick", () => {
|
||||
@@ -367,7 +355,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onGraphDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onGraphDocumentsClick before collections are fetched", () => {
|
||||
@@ -379,10 +367,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onGraphDocumentsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onGraphDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onGraphDocumentsClick", () => {
|
||||
@@ -395,7 +383,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onGraphDocumentsClick).toHaveBeenCalled();
|
||||
expect(collection.onGraphDocumentsClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -409,10 +397,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onNewQueryClick).not.toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onNewQueryClick).toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onNewQueryClick", () => {
|
||||
@@ -425,7 +413,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onNewQueryClick).toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onNewQueryClick before collections are fetched", () => {
|
||||
@@ -437,10 +425,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onNewQueryClick).not.toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onNewQueryClick).toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onNewQueryClick", () => {
|
||||
@@ -453,7 +441,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onNewQueryClick).toHaveBeenCalled();
|
||||
expect(collection.onNewQueryClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -467,10 +455,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onSettingsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onSettingsClick).toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("string value should call onSettingsClick", () => {
|
||||
@@ -483,7 +471,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onSettingsClick).toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onSettingsClick before collections are fetched", () => {
|
||||
@@ -495,10 +483,10 @@ describe("OpenActions", () => {
|
||||
};
|
||||
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onSettingsClick).not.toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).not.toHaveBeenCalled();
|
||||
|
||||
database.collections([collection]);
|
||||
expect(onSettingsClick).toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enum value should call onSettingsClick", () => {
|
||||
@@ -511,7 +499,7 @@ describe("OpenActions", () => {
|
||||
|
||||
database.collections([collection]);
|
||||
handleOpenAction(action, [database], explorer);
|
||||
expect(onSettingsClick).toHaveBeenCalled();
|
||||
expect(collection.onSettingsClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { ActionContracts } from "../Contracts/ExplorerContracts";
|
||||
import Explorer from "./Explorer";
|
||||
|
||||
export function handleOpenAction(
|
||||
action: ActionContracts.DataExplorerAction,
|
||||
databases: ViewModels.Database[],
|
||||
explorer: ViewModels.Explorer
|
||||
explorer: Explorer
|
||||
): boolean {
|
||||
if (
|
||||
action.actionType === ActionContracts.ActionType.OpenCollectionTab ||
|
||||
@@ -126,7 +127,7 @@ function openCollectionTab(
|
||||
}
|
||||
}
|
||||
|
||||
function openPane(action: ActionContracts.OpenPane, explorer: ViewModels.Explorer) {
|
||||
function openPane(action: ActionContracts.OpenPane, explorer: Explorer) {
|
||||
if (
|
||||
action.paneKind === ActionContracts.PaneKind.AddCollection ||
|
||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
||||
@@ -154,7 +155,7 @@ function openPane(action: ActionContracts.OpenPane, explorer: ViewModels.Explore
|
||||
}
|
||||
}
|
||||
|
||||
function openFile(action: ActionContracts.OpenSampleNotebook, explorer: ViewModels.Explorer) {
|
||||
function openFile(action: ActionContracts.OpenSampleNotebook, explorer: Explorer) {
|
||||
explorer.handleOpenFileAction(decodeURIComponent(action.path));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,850 +0,0 @@
|
||||
import * as DataModels from "../../src/Contracts/DataModels";
|
||||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../../src/Contracts/ViewModels";
|
||||
import DocumentClientUtilityBase from "../Common/DocumentClientUtilityBase";
|
||||
import Q from "q";
|
||||
import { ArcadiaWorkspaceItem } from "./Controls/Arcadia/ArcadiaMenuPicker";
|
||||
import { CassandraTableKey, CassandraTableKeys, TableDataClient } from "../../src/Explorer/Tables/TableDataClient";
|
||||
import { ConsoleData } from "../../src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { MostRecentActivity } from "./MostRecentActivity/MostRecentActivity";
|
||||
import { NotebookContentItem } from "./Notebook/NotebookContentItem";
|
||||
import { PlatformType } from "../../src/PlatformType";
|
||||
import { QuerySelectPane } from "../../src/Explorer/Panes/Tables/QuerySelectPane";
|
||||
import { SetupNotebooksPane } from "./Panes/SetupNotebooksPane";
|
||||
import { Splitter } from "../../src/Common/Splitter";
|
||||
import { StringInputPane } from "./Panes/StringInputPane";
|
||||
import { TableColumnOptionsPane } from "../../src/Explorer/Panes/Tables/TableColumnOptionsPane";
|
||||
import { TextFieldProps } from "./Controls/DialogReactComponent/DialogComponent";
|
||||
import { UploadDetails } from "../workers/upload/definitions";
|
||||
import { UploadFilePane } from "./Panes/UploadFilePane";
|
||||
import { UploadItemsPaneAdapter } from "./Panes/UploadItemsPaneAdapter";
|
||||
import { Versions } from "../../src/Contracts/ExplorerContracts";
|
||||
import { CollectionCreationDefaults } from "../Shared/Constants";
|
||||
import { IGalleryItem } from "../Juno/JunoClient";
|
||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
||||
import { TabsManager } from "./Tabs/TabsManager";
|
||||
|
||||
export class ExplorerStub implements ViewModels.Explorer {
|
||||
public flight: ko.Observable<string>;
|
||||
public addCollectionText: ko.Observable<string>;
|
||||
public hasAutoPilotV2FeatureFlag: ko.Computed<boolean>;
|
||||
public addDatabaseText: ko.Observable<string>;
|
||||
public collectionTitle: ko.Observable<string>;
|
||||
public deleteCollectionText: ko.Observable<string>;
|
||||
public deleteDatabaseText: ko.Observable<string>;
|
||||
public collectionTreeNodeAltText: ko.Observable<string>;
|
||||
public refreshTreeTitle: ko.Observable<string>;
|
||||
public collapsedResourceTreeWidth: number;
|
||||
public collectionCreationDefaults: ViewModels.CollectionCreationDefaults = CollectionCreationDefaults;
|
||||
public hasWriteAccess: ko.Observable<boolean> = ko.observable<boolean>(false);
|
||||
public databaseAccount: ko.Observable<ViewModels.DatabaseAccount>;
|
||||
public subscriptionType: ko.Observable<ViewModels.SubscriptionType>;
|
||||
public quotaId: ko.Observable<string>;
|
||||
public defaultExperience: ko.Observable<string>;
|
||||
public isPreferredApiDocumentDB: ko.Computed<boolean>;
|
||||
public isPreferredApiCassandra: ko.Computed<boolean>;
|
||||
public isPreferredApiMongoDB: ko.Computed<boolean>;
|
||||
public isPreferredApiGraph: ko.Computed<boolean>;
|
||||
public isPreferredApiTable: ko.Computed<boolean>;
|
||||
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
||||
public isEmulator: boolean;
|
||||
public isAccountReady: ko.Observable<boolean>;
|
||||
public canSaveQueries: ko.Computed<boolean>;
|
||||
public features: ko.Observable<any>;
|
||||
public serverId: ko.Observable<string>;
|
||||
public extensionEndpoint: ko.Observable<string> = ko.observable<string>(undefined);
|
||||
public armEndpoint: ko.Observable<string>;
|
||||
public isTryCosmosDBSubscription: ko.Observable<boolean>;
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
public notificationsClient: ViewModels.NotificationsClient;
|
||||
public queriesClient: ViewModels.QueriesClient;
|
||||
public tableDataClient: TableDataClient;
|
||||
public splitter: Splitter;
|
||||
public notificationConsoleData: ko.ObservableArray<ConsoleData>;
|
||||
public isNotificationConsoleExpanded: ko.Observable<boolean>;
|
||||
public contextPanes: ViewModels.ContextualPane[];
|
||||
public databases: ko.ObservableArray<ViewModels.Database>;
|
||||
public nonSystemDatabases: ko.Computed<ViewModels.Database[]>;
|
||||
public selectedDatabaseId: ko.Computed<string>;
|
||||
public selectedCollectionId: ko.Computed<string>;
|
||||
public isLeftPaneExpanded: ko.Observable<boolean>;
|
||||
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
||||
public isRefreshingExplorer: ko.Observable<boolean>;
|
||||
public isTabsContentExpanded: ko.Observable<boolean>;
|
||||
public addCollectionPane: ViewModels.AddCollectionPane;
|
||||
public addDatabasePane: ViewModels.AddDatabasePane;
|
||||
public deleteCollectionConfirmationPane: ViewModels.DeleteCollectionConfirmationPane;
|
||||
public deleteDatabaseConfirmationPane: ViewModels.DeleteDatabaseConfirmationPane;
|
||||
public graphStylingPane: ViewModels.GraphStylingPane;
|
||||
public addTableEntityPane: ViewModels.AddTableEntityPane;
|
||||
public editTableEntityPane: ViewModels.EditTableEntityPane;
|
||||
public tableColumnOptionsPane: TableColumnOptionsPane;
|
||||
public querySelectPane: QuerySelectPane;
|
||||
public newVertexPane: ViewModels.NewVertexPane;
|
||||
public cassandraAddCollectionPane: ViewModels.CassandraAddCollectionPane;
|
||||
public renewAdHocAccessPane: ViewModels.RenewAdHocAccessPane;
|
||||
public renewExplorerShareAccess: (explorer: ViewModels.Explorer, token: string) => Q.Promise<void>;
|
||||
public settingsPane: ViewModels.SettingsPane;
|
||||
public executeSprocParamsPane: ViewModels.ExecuteSprocParamsPane;
|
||||
public uploadItemsPane: ViewModels.UploadItemsPane;
|
||||
public uploadItemsPaneAdapter: UploadItemsPaneAdapter;
|
||||
public loadQueryPane: ViewModels.LoadQueryPane;
|
||||
public saveQueryPane: ViewModels.ContextualPane;
|
||||
public browseQueriesPane: ViewModels.BrowseQueriesPane;
|
||||
public uploadFilePane: UploadFilePane;
|
||||
public stringInputPane: StringInputPane;
|
||||
public setupNotebooksPane: SetupNotebooksPane;
|
||||
public isGalleryPublishEnabled: ko.Computed<boolean>;
|
||||
public isGitHubPaneEnabled: ko.Observable<boolean>;
|
||||
public isPublishNotebookPaneEnabled: ko.Observable<boolean>;
|
||||
public isRightPanelV2Enabled: ko.Computed<boolean>;
|
||||
public canExceedMaximumValue: ko.Computed<boolean>;
|
||||
public isHostedDataExplorerEnabled: ko.Computed<boolean>;
|
||||
public parentFrameDataExplorerVersion: ko.Observable<string> = ko.observable<string>(Versions.DataExplorer);
|
||||
public mostRecentActivity: MostRecentActivity;
|
||||
public isNotebookEnabled: ko.Observable<boolean>;
|
||||
public isSparkEnabled: ko.Observable<boolean>;
|
||||
public isNotebooksEnabledForAccount: ko.Observable<boolean>;
|
||||
public isSparkEnabledForAccount: ko.Observable<boolean>;
|
||||
public arcadiaToken: ko.Observable<string>;
|
||||
public notebookWorkspaceManager: ViewModels.NotebookWorkspaceManager;
|
||||
public sparkClusterManager: ViewModels.SparkClusterManager;
|
||||
public notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>;
|
||||
public sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
|
||||
public libraryManagePane: ViewModels.ContextualPane;
|
||||
public clusterLibraryPane: ViewModels.ContextualPane;
|
||||
public gitHubReposPane: ViewModels.ContextualPane;
|
||||
public publishNotebookPaneAdapter: ReactAdapter;
|
||||
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||
public notebookManager?: any;
|
||||
public openGallery: (notebookUrl?: string, galleryItem?: IGalleryItem, isFavorite?: boolean) => void;
|
||||
public openNotebookViewer: (notebookUrl: string) => void;
|
||||
public resourceTokenDatabaseId: ko.Observable<string>;
|
||||
public resourceTokenCollectionId: ko.Observable<string>;
|
||||
public resourceTokenCollection: ko.Observable<ViewModels.CollectionBase>;
|
||||
public resourceTokenPartitionKey: ko.Observable<string>;
|
||||
public isAuthWithResourceToken: ko.Observable<boolean>;
|
||||
public isResourceTokenCollectionNodeSelected: ko.Computed<boolean>;
|
||||
public tabsManager: TabsManager;
|
||||
|
||||
private _featureEnabledReturnValue: boolean;
|
||||
|
||||
constructor(options?: any) {
|
||||
options = options || {};
|
||||
this._featureEnabledReturnValue = options.featureEnabledReturnValue || false;
|
||||
this.isSynapseLinkUpdating = ko.observable<boolean>(options.isSynapseLinkUpdating || false);
|
||||
}
|
||||
|
||||
public openEnableSynapseLinkDialog() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createWorkspace(): Promise<string> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createSparkPool(workspaceId: string): Promise<string> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isDatabaseNodeOrNoneSelected(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isDatabaseNodeSelected(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isNodeKindSelected(nodeKind: string): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isNoneSelected(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isFeatureEnabled(feature: string): boolean {
|
||||
return this._featureEnabledReturnValue;
|
||||
}
|
||||
|
||||
public isSelectedDatabaseShared(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public logConsoleData(consoleData: ConsoleData): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public deleteInProgressConsoleDataWithId(id: string): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public toggleLeftPaneExpanded() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public refreshAllDatabases(): Q.Promise<any> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public refreshDatabaseForResourceToken(): Q.Promise<void> {
|
||||
throw new Error("Note impplemented");
|
||||
}
|
||||
|
||||
public onRefreshDatabasesKeyPress = (source: any, event: KeyboardEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public onRefreshResourcesClick = (source: any, event: MouseEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public toggleLeftPaneExpandedKeyPress = (source: any, event: KeyboardEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
// Facade
|
||||
public provideFeedbackEmail = () => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public handleMessage(event: MessageEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findSelectedDatabase(): ViewModels.Database {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findDatabaseWithId(databaseId: string): ViewModels.Database {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isLastDatabase(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isLastNonEmptyDatabase(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public initDataExplorerWithFrameInputs(inputs: ViewModels.DataExplorerInputsFrame): Q.Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findSelectedCollection(): ViewModels.Collection {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findCollection(rid: string): ViewModels.Collection {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isLastCollection(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findSelectedStoredProcedure(): ViewModels.StoredProcedure {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findSelectedUDF(): ViewModels.UserDefinedFunction {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findSelectedTrigger(): ViewModels.Trigger {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public generateSharedAccessData(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public displayConnectExplorerForm(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public displayContextSwitchPromptForConnectionString(connectionString: string): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public hideConnectExplorerForm(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public displayGuestAccessTokenRenewalPrompt(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandConsole(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseConsole(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public rebindDocumentClientUtility(documentClientUtility: any) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public renewShareAccess(token: string): Q.Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public getPlatformType(): PlatformType {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isRunningOnNationalCloud(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isConnectExplorerVisible(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public closeAllPanes(): void {
|
||||
// return for now so tests dont break
|
||||
// TODO: implement once we start testing pane close
|
||||
return;
|
||||
}
|
||||
|
||||
public onUpdateTabsButtons(buttons: ViewModels.NavbarButtonConfig[]): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public importAndOpen(path: string): Promise<boolean> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public importAndOpenContent(name: string, content: string): Promise<boolean> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public publishNotebook(name: string, content: string): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public async openNotebook(notebookContentItem: NotebookContentItem): Promise<boolean> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public deleteNotebookFile(item: NotebookContentItem): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onCreateDirectory(parent: NotebookContentItem): Q.Promise<NotebookContentItem> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewNotebookClicked(parent?: NotebookContentItem): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public openNotebookTerminal(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public resetNotebookWorkspace(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewCollectionClicked(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onUploadToNotebookServerClicked(parent?: NotebookContentItem): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public renameNotebook(notebookFile: NotebookContentItem): Q.Promise<NotebookContentItem> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public readFile(notebookFile: NotebookContentItem): Promise<string> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public downloadFile(notebookFile: NotebookContentItem): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public initNotebooks(databaseAccount: DataModels.DatabaseAccount): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public showOkModalDialog(title: string, msg: string): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public showOkCancelModalDialog(
|
||||
title: string,
|
||||
msg: string,
|
||||
okLabel: string,
|
||||
onOk: () => void,
|
||||
cancelLabel: string,
|
||||
onCancel: () => void
|
||||
): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public showOkCancelTextFieldModalDialog(
|
||||
title: string,
|
||||
msg: string,
|
||||
okLabel: string,
|
||||
onOk: () => void,
|
||||
cancelLabel: string,
|
||||
onCancel: () => void,
|
||||
textFieldProps: TextFieldProps,
|
||||
isPrimaryButtonDisabled?: boolean
|
||||
): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public deleteCluster(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public async openSparkMasterTab(): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createNotebookContentItemFile(name: string, filepath: string): NotebookContentItem {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public refreshContentItem(item: NotebookContentItem): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public getNotebookBasePath(): string {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public handleOpenFileAction(): Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
export class DatabaseStub implements ViewModels.Database {
|
||||
public nodeKind: string;
|
||||
public container: ViewModels.Explorer;
|
||||
public self: string;
|
||||
public rid: string;
|
||||
public id: ko.Observable<string>;
|
||||
public collections: ko.ObservableArray<ViewModels.Collection>;
|
||||
public isDatabaseExpanded: ko.Observable<boolean>;
|
||||
public isDatabaseShared: ko.Computed<boolean>;
|
||||
public selectedSubnodeKind: ko.Observable<ViewModels.CollectionTabKind>;
|
||||
public offer: ko.Observable<DataModels.Offer>;
|
||||
|
||||
constructor(options?: any) {
|
||||
this.nodeKind = options.nodeKind;
|
||||
this.container = options.container;
|
||||
this.self = options.self;
|
||||
this.rid = options.rid;
|
||||
this.id = options.id;
|
||||
this.collections = options.collections;
|
||||
this.isDatabaseExpanded = options.isDatabaseExpanded;
|
||||
this.offer = options.offer;
|
||||
this.selectedSubnodeKind = options.selectedSubnodeKind;
|
||||
}
|
||||
|
||||
public onKeyPress = (source: any, event: KeyboardEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public onKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public onMenuKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public onDeleteDatabaseContextMenuClick(source: ViewModels.Database, event: MouseEvent | KeyboardEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public selectDatabase() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandCollapseDatabase() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandDatabase() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseDatabase() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public loadCollections(): Q.Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findCollectionWithId(collectionId: string): ViewModels.Collection {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public openAddCollection(database: ViewModels.Database, event: MouseEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public readSettings() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onSettingsClick(): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
export class CollectionStub implements ViewModels.Collection {
|
||||
public nodeKind: string;
|
||||
public container: ViewModels.Explorer;
|
||||
public rawDataModel: DataModels.Collection;
|
||||
public self: string;
|
||||
public rid: string;
|
||||
public databaseId: string;
|
||||
public partitionKey: DataModels.PartitionKey;
|
||||
public partitionKeyPropertyHeader: string;
|
||||
public partitionKeyProperty: string;
|
||||
public id: ko.Observable<string>;
|
||||
public defaultTtl: ko.Observable<number>;
|
||||
public analyticalStorageTtl: ko.Observable<number>;
|
||||
public indexingPolicy: ko.Observable<DataModels.IndexingPolicy>;
|
||||
public uniqueKeyPolicy: DataModels.UniqueKeyPolicy;
|
||||
public quotaInfo: ko.Observable<DataModels.CollectionQuotaInfo>;
|
||||
public offer: ko.Observable<DataModels.Offer>;
|
||||
public partitions: ko.Computed<number>;
|
||||
public throughput: ko.Computed<number>;
|
||||
public cassandraKeys: CassandraTableKeys;
|
||||
public cassandraSchema: CassandraTableKey[];
|
||||
public documentIds: ko.ObservableArray<ViewModels.DocumentId>;
|
||||
public children: ko.ObservableArray<ViewModels.TreeNode>;
|
||||
public storedProcedures: ko.Computed<ViewModels.StoredProcedure[]>;
|
||||
public userDefinedFunctions: ko.Computed<ViewModels.UserDefinedFunction[]>;
|
||||
public triggers: ko.Computed<ViewModels.Trigger[]>;
|
||||
public showStoredProcedures: ko.Observable<boolean>;
|
||||
public showTriggers: ko.Observable<boolean>;
|
||||
public showUserDefinedFunctions: ko.Observable<boolean>;
|
||||
public selectedDocumentContent: ViewModels.Editable<any>;
|
||||
public selectedSubnodeKind: ko.Observable<ViewModels.CollectionTabKind>;
|
||||
public focusedSubnodeKind: ko.Observable<ViewModels.CollectionTabKind>;
|
||||
public isCollectionExpanded: ko.Observable<boolean>;
|
||||
public isStoredProceduresExpanded: ko.Observable<boolean>;
|
||||
public isUserDefinedFunctionsExpanded: ko.Observable<boolean>;
|
||||
public isTriggersExpanded: ko.Observable<boolean>;
|
||||
public documentsFocused: ko.Observable<boolean>;
|
||||
public settingsFocused: ko.Observable<boolean>;
|
||||
public storedProceduresFocused: ko.Observable<boolean>;
|
||||
public userDefinedFunctionsFocused: ko.Observable<boolean>;
|
||||
public triggersFocused: ko.Observable<boolean>;
|
||||
public conflictResolutionPolicy: ko.Observable<DataModels.ConflictResolutionPolicy>;
|
||||
public changeFeedPolicy: ko.Observable<DataModels.ChangeFeedPolicy>;
|
||||
public geospatialConfig: ko.Observable<DataModels.GeospatialConfig>;
|
||||
|
||||
constructor(options: any) {
|
||||
this.nodeKind = options.nodeKind;
|
||||
this.container = options.container;
|
||||
this.self = options.self;
|
||||
this.rid = options.rid;
|
||||
this.databaseId = options.databaseId;
|
||||
this.partitionKey = options.partitionKey;
|
||||
this.partitionKeyPropertyHeader = options.partitionKeyPropertyHeader;
|
||||
this.partitionKeyProperty = options.partitionKeyProperty;
|
||||
this.id = options.id;
|
||||
this.defaultTtl = options.defaultTtl;
|
||||
this.analyticalStorageTtl = options.analyticalStorageTtl;
|
||||
this.indexingPolicy = options.indexingPolicy;
|
||||
this.uniqueKeyPolicy = options.uniqueKeyPolicy;
|
||||
this.quotaInfo = options.quotaInfo;
|
||||
this.offer = options.offer;
|
||||
this.partitions = options.partitions;
|
||||
this.throughput = options.throughput;
|
||||
this.cassandraKeys = options.cassandraKeys;
|
||||
this.cassandraSchema = options.cassandraSchema;
|
||||
this.documentIds = options.documentIds;
|
||||
this.children = options.children;
|
||||
this.storedProcedures = options.storedProcedures;
|
||||
this.userDefinedFunctions = options.userDefinedFunctions;
|
||||
this.triggers = options.triggers;
|
||||
this.showStoredProcedures = options.showStoredProcedures;
|
||||
this.showTriggers = options.showTriggers;
|
||||
this.showUserDefinedFunctions = options.showUserDefinedFunctions;
|
||||
this.selectedDocumentContent = options.selectedDocumentContent;
|
||||
this.selectedSubnodeKind = options.selectedSubnodeKind;
|
||||
this.focusedSubnodeKind = options.focusedSubnodeKind;
|
||||
this.isCollectionExpanded = options.isCollectionExpanded;
|
||||
this.isStoredProceduresExpanded = options.isStoredProceduresExpanded;
|
||||
this.isUserDefinedFunctionsExpanded = options.isUserDefinedFunctionsExpanded;
|
||||
this.isTriggersExpanded = options.isTriggersExpanded;
|
||||
this.documentsFocused = options.documentsFocused;
|
||||
this.settingsFocused = options.settingsFocused;
|
||||
this.storedProceduresFocused = options.storedProceduresFocused;
|
||||
this.userDefinedFunctionsFocused = options.userDefinedFunctionsFocused;
|
||||
this.triggersFocused = options.triggersFocused;
|
||||
}
|
||||
|
||||
public expandCollapseCollection() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseCollection() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandCollection(): Q.Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onDocumentDBDocumentsClick() {
|
||||
throw new Error("onDocumentDBDocumentsClick");
|
||||
}
|
||||
|
||||
public onTableEntitiesClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onGraphDocumentsClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onMongoDBDocumentsClick = () => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public openTab = () => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public onSettingsClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onConflictsClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public readSettings(): Q.Promise<void> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewQueryClick(source: any, event: MouseEvent, queryText?: string) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewMongoQueryClick(source: any, event: MouseEvent, queryText?: string) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewGraphClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewMongoShellClick() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewStoredProcedureClick(source: ViewModels.Collection, event: MouseEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewUserDefinedFunctionClick(source: ViewModels.Collection, event: MouseEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onNewTriggerClick(source: ViewModels.Collection, event: MouseEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createStoredProcedureNode(data: DataModels.StoredProcedure): ViewModels.StoredProcedure {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createUserDefinedFunctionNode(data: DataModels.UserDefinedFunction): ViewModels.UserDefinedFunction {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public createTriggerNode(data: DataModels.Trigger): ViewModels.Trigger {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandCollapseStoredProcedures() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandStoredProcedures() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseStoredProcedures() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandCollapseUserDefinedFunctions() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandUserDefinedFunctions() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseUserDefinedFunctions() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandCollapseTriggers() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public expandTriggers() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public collapseTriggers() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public loadStoredProcedures(): Q.Promise<any> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public loadUserDefinedFunctions(): Q.Promise<any> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public loadTriggers(): Q.Promise<any> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onDragOver(source: ViewModels.Collection, event: { originalEvent: DragEvent }) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onDrop(source: ViewModels.Collection, event: { originalEvent: DragEvent }) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isCollectionNodeSelected(): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public isSubNodeSelected(nodeKind: ViewModels.CollectionTabKind): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onDeleteCollectionContextMenuClick(source: ViewModels.Collection, event: MouseEvent | KeyboardEvent) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findStoredProcedureWithId(sprocId: string): ViewModels.StoredProcedure {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findTriggerWithId(triggerId: string): ViewModels.Trigger {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public findUserDefinedFunctionWithId(userDefinedFunctionId: string): ViewModels.UserDefinedFunction {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public uploadFiles = (fileList: FileList): Q.Promise<UploadDetails> => {
|
||||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
public getLabel(): string {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public getDatabase(): ViewModels.Database {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
class ContextualPaneStub implements ViewModels.ContextualPane {
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
public formErrors: ko.Observable<string>;
|
||||
public formErrorsDetails: ko.Observable<string>;
|
||||
public id: string;
|
||||
public title: ko.Observable<string>;
|
||||
public visible: ko.Observable<boolean>;
|
||||
public firstFieldHasFocus: ko.Observable<boolean>;
|
||||
public isExecuting: ko.Observable<boolean>;
|
||||
|
||||
public submit() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public open() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public close() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public hideErrorDetails() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public resetData() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public showErrorDetails() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onCloseKeyPress(source: any, event: KeyboardEvent): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onPaneKeyDown(source: any, event: KeyboardEvent): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
export class AddCollectionPaneStub extends ContextualPaneStub implements ViewModels.AddCollectionPane {
|
||||
public collectionIdTitle: ko.Observable<string>;
|
||||
public databaseId: ko.Observable<string>;
|
||||
public partitionKey: ko.Observable<string>;
|
||||
public storage: ko.Observable<string>;
|
||||
public throughputSinglePartition: ko.Observable<number>;
|
||||
public throughputMultiPartition: ko.Observable<number>;
|
||||
public collectionMaxSharedThroughputTitle: ko.Observable<string>;
|
||||
public collectionWithThroughputInSharedTitle: ko.Observable<string>;
|
||||
|
||||
public onEnableSynapseLinkButtonClicked() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onStorageOptionsKeyDown(source: any, event: KeyboardEvent): boolean {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public onRupmOptionsKeyDown(source: any, event: KeyboardEvent): void {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
export class AddDatabasePaneStub extends ContextualPaneStub implements ViewModels.AddDatabasePane {}
|
||||
|
||||
export class CassandraAddCollectionPane extends ContextualPaneStub implements ViewModels.CassandraAddCollectionPane {
|
||||
public createTableQuery: ko.Observable<string>;
|
||||
public keyspaceId: ko.Observable<string>;
|
||||
public userTableQuery: ko.Observable<string>;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { AutopilotTier } from "../../Contracts/DataModels";
|
||||
|
||||
describe("Add Collection Pane", () => {
|
||||
describe("isValid()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
const mockDatabaseAccount: ViewModels.DatabaseAccount = {
|
||||
id: "mock",
|
||||
kind: "DocumentDB",
|
||||
|
||||
@@ -21,7 +21,7 @@ import { DynamicListItem } from "../Controls/DynamicList/DynamicListComponent";
|
||||
import { HashMap } from "../../Common/HashMap";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
|
||||
export default class AddCollectionPane extends ContextualPaneBase implements ViewModels.AddCollectionPane {
|
||||
export default class AddCollectionPane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
public databaseIds: ko.ObservableArray<string>;
|
||||
public collectionId: ko.Observable<string>;
|
||||
|
||||
@@ -5,7 +5,7 @@ import AddDatabasePane from "./AddDatabasePane";
|
||||
|
||||
describe("Add Database Pane", () => {
|
||||
describe("getSharedThroughputDefault()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
const mockDatabaseAccount: ViewModels.DatabaseAccount = {
|
||||
id: "mock",
|
||||
kind: "DocumentDB",
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
|
||||
export default class AddDatabasePane extends ContextualPaneBase implements ViewModels.AddDatabasePane {
|
||||
export default class AddDatabasePane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
public databaseIdLabel: ko.Computed<string>;
|
||||
public databaseId: ko.Observable<string>;
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as Logger from "../../Common/Logger";
|
||||
import { QueriesGridComponentAdapter } from "../Controls/QueriesGridReactComponent/QueriesGridComponentAdapter";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
export class BrowseQueriesPane extends ContextualPaneBase implements ViewModels.BrowseQueriesPane {
|
||||
export class BrowseQueriesPane extends ContextualPaneBase {
|
||||
public queriesGridComponentAdapter: QueriesGridComponentAdapter;
|
||||
public canSaveQueries: ko.Computed<boolean>;
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { HashMap } from "../../Common/HashMap";
|
||||
|
||||
export default class CassandraAddCollectionPane extends ContextualPaneBase
|
||||
implements ViewModels.CassandraAddCollectionPane {
|
||||
export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
||||
public createTableQuery: ko.Observable<string>;
|
||||
public keyspaceId: ko.Observable<string>;
|
||||
public maxThroughputRU: ko.Observable<number>;
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
||||
<div class="contextual-pane-out" data-bind="click: cancel, clickBubble: false"></div>
|
||||
<div class="contextual-pane" id="clusterLibraryPane">
|
||||
<!-- Cluster Library -- Start -->
|
||||
<div class="contextual-pane-in">
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Cluster Library header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
aria-label="Close pane"
|
||||
tabindex="0"
|
||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }"
|
||||
>
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Cluster Library header - End -->
|
||||
|
||||
<!-- Cluster Library errors - Start -->
|
||||
<div
|
||||
class="warningErrorContainer"
|
||||
aria-live="assertive"
|
||||
data-bind="visible: formErrors() && formErrors() !== ''"
|
||||
>
|
||||
<div class="warningErrorContent">
|
||||
<span><img class="paneErrorIcon" src="/error_red.svg" alt="Error"/></span>
|
||||
<span class="warningErrorDetailsLinkContainer">
|
||||
<span class="formErrors" data-bind="text: formErrors, attr: { title: formErrors }"></span>
|
||||
<a
|
||||
class="errorLink"
|
||||
role="link"
|
||||
data-bind="visible: formErrorsDetails() && formErrorsDetails() !== '', click: showErrorDetails"
|
||||
>More details</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Cluster Library errors - End -->
|
||||
|
||||
<!-- Cluster Library inputs - Start -->
|
||||
<div class="paneMainContent"><div data-bind="react: clusterLibraryGridAdapter"></div></div>
|
||||
<!-- Cluster Library inputs - End -->
|
||||
|
||||
<div class="paneFooter">
|
||||
<div class="leftpanel-okbut"><input type="submit" value="Save" class="btncreatecoll1" /></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- Cluster Library - End -->
|
||||
<!-- Loader - Start -->
|
||||
<div class="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer" data-bind="visible: isExecuting">
|
||||
<img class="dataExplorerLoader" src="/LoadingIndicator_3Squares.gif" />
|
||||
</div>
|
||||
<!-- Loader - End -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,237 +0,0 @@
|
||||
import _ from "underscore";
|
||||
import * as ko from "knockout";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import * as ErrorParserUtility from "../../Common/ErrorParserUtility";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { ClusterLibraryGridAdapter } from "../Controls/LibraryManagement/ClusterLibraryGridAdapter";
|
||||
import { ClusterLibraryGridProps, ClusterLibraryItem } from "../Controls/LibraryManagement/ClusterLibraryGrid";
|
||||
import { Library, SparkCluster, SparkClusterLibrary } from "../../Contracts/DataModels";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
|
||||
export class ClusterLibraryPane extends ContextualPaneBase {
|
||||
public clusterLibraryGridAdapter: ClusterLibraryGridAdapter;
|
||||
|
||||
private _clusterLibraryProps: ko.Observable<ClusterLibraryGridProps>;
|
||||
private _originalCluster: SparkCluster;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
this.title("Cluster Libraries");
|
||||
|
||||
this._clusterLibraryProps = ko.observable<ClusterLibraryGridProps>({
|
||||
libraryItems: [],
|
||||
onInstalledChanged: this._onInstalledChanged
|
||||
});
|
||||
this.clusterLibraryGridAdapter = new ClusterLibraryGridAdapter();
|
||||
this.clusterLibraryGridAdapter.parameters = this._clusterLibraryProps;
|
||||
|
||||
this.resetData();
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
const resourceId: string = this.container.databaseAccount() && this.container.databaseAccount().id;
|
||||
Promise.all([this._getLibraries(resourceId), this._getDefaultCluster(resourceId)]).then(
|
||||
result => {
|
||||
const [libraries, cluster] = result;
|
||||
this._originalCluster = cluster;
|
||||
const libraryItems = this._mapClusterLibraries(cluster, libraries);
|
||||
this._updateClusterLibraryGridStates({ libraryItems });
|
||||
},
|
||||
reason => {
|
||||
const parsedError = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(parsedError[0].message);
|
||||
}
|
||||
);
|
||||
super.open();
|
||||
}
|
||||
|
||||
public submit(): void {
|
||||
const resourceId: string = this.container.databaseAccount() && this.container.databaseAccount().id;
|
||||
this.isExecuting(true);
|
||||
if (this._areLibrariesChanged()) {
|
||||
const newLibraries = this._clusterLibraryProps()
|
||||
.libraryItems.filter(lib => lib.installed)
|
||||
.map(lib => ({ name: lib.name }));
|
||||
this._updateClusterLibraries(resourceId, this._originalCluster, newLibraries).then(
|
||||
() => {
|
||||
this.isExecuting(false);
|
||||
this.close();
|
||||
},
|
||||
reason => {
|
||||
this.isExecuting(false);
|
||||
const parsedError = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(parsedError[0].message);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.isExecuting(false);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
private _updateClusterLibraryGridStates(states: Partial<ClusterLibraryGridProps>): void {
|
||||
const merged = { ...this._clusterLibraryProps(), ...states };
|
||||
this._clusterLibraryProps(merged);
|
||||
this._clusterLibraryProps.valueHasMutated();
|
||||
}
|
||||
|
||||
private _onInstalledChanged = (libraryName: string, installed: boolean): void => {
|
||||
const items = this._clusterLibraryProps().libraryItems;
|
||||
const library = _.find(items, item => item.name === libraryName);
|
||||
library.installed = installed;
|
||||
this._clusterLibraryProps.valueHasMutated();
|
||||
};
|
||||
|
||||
private _areLibrariesChanged(): boolean {
|
||||
const original = this._originalCluster.properties && this._originalCluster.properties.libraries;
|
||||
const changed = this._clusterLibraryProps()
|
||||
.libraryItems.filter(lib => lib.installed)
|
||||
.map(lib => lib.name);
|
||||
if (original.length !== changed.length) {
|
||||
return true;
|
||||
}
|
||||
const newLibraries = new Set(changed);
|
||||
for (let o of original) {
|
||||
if (!newLibraries.has(o.name)) {
|
||||
return false;
|
||||
}
|
||||
newLibraries.delete(o.name);
|
||||
}
|
||||
return newLibraries.size === 0;
|
||||
}
|
||||
|
||||
private _mapClusterLibraries(cluster: SparkCluster, libraries: Library[]): ClusterLibraryItem[] {
|
||||
const clusterLibraries = cluster && cluster.properties && cluster.properties.libraries;
|
||||
const libraryItems = libraries.map(lib => ({
|
||||
...lib,
|
||||
installed: clusterLibraries.some(clusterLib => clusterLib.name === lib.name)
|
||||
}));
|
||||
return libraryItems;
|
||||
}
|
||||
|
||||
private async _getLibraries(resourceId: string): Promise<Library[]> {
|
||||
if (!resourceId) {
|
||||
return Promise.reject("invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
const inProgressId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Fetching libraries...`
|
||||
);
|
||||
try {
|
||||
return await this.container.sparkClusterManager.getLibrariesAsync(resourceId);
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to fetch libraries. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
Logger.logError(e, "Explorer/_getLibraries");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressId);
|
||||
}
|
||||
}
|
||||
|
||||
private async _getDefaultCluster(resourceId: string, clusterId: string = "default"): Promise<SparkCluster> {
|
||||
if (!resourceId) {
|
||||
return Promise.reject("invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
const inProgressId = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, `Fetching cluster...`);
|
||||
try {
|
||||
const cluster = await this.container.sparkClusterManager.getClusterAsync(resourceId, clusterId);
|
||||
return cluster;
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to fetch cluster. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
Logger.logError(e, "Explorer/_getCluster");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressId);
|
||||
}
|
||||
}
|
||||
|
||||
private async _updateClusterLibraries(
|
||||
resourceId: string,
|
||||
originalCluster: SparkCluster,
|
||||
newLibrarys: SparkClusterLibrary[]
|
||||
): Promise<void> {
|
||||
if (!originalCluster || !resourceId) {
|
||||
return Promise.reject("Invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("Cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
TelemetryProcessor.traceStart(Action.ClusterLibraryManage, {
|
||||
resourceId,
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
paneTitle: this.title(),
|
||||
area: "ClusterLibraryPane/_updateClusterLibraries",
|
||||
originalCluster,
|
||||
newLibrarys
|
||||
});
|
||||
|
||||
let newCluster = originalCluster;
|
||||
newCluster.properties.libraries = newLibrarys;
|
||||
|
||||
const consoleId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Updating ${newCluster.name} libraries...`
|
||||
);
|
||||
|
||||
try {
|
||||
const cluster = await this.container.sparkClusterManager.updateClusterAsync(
|
||||
resourceId,
|
||||
originalCluster.name,
|
||||
newCluster
|
||||
);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully updated ${newCluster.name} libraries.`
|
||||
);
|
||||
TelemetryProcessor.traceSuccess(Action.ClusterLibraryManage, {
|
||||
resourceId,
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
paneTitle: this.title(),
|
||||
area: "ClusterLibraryPane/_updateClusterLibraries",
|
||||
cluster
|
||||
});
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to upload ${newCluster.name} libraries. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
TelemetryProcessor.traceFailure(Action.ClusterLibraryManage, {
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
paneTitle: this.title(),
|
||||
area: "ClusterLibraryPane/_updateClusterLibraries",
|
||||
error: e
|
||||
});
|
||||
Logger.logError(e, "Explorer/_updateClusterLibraries");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(consoleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as ko from "knockout";
|
||||
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
@@ -7,11 +6,12 @@ import { KeyCodes } from "../../Common/Constants";
|
||||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
// TODO: Use specific actions for logging telemetry data
|
||||
export abstract class ContextualPaneBase extends WaitsForTemplateViewModel implements ViewModels.ContextualPane {
|
||||
public id: string;
|
||||
public container: ViewModels.Explorer;
|
||||
public container: Explorer;
|
||||
public firstFieldHasFocus: ko.Observable<boolean>;
|
||||
public formErrorsDetails: ko.Observable<string>;
|
||||
public formErrors: ko.Observable<string>;
|
||||
|
||||
@@ -9,45 +9,44 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { CollectionStub, DatabaseStub, ExplorerStub } from "../OpenActionsStubs";
|
||||
import { TreeNode } from "../../Contracts/ViewModels";
|
||||
|
||||
describe("Delete Collection Confirmation Pane", () => {
|
||||
describe("Explorer.isLastCollection()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true if 1 database and 1 collection", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([new CollectionStub({})]);
|
||||
let database = {} as ViewModels.Database;
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([{} as ViewModels.Collection]);
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||
expect(explorer.isLastCollection()).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false if if 1 database and 2 collection", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
let database = {} as ViewModels.Database;
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([
|
||||
new CollectionStub({}),
|
||||
new CollectionStub({})
|
||||
{} as ViewModels.Collection,
|
||||
{} as ViewModels.Collection
|
||||
]);
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||
expect(explorer.isLastCollection()).toBe(false);
|
||||
});
|
||||
|
||||
it("should be false if 2 database and 1 collection each", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([new CollectionStub({})]);
|
||||
let database2: ViewModels.Database = new DatabaseStub({});
|
||||
database2.collections = ko.observableArray<ViewModels.Collection>([new CollectionStub({})]);
|
||||
let database = {} as ViewModels.Database;
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([{} as ViewModels.Collection]);
|
||||
let database2 = {} as ViewModels.Database;
|
||||
database2.collections = ko.observableArray<ViewModels.Collection>([{} as ViewModels.Collection]);
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database, database2]);
|
||||
expect(explorer.isLastCollection()).toBe(false);
|
||||
});
|
||||
|
||||
it("should be false if 0 databases", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
let database = {} as ViewModels.Database;
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>();
|
||||
database.collections = ko.observableArray<ViewModels.Collection>();
|
||||
expect(explorer.isLastCollection()).toBe(false);
|
||||
@@ -59,29 +58,27 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||
let fakeDocumentClientUtility = sinon.createStubInstance<DocumentClientUtilityBase>(
|
||||
DocumentClientUtilityBase as any
|
||||
);
|
||||
let fakeExplorer = sinon.createStubInstance<ExplorerStub>(ExplorerStub as any);
|
||||
sinon.stub(fakeExplorer, "isNotificationConsoleExpanded").value(ko.observable<boolean>(false));
|
||||
let fakeExplorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
|
||||
let pane = new DeleteCollectionConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
id: "deletecollectionconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: fakeExplorer as any
|
||||
container: fakeExplorer
|
||||
});
|
||||
|
||||
fakeExplorer.isLastCollection.returns(true);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
pane.container = fakeExplorer as any;
|
||||
fakeExplorer.isLastCollection = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
expect(pane.shouldRecordFeedback()).toBe(true);
|
||||
|
||||
fakeExplorer.isLastCollection.returns(true);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(true);
|
||||
pane.container = fakeExplorer as any;
|
||||
fakeExplorer.isLastCollection = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => true;
|
||||
expect(pane.shouldRecordFeedback()).toBe(false);
|
||||
|
||||
fakeExplorer.isLastCollection.returns(false);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
pane.container = fakeExplorer as any;
|
||||
fakeExplorer.isLastCollection = () => false;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
expect(pane.shouldRecordFeedback()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -99,38 +96,35 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||
|
||||
it("it should log feedback if last collection and database is not shared", () => {
|
||||
let selectedCollectionId = "testCol";
|
||||
let fakeDocumentClientUtility = sinon.createStubInstance<DocumentClientUtilityBase>(
|
||||
DocumentClientUtilityBase as any
|
||||
);
|
||||
fakeDocumentClientUtility.deleteCollection.returns(Q.resolve(null));
|
||||
let fakeExplorer = sinon.createStubInstance<ExplorerStub>(ExplorerStub as any);
|
||||
fakeExplorer.findSelectedCollection.returns(
|
||||
new CollectionStub({
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
fakeDocumentClientUtility.deleteCollection = () => Q(null);
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.findSelectedCollection = () => {
|
||||
return {
|
||||
id: ko.observable<string>(selectedCollectionId),
|
||||
rid: "test"
|
||||
})
|
||||
);
|
||||
sinon.stub(fakeExplorer, "isNotificationConsoleExpanded").value(ko.observable<boolean>(false));
|
||||
sinon.stub(fakeExplorer, "selectedCollectionId").value(ko.observable<string>(selectedCollectionId));
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
} as ViewModels.Collection;
|
||||
};
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
fakeExplorer.selectedCollectionId = ko.computed<string>(() => selectedCollectionId);
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
const SubscriptionId = "testId";
|
||||
const AccountName = "testAccount";
|
||||
sinon.stub(fakeExplorer, "databaseAccount").value(
|
||||
ko.observable<ViewModels.DatabaseAccount>({
|
||||
id: SubscriptionId,
|
||||
name: AccountName
|
||||
} as ViewModels.DatabaseAccount)
|
||||
);
|
||||
sinon.stub(fakeExplorer, "defaultExperience").value(ko.observable<string>("DocumentDB"));
|
||||
sinon.stub(fakeExplorer, "isPreferredApiCassandra").value(
|
||||
ko.computed(() => {
|
||||
return false;
|
||||
})
|
||||
);
|
||||
sinon.stub(fakeExplorer, "documentClientUtility").value(fakeDocumentClientUtility);
|
||||
sinon.stub(fakeExplorer, "selectedNode").value(ko.observable<TreeNode>());
|
||||
fakeExplorer.isLastCollection.returns(true);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
fakeExplorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({
|
||||
id: SubscriptionId,
|
||||
name: AccountName
|
||||
} as ViewModels.DatabaseAccount);
|
||||
|
||||
fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB");
|
||||
fakeExplorer.isPreferredApiCassandra = ko.computed(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
fakeExplorer.documentClientUtility = fakeDocumentClientUtility;
|
||||
fakeExplorer.selectedNode = ko.observable<TreeNode>();
|
||||
fakeExplorer.isLastCollection = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
|
||||
let pane = new DeleteCollectionConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
|
||||
@@ -12,8 +12,7 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
export default class DeleteCollectionConfirmationPane extends ContextualPaneBase
|
||||
implements ViewModels.DeleteCollectionConfirmationPane {
|
||||
export default class DeleteCollectionConfirmationPane extends ContextualPaneBase {
|
||||
public collectionIdConfirmationText: ko.Observable<string>;
|
||||
public collectionIdConfirmation: ko.Observable<string>;
|
||||
public containerDeleteFeedback: ko.Observable<string>;
|
||||
|
||||
@@ -8,41 +8,40 @@ import DeleteDatabaseConfirmationPane from "./DeleteDatabaseConfirmationPane";
|
||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import { CollectionStub, DatabaseStub, ExplorerStub } from "../OpenActionsStubs";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { TreeNode } from "../../Contracts/ViewModels";
|
||||
import { TabsManager } from "../Tabs/TabsManager";
|
||||
|
||||
describe("Delete Database Confirmation Pane", () => {
|
||||
describe("Explorer.isLastDatabase() and Explorer.isLastNonEmptyDatabase()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true if only 1 database", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
let database = {} as ViewModels.Database;
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||
expect(explorer.isLastDatabase()).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false if only 2 databases", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
let database2: ViewModels.Database = new DatabaseStub({});
|
||||
let database = {} as ViewModels.Database;
|
||||
let database2 = {} as ViewModels.Database;
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database, database2]);
|
||||
expect(explorer.isLastDatabase()).toBe(false);
|
||||
});
|
||||
|
||||
it("should be false if not last empty database", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
let database = {} as ViewModels.Database;
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||
expect(explorer.isLastNonEmptyDatabase()).toBe(false);
|
||||
});
|
||||
|
||||
it("should be true if last non empty database", () => {
|
||||
let database: ViewModels.Database = new DatabaseStub({});
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([new CollectionStub({})]);
|
||||
let database = {} as ViewModels.Database;
|
||||
database.collections = ko.observableArray<ViewModels.Collection>([{} as ViewModels.Collection]);
|
||||
explorer.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||
expect(explorer.isLastNonEmptyDatabase()).toBe(true);
|
||||
});
|
||||
@@ -50,11 +49,9 @@ describe("Delete Database Confirmation Pane", () => {
|
||||
|
||||
describe("shouldRecordFeedback()", () => {
|
||||
it("should return true if last non empty database or is last database that has shared throughput, else false", () => {
|
||||
let fakeDocumentClientUtility = sinon.createStubInstance<DocumentClientUtilityBase>(
|
||||
DocumentClientUtilityBase as any
|
||||
);
|
||||
let fakeExplorer = sinon.createStubInstance<ExplorerStub>(ExplorerStub as any);
|
||||
sinon.stub(fakeExplorer, "isNotificationConsoleExpanded").value(ko.observable<boolean>(false));
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
|
||||
let pane = new DeleteDatabaseConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
@@ -63,18 +60,18 @@ describe("Delete Database Confirmation Pane", () => {
|
||||
container: fakeExplorer as any
|
||||
});
|
||||
|
||||
fakeExplorer.isLastNonEmptyDatabase.returns(true);
|
||||
fakeExplorer.isLastNonEmptyDatabase = () => true;
|
||||
pane.container = fakeExplorer as any;
|
||||
expect(pane.shouldRecordFeedback()).toBe(true);
|
||||
|
||||
fakeExplorer.isLastDatabase.returns(true);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(true);
|
||||
fakeExplorer.isLastDatabase = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => true;
|
||||
pane.container = fakeExplorer as any;
|
||||
expect(pane.shouldRecordFeedback()).toBe(true);
|
||||
|
||||
fakeExplorer.isLastNonEmptyDatabase.returns(false);
|
||||
fakeExplorer.isLastDatabase.returns(true);
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
fakeExplorer.isLastNonEmptyDatabase = () => false;
|
||||
fakeExplorer.isLastDatabase = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
pane.container = fakeExplorer as any;
|
||||
expect(pane.shouldRecordFeedback()).toBe(false);
|
||||
});
|
||||
@@ -93,39 +90,34 @@ describe("Delete Database Confirmation Pane", () => {
|
||||
|
||||
it("on submit() it should log feedback if last non empty database or is last database that has shared throughput", () => {
|
||||
let selectedDatabaseId = "testDB";
|
||||
let fakeDocumentClientUtility = sinon.createStubInstance<DocumentClientUtilityBase>(
|
||||
DocumentClientUtilityBase as any
|
||||
);
|
||||
fakeDocumentClientUtility.deleteDatabase.returns(Q.resolve(null));
|
||||
let fakeExplorer = sinon.createStubInstance<ExplorerStub>(ExplorerStub as any);
|
||||
fakeExplorer.findSelectedDatabase.returns(
|
||||
new DatabaseStub({
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
fakeDocumentClientUtility.deleteDatabase = () => Q.resolve(null);
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.findSelectedDatabase = () => {
|
||||
return {
|
||||
id: ko.observable<string>(selectedDatabaseId),
|
||||
rid: "test",
|
||||
collections: ko.observableArray<ViewModels.Collection>()
|
||||
})
|
||||
);
|
||||
sinon.stub(fakeExplorer, "isNotificationConsoleExpanded").value(ko.observable<boolean>(false));
|
||||
sinon.stub(fakeExplorer, "selectedDatabaseId").value(ko.observable<string>(selectedDatabaseId));
|
||||
fakeExplorer.isSelectedDatabaseShared.returns(false);
|
||||
} as ViewModels.Database;
|
||||
};
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
fakeExplorer.selectedDatabaseId = ko.computed<string>(() => selectedDatabaseId);
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
const SubscriptionId = "testId";
|
||||
const AccountName = "testAccount";
|
||||
sinon.stub(fakeExplorer, "databaseAccount").value(
|
||||
ko.observable<ViewModels.DatabaseAccount>({
|
||||
id: SubscriptionId,
|
||||
name: AccountName
|
||||
} as ViewModels.DatabaseAccount)
|
||||
);
|
||||
sinon.stub(fakeExplorer, "defaultExperience").value(ko.observable<string>("DocumentDB"));
|
||||
sinon.stub(fakeExplorer, "isPreferredApiCassandra").value(
|
||||
ko.computed(() => {
|
||||
return false;
|
||||
})
|
||||
);
|
||||
sinon.stub(fakeExplorer, "documentClientUtility").value(fakeDocumentClientUtility);
|
||||
sinon.stub(fakeExplorer, "selectedNode").value(ko.observable<TreeNode>());
|
||||
sinon.stub(fakeExplorer, "tabsManager").value(new TabsManager());
|
||||
fakeExplorer.isLastNonEmptyDatabase.returns(true);
|
||||
fakeExplorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({
|
||||
id: SubscriptionId,
|
||||
name: AccountName
|
||||
} as ViewModels.DatabaseAccount);
|
||||
fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB");
|
||||
fakeExplorer.isPreferredApiCassandra = ko.computed(() => {
|
||||
return false;
|
||||
});
|
||||
fakeExplorer.documentClientUtility = fakeDocumentClientUtility;
|
||||
fakeExplorer.selectedNode = ko.observable<TreeNode>();
|
||||
fakeExplorer.tabsManager = new TabsManager();
|
||||
fakeExplorer.isLastNonEmptyDatabase = () => true;
|
||||
|
||||
let pane = new DeleteDatabaseConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
|
||||
@@ -13,8 +13,7 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase
|
||||
implements ViewModels.DeleteDatabaseConfirmationPane {
|
||||
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||
public databaseIdConfirmationText: ko.Observable<string>;
|
||||
public databaseIdConfirmation: ko.Observable<string>;
|
||||
public databaseDeleteFeedback: ko.Observable<string>;
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as _ from "underscore";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import StoredProcedure from "../Tree/StoredProcedure";
|
||||
|
||||
export interface ExecuteSprocParam {
|
||||
type: ko.Observable<string>;
|
||||
@@ -14,7 +15,7 @@ type UnwrappedExecuteSprocParam = {
|
||||
value: any;
|
||||
};
|
||||
|
||||
export class ExecuteSprocParamsPane extends ContextualPaneBase implements ViewModels.ExecuteSprocParamsPane {
|
||||
export class ExecuteSprocParamsPane extends ContextualPaneBase {
|
||||
public params: ko.ObservableArray<ExecuteSprocParam>;
|
||||
public partitionKeyType: ko.Observable<string>;
|
||||
public partitionKeyValue: ko.Observable<string>;
|
||||
@@ -22,7 +23,7 @@ export class ExecuteSprocParamsPane extends ContextualPaneBase implements ViewMo
|
||||
public addNewParamLabel: string = "Add New Param";
|
||||
public executeButtonEnabled: ko.Computed<boolean>;
|
||||
|
||||
private _selectedSproc: ViewModels.StoredProcedure;
|
||||
private _selectedSproc: StoredProcedure;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
@@ -39,8 +40,7 @@ export class ExecuteSprocParamsPane extends ContextualPaneBase implements ViewMo
|
||||
|
||||
public open() {
|
||||
super.open();
|
||||
const currentSelectedSproc: ViewModels.StoredProcedure =
|
||||
this.container && this.container.findSelectedStoredProcedure();
|
||||
const currentSelectedSproc = this.container && this.container.findSelectedStoredProcedure();
|
||||
if (!!currentSelectedSproc && !!this._selectedSproc && this._selectedSproc.rid !== currentSelectedSproc.rid) {
|
||||
this.params([]);
|
||||
this.partitionKeyValue("");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { IconButton, PrimaryButton } from "office-ui-fabric-react/lib/Button";
|
||||
import { KeyCodes } from "../../Common/Constants";
|
||||
import { Subscription } from "knockout";
|
||||
import ErrorRedIcon from "../../../images/error_red.svg";
|
||||
import LoadingIndicatorIcon from "../../../images/LoadingIndicator_3Squares.gif";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export interface GenericRightPaneProps {
|
||||
container: ViewModels.Explorer;
|
||||
container: Explorer;
|
||||
content: JSX.Element;
|
||||
formError: string;
|
||||
formErrorDetail: string;
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as ko from "knockout";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
|
||||
export default class GraphStylingPane extends ContextualPaneBase implements ViewModels.GraphStylingPane {
|
||||
export default class GraphStylingPane extends ContextualPaneBase {
|
||||
public graphConfigUIData: ViewModels.GraphConfigUiData;
|
||||
private remoteConfig: ViewModels.GraphConfigUiData;
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
||||
<div class="contextual-pane-out" data-bind="click: cancel, clickBubble: false"></div>
|
||||
<div class="contextual-pane" id="libraryManagePane">
|
||||
<!-- Library Manage -- Start -->
|
||||
<div class="contextual-pane-in">
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Library Manage header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
aria-label="Close pane"
|
||||
tabindex="0"
|
||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }"
|
||||
>
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Library Manage header - End -->
|
||||
|
||||
<!-- Library Manage errors - Start -->
|
||||
<div
|
||||
class="warningErrorContainer"
|
||||
aria-live="assertive"
|
||||
data-bind="visible: formErrors() && formErrors() !== ''"
|
||||
>
|
||||
<div class="warningErrorContent">
|
||||
<span><img class="paneErrorIcon" src="/error_red.svg" alt="Error"/></span>
|
||||
<span class="warningErrorDetailsLinkContainer">
|
||||
<span class="formErrors" data-bind="text: formErrors, attr: { title: formErrors }"></span>
|
||||
<a
|
||||
class="errorLink"
|
||||
role="link"
|
||||
data-bind="visible: formErrorsDetails() && formErrorsDetails() !== '', click: showErrorDetails"
|
||||
>More details</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Library Manage errors - End -->
|
||||
|
||||
<!-- Library Manage inputs - Start -->
|
||||
<div class="paneMainContent"><div data-bind="react: libraryManageComponentAdapter"></div></div>
|
||||
<!-- Library Manage inputs - End -->
|
||||
</form>
|
||||
</div>
|
||||
<!-- Library Manage - End -->
|
||||
<!-- Loader - Start -->
|
||||
<div class="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer" data-bind="visible: isExecuting">
|
||||
<img class="dataExplorerLoader" src="/LoadingIndicator_3Squares.gif" />
|
||||
</div>
|
||||
<!-- Loader - End -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,372 +0,0 @@
|
||||
import * as ko from "knockout";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import * as ErrorParserUtility from "../../Common/ErrorParserUtility";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { LibraryManageComponentAdapter } from "../Controls/LibraryManagement/LibraryManageComponentAdapter";
|
||||
import {
|
||||
LibraryManageComponentProps,
|
||||
LibraryAddNameTextFieldProps,
|
||||
LibraryAddUrlTextFieldProps,
|
||||
LibraryAddButtonProps,
|
||||
LibraryManageGridProps
|
||||
} from "../Controls/LibraryManagement/LibraryManage";
|
||||
import { Library } from "../../Contracts/DataModels";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
|
||||
export class LibraryManagePane extends ContextualPaneBase {
|
||||
public libraryManageComponentAdapter: LibraryManageComponentAdapter;
|
||||
|
||||
private _libraryManageProps: ko.Observable<LibraryManageComponentProps>;
|
||||
private _libraryManageStates: { isNameValid: boolean; isUrlValid: boolean };
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
this.title("Libraries");
|
||||
|
||||
this._libraryManageStates = {
|
||||
isNameValid: true,
|
||||
isUrlValid: true
|
||||
};
|
||||
this._libraryManageProps = ko.observable<LibraryManageComponentProps>({
|
||||
addProps: {
|
||||
nameProps: {
|
||||
libraryName: "",
|
||||
onLibraryNameChange: this._onLibraryNameChange,
|
||||
onLibraryNameValidated: this._onLibraryNameValidated
|
||||
},
|
||||
urlProps: {
|
||||
libraryAddress: "",
|
||||
onLibraryAddressChange: this._onLibraryAddressChange,
|
||||
onLibraryAddressValidated: this._onLibraryAddressValidated
|
||||
},
|
||||
buttonProps: {
|
||||
disabled: false,
|
||||
onLibraryAddClick: this._onLibraryAddClick
|
||||
}
|
||||
},
|
||||
gridProps: {
|
||||
items: [],
|
||||
onLibraryDeleteClick: this._onLibraryDeleteClick
|
||||
}
|
||||
});
|
||||
this.libraryManageComponentAdapter = new LibraryManageComponentAdapter();
|
||||
this.libraryManageComponentAdapter.parameters = this._libraryManageProps;
|
||||
|
||||
this.resetData();
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
const resourceId: string = this.container.databaseAccount() && this.container.databaseAccount().id;
|
||||
this._getLibraries(resourceId).then(
|
||||
(libraries: Library[]) => {
|
||||
this._updateLibraryManageComponentProps(null, null, null, {
|
||||
items: libraries
|
||||
});
|
||||
},
|
||||
reason => {
|
||||
const parsedError = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(parsedError[0].message);
|
||||
}
|
||||
);
|
||||
super.open();
|
||||
}
|
||||
|
||||
public submit(): void {
|
||||
// override default behavior because this is not a form
|
||||
}
|
||||
|
||||
private _updateLibraryManageComponentProps(
|
||||
newNameProps?: Partial<LibraryAddNameTextFieldProps>,
|
||||
newUrlProps?: Partial<LibraryAddUrlTextFieldProps>,
|
||||
newButtonProps?: Partial<LibraryAddButtonProps>,
|
||||
newGridProps?: Partial<LibraryManageGridProps>
|
||||
): void {
|
||||
let {
|
||||
addProps: { buttonProps, nameProps, urlProps },
|
||||
gridProps
|
||||
} = this._libraryManageProps();
|
||||
if (newNameProps) {
|
||||
nameProps = { ...nameProps, ...newNameProps };
|
||||
}
|
||||
if (newUrlProps) {
|
||||
urlProps = { ...urlProps, ...newUrlProps };
|
||||
}
|
||||
if (newButtonProps) {
|
||||
buttonProps = { ...buttonProps, ...newButtonProps };
|
||||
}
|
||||
if (newGridProps) {
|
||||
gridProps = { ...gridProps, ...newGridProps };
|
||||
}
|
||||
this._libraryManageProps({
|
||||
addProps: {
|
||||
nameProps,
|
||||
urlProps,
|
||||
buttonProps
|
||||
},
|
||||
gridProps
|
||||
});
|
||||
this._libraryManageProps.valueHasMutated();
|
||||
}
|
||||
|
||||
private _onLibraryNameChange = (libraryName: string): void => {
|
||||
this._updateLibraryManageComponentProps({ libraryName });
|
||||
};
|
||||
|
||||
private _onLibraryNameValidated = (errorMessage: string): void => {
|
||||
this._libraryManageStates.isNameValid = !errorMessage;
|
||||
this._validateAddButton();
|
||||
};
|
||||
|
||||
private _onLibraryAddressChange = (libraryAddress: string): void => {
|
||||
this._updateLibraryManageComponentProps(null, {
|
||||
libraryAddress
|
||||
});
|
||||
|
||||
if (!this._libraryManageProps().addProps.nameProps.libraryName) {
|
||||
const parsedLibraryAddress = this._parseLibraryUrl(libraryAddress);
|
||||
if (!parsedLibraryAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
let libraryName = this._sanitizeLibraryName(parsedLibraryAddress[2]);
|
||||
this._updateLibraryManageComponentProps({ libraryName });
|
||||
}
|
||||
};
|
||||
|
||||
private _sanitizeLibraryName = (libraryName: string): string => {
|
||||
const invalidCharRegex = /[^a-zA-Z0-9-]/gm;
|
||||
return libraryName
|
||||
.replace(invalidCharRegex, "-")
|
||||
.substring(0, Math.min(Constants.SparkLibrary.nameMaxLength, libraryName.length));
|
||||
};
|
||||
|
||||
private _onLibraryAddressValidated = (errorMessage: string): void => {
|
||||
this._libraryManageStates.isUrlValid = !errorMessage;
|
||||
this._validateAddButton();
|
||||
};
|
||||
|
||||
private _validateAddButton = (): void => {
|
||||
const isValid = this._libraryManageStates.isNameValid && this._libraryManageStates.isUrlValid;
|
||||
const isUploadDisabled = this._libraryManageProps().addProps.buttonProps.disabled;
|
||||
if (isValid === isUploadDisabled) {
|
||||
this._updateLibraryManageComponentProps(null, null, {
|
||||
disabled: !isUploadDisabled
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private _onLibraryDeleteClick = (libraryName: string): void => {
|
||||
const resourceId: string = this.container.databaseAccount() && this.container.databaseAccount().id;
|
||||
this.isExecuting(true);
|
||||
this._deleteLibrary(resourceId, libraryName).then(
|
||||
() => {
|
||||
this.isExecuting(false);
|
||||
const items = this._libraryManageProps().gridProps.items.filter(lib => lib.name !== libraryName);
|
||||
this._updateLibraryManageComponentProps(null, null, null, {
|
||||
items
|
||||
});
|
||||
},
|
||||
reason => {
|
||||
this.isExecuting(false);
|
||||
const parsedError = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(parsedError[0].message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
private _onLibraryAddClick = (): void => {
|
||||
const libraryAddress = this._libraryManageProps().addProps.urlProps.libraryAddress;
|
||||
if (!libraryAddress) {
|
||||
this.formErrors("Library Url cannot be null");
|
||||
return;
|
||||
}
|
||||
const libraryName = this._libraryManageProps().addProps.nameProps.libraryName || this._generateLibraryName();
|
||||
if (!libraryName) {
|
||||
this.formErrors("Library Name cannot be null");
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedLibraryAddress = this._parseLibraryUrl(libraryAddress);
|
||||
if (!parsedLibraryAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const library: Library = {
|
||||
name: libraryName,
|
||||
properties: {
|
||||
kind: "Jar",
|
||||
source: {
|
||||
kind: "HttpsUri",
|
||||
libraryFileName: `${libraryName}.${parsedLibraryAddress[3]}`,
|
||||
uri: libraryAddress
|
||||
}
|
||||
}
|
||||
};
|
||||
const resourceId: string = this.container.databaseAccount() && this.container.databaseAccount().id;
|
||||
|
||||
this.isExecuting(true);
|
||||
this._updateLibraryManageComponentProps(null, null, { disabled: true });
|
||||
this._addLibrary(resourceId, library).then(
|
||||
() => {
|
||||
this.isExecuting(false);
|
||||
this._updateLibraryManageComponentProps(
|
||||
{
|
||||
libraryName: ""
|
||||
},
|
||||
{
|
||||
libraryAddress: ""
|
||||
},
|
||||
{
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
items: [...this._libraryManageProps().gridProps.items, library]
|
||||
}
|
||||
);
|
||||
},
|
||||
reason => {
|
||||
this.isExecuting(false);
|
||||
const parsedError = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(parsedError[0].message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
private _parseLibraryUrl = (url: string): RegExpExecArray => {
|
||||
const libraryUrlRegex = /^(https:\/\/.+\/)(.+)\.(jar)$/gi;
|
||||
return libraryUrlRegex.exec(url);
|
||||
};
|
||||
|
||||
private _generateLibraryName = (): string => {
|
||||
return `library-${Math.random()
|
||||
.toString(32)
|
||||
.substring(2)}`;
|
||||
};
|
||||
|
||||
private async _getLibraries(resourceId: string): Promise<Library[]> {
|
||||
if (!resourceId) {
|
||||
return Promise.reject("Invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("Cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
const inProgressId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Fetching libraries...`
|
||||
);
|
||||
try {
|
||||
const libraries = await this.container.sparkClusterManager.getLibrariesAsync(resourceId);
|
||||
return libraries;
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to fetch libraries. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
Logger.logError(e, "Explorer/_getLibraries");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressId);
|
||||
}
|
||||
}
|
||||
|
||||
private async _addLibrary(resourceId: string, library: Library): Promise<void> {
|
||||
if (!library || !resourceId) {
|
||||
return Promise.reject("invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
TelemetryProcessor.traceStart(Action.LibraryManage, {
|
||||
resourceId,
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
paneTitle: this.title(),
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName: library.name
|
||||
});
|
||||
|
||||
const libraryName = library.name;
|
||||
const inProgressId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Uploading ${libraryName}...`
|
||||
);
|
||||
try {
|
||||
await this.container.sparkClusterManager.addLibraryAsync(resourceId, libraryName, library);
|
||||
TelemetryProcessor.traceSuccess(Action.LibraryManage, {
|
||||
resourceId,
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName: library.name
|
||||
});
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to upload ${libraryName}. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
TelemetryProcessor.traceFailure(Action.LibraryManage, {
|
||||
resourceId,
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName: library.name,
|
||||
error: e
|
||||
});
|
||||
Logger.logError(e, "Explorer/_uploadLibrary");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressId);
|
||||
}
|
||||
}
|
||||
|
||||
private async _deleteLibrary(resourceId: string, libraryName: string): Promise<void> {
|
||||
if (!libraryName || !resourceId) {
|
||||
return Promise.reject("invalid inputs");
|
||||
}
|
||||
|
||||
if (!this.container.sparkClusterManager) {
|
||||
return Promise.reject("cluster client is not initialized yet");
|
||||
}
|
||||
|
||||
TelemetryProcessor.traceStart(Action.LibraryManage, {
|
||||
resourceId,
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
paneTitle: this.title(),
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName
|
||||
});
|
||||
const inProgressId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Deleting ${libraryName}...`
|
||||
);
|
||||
try {
|
||||
await this.container.sparkClusterManager.deleteLibraryAsync(resourceId, libraryName);
|
||||
TelemetryProcessor.traceSuccess(Action.LibraryManage, {
|
||||
resourceId,
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName
|
||||
});
|
||||
} catch (e) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to delete ${libraryName}. Reason: ${JSON.stringify(e)}`
|
||||
);
|
||||
TelemetryProcessor.traceFailure(Action.LibraryManage, {
|
||||
resourceId,
|
||||
area: "LibraryManagePane/_deleteLibrary",
|
||||
libraryName,
|
||||
error: e
|
||||
});
|
||||
Logger.logError(e, "Explorer/_deleteLibrary");
|
||||
throw e;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsol
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
|
||||
export class LoadQueryPane extends ContextualPaneBase implements ViewModels.LoadQueryPane {
|
||||
export class LoadQueryPane extends ContextualPaneBase {
|
||||
public selectedFilesTitle: ko.Observable<string>;
|
||||
public files: ko.Observable<FileList>;
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@ import * as ko from "knockout";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { KeyCodes } from "../../Common/Constants";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class NewVertexPane extends ContextualPaneBase implements ViewModels.NewVertexPane {
|
||||
public container: ViewModels.Explorer;
|
||||
export default class NewVertexPane extends ContextualPaneBase {
|
||||
public container: Explorer;
|
||||
public visible: ko.Observable<boolean>;
|
||||
public formErrors: ko.Observable<string>;
|
||||
public formErrorsDetails: ko.Observable<string>;
|
||||
|
||||
@@ -19,8 +19,6 @@ import BrowseQueriesPaneTemplate from "./BrowseQueriesPane.html";
|
||||
import UploadFilePaneTemplate from "./UploadFilePane.html";
|
||||
import StringInputPaneTemplate from "./StringInputPane.html";
|
||||
import SetupNotebooksPaneTemplate from "./SetupNotebooksPane.html";
|
||||
import LibraryManagePaneTemplate from "./LibraryManagePane.html";
|
||||
import ClusterLibraryPaneTemplate from "./ClusterLibraryPane.html";
|
||||
import GitHubReposPaneTemplate from "./GitHubReposPane.html";
|
||||
|
||||
export class PaneComponent {
|
||||
@@ -218,24 +216,6 @@ export class SetupNotebooksPaneComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export class LibraryManagePaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
viewModel: PaneComponent,
|
||||
template: LibraryManagePaneTemplate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ClusterLibraryPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
viewModel: PaneComponent,
|
||||
template: ClusterLibraryPaneTemplate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class GitHubReposPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
|
||||
@@ -1,164 +1,156 @@
|
||||
import ko from "knockout";
|
||||
import { ITextFieldProps, Stack, Text, TextField } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { JunoClient } from "../../Juno/JunoClient";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { FileSystemUtil } from "../Notebook/FileSystemUtil";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent";
|
||||
|
||||
export class PublishNotebookPaneAdapter implements ReactAdapter {
|
||||
parameters: ko.Observable<number>;
|
||||
private isOpened: boolean;
|
||||
private isExecuting: boolean;
|
||||
private formError: string;
|
||||
private formErrorDetail: string;
|
||||
|
||||
private name: string;
|
||||
private author: string;
|
||||
private content: string;
|
||||
private description: string;
|
||||
private tags: string;
|
||||
private thumbnailUrl: string;
|
||||
|
||||
constructor(private container: ViewModels.Explorer, private junoClient: JunoClient) {
|
||||
this.parameters = ko.observable(Date.now());
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
if (!this.isOpened) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const props: GenericRightPaneProps = {
|
||||
container: this.container,
|
||||
content: this.createContent(),
|
||||
formError: this.formError,
|
||||
formErrorDetail: this.formErrorDetail,
|
||||
id: "publishnotebookpane",
|
||||
isExecuting: this.isExecuting,
|
||||
title: "Publish to gallery",
|
||||
submitButtonText: "Publish",
|
||||
onClose: () => this.close(),
|
||||
onSubmit: () => this.submit()
|
||||
};
|
||||
|
||||
return <GenericRightPaneComponent {...props} />;
|
||||
}
|
||||
|
||||
public triggerRender(): void {
|
||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||
}
|
||||
|
||||
public open(name: string, author: string, content: string): void {
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
this.content = content;
|
||||
|
||||
this.isOpened = true;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public async submit(): Promise<void> {
|
||||
const notificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Publishing ${this.name} to gallery`
|
||||
);
|
||||
this.isExecuting = true;
|
||||
this.triggerRender();
|
||||
|
||||
try {
|
||||
if (!this.name || !this.description || !this.author) {
|
||||
throw new Error("Name, description, and author are required");
|
||||
}
|
||||
|
||||
const response = await this.junoClient.publishNotebook(
|
||||
this.name,
|
||||
this.description,
|
||||
this.tags?.split(","),
|
||||
this.author,
|
||||
this.thumbnailUrl,
|
||||
this.content
|
||||
);
|
||||
if (!response.data) {
|
||||
throw new Error(`Received HTTP ${response.status} when publishing ${name} to gallery`);
|
||||
}
|
||||
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, `Published ${name} to gallery`);
|
||||
} catch (error) {
|
||||
this.formError = `Failed to publish ${this.name} to gallery`;
|
||||
this.formErrorDetail = `${error}`;
|
||||
|
||||
const message = `${this.formError}: ${this.formErrorDetail}`;
|
||||
Logger.logError(message, "PublishNotebookPaneAdapter/submit");
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Error, message);
|
||||
return;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(notificationId);
|
||||
this.isExecuting = false;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
|
||||
private createContent = (): JSX.Element => {
|
||||
const descriptionPara1 =
|
||||
"This notebook has your data. Please make sure you delete any sensitive data/output before publishing.";
|
||||
const descriptionPara2 = `Would you like to publish and share ${FileSystemUtil.stripExtension(
|
||||
this.name,
|
||||
"ipynb"
|
||||
)} to the gallery?`;
|
||||
const descriptionProps: ITextFieldProps = {
|
||||
label: "Description",
|
||||
ariaLabel: "Description",
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
required: true,
|
||||
onChange: (event, newValue) => (this.description = newValue)
|
||||
};
|
||||
const tagsProps: ITextFieldProps = {
|
||||
label: "Tags",
|
||||
ariaLabel: "Tags",
|
||||
placeholder: "Optional tag 1, Optional tag 2",
|
||||
onChange: (event, newValue) => (this.tags = newValue)
|
||||
};
|
||||
const thumbnailProps: ITextFieldProps = {
|
||||
label: "Cover image url",
|
||||
ariaLabel: "Cover image url",
|
||||
onChange: (event, newValue) => (this.thumbnailUrl = newValue)
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="panelContent">
|
||||
<Stack className="paneMainContent" tokens={{ childrenGap: 20 }}>
|
||||
<Text>{descriptionPara1}</Text>
|
||||
<Text>{descriptionPara2}</Text>
|
||||
<TextField {...descriptionProps} />
|
||||
<TextField {...tagsProps} />
|
||||
<TextField {...thumbnailProps} />
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private reset = (): void => {
|
||||
this.isOpened = false;
|
||||
this.isExecuting = false;
|
||||
this.formError = undefined;
|
||||
this.formErrorDetail = undefined;
|
||||
this.name = undefined;
|
||||
this.author = undefined;
|
||||
this.content = undefined;
|
||||
};
|
||||
}
|
||||
import ko from "knockout";
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import { JunoClient } from "../../Juno/JunoClient";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent";
|
||||
import Explorer from "../Explorer";
|
||||
import { PublishNotebookPaneComponent, PublishNotebookPaneProps } from "./PublishNotebookPaneComponent";
|
||||
|
||||
export class PublishNotebookPaneAdapter implements ReactAdapter {
|
||||
parameters: ko.Observable<number>;
|
||||
private isOpened: boolean;
|
||||
private isExecuting: boolean;
|
||||
private formError: string;
|
||||
private formErrorDetail: string;
|
||||
|
||||
private name: string;
|
||||
private author: string;
|
||||
private content: string;
|
||||
private description: string;
|
||||
private tags: string;
|
||||
private imageSrc: string;
|
||||
|
||||
constructor(private container: Explorer, private junoClient: JunoClient) {
|
||||
this.parameters = ko.observable(Date.now());
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
if (!this.isOpened) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const props: GenericRightPaneProps = {
|
||||
container: this.container,
|
||||
content: this.createContent(),
|
||||
formError: this.formError,
|
||||
formErrorDetail: this.formErrorDetail,
|
||||
id: "publishnotebookpane",
|
||||
isExecuting: this.isExecuting,
|
||||
title: "Publish to gallery",
|
||||
submitButtonText: "Publish",
|
||||
onClose: () => this.close(),
|
||||
onSubmit: () => this.submit()
|
||||
};
|
||||
|
||||
return <GenericRightPaneComponent {...props} />;
|
||||
}
|
||||
|
||||
public triggerRender(): void {
|
||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||
}
|
||||
|
||||
public open(name: string, author: string, content: string): void {
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
this.content = content;
|
||||
|
||||
this.isOpened = true;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public async submit(): Promise<void> {
|
||||
const notificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Publishing ${this.name} to gallery`
|
||||
);
|
||||
this.isExecuting = true;
|
||||
this.triggerRender();
|
||||
|
||||
try {
|
||||
if (!this.name || !this.description || !this.author) {
|
||||
throw new Error("Name, description, and author are required");
|
||||
}
|
||||
|
||||
const response = await this.junoClient.publishNotebook(
|
||||
this.name,
|
||||
this.description,
|
||||
this.tags?.split(","),
|
||||
this.author,
|
||||
this.imageSrc,
|
||||
this.content
|
||||
);
|
||||
if (!response.data) {
|
||||
throw new Error(`Received HTTP ${response.status} when publishing ${name} to gallery`);
|
||||
}
|
||||
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, `Published ${name} to gallery`);
|
||||
} catch (error) {
|
||||
this.formError = `Failed to publish ${this.name} to gallery`;
|
||||
this.formErrorDetail = `${error}`;
|
||||
|
||||
const message = `${this.formError}: ${this.formErrorDetail}`;
|
||||
Logger.logError(message, "PublishNotebookPaneAdapter/submit");
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Error, message);
|
||||
return;
|
||||
} finally {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(notificationId);
|
||||
this.isExecuting = false;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
|
||||
private createFormErrorForLargeImageSelection = (formError: string, formErrorDetail: string, area: string): void => {
|
||||
this.formError = formError;
|
||||
this.formErrorDetail = formErrorDetail;
|
||||
|
||||
const message = `${this.formError}: ${this.formErrorDetail}`;
|
||||
Logger.logError(message, area);
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Error, message);
|
||||
this.triggerRender();
|
||||
};
|
||||
|
||||
private clearFormError = (): void => {
|
||||
this.formError = undefined;
|
||||
this.formErrorDetail = undefined;
|
||||
this.triggerRender();
|
||||
};
|
||||
|
||||
private createContent = (): JSX.Element => {
|
||||
const publishNotebookPaneProps: PublishNotebookPaneProps = {
|
||||
notebookName: this.name,
|
||||
notebookDescription: "",
|
||||
notebookTags: "",
|
||||
notebookAuthor: this.author,
|
||||
notebookCreatedDate: new Date().toISOString(),
|
||||
onChangeDescription: (newValue: string) => (this.description = newValue),
|
||||
onChangeTags: (newValue: string) => (this.tags = newValue),
|
||||
onChangeImageSrc: (newValue: string) => (this.imageSrc = newValue),
|
||||
onError: this.createFormErrorForLargeImageSelection,
|
||||
clearFormError: this.clearFormError
|
||||
};
|
||||
|
||||
return <PublishNotebookPaneComponent {...publishNotebookPaneProps} />;
|
||||
};
|
||||
|
||||
private reset = (): void => {
|
||||
this.isOpened = false;
|
||||
this.isExecuting = false;
|
||||
this.formError = undefined;
|
||||
this.formErrorDetail = undefined;
|
||||
this.name = undefined;
|
||||
this.author = undefined;
|
||||
this.content = undefined;
|
||||
};
|
||||
}
|
||||
|
||||
6
src/Explorer/Panes/PublishNotebookPaneComponent.less
Normal file
6
src/Explorer/Panes/PublishNotebookPaneComponent.less
Normal file
@@ -0,0 +1,6 @@
|
||||
.publishNotebookPanelContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
23
src/Explorer/Panes/PublishNotebookPaneComponent.test.tsx
Normal file
23
src/Explorer/Panes/PublishNotebookPaneComponent.test.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
import { PublishNotebookPaneComponent, PublishNotebookPaneProps } from "./PublishNotebookPaneComponent";
|
||||
|
||||
describe("PublishNotebookPaneComponent", () => {
|
||||
it("renders", () => {
|
||||
const props: PublishNotebookPaneProps = {
|
||||
notebookName: "SampleNotebook.ipynb",
|
||||
notebookDescription: "sample description",
|
||||
notebookTags: "tag1, tag2",
|
||||
notebookAuthor: "CosmosDB",
|
||||
notebookCreatedDate: "2020-07-17T00:00:00Z",
|
||||
onChangeDescription: undefined,
|
||||
onChangeTags: undefined,
|
||||
onChangeImageSrc: undefined,
|
||||
onError: undefined,
|
||||
clearFormError: undefined
|
||||
};
|
||||
|
||||
const wrapper = shallow(<PublishNotebookPaneComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
205
src/Explorer/Panes/PublishNotebookPaneComponent.tsx
Normal file
205
src/Explorer/Panes/PublishNotebookPaneComponent.tsx
Normal file
@@ -0,0 +1,205 @@
|
||||
import { ITextFieldProps, Stack, Text, TextField, Dropdown, IDropdownProps } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { GalleryCardComponent } from "../Controls/NotebookGallery/Cards/GalleryCardComponent";
|
||||
import { FileSystemUtil } from "../Notebook/FileSystemUtil";
|
||||
import "./PublishNotebookPaneComponent.less";
|
||||
|
||||
export interface PublishNotebookPaneProps {
|
||||
notebookName: string;
|
||||
notebookDescription: string;
|
||||
notebookTags: string;
|
||||
notebookAuthor: string;
|
||||
notebookCreatedDate: string;
|
||||
onChangeDescription: (newValue: string) => void;
|
||||
onChangeTags: (newValue: string) => void;
|
||||
onChangeImageSrc: (newValue: string) => void;
|
||||
onError: (formError: string, formErrorDetail: string, area: string) => void;
|
||||
clearFormError: () => void;
|
||||
}
|
||||
|
||||
interface PublishNotebookPaneState {
|
||||
type: string;
|
||||
notebookDescription: string;
|
||||
notebookTags: string;
|
||||
imageSrc: string;
|
||||
}
|
||||
|
||||
export class PublishNotebookPaneComponent extends React.Component<PublishNotebookPaneProps, PublishNotebookPaneState> {
|
||||
private static readonly maxImageSizeInMib = 1.5;
|
||||
private static readonly ImageTypes = ["URL", "Custom Image"];
|
||||
private descriptionPara1: string;
|
||||
private descriptionPara2: string;
|
||||
private descriptionProps: ITextFieldProps;
|
||||
private tagsProps: ITextFieldProps;
|
||||
private thumbnailUrlProps: ITextFieldProps;
|
||||
private thumbnailSelectorProps: IDropdownProps;
|
||||
private imageToBase64: (file: File, updateImageSrc: (result: string) => void) => void;
|
||||
|
||||
constructor(props: PublishNotebookPaneProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
type: PublishNotebookPaneComponent.ImageTypes[0],
|
||||
notebookDescription: "",
|
||||
notebookTags: "",
|
||||
imageSrc: undefined
|
||||
};
|
||||
|
||||
this.imageToBase64 = (file: File, updateImageSrc: (result: string) => void) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = function() {
|
||||
updateImageSrc(reader.result.toString());
|
||||
};
|
||||
|
||||
const onError = this.props.onError;
|
||||
reader.onerror = function(error) {
|
||||
const formError = `Failed to convert ${file.name} to base64 format`;
|
||||
const formErrorDetail = `${error}`;
|
||||
const area = "PublishNotebookPaneComponent/selectImageFile";
|
||||
onError(formError, formErrorDetail, area);
|
||||
};
|
||||
};
|
||||
|
||||
this.descriptionPara1 =
|
||||
"This notebook has your data. Please make sure you delete any sensitive data/output before publishing.";
|
||||
|
||||
this.descriptionPara2 = `Would you like to publish and share "${FileSystemUtil.stripExtension(
|
||||
this.props.notebookName,
|
||||
"ipynb"
|
||||
)}" to the gallery?`;
|
||||
|
||||
this.thumbnailUrlProps = {
|
||||
label: "Cover image url",
|
||||
ariaLabel: "Cover image url",
|
||||
onChange: (event, newValue) => {
|
||||
this.props.onChangeImageSrc(newValue);
|
||||
this.setState({ imageSrc: newValue });
|
||||
}
|
||||
};
|
||||
|
||||
this.thumbnailSelectorProps = {
|
||||
label: "Cover image",
|
||||
defaultSelectedKey: PublishNotebookPaneComponent.ImageTypes[0],
|
||||
ariaLabel: "Cover image",
|
||||
options: PublishNotebookPaneComponent.ImageTypes.map((value: string) => ({ text: value, key: value })),
|
||||
onChange: (event, options) => {
|
||||
this.setState({ type: options.text });
|
||||
}
|
||||
};
|
||||
|
||||
this.descriptionProps = {
|
||||
label: "Description",
|
||||
ariaLabel: "Description",
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
required: true,
|
||||
onChange: (event, newValue) => {
|
||||
this.props.onChangeDescription(newValue);
|
||||
this.setState({ notebookDescription: newValue });
|
||||
}
|
||||
};
|
||||
|
||||
this.tagsProps = {
|
||||
label: "Tags",
|
||||
ariaLabel: "Tags",
|
||||
placeholder: "Optional tag 1, Optional tag 2",
|
||||
onChange: (event, newValue) => {
|
||||
this.props.onChangeTags(newValue);
|
||||
this.setState({ notebookTags: newValue });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="publishNotebookPanelContent">
|
||||
<Stack className="panelMainContent" tokens={{ childrenGap: 20 }}>
|
||||
<Stack.Item>
|
||||
<Text>{this.descriptionPara1}</Text>
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item>
|
||||
<Text>{this.descriptionPara2}</Text>
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item>
|
||||
<TextField {...this.descriptionProps} />
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item>
|
||||
<TextField {...this.tagsProps} />
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item>
|
||||
<Dropdown {...this.thumbnailSelectorProps} />
|
||||
</Stack.Item>
|
||||
|
||||
{this.state.type === PublishNotebookPaneComponent.ImageTypes[0] ? (
|
||||
<Stack.Item>
|
||||
<TextField {...this.thumbnailUrlProps} />
|
||||
</Stack.Item>
|
||||
) : (
|
||||
<Stack.Item>
|
||||
<input
|
||||
id="selectImageFile"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={event => {
|
||||
const file = event.target.files[0];
|
||||
if (file.size / 1024 ** 2 > PublishNotebookPaneComponent.maxImageSizeInMib) {
|
||||
event.target.value = "";
|
||||
const formError = `Failed to upload ${file.name}`;
|
||||
const formErrorDetail = `Image is larger than ${PublishNotebookPaneComponent.maxImageSizeInMib} MiB. Please Choose a different image.`;
|
||||
const area = "PublishNotebookPaneComponent/selectImageFile";
|
||||
|
||||
this.props.onError(formError, formErrorDetail, area);
|
||||
this.props.onChangeImageSrc(undefined);
|
||||
this.setState({ imageSrc: undefined });
|
||||
return;
|
||||
} else {
|
||||
this.props.clearFormError();
|
||||
}
|
||||
this.imageToBase64(file, (result: string) => {
|
||||
this.props.onChangeImageSrc(result);
|
||||
this.setState({ imageSrc: result });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
)}
|
||||
<Stack.Item>
|
||||
<Text>Preview</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<GalleryCardComponent
|
||||
data={{
|
||||
id: undefined,
|
||||
name: this.props.notebookName,
|
||||
description: this.state.notebookDescription,
|
||||
gitSha: undefined,
|
||||
tags: this.state.notebookTags.split(","),
|
||||
author: this.props.notebookAuthor,
|
||||
thumbnailUrl: this.state.imageSrc,
|
||||
created: this.props.notebookCreatedDate,
|
||||
isSample: false,
|
||||
downloads: 0,
|
||||
favorites: 0,
|
||||
views: 0
|
||||
}}
|
||||
isFavorite={false}
|
||||
showDownload={true}
|
||||
showDelete={true}
|
||||
onClick={undefined}
|
||||
onTagClick={undefined}
|
||||
onFavoriteClick={undefined}
|
||||
onUnfavoriteClick={undefined}
|
||||
onDownloadClick={undefined}
|
||||
onDeleteClick={undefined}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsol
|
||||
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
|
||||
export class RenewAdHocAccessPane extends ContextualPaneBase implements ViewModels.RenewAdHocAccessPane {
|
||||
export class RenewAdHocAccessPane extends ContextualPaneBase {
|
||||
public accessKey: ko.Observable<string>;
|
||||
public isHelperImageVisible: ko.Observable<boolean>;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import Explorer from "../Explorer";
|
||||
|
||||
describe("Settings Pane", () => {
|
||||
describe("shouldShowQueryPageOptions()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
|
||||
@@ -8,7 +8,7 @@ import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { StringUtility } from "../../Shared/StringUtility";
|
||||
import { config } from "../../Config";
|
||||
|
||||
export class SettingsPane extends ContextualPaneBase implements ViewModels.SettingsPane {
|
||||
export class SettingsPane extends ContextualPaneBase {
|
||||
public pageOption: ko.Observable<string>;
|
||||
public customItemPerPage: ko.Observable<number>;
|
||||
public crossPartitionQueryEnabled: ko.Observable<boolean>;
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as Utilities from "../../Tables/Utilities";
|
||||
import EntityPropertyViewModel from "./EntityPropertyViewModel";
|
||||
import TableEntityPane from "./TableEntityPane";
|
||||
|
||||
export default class AddTableEntityPane extends TableEntityPane implements ViewModels.AddTableEntityPane {
|
||||
export default class AddTableEntityPane extends TableEntityPane {
|
||||
private static _excludedFields: string[] = [TableConstants.EntityKeyNames.Timestamp];
|
||||
|
||||
private static _readonlyFields: string[] = [
|
||||
|
||||
@@ -8,9 +8,10 @@ import * as Utilities from "../../Tables/Utilities";
|
||||
import * as TableConstants from "../../Tables/Constants";
|
||||
import EntityPropertyViewModel from "./EntityPropertyViewModel";
|
||||
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export default class EditTableEntityPane extends TableEntityPane implements ViewModels.EditTableEntityPane {
|
||||
container: ViewModels.Explorer;
|
||||
export default class EditTableEntityPane extends TableEntityPane {
|
||||
container: Explorer;
|
||||
visible: ko.Observable<boolean>;
|
||||
|
||||
public originEntity: Entities.ITableEntity;
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface ISelectColumn {
|
||||
editable: ko.Observable<boolean>;
|
||||
}
|
||||
|
||||
export class QuerySelectPane extends ContextualPaneBase implements ViewModels.QuerySelectPane {
|
||||
export class QuerySelectPane extends ContextualPaneBase {
|
||||
public titleLabel: string = "Select Columns";
|
||||
public instructionLabel: string = "Select the columns that you want to query.";
|
||||
public availableColumnsTableQueryLabel: string = "Available Columns";
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface IColumnSetting {
|
||||
order?: number[];
|
||||
}
|
||||
|
||||
export class TableColumnOptionsPane extends ContextualPaneBase implements ViewModels.TableColumnOptionsPane {
|
||||
export class TableColumnOptionsPane extends ContextualPaneBase {
|
||||
public titleLabel: string = "Column Options";
|
||||
public instructionLabel: string = "Choose the columns and the order in which you want to display them in the table.";
|
||||
public availableColumnsLabel: string = "Available Columns";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
|
||||
export class UploadFilePane extends ContextualPaneBase implements ViewModels.UploadFilePane {
|
||||
export class UploadFilePane extends ContextualPaneBase {
|
||||
public selectedFilesTitle: ko.Observable<string>;
|
||||
public files: ko.Observable<FileList>;
|
||||
private openOptions: ViewModels.UploadFilePaneOpenOptions;
|
||||
|
||||
@@ -10,6 +10,7 @@ import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
||||
import { UploadDetailsRecord, UploadDetails } from "../../workers/upload/definitions";
|
||||
import InfoBubbleIcon from "../../../images/info-bubble.svg";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
const UPLOAD_FILE_SIZE_LIMIT = 2097152;
|
||||
|
||||
@@ -23,7 +24,7 @@ export class UploadItemsPaneAdapter implements ReactAdapter {
|
||||
private selectedFilesTitle: string;
|
||||
private uploadFileData: UploadDetailsRecord[];
|
||||
|
||||
public constructor(private container: ViewModels.Explorer) {
|
||||
public constructor(private container: Explorer) {
|
||||
this.parameters = ko.observable(Date.now());
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PublishNotebookPaneComponent renders 1`] = `
|
||||
<div
|
||||
className="publishNotebookPanelContent"
|
||||
>
|
||||
<Stack
|
||||
className="panelMainContent"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<Text>
|
||||
This notebook has your data. Please make sure you delete any sensitive data/output before publishing.
|
||||
</Text>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<Text>
|
||||
Would you like to publish and share "SampleNotebook" to the gallery?
|
||||
</Text>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Description"
|
||||
label="Description"
|
||||
multiline={true}
|
||||
onChange={[Function]}
|
||||
required={true}
|
||||
rows={3}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Tags"
|
||||
label="Tags"
|
||||
onChange={[Function]}
|
||||
placeholder="Optional tag 1, Optional tag 2"
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<StyledWithResponsiveMode
|
||||
ariaLabel="Cover image"
|
||||
defaultSelectedKey="URL"
|
||||
label="Cover image"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"key": "URL",
|
||||
"text": "URL",
|
||||
},
|
||||
Object {
|
||||
"key": "Custom Image",
|
||||
"text": "Custom Image",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Cover image url"
|
||||
label="Cover image url"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<Text>
|
||||
Preview
|
||||
</Text>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<GalleryCardComponent
|
||||
data={
|
||||
Object {
|
||||
"author": "CosmosDB",
|
||||
"created": "2020-07-17T00:00:00Z",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"favorites": 0,
|
||||
"gitSha": undefined,
|
||||
"id": undefined,
|
||||
"isSample": false,
|
||||
"name": "SampleNotebook.ipynb",
|
||||
"tags": Array [
|
||||
"",
|
||||
],
|
||||
"thumbnailUrl": undefined,
|
||||
"views": 0,
|
||||
}
|
||||
}
|
||||
isFavorite={false}
|
||||
showDelete={true}
|
||||
showDownload={true}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
`;
|
||||
@@ -18,6 +18,7 @@ import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
||||
import AddDatabaseIcon from "../../../images/AddDatabase.svg";
|
||||
import SampleIcon from "../../../images/Hero-sample.svg";
|
||||
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
/**
|
||||
* TODO Remove this when fully ported to ReactJS
|
||||
@@ -29,7 +30,7 @@ export class SplashScreenComponentAdapter implements ReactAdapter {
|
||||
|
||||
public parameters: ko.Observable<number>;
|
||||
|
||||
constructor(private container: ViewModels.Explorer) {
|
||||
constructor(private container: Explorer) {
|
||||
this.parameters = ko.observable<number>(Date.now());
|
||||
this.container.tabsManager.openedTabs.subscribe((tabs: ViewModels.Tab[]) => {
|
||||
if (tabs.length === 0) {
|
||||
|
||||
@@ -237,7 +237,7 @@ function updateTableScrollableRegionHeight(): void {
|
||||
.offset().top;
|
||||
var dataTablesInfoElem = $(tabElement).find(".dataTables_info");
|
||||
var dataTablesPaginateElem = $(tabElement).find(".dataTables_paginate");
|
||||
const explorer = window.dataExplorer as ViewModels.Explorer;
|
||||
const explorer = window.dataExplorer;
|
||||
const notificationConsoleHeight = explorer.isNotificationConsoleExpanded()
|
||||
? 252 /** 32px(header) + 220px(content height) **/
|
||||
: 32 /** Header height **/;
|
||||
|
||||
@@ -6,6 +6,7 @@ import TableEntityListViewModel from "./TableEntityListViewModel";
|
||||
import * as Entities from "../Entities";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import * as TableColumnOptionsPane from "../../Panes/Tables/TableColumnOptionsPane";
|
||||
import Explorer from "../../Explorer";
|
||||
|
||||
export default class TableCommands {
|
||||
// Command Ids
|
||||
@@ -15,9 +16,9 @@ export default class TableCommands {
|
||||
public static resetColumnsCommand: string = "reset";
|
||||
public static customizeColumnsCommand: string = "customizeColumns";
|
||||
|
||||
private _container: ViewModels.Explorer;
|
||||
private _container: Explorer;
|
||||
|
||||
constructor(container: ViewModels.Explorer) {
|
||||
constructor(container: Explorer) {
|
||||
this._container = container;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { MessageTypes } from "../../Contracts/ExplorerContracts";
|
||||
import { MessageHandler } from "../../Common/MessageHandler";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export interface CassandraTableKeys {
|
||||
partitionKeys: CassandraTableKey[];
|
||||
@@ -405,7 +406,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
public createKeyspace(
|
||||
cassandraEndpoint: string,
|
||||
resourceId: string,
|
||||
explorer: ViewModels.Explorer,
|
||||
explorer: Explorer,
|
||||
createKeyspaceQuery: string
|
||||
): Q.Promise<any> {
|
||||
if (!createKeyspaceQuery) {
|
||||
@@ -446,7 +447,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
public createTableAndKeyspace(
|
||||
cassandraEndpoint: string,
|
||||
resourceId: string,
|
||||
explorer: ViewModels.Explorer,
|
||||
explorer: Explorer,
|
||||
createTableQuery: string,
|
||||
createKeyspaceQuery?: string
|
||||
): Q.Promise<any> {
|
||||
@@ -506,7 +507,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
cassandraEndpoint: string,
|
||||
resourceId: string,
|
||||
deleteQuery: string,
|
||||
explorer: ViewModels.Explorer
|
||||
explorer: Explorer
|
||||
): Q.Promise<any> {
|
||||
const deferred = Q.defer<any>();
|
||||
const notificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
@@ -660,7 +661,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
cassandraEndpoint: string,
|
||||
resourceId: string,
|
||||
query: string,
|
||||
explorer: ViewModels.Explorer
|
||||
explorer: Explorer
|
||||
): Q.Promise<any> {
|
||||
const deferred = Q.defer();
|
||||
const authType = window.authType;
|
||||
|
||||
@@ -20,8 +20,9 @@ import DiscardIcon from "../../../images/discard.svg";
|
||||
import DeleteIcon from "../../../images/delete.svg";
|
||||
import { QueryIterator, ItemDefinition, Resource, ConflictDefinition } from "@azure/cosmos";
|
||||
import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class ConflictsTab extends TabsBase implements ViewModels.ConflictsTab {
|
||||
export default class ConflictsTab extends TabsBase {
|
||||
public selectedConflictId: ko.Observable<ViewModels.ConflictId>;
|
||||
public selectedConflictContent: ViewModels.Editable<string>;
|
||||
public selectedConflictCurrent: ViewModels.Editable<string>;
|
||||
@@ -49,7 +50,7 @@ export default class ConflictsTab extends TabsBase implements ViewModels.Conflic
|
||||
public conflictIds: ko.ObservableArray<ViewModels.ConflictId>;
|
||||
|
||||
private _documentsIterator: MinimalQueryIterator;
|
||||
private _container: ViewModels.Explorer;
|
||||
private _container: Explorer;
|
||||
private _acceptButtonLabel: ko.Observable<string> = ko.observable("Save");
|
||||
protected _selfLink: string;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
const updateThroughputBeyondLimitWarningMessage: string = `
|
||||
You are about to request an increase in throughput beyond the pre-allocated capacity.
|
||||
@@ -47,8 +48,7 @@ const throughputApplyLongDelayMessage = (isAutoscale: boolean, throughput: numbe
|
||||
This operation will take 1-3 business days to complete. View the latest status in Notifications.<br />
|
||||
Database: ${databaseName}, ${currentThroughput(isAutoscale, throughput)}`;
|
||||
|
||||
export default class DatabaseSettingsTab extends TabsBase
|
||||
implements ViewModels.DatabaseSettingsTab, ViewModels.WaitsForTemplate {
|
||||
export default class DatabaseSettingsTab extends TabsBase implements ViewModels.WaitsForTemplate {
|
||||
// editables
|
||||
public isAutoPilotSelected: ViewModels.Editable<boolean>;
|
||||
public throughput: ViewModels.Editable<number>;
|
||||
@@ -94,7 +94,7 @@ export default class DatabaseSettingsTab extends TabsBase
|
||||
private _hasProvisioningTypeChanged: ko.Computed<boolean>;
|
||||
private _wasAutopilotOriginallySet: ko.Observable<boolean>;
|
||||
private _offerReplacePending: ko.Computed<boolean>;
|
||||
private container: ViewModels.Explorer;
|
||||
private container: Explorer;
|
||||
|
||||
constructor(options: ViewModels.TabOptions) {
|
||||
super(options);
|
||||
|
||||
@@ -25,6 +25,7 @@ import SynapseIcon from "../../../images/synapse-link.svg";
|
||||
import { extractPartitionKey, PartitionKeyDefinition, QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class DocumentsTab extends TabsBase implements ViewModels.DocumentsTab {
|
||||
public selectedDocumentId: ko.Observable<ViewModels.DocumentId>;
|
||||
@@ -957,7 +958,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
|
||||
);
|
||||
}
|
||||
|
||||
public static _createUploadButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
public static _createUploadButton(container: Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Upload Item";
|
||||
return {
|
||||
iconSrc: UploadIcon,
|
||||
|
||||
@@ -3,12 +3,13 @@ import { GalleryAndNotebookViewerComponentProps } from "../Controls/NotebookGall
|
||||
import { GalleryAndNotebookViewerComponentAdapter } from "../Controls/NotebookGallery/GalleryAndNotebookViewerComponentAdapter";
|
||||
import { GalleryTab as GalleryViewerTab, SortBy } from "../Controls/NotebookGallery/GalleryViewerComponent";
|
||||
import TabsBase from "./TabsBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
/**
|
||||
* Notebook gallery tab
|
||||
*/
|
||||
export default class GalleryTab extends TabsBase implements ViewModels.Tab {
|
||||
private container: ViewModels.Explorer;
|
||||
private container: Explorer;
|
||||
public galleryAndNotebookViewerComponentAdapter: GalleryAndNotebookViewerComponentAdapter;
|
||||
|
||||
constructor(options: ViewModels.GalleryTabOptions) {
|
||||
@@ -29,7 +30,7 @@ export default class GalleryTab extends TabsBase implements ViewModels.Tab {
|
||||
this.galleryAndNotebookViewerComponentAdapter = new GalleryAndNotebookViewerComponentAdapter(props);
|
||||
}
|
||||
|
||||
protected getContainer(): ViewModels.Explorer {
|
||||
protected getContainer(): Explorer {
|
||||
return this.container;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplo
|
||||
import { GraphAccessor, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer";
|
||||
import NewVertexIcon from "../../../images/NewVertex.svg";
|
||||
import StyleIcon from "../../../images/Style.svg";
|
||||
import GraphStylingPane from "../Panes/GraphStylingPane";
|
||||
import NewVertexPane from "../Panes/NewVertexPane";
|
||||
|
||||
export interface GraphIconMap {
|
||||
[key: string]: { data: string; format: string };
|
||||
@@ -41,8 +43,8 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
|
||||
private graphConfigUiData: ViewModels.GraphConfigUiData;
|
||||
private isFilterQueryLoading: ko.Observable<boolean>;
|
||||
private isValidQuery: ko.Observable<boolean>;
|
||||
private newVertexPane: ViewModels.NewVertexPane;
|
||||
private graphStylingPane: ViewModels.GraphStylingPane;
|
||||
private newVertexPane: NewVertexPane;
|
||||
private graphStylingPane: GraphStylingPane;
|
||||
private collectionPartitionKeyProperty: string;
|
||||
|
||||
constructor(options: ViewModels.GraphTabOptions) {
|
||||
|
||||
@@ -13,10 +13,11 @@ import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { HashMap } from "../../Common/HashMap";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class MongoShellTab extends TabsBase implements ViewModels.MongoShellTab {
|
||||
public url: ko.Computed<string>;
|
||||
private _container: ViewModels.Explorer;
|
||||
private _container: Explorer;
|
||||
private _runtimeEndpoint: string;
|
||||
private _logTraces: HashMap<number>;
|
||||
|
||||
|
||||
@@ -27,10 +27,11 @@ import { NotebookComponentAdapter } from "../Notebook/NotebookComponent/Notebook
|
||||
import { NotebookConfigurationUtils } from "../../Utils/NotebookConfigurationUtils";
|
||||
import { KernelSpecsDisplay, NotebookClientV2 } from "../Notebook/NotebookClientV2";
|
||||
import { config } from "../../Config";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
|
||||
private static clientManager: NotebookClientV2;
|
||||
private container: ViewModels.Explorer;
|
||||
private container: Explorer;
|
||||
public notebookPath: ko.Observable<string>;
|
||||
private selectedSparkPool: ko.Observable<string>;
|
||||
private notebookComponentAdapter: NotebookComponentAdapter;
|
||||
@@ -104,7 +105,7 @@ export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
|
||||
return await this.configureServiceEndpoints(this.notebookComponentAdapter.getCurrentKernelName());
|
||||
}
|
||||
|
||||
protected getContainer(): ViewModels.Explorer {
|
||||
protected getContainer(): Explorer {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
NotebookViewerComponentProps
|
||||
} from "../Controls/NotebookViewer/NotebookViewerComponent";
|
||||
import TabsBase from "./TabsBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
/**
|
||||
* Notebook Viewer tab
|
||||
@@ -29,7 +30,7 @@ class NotebookViewerComponentAdapter implements ReactAdapter {
|
||||
}
|
||||
|
||||
export default class NotebookViewerTab extends TabsBase implements ViewModels.Tab {
|
||||
private container: ViewModels.Explorer;
|
||||
private container: Explorer;
|
||||
public notebookUrl: string;
|
||||
|
||||
public notebookViewerComponentAdapter: NotebookViewerComponentAdapter;
|
||||
@@ -49,7 +50,7 @@ export default class NotebookViewerTab extends TabsBase implements ViewModels.Ta
|
||||
});
|
||||
}
|
||||
|
||||
protected getContainer(): ViewModels.Explorer {
|
||||
protected getContainer(): Explorer {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,22 @@ import * as ko from "knockout";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import Explorer from "../Explorer";
|
||||
import { CollectionStub, DatabaseStub } from "../../Explorer/OpenActionsStubs";
|
||||
import QueryTab from "./QueryTab";
|
||||
import { View } from "@nteract/data-explorer/lib/utilities/types";
|
||||
import { PartitionKey } from "../../Contracts/DataModels";
|
||||
|
||||
describe("Query Tab", () => {
|
||||
function getNewQueryTabForContainer(container: ViewModels.Explorer): ViewModels.QueryTab {
|
||||
const database: ViewModels.Database = new DatabaseStub({
|
||||
function getNewQueryTabForContainer(container: Explorer): ViewModels.QueryTab {
|
||||
const database = {
|
||||
container: container,
|
||||
id: ko.observable<string>("test"),
|
||||
isDatabaseShared: () => false
|
||||
});
|
||||
const collection: ViewModels.Collection = new CollectionStub({
|
||||
} as ViewModels.Database;
|
||||
const collection = {
|
||||
container: container,
|
||||
databaseId: "test",
|
||||
id: ko.observable<string>("test")
|
||||
});
|
||||
} as ViewModels.Collection;
|
||||
|
||||
return new QueryTab({
|
||||
tabKind: ViewModels.CollectionTabKind.Query,
|
||||
@@ -33,19 +34,12 @@ describe("Query Tab", () => {
|
||||
}
|
||||
|
||||
describe("shouldSetSystemPartitionKeyContainerPartitionKeyValueUndefined", () => {
|
||||
const collection: ViewModels.Collection = new CollectionStub({
|
||||
id: "withoutsystempk",
|
||||
const collection = {
|
||||
id: ko.observable<string>("withoutsystempk"),
|
||||
partitionKey: {
|
||||
systemKey: true
|
||||
}
|
||||
});
|
||||
|
||||
const collectionSystemPK: ViewModels.Collection = new CollectionStub({
|
||||
id: "withsystempk",
|
||||
partitionKey: {
|
||||
systemKey: true
|
||||
}
|
||||
});
|
||||
} as ViewModels.Collection;
|
||||
|
||||
it("no container with system pk, should not set partition key option", () => {
|
||||
const iteratorOptions = QueryTab.getIteratorOptions(collection);
|
||||
@@ -54,7 +48,7 @@ describe("Query Tab", () => {
|
||||
});
|
||||
|
||||
describe("isQueryMetricsEnabled()", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
@@ -74,7 +68,7 @@ describe("Query Tab", () => {
|
||||
});
|
||||
|
||||
describe("Save Queries command button", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
|
||||
@@ -115,7 +115,7 @@ export default class QueryTab extends TabsBase implements ViewModels.QueryTab, V
|
||||
};
|
||||
|
||||
this._isSaveQueriesEnabled = ko.computed<boolean>(() => {
|
||||
const container: ViewModels.Explorer = this.collection && this.collection.container;
|
||||
const container = this.collection && this.collection.container;
|
||||
return (container && (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph())) || false;
|
||||
});
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
||||
import AddEntityIcon from "../../../images/AddEntity.svg";
|
||||
import EditEntityIcon from "../../../images/Edit-entity.svg";
|
||||
import DeleteEntitiesIcon from "../../../images/DeleteEntities.svg";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
// Will act as table explorer class
|
||||
export default class QueryTablesTab extends TabsBase {
|
||||
@@ -31,7 +32,7 @@ export default class QueryTablesTab extends TabsBase {
|
||||
public deleteEntityButton: ViewModels.Button;
|
||||
public queryBuilderButton: ViewModels.Button;
|
||||
public queryTextButton: ViewModels.Button;
|
||||
public container: ViewModels.Explorer;
|
||||
public container: Explorer;
|
||||
|
||||
constructor(options: ViewModels.TabOptions) {
|
||||
super(options);
|
||||
|
||||
@@ -177,7 +177,7 @@ describe("Settings tab", () => {
|
||||
});
|
||||
|
||||
describe("Should update collection", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
@@ -259,7 +259,7 @@ describe("Settings tab", () => {
|
||||
});
|
||||
|
||||
describe("Get Conflict Resolution configuration from user", () => {
|
||||
let explorer: ViewModels.Explorer;
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
const ttlWarning: string = `
|
||||
The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application.
|
||||
@@ -124,7 +125,7 @@ enum ChangeFeedPolicyToggledState {
|
||||
On = "On"
|
||||
}
|
||||
|
||||
export default class SettingsTab extends TabsBase implements ViewModels.SettingsTab, ViewModels.WaitsForTemplate {
|
||||
export default class SettingsTab extends TabsBase implements ViewModels.WaitsForTemplate {
|
||||
public GEOGRAPHY: string = "Geography";
|
||||
public GEOMETRY: string = "Geometry";
|
||||
|
||||
@@ -218,7 +219,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.Settings
|
||||
public throughputModeRadioName: string;
|
||||
|
||||
private _offerReplacePending: ko.PureComputed<boolean>;
|
||||
private container: ViewModels.Explorer;
|
||||
private container: Explorer;
|
||||
private _wasAutopilotOriginallySet: ko.Observable<boolean>;
|
||||
private _isAutoPilotDirty: ko.Computed<boolean>;
|
||||
private _hasProvisioningTypeChanged: ko.Computed<boolean>;
|
||||
|
||||
@@ -2,12 +2,13 @@ import * as ko from "knockout";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import TabsBase from "./TabsBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
export default class SparkMasterTab extends TabsBase {
|
||||
public sparkMasterSrc: ko.Observable<string>;
|
||||
|
||||
private _clusterConnectionInfo: DataModels.SparkClusterConnectionInfo;
|
||||
private _container: ViewModels.Explorer;
|
||||
private _container: Explorer;
|
||||
|
||||
constructor(options: ViewModels.SparkMasterTabOptions) {
|
||||
super(options);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user