mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-24 19:31:36 +00:00
Compare commits
83 Commits
Remove-Exp
...
genericRig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ed4465885 | ||
|
|
af5d77d754 | ||
|
|
a52a156005 | ||
|
|
f9e8b5eaaa | ||
|
|
a6b82c8340 | ||
|
|
404b1fc0f1 | ||
|
|
d7c62ac7f1 | ||
|
|
8e6d274b11 | ||
|
|
2d506f0312 | ||
|
|
d76aaca0dd | ||
|
|
14e58e5519 | ||
|
|
2f6dbd83f3 | ||
|
|
0a6c7c0ff9 | ||
|
|
66281447df | ||
|
|
c5f76ac2a9 | ||
|
|
861042c27e | ||
|
|
4ed8fe9e7d | ||
|
|
4c506da7b9 | ||
|
|
a81b1a40a3 | ||
|
|
9d5c9d6296 | ||
|
|
7efa8ca58f | ||
|
|
487fbf2072 | ||
|
|
aa308b3e4d | ||
|
|
db227084be | ||
|
|
ead93b9fa5 | ||
|
|
d62baf327b | ||
|
|
78eafe1aec | ||
|
|
a91ea6c1e4 | ||
|
|
5606ef3266 | ||
|
|
503f044a70 | ||
|
|
88491ba6a9 | ||
|
|
fc83484b6c | ||
|
|
23223cfb23 | ||
|
|
bd47e5ed49 | ||
|
|
8c05ac740c | ||
|
|
fdd12b41c4 | ||
|
|
d1d28885d0 | ||
|
|
aab624e241 | ||
|
|
181b53c858 | ||
|
|
1fdb339fbf | ||
|
|
b7579d5c8b | ||
|
|
e91145234f | ||
|
|
7c4bc9e0c0 | ||
|
|
40d71d3d7a | ||
|
|
0c3f8bd625 | ||
|
|
038f3ee684 | ||
|
|
4efacace16 | ||
|
|
9878bf0d5e | ||
|
|
5e0523c7d9 | ||
|
|
9d0bc86197 | ||
|
|
6bdf1c7f7c | ||
|
|
f048f21def | ||
|
|
38ffa6a003 | ||
|
|
7902df4d16 | ||
|
|
e701dcc881 | ||
|
|
3a6c7f9f94 | ||
|
|
7b5b752d9c | ||
|
|
a0d22960ff | ||
|
|
531df811da | ||
|
|
5a019eb431 | ||
|
|
4c6650760b | ||
|
|
8f3cb7282b | ||
|
|
154db1dcd5 | ||
|
|
e8b79d6260 | ||
|
|
10c4dd0f19 | ||
|
|
5cf16d01b5 | ||
|
|
127784abdd | ||
|
|
c7b9ff6794 | ||
|
|
71e7ad4547 | ||
|
|
0b1ac8f445 | ||
|
|
96305f50f8 | ||
|
|
67062c18aa | ||
|
|
ab283cb8ff | ||
|
|
045a28b7a4 | ||
|
|
b7c911d19a | ||
|
|
5323f6ca4b | ||
|
|
3e011f939d | ||
|
|
10961a2f9f | ||
|
|
ba25eea41e | ||
|
|
e17fe25292 | ||
|
|
9494c9cd55 | ||
|
|
8f0bb1add8 | ||
|
|
5c9ab15b3a |
@@ -1,11 +1,11 @@
|
|||||||
**/node_modules/
|
**/node_modules/
|
||||||
|
src/**/__mocks__/**/*
|
||||||
dist/
|
dist/
|
||||||
Contracts/
|
Contracts/
|
||||||
src/Api/Apis.ts
|
src/Api/Apis.ts
|
||||||
src/AuthType.ts
|
src/AuthType.ts
|
||||||
src/Bindings/BindingHandlersRegisterer.ts
|
src/Bindings/BindingHandlersRegisterer.ts
|
||||||
src/Bindings/ReactBindingHandler.ts
|
src/Bindings/ReactBindingHandler.ts
|
||||||
src/Common/ArrayHashMap.ts
|
|
||||||
src/Common/Constants.ts
|
src/Common/Constants.ts
|
||||||
src/Common/CosmosClient.test.ts
|
src/Common/CosmosClient.test.ts
|
||||||
src/Common/CosmosClient.ts
|
src/Common/CosmosClient.ts
|
||||||
@@ -13,15 +13,12 @@ src/Common/DataAccessUtilityBase.test.ts
|
|||||||
src/Common/DataAccessUtilityBase.ts
|
src/Common/DataAccessUtilityBase.ts
|
||||||
src/Common/EditableUtility.ts
|
src/Common/EditableUtility.ts
|
||||||
src/Common/HashMap.test.ts
|
src/Common/HashMap.test.ts
|
||||||
src/Common/HashMap.ts
|
|
||||||
src/Common/Logger.test.ts
|
src/Common/Logger.test.ts
|
||||||
src/Common/MessageHandler.test.ts
|
src/Common/MessageHandler.test.ts
|
||||||
src/Common/MessageHandler.ts
|
src/Common/MessageHandler.ts
|
||||||
src/Common/MongoProxyClient.test.ts
|
src/Common/MongoProxyClient.test.ts
|
||||||
src/Common/MongoUtility.ts
|
src/Common/MongoUtility.ts
|
||||||
src/Common/NotificationsClientBase.ts
|
src/Common/NotificationsClientBase.ts
|
||||||
src/Common/ObjectCache.test.ts
|
|
||||||
src/Common/ObjectCache.ts
|
|
||||||
src/Common/QueriesClient.ts
|
src/Common/QueriesClient.ts
|
||||||
src/Common/Splitter.ts
|
src/Common/Splitter.ts
|
||||||
src/Config.ts
|
src/Config.ts
|
||||||
@@ -57,7 +54,6 @@ src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts
|
|||||||
src/Explorer/Controls/InputTypeahead/InputTypeahead.ts
|
src/Explorer/Controls/InputTypeahead/InputTypeahead.ts
|
||||||
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
|
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
|
||||||
src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts
|
src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts
|
||||||
src/Explorer/Controls/ThroughputInput/ThroughputInput.test.ts
|
|
||||||
src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts
|
src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts
|
||||||
src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts
|
src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts
|
||||||
src/Explorer/Controls/Toolbar/IToolbarAction.ts
|
src/Explorer/Controls/Toolbar/IToolbarAction.ts
|
||||||
@@ -88,8 +84,8 @@ src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
|
|||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
||||||
src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
# src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
||||||
src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
# src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
||||||
|
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
||||||
@@ -112,24 +108,19 @@ src/Explorer/Notebook/NotebookUtil.ts
|
|||||||
src/Explorer/OpenActions.test.ts
|
src/Explorer/OpenActions.test.ts
|
||||||
src/Explorer/OpenActions.ts
|
src/Explorer/OpenActions.ts
|
||||||
src/Explorer/OpenActionsStubs.ts
|
src/Explorer/OpenActionsStubs.ts
|
||||||
src/Explorer/Panes/AddCollectionPane.test.ts
|
|
||||||
src/Explorer/Panes/AddCollectionPane.ts
|
|
||||||
src/Explorer/Panes/AddDatabasePane.test.ts
|
|
||||||
src/Explorer/Panes/AddDatabasePane.ts
|
src/Explorer/Panes/AddDatabasePane.ts
|
||||||
|
src/Explorer/Panes/AddDatabasePane.test.ts
|
||||||
src/Explorer/Panes/BrowseQueriesPane.ts
|
src/Explorer/Panes/BrowseQueriesPane.ts
|
||||||
src/Explorer/Panes/CassandraAddCollectionPane.ts
|
src/Explorer/Panes/CassandraAddCollectionPane.ts
|
||||||
src/Explorer/Panes/ContextualPaneBase.ts
|
src/Explorer/Panes/ContextualPaneBase.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
||||||
src/Explorer/Panes/GraphStylingPane.ts
|
# src/Explorer/Panes/GraphStylingPane.ts
|
||||||
# src/Explorer/Panes/NewVertexPane.ts
|
# src/Explorer/Panes/NewVertexPane.ts
|
||||||
src/Explorer/Panes/PaneComponents.ts
|
src/Explorer/Panes/PaneComponents.ts
|
||||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||||
src/Explorer/Panes/StringInputPane.ts
|
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||||
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
|
||||||
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
|
||||||
src/Explorer/Panes/Tables/TableEntityPane.ts
|
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
parser: "@typescript-eslint/parser",
|
parser: "@typescript-eslint/parser",
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
project: ["./tsconfig.json", "./tsconfig.test.json"],
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
jsx: true,
|
jsx: true,
|
||||||
},
|
},
|
||||||
@@ -35,6 +36,7 @@ module.exports = {
|
|||||||
rules: {
|
rules: {
|
||||||
"no-console": ["error", { allow: ["error", "warn", "dir"] }],
|
"no-console": ["error", { allow: ["error", "warn", "dir"] }],
|
||||||
curly: "error",
|
curly: "error",
|
||||||
|
"@typescript-eslint/switch-exhaustiveness-check": "error",
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
"@typescript-eslint/no-unused-vars": "error",
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
"@typescript-eslint/no-extraneous-class": "error",
|
||||||
"no-null/no-null": "error",
|
"no-null/no-null": "error",
|
||||||
|
|||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -138,8 +138,10 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
test-file:
|
test-file:
|
||||||
- ./test/cassandra/container.spec.ts
|
- ./test/cassandra/container.spec.ts
|
||||||
|
- ./test/graph/container.spec.ts
|
||||||
- ./test/sql/container.spec.ts
|
- ./test/sql/container.spec.ts
|
||||||
- ./test/mongo/container.spec.ts
|
- ./test/mongo/container.spec.ts
|
||||||
|
- ./test/mongo/container32.spec.ts
|
||||||
- ./test/selfServe/selfServeExample.spec.ts
|
- ./test/selfServe/selfServeExample.spec.ts
|
||||||
- ./test/notebooks/upload.spec.ts
|
- ./test/notebooks/upload.spec.ts
|
||||||
- ./test/sql/resourceToken.spec.ts
|
- ./test/sql/resourceToken.spec.ts
|
||||||
|
|||||||
@@ -188,7 +188,3 @@ Cosmos Explorer has been under constant development for over 5 years. As a resul
|
|||||||
✅ DO
|
✅ DO
|
||||||
|
|
||||||
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
||||||
- Support IE11
|
|
||||||
- In practice, this should not need to be considered as part of a normal development workflow
|
|
||||||
- Polyfills and transpilation are already provided by our engineering systems.
|
|
||||||
- This requirement will be removed on March 30th, 2021 when Azure drops IE11 support.
|
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ module.exports = {
|
|||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
|
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
|
||||||
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
|
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
|
||||||
"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1", // https://github.com/OfficeDev/office-ui-fabric-react/wiki/Fabric-6-Release-Notes
|
"@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes
|
||||||
|
"monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor",
|
||||||
"^dnd-core$": "dnd-core/dist/cjs",
|
"^dnd-core$": "dnd-core/dist/cjs",
|
||||||
"^react-dnd$": "react-dnd/dist/cjs",
|
"^react-dnd$": "react-dnd/dist/cjs",
|
||||||
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",
|
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: wf_segoe-ui_normal;
|
font-family: wf_segoe-ui_normal;
|
||||||
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff");
|
src: local("Segoe UI"), url("../../fonts/segoe-ui/west-european/normal/latest.woff");
|
||||||
}
|
}
|
||||||
|
|
||||||
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||||
|
|||||||
@@ -1757,7 +1757,7 @@ input::-webkit-calendar-picker-indicator {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contextual-pane .paneMainContent {
|
.paneMainContent {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-left: 34px;
|
padding-left: 34px;
|
||||||
padding-right: 34px;
|
padding-right: 34px;
|
||||||
@@ -2099,7 +2099,7 @@ a:link {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: auto;
|
overflow-y: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3085,3 +3085,7 @@ settings-pane {
|
|||||||
padding-left: @SmallSpace;
|
padding-left: @SmallSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hiddenMain {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
.resourceTree {
|
.resourceTree {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 20%;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
.main {
|
.main {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
1062
package-lock.json
generated
1062
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -11,6 +11,7 @@
|
|||||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||||
"@babel/plugin-proposal-class-properties": "7.12.1",
|
"@babel/plugin-proposal-class-properties": "7.12.1",
|
||||||
"@babel/plugin-proposal-decorators": "7.12.12",
|
"@babel/plugin-proposal-decorators": "7.12.12",
|
||||||
|
"@fluentui/react": "8.14.3",
|
||||||
"@jupyterlab/services": "6.0.2",
|
"@jupyterlab/services": "6.0.2",
|
||||||
"@jupyterlab/terminal": "3.0.3",
|
"@jupyterlab/terminal": "3.0.3",
|
||||||
"@microsoft/applicationinsights-web": "2.6.1",
|
"@microsoft/applicationinsights-web": "2.6.1",
|
||||||
@@ -42,8 +43,6 @@
|
|||||||
"@testing-library/jest-dom": "5.11.9",
|
"@testing-library/jest-dom": "5.11.9",
|
||||||
"@types/mkdirp": "1.0.1",
|
"@types/mkdirp": "1.0.1",
|
||||||
"@types/node-fetch": "2.5.7",
|
"@types/node-fetch": "2.5.7",
|
||||||
"@uifabric/react-cards": "0.109.110",
|
|
||||||
"@uifabric/styling": "7.13.7",
|
|
||||||
"applicationinsights": "1.8.0",
|
"applicationinsights": "1.8.0",
|
||||||
"bootstrap": "3.4.1",
|
"bootstrap": "3.4.1",
|
||||||
"canvas": "file:./canvas",
|
"canvas": "file:./canvas",
|
||||||
@@ -57,6 +56,7 @@
|
|||||||
"datatables.net-dt": "1.10.19",
|
"datatables.net-dt": "1.10.19",
|
||||||
"date-fns": "1.29.0",
|
"date-fns": "1.29.0",
|
||||||
"dayjs": "1.8.19",
|
"dayjs": "1.8.19",
|
||||||
|
"dom-to-image": "2.6.0",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
"eslint-plugin-jest": "23.13.2",
|
"eslint-plugin-jest": "23.13.2",
|
||||||
"eslint-plugin-react": "7.20.0",
|
"eslint-plugin-react": "7.20.0",
|
||||||
@@ -76,7 +76,6 @@
|
|||||||
"monaco-editor": "0.18.1",
|
"monaco-editor": "0.18.1",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
"msal": "1.4.4",
|
"msal": "1.4.4",
|
||||||
"office-ui-fabric-react": "7.164.2",
|
|
||||||
"p-retry": "4.2.0",
|
"p-retry": "4.2.0",
|
||||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||||
"post-robot": "10.0.42",
|
"post-robot": "10.0.42",
|
||||||
@@ -99,7 +98,8 @@
|
|||||||
"swr": "0.4.0",
|
"swr": "0.4.0",
|
||||||
"terser-webpack-plugin": "3.1.0",
|
"terser-webpack-plugin": "3.1.0",
|
||||||
"underscore": "1.9.1",
|
"underscore": "1.9.1",
|
||||||
"utility-types": "3.10.0"
|
"utility-types": "3.10.0",
|
||||||
|
"zustand": "3.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.9.0",
|
"@babel/core": "7.9.0",
|
||||||
@@ -111,6 +111,7 @@
|
|||||||
"@types/codemirror": "0.0.56",
|
"@types/codemirror": "0.0.56",
|
||||||
"@types/crossroads": "0.0.30",
|
"@types/crossroads": "0.0.30",
|
||||||
"@types/d3": "5.9.2",
|
"@types/d3": "5.9.2",
|
||||||
|
"@types/dom-to-image": "2.6.2",
|
||||||
"@types/enzyme": "3.10.7",
|
"@types/enzyme": "3.10.7",
|
||||||
"@types/enzyme-adapter-react-16": "1.0.6",
|
"@types/enzyme-adapter-react-16": "1.0.6",
|
||||||
"@types/hasher": "0.0.31",
|
"@types/hasher": "0.0.31",
|
||||||
@@ -128,8 +129,8 @@
|
|||||||
"@types/sinon": "2.3.3",
|
"@types/sinon": "2.3.3",
|
||||||
"@types/styled-components": "5.1.1",
|
"@types/styled-components": "5.1.1",
|
||||||
"@types/underscore": "1.7.36",
|
"@types/underscore": "1.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "4.0.1",
|
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||||
"@typescript-eslint/parser": "4.0.1",
|
"@typescript-eslint/parser": "4.22.0",
|
||||||
"babel-jest": "24.9.0",
|
"babel-jest": "24.9.0",
|
||||||
"babel-loader": "8.1.0",
|
"babel-loader": "8.1.0",
|
||||||
"buffer": "5.1.0",
|
"buffer": "5.1.0",
|
||||||
@@ -176,7 +177,7 @@
|
|||||||
"typescript": "4.2.4",
|
"typescript": "4.2.4",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"wait-on": "4.0.2",
|
"wait-on": "4.0.2",
|
||||||
"webpack": "4.43.0",
|
"webpack": "4.46.0",
|
||||||
"webpack-bundle-analyzer": "3.6.1",
|
"webpack-bundle-analyzer": "3.6.1",
|
||||||
"webpack-cli": "3.3.10",
|
"webpack-cli": "3.3.10",
|
||||||
"webpack-dev-server": "3.11.0"
|
"webpack-dev-server": "3.11.0"
|
||||||
@@ -191,7 +192,7 @@
|
|||||||
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
||||||
"copyToConsumers": "node copyToConsumers",
|
"copyToConsumers": "node copyToConsumers",
|
||||||
"test": "rimraf coverage && jest",
|
"test": "rimraf coverage && jest",
|
||||||
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles",
|
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
|
||||||
"watch": "npm run start",
|
"watch": "npm run start",
|
||||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||||
"build:ase": "gulp build:ase",
|
"build:ase": "gulp build:ase",
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ export interface ReactAdapter {
|
|||||||
export class Registerer {
|
export class Registerer {
|
||||||
public static register(): void {
|
public static register(): void {
|
||||||
ko.bindingHandlers.react = {
|
ko.bindingHandlers.react = {
|
||||||
init: (
|
init: (element: any, wrappedValueAccessor: () => any) => {
|
||||||
element: any,
|
|
||||||
wrappedValueAccessor: () => any,
|
|
||||||
allBindings?: ko.AllBindings,
|
|
||||||
viewModel?: any,
|
|
||||||
bindingContext?: ko.BindingContext
|
|
||||||
) => {
|
|
||||||
const adapter: ReactAdapter = wrappedValueAccessor();
|
const adapter: ReactAdapter = wrappedValueAccessor();
|
||||||
|
|
||||||
if (adapter.setElement) {
|
if (adapter.setElement) {
|
||||||
|
|||||||
15
src/CellOutputViewer/CellOutputViewer.less
Normal file
15
src/CellOutputViewer/CellOutputViewer.less
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.schema-analyzer-cell-outputs {
|
||||||
|
padding: 10px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mimic FluentUI8's DocumentCard style
|
||||||
|
.schema-analyzer-cell-output {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 14px 20px;
|
||||||
|
border: 1px solid rgb(237, 235, 233);
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-analyzer-cell-output:hover {
|
||||||
|
border-color: rgb(200, 198, 196);
|
||||||
|
box-shadow: inset 0 0 0 1px rgb(200, 198, 196)
|
||||||
|
}
|
||||||
@@ -9,15 +9,22 @@ import postRobot from "post-robot";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work
|
import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work
|
||||||
|
import { SnapshotRequest } from "../Explorer/Notebook/NotebookComponent/types";
|
||||||
import "../Explorer/Notebook/NotebookRenderer/base.css";
|
import "../Explorer/Notebook/NotebookRenderer/base.css";
|
||||||
import "../Explorer/Notebook/NotebookRenderer/default.css";
|
import "../Explorer/Notebook/NotebookRenderer/default.css";
|
||||||
|
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
|
||||||
|
import "./CellOutputViewer.less";
|
||||||
import { TransformMedia } from "./TransformMedia";
|
import { TransformMedia } from "./TransformMedia";
|
||||||
|
|
||||||
|
export interface SnapshotResponse {
|
||||||
|
imageSrc: string;
|
||||||
|
requestId: string;
|
||||||
|
}
|
||||||
export interface CellOutputViewerProps {
|
export interface CellOutputViewerProps {
|
||||||
id: string;
|
id: string;
|
||||||
contentRef: ContentRef;
|
contentRef: ContentRef;
|
||||||
hidden: boolean;
|
outputsContainerClassName: string;
|
||||||
expanded: boolean;
|
outputClassName: string;
|
||||||
outputs: OnDiskOutput[];
|
outputs: OnDiskOutput[];
|
||||||
onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void;
|
onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void;
|
||||||
}
|
}
|
||||||
@@ -34,27 +41,26 @@ const onInit = async () => {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const props = (event as any).data as CellOutputViewerProps;
|
const props = (event as any).data as CellOutputViewerProps;
|
||||||
const outputs = (
|
const outputs = (
|
||||||
<div
|
<div data-iframe-height className={props.outputsContainerClassName}>
|
||||||
data-iframe-height
|
|
||||||
className={`nteract-cell-outputs ${props.hidden ? "hidden" : ""} ${props.expanded ? "expanded" : ""}`}
|
|
||||||
>
|
|
||||||
{props.outputs?.map((output, index) => (
|
{props.outputs?.map((output, index) => (
|
||||||
<Output output={createImmutableOutput(output)} key={index}>
|
<div className={props.outputClassName} key={index}>
|
||||||
<TransformMedia
|
<Output output={createImmutableOutput(output)} key={index}>
|
||||||
output_type={"display_data"}
|
<TransformMedia
|
||||||
id={props.id}
|
output_type={"display_data"}
|
||||||
contentRef={props.contentRef}
|
id={props.id}
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
contentRef={props.contentRef}
|
||||||
/>
|
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
||||||
<TransformMedia
|
/>
|
||||||
output_type={"execute_result"}
|
<TransformMedia
|
||||||
id={props.id}
|
output_type={"execute_result"}
|
||||||
contentRef={props.contentRef}
|
id={props.id}
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
contentRef={props.contentRef}
|
||||||
/>
|
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
||||||
<KernelOutputError />
|
/>
|
||||||
<StreamText />
|
<KernelOutputError />
|
||||||
</Output>
|
<StreamText />
|
||||||
|
</Output>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -62,6 +68,36 @@ const onInit = async () => {
|
|||||||
ReactDOM.render(outputs, document.getElementById("cellOutput"));
|
ReactDOM.render(outputs, document.getElementById("cellOutput"));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
postRobot.on(
|
||||||
|
"snapshotRequest",
|
||||||
|
{
|
||||||
|
window: window.parent,
|
||||||
|
domain: window.location.origin,
|
||||||
|
},
|
||||||
|
async (event): Promise<SnapshotResponse> => {
|
||||||
|
const topNode = document.getElementById("cellOutput");
|
||||||
|
if (!topNode) {
|
||||||
|
const errorMsg = "No top node to snapshot";
|
||||||
|
return Promise.reject(new Error(errorMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typescript definition for event is wrong. So read props by casting to <any>
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const snapshotRequest = (event as any).data as SnapshotRequest;
|
||||||
|
const result = await NotebookUtil.takeScreenshotDomToImage(
|
||||||
|
topNode,
|
||||||
|
snapshotRequest.aspectRatio,
|
||||||
|
undefined,
|
||||||
|
snapshotRequest.downloadFilename
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
imageSrc: result.imageSrc,
|
||||||
|
requestId: snapshotRequest.requestId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Entry point
|
// Entry point
|
||||||
|
|||||||
@@ -1,49 +1,9 @@
|
|||||||
import { HashMap } from "./HashMap";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash map of arrays which allows to:
|
* Hash map of arrays which allows to:
|
||||||
* - push an item by key: add to array and create array if needed
|
* - push an item by key: add to array and create array if needed
|
||||||
* - remove item by key: remove from array and delete array if needed
|
* - remove item by key: remove from array and delete array if needed
|
||||||
*/
|
*/
|
||||||
|
export class ArrayHashMap<T> extends Map<string, T[]> {
|
||||||
export class ArrayHashMap<T> {
|
|
||||||
private store: HashMap<T[]>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.store = new HashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public has(key: string): boolean {
|
|
||||||
return this.store.has(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: string): T[] {
|
|
||||||
return this.store.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public size(): number {
|
|
||||||
return this.store.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(): void {
|
|
||||||
this.store.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public keys(): string[] {
|
|
||||||
return this.store.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(key: string): boolean {
|
|
||||||
return this.store.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(key: string, iteratorFct: (value: T) => void) {
|
|
||||||
const values = this.store.get(key);
|
|
||||||
if (values) {
|
|
||||||
values.forEach((value) => iteratorFct(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item into array.
|
* Insert item into array.
|
||||||
* If no array, create one.
|
* If no array, create one.
|
||||||
@@ -52,16 +12,8 @@ export class ArrayHashMap<T> {
|
|||||||
* @param item
|
* @param item
|
||||||
*/
|
*/
|
||||||
public push(key: string, item: T): void {
|
public push(key: string, item: T): void {
|
||||||
let itemsArray: T[] = this.store.get(key);
|
const array = this.get(key);
|
||||||
if (!itemsArray) {
|
array ? array.includes(item) || array.push(item) : this.set(key, [item]);
|
||||||
itemsArray = [item];
|
|
||||||
this.store.set(key, itemsArray);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemsArray.indexOf(item) === -1) {
|
|
||||||
itemsArray.push(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,18 +22,11 @@ export class ArrayHashMap<T> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param itemToRemove
|
* @param itemToRemove
|
||||||
*/
|
*/
|
||||||
public remove(key: string, itemToRemove: T) {
|
public remove(key: string, itemToRemove: T): void {
|
||||||
if (!this.store.has(key)) {
|
const array = this.get(key);
|
||||||
return;
|
if (array) {
|
||||||
}
|
const remaining = array.filter((item) => item !== itemToRemove);
|
||||||
|
remaining.length ? this.set(key, remaining) : this.delete(key);
|
||||||
const itemsArray = this.store.get(key);
|
|
||||||
const index = itemsArray.indexOf(itemToRemove);
|
|
||||||
if (index >= 0) {
|
|
||||||
itemsArray.splice(index, 1);
|
|
||||||
if (itemsArray.length === 0) {
|
|
||||||
this.store.delete(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/Common/CollapsedResourceTree.tsx
Normal file
35
src/Common/CollapsedResourceTree.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { FunctionComponent } from "react";
|
||||||
|
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
|
||||||
|
|
||||||
|
export interface CollapsedResourceTreeProps {
|
||||||
|
toggleLeftPaneExpanded: () => void;
|
||||||
|
isLeftPaneExpanded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps> = ({
|
||||||
|
toggleLeftPaneExpanded,
|
||||||
|
isLeftPaneExpanded,
|
||||||
|
}: CollapsedResourceTreeProps): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
|
||||||
|
<div className="main-nav nav">
|
||||||
|
<ul className="nav">
|
||||||
|
<li
|
||||||
|
className="resourceTreeCollapse"
|
||||||
|
id="collapseToggleLeftPaneButton"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label="Expand Tree"
|
||||||
|
>
|
||||||
|
<span className="leftarrowCollapsed" onClick={toggleLeftPaneExpanded}>
|
||||||
|
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
|
||||||
|
</span>
|
||||||
|
<span className="collectionCollapsed" onClick={toggleLeftPaneExpanded}>
|
||||||
|
<span data-bind="text: collectionTitle" />
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -65,28 +65,18 @@ export class ClientDefaults {
|
|||||||
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
|
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AccountKind {
|
export enum AccountKind {
|
||||||
public static DocumentDB: string = "DocumentDB";
|
DocumentDB = "DocumentDB",
|
||||||
public static MongoDB: string = "MongoDB";
|
MongoDB = "MongoDB",
|
||||||
public static Parse: string = "Parse";
|
Parse = "Parse",
|
||||||
public static GlobalDocumentDB: string = "GlobalDocumentDB";
|
GlobalDocumentDB = "GlobalDocumentDB",
|
||||||
public static Default: string = AccountKind.DocumentDB;
|
Default = "DocumentDB",
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CorrelationBackend {
|
export class CorrelationBackend {
|
||||||
public static Url: string = "https://aka.ms/cosmosdbanalytics";
|
public static Url: string = "https://aka.ms/cosmosdbanalytics";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultAccountExperience {
|
|
||||||
public static DocumentDB: string = "DocumentDB";
|
|
||||||
public static Graph: string = "Graph";
|
|
||||||
public static MongoDB: string = "MongoDB";
|
|
||||||
public static ApiForMongoDB: string = "Azure Cosmos DB for MongoDB API";
|
|
||||||
public static Table: string = "Table";
|
|
||||||
public static Cassandra: string = "Cassandra";
|
|
||||||
public static Default: string = DefaultAccountExperience.DocumentDB;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CapabilityNames {
|
export class CapabilityNames {
|
||||||
public static EnableTable: string = "EnableTable";
|
public static EnableTable: string = "EnableTable";
|
||||||
public static EnableGremlin: string = "EnableGremlin";
|
public static EnableGremlin: string = "EnableGremlin";
|
||||||
@@ -104,6 +94,7 @@ export class Flights {
|
|||||||
public static readonly MongoIndexEditor = "mongoindexeditor";
|
public static readonly MongoIndexEditor = "mongoindexeditor";
|
||||||
public static readonly MongoIndexing = "mongoindexing";
|
public static readonly MongoIndexing = "mongoindexing";
|
||||||
public static readonly AutoscaleTest = "autoscaletest";
|
public static readonly AutoscaleTest = "autoscaletest";
|
||||||
|
public static readonly SchemaAnalyzer = "schemaanalyzer";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AfecFeatures {
|
export class AfecFeatures {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ResourceType } from "@azure/cosmos/dist-esm/common/constants";
|
import { ResourceType } from "@azure/cosmos/dist-esm/common/constants";
|
||||||
import { configContext, Platform, updateConfigContext, resetConfigContext } from "../ConfigContext";
|
import { Platform, resetConfigContext, updateConfigContext } from "../ConfigContext";
|
||||||
import { updateUserContext } from "../UserContext";
|
import { updateUserContext } from "../UserContext";
|
||||||
import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient";
|
import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient";
|
||||||
|
|
||||||
@@ -91,7 +91,6 @@ describe("endpoint", () => {
|
|||||||
location: "foo",
|
location: "foo",
|
||||||
type: "foo",
|
type: "foo",
|
||||||
kind: "foo",
|
kind: "foo",
|
||||||
tags: [],
|
|
||||||
properties: {
|
properties: {
|
||||||
documentEndpoint: "bar",
|
documentEndpoint: "bar",
|
||||||
gremlinEndpoint: "foo",
|
gremlinEndpoint: "foo",
|
||||||
|
|||||||
@@ -43,12 +43,7 @@ export const endpoint = () => {
|
|||||||
const location = _global.parent ? _global.parent.location : _global.location;
|
const location = _global.parent ? _global.parent.location : _global.location;
|
||||||
return configContext.EMULATOR_ENDPOINT || location.origin;
|
return configContext.EMULATOR_ENDPOINT || location.origin;
|
||||||
}
|
}
|
||||||
return (
|
return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
|
||||||
userContext.endpoint ||
|
|
||||||
(userContext.databaseAccount &&
|
|
||||||
userContext.databaseAccount.properties &&
|
|
||||||
userContext.databaseAccount.properties.documentEndpoint)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
export const getEntityName = (): string => {
|
export const getEntityName = (): string => {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return "document";
|
return "document";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DatePicker, TextField } from "office-ui-fabric-react";
|
import { DatePicker, TextField } from "@fluentui/react";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
export interface TableEntityProps {
|
export interface TableEntityProps {
|
||||||
@@ -6,6 +6,7 @@ export interface TableEntityProps {
|
|||||||
entityValuePlaceholder: string;
|
entityValuePlaceholder: string;
|
||||||
entityValue: string | Date;
|
entityValue: string | Date;
|
||||||
isEntityTypeDate: boolean;
|
isEntityTypeDate: boolean;
|
||||||
|
isEntityValueDisable?: boolean;
|
||||||
entityTimeValue: string;
|
entityTimeValue: string;
|
||||||
entityValueType: string;
|
entityValueType: string;
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
||||||
@@ -22,6 +23,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
entityValueType,
|
entityValueType,
|
||||||
onEntityValueChange,
|
onEntityValueChange,
|
||||||
onSelectDate,
|
onSelectDate,
|
||||||
|
isEntityValueDisable,
|
||||||
onEntityTimeValueChange,
|
onEntityTimeValueChange,
|
||||||
}: TableEntityProps): JSX.Element => {
|
}: TableEntityProps): JSX.Element => {
|
||||||
if (isEntityTypeDate) {
|
if (isEntityTypeDate) {
|
||||||
@@ -33,6 +35,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
value={entityValue && new Date(entityValue)}
|
value={entityValue && new Date(entityValue)}
|
||||||
ariaLabel={entityValuePlaceholder}
|
ariaLabel={entityValuePlaceholder}
|
||||||
onSelectDate={onSelectDate}
|
onSelectDate={onSelectDate}
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={entityValueLabel && entityValueLabel}
|
label={entityValueLabel && entityValueLabel}
|
||||||
@@ -41,6 +44,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
type="time"
|
type="time"
|
||||||
value={entityTimeValue}
|
value={entityTimeValue}
|
||||||
onChange={onEntityTimeValueChange}
|
onChange={onEntityTimeValueChange}
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -52,6 +56,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
className="addEntityTextField"
|
className="addEntityTextField"
|
||||||
id="entityValueId"
|
id="entityValueId"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
type={entityValueType}
|
type={entityValueType}
|
||||||
placeholder={entityValuePlaceholder}
|
placeholder={entityValuePlaceholder}
|
||||||
value={typeof entityValue === "string" && entityValue}
|
value={typeof entityValue === "string" && entityValue}
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import { HashMap } from "./HashMap";
|
|
||||||
|
|
||||||
describe("HashMap", () => {
|
|
||||||
it("should test if key/val exists", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 123);
|
|
||||||
|
|
||||||
expect(map.has("a")).toBe(true);
|
|
||||||
expect(map.has("b")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should get object back", () => {
|
|
||||||
const map = new HashMap<string>();
|
|
||||||
map.set("a", "123");
|
|
||||||
map.set("a", "456");
|
|
||||||
|
|
||||||
expect(map.get("a")).toBe("456");
|
|
||||||
expect(map.get("a")).not.toBe("123");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the right size", () => {
|
|
||||||
const map = new HashMap<string>();
|
|
||||||
map.set("a", "123");
|
|
||||||
map.set("b", "456");
|
|
||||||
|
|
||||||
expect(map.size()).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be iterable", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 10);
|
|
||||||
map.set("c", 100);
|
|
||||||
map.set("d", 1000);
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
map.forEach((key: string, value: number) => {
|
|
||||||
i += value;
|
|
||||||
});
|
|
||||||
expect(i).toBe(1111);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be deleted", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 10);
|
|
||||||
|
|
||||||
expect(map.delete("a")).toBe(true);
|
|
||||||
expect(map.delete("c")).toBe(false);
|
|
||||||
expect(map.has("a")).toBe(false);
|
|
||||||
expect(map.has("b")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should clear", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.clear();
|
|
||||||
expect(map.size()).toBe(0);
|
|
||||||
expect(map.has("a")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return all keys", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 1);
|
|
||||||
expect(map.keys()).toEqual(["a", "b"]);
|
|
||||||
map.clear();
|
|
||||||
expect(map.keys().length).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* Simple hashmap implementation that doesn't rely on ES6 Map nor polyfills
|
|
||||||
*/
|
|
||||||
export class HashMap<T> {
|
|
||||||
constructor(private container: { [key: string]: T } = {}) {}
|
|
||||||
|
|
||||||
public has(key: string): boolean {
|
|
||||||
return this.container.hasOwnProperty(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(key: string, value: T): void {
|
|
||||||
this.container[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: string): T {
|
|
||||||
return this.container[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public size(): number {
|
|
||||||
return Object.keys(this.container).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(key: string): boolean {
|
|
||||||
if (this.has(key)) {
|
|
||||||
delete this.container[key];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(): void {
|
|
||||||
this.container = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public keys(): string[] {
|
|
||||||
return Object.keys(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(iteratorFct: (key: string, value: T) => void) {
|
|
||||||
for (const k in this.container) {
|
|
||||||
iteratorFct(k, this.container[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -61,7 +61,7 @@ export function queryDocuments(
|
|||||||
query: string,
|
query: string,
|
||||||
continuationToken?: string
|
continuationToken?: string
|
||||||
): Promise<QueryResponse> {
|
): Promise<QueryResponse> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const params = {
|
const params = {
|
||||||
db: databaseId,
|
db: databaseId,
|
||||||
@@ -121,7 +121,7 @@ export function readDocument(
|
|||||||
collection: Collection,
|
collection: Collection,
|
||||||
documentId: DocumentId
|
documentId: DocumentId
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 4).join("/");
|
const path = idComponents.slice(0, 4).join("/");
|
||||||
@@ -167,7 +167,7 @@ export function createDocument(
|
|||||||
partitionKeyProperty: string,
|
partitionKeyProperty: string,
|
||||||
documentContent: unknown
|
documentContent: unknown
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const params = {
|
const params = {
|
||||||
db: databaseId,
|
db: databaseId,
|
||||||
@@ -206,7 +206,7 @@ export function updateDocument(
|
|||||||
documentId: DocumentId,
|
documentId: DocumentId,
|
||||||
documentContent: string
|
documentContent: string
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 5).join("/");
|
const path = idComponents.slice(0, 5).join("/");
|
||||||
@@ -247,7 +247,7 @@ export function updateDocument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
|
export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 5).join("/");
|
const path = idComponents.slice(0, 5).join("/");
|
||||||
@@ -289,7 +289,7 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
|
|||||||
export function createMongoCollectionWithProxy(
|
export function createMongoCollectionWithProxy(
|
||||||
params: DataModels.CreateCollectionParams
|
params: DataModels.CreateCollectionParams
|
||||||
): Promise<DataModels.Collection> {
|
): Promise<DataModels.Collection> {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount } = userContext;
|
||||||
const shardKey: string = params.partitionKey?.paths[0];
|
const shardKey: string = params.partitionKey?.paths[0];
|
||||||
const mongoParams: DataModels.MongoParameters = {
|
const mongoParams: DataModels.MongoParameters = {
|
||||||
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe("Object cache", () => {
|
|||||||
cache.set("b", 2);
|
cache.set("b", 2);
|
||||||
cache.set("c", 3);
|
cache.set("c", 3);
|
||||||
cache.set("d", 4);
|
cache.set("d", 4);
|
||||||
expect(cache.size()).toBe(2);
|
expect(cache.size).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove first added element to keep size at limit", () => {
|
it("should remove first added element to keep size at limit", () => {
|
||||||
|
|||||||
@@ -1,56 +1,27 @@
|
|||||||
import { HashMap } from "./HashMap";
|
export class ObjectCache<T> extends Map<string, T> {
|
||||||
|
constructor(private limit: number) {
|
||||||
export class ObjectCache<T> extends HashMap<T> {
|
|
||||||
private keyQueue: string[]; // Last touched key FIFO to purge cache if too big.
|
|
||||||
private maxNbElements: number;
|
|
||||||
|
|
||||||
public constructor(maxNbElements: number) {
|
|
||||||
super();
|
super();
|
||||||
this.keyQueue = [];
|
|
||||||
this.maxNbElements = maxNbElements;
|
|
||||||
this.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public get(key: string): T | undefined {
|
||||||
super.clear();
|
return this.touch(key);
|
||||||
this.keyQueue = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): T {
|
public set(key: string, value: T): this {
|
||||||
this.markKeyAsTouched(key);
|
if (this.size === this.limit) {
|
||||||
return super.get(key);
|
this.delete(this.keys().next().value);
|
||||||
}
|
|
||||||
|
|
||||||
public set(key: string, value: T): void {
|
|
||||||
super.set(key, value);
|
|
||||||
|
|
||||||
this.markKeyAsTouched(key);
|
|
||||||
|
|
||||||
if (super.size() > this.maxNbElements && key !== this.keyQueue[0]) {
|
|
||||||
this.reduceCacheSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.touch(key, value), this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private touch(key: string, value = super.get(key)) {
|
||||||
* Invalidate elements to keep the total number below the limit
|
// Map keeps (re) insertion order according to ES6 spec
|
||||||
*/
|
if (value) {
|
||||||
private reduceCacheSize(): void {
|
this.delete(key);
|
||||||
// remove a key
|
super.set(key, value);
|
||||||
const oldKey = this.keyQueue.shift();
|
|
||||||
if (oldKey) {
|
|
||||||
super.delete(oldKey);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return value;
|
||||||
* Bubble up this key as new.
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
private markKeyAsTouched(key: string) {
|
|
||||||
const n = this.keyQueue.indexOf(key);
|
|
||||||
if (n > -1) {
|
|
||||||
this.keyQueue.splice(n, 1);
|
|
||||||
}
|
|
||||||
this.keyQueue.push(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { configContext, Platform } from "../ConfigContext";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { configContext, Platform } from "../ConfigContext";
|
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
const notificationsPath = () => {
|
const notificationsPath = () => {
|
||||||
switch (configContext.platform) {
|
switch (configContext.platform) {
|
||||||
@@ -20,9 +20,7 @@ export const fetchPortalNotifications = async (): Promise<DataModels.Notificatio
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount, resourceGroup, subscriptionId } = userContext;
|
||||||
const subscriptionId = userContext.subscriptionId;
|
|
||||||
const resourceGroup = userContext.resourceGroup;
|
|
||||||
const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${
|
const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${
|
||||||
databaseAccount.name
|
databaseAccount.name
|
||||||
}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;
|
}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import * as ViewModels from "../Contracts/ViewModels";
|
|||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import * as QueryUtils from "../Utils/QueryUtils";
|
import * as QueryUtils from "../Utils/QueryUtils";
|
||||||
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
|
||||||
import { createCollection } from "./dataAccess/createCollection";
|
import { createCollection } from "./dataAccess/createCollection";
|
||||||
import { handleError } from "./ErrorHandlingUtils";
|
|
||||||
import { createDocument } from "./dataAccess/createDocument";
|
import { createDocument } from "./dataAccess/createDocument";
|
||||||
import { deleteDocument } from "./dataAccess/deleteDocument";
|
import { deleteDocument } from "./dataAccess/deleteDocument";
|
||||||
import { queryDocuments } from "./dataAccess/queryDocuments";
|
import { queryDocuments } from "./dataAccess/queryDocuments";
|
||||||
|
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
||||||
|
import { handleError } from "./ErrorHandlingUtils";
|
||||||
|
|
||||||
export class QueriesClient {
|
export class QueriesClient {
|
||||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||||
@@ -182,11 +182,8 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getResourceId(): string {
|
public getResourceId(): string {
|
||||||
const databaseAccount = userContext.databaseAccount;
|
const { databaseAccount, subscriptionId = "", resourceGroup = "" } = userContext;
|
||||||
const databaseAccountName = (databaseAccount && databaseAccount.name) || "";
|
const databaseAccountName = databaseAccount?.name || "";
|
||||||
const subscriptionId = userContext.subscriptionId || "";
|
|
||||||
const resourceGroup = userContext.resourceGroup || "";
|
|
||||||
|
|
||||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`;
|
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +208,7 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fetchQueriesQuery(): string {
|
private fetchQueriesQuery(): string {
|
||||||
if (this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return QueriesClient.FetchMongoQuery;
|
return QueriesClient.FetchMongoQuery;
|
||||||
}
|
}
|
||||||
return QueriesClient.FetchQuery;
|
return QueriesClient.FetchQuery;
|
||||||
|
|||||||
59
src/Common/ResourceTree.tsx
Normal file
59
src/Common/ResourceTree.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import React, { FunctionComponent } from "react";
|
||||||
|
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
|
||||||
|
import refreshImg from "../../images/refresh-cosmos.svg";
|
||||||
|
import { AuthType } from "../AuthType";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
|
export interface ResourceTreeProps {
|
||||||
|
toggleLeftPaneExpanded: () => void;
|
||||||
|
isLeftPaneExpanded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ResourceTree: FunctionComponent<ResourceTreeProps> = ({
|
||||||
|
toggleLeftPaneExpanded,
|
||||||
|
isLeftPaneExpanded,
|
||||||
|
}: ResourceTreeProps): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div id="main" className={isLeftPaneExpanded ? "main" : "hiddenMain"}>
|
||||||
|
{/* Collections Window - - Start */}
|
||||||
|
<div id="mainslide" className="flexContainer">
|
||||||
|
{/* Collections Window Title/Command Bar - Start */}
|
||||||
|
<div className="collectiontitle">
|
||||||
|
<div className="coltitle">
|
||||||
|
<span className="titlepadcol" data-bind="text: collectionTitle" />
|
||||||
|
<div className="float-right">
|
||||||
|
<span
|
||||||
|
className="padimgcolrefresh"
|
||||||
|
data-test="refreshTree"
|
||||||
|
role="button"
|
||||||
|
data-bind="click: onRefreshResourcesClick, clickBubble: false, event: { keypress: onRefreshDatabasesKeyPress }"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label="Refresh tree"
|
||||||
|
title="Refresh tree"
|
||||||
|
>
|
||||||
|
<img className="refreshcol" src={refreshImg} alt="Refresh tree" />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="padimgcolrefresh1"
|
||||||
|
id="expandToggleLeftPaneButton"
|
||||||
|
role="button"
|
||||||
|
onClick={toggleLeftPaneExpanded}
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label="Collapse Tree"
|
||||||
|
title="Collapse Tree"
|
||||||
|
>
|
||||||
|
<img className="refreshcol1" src={arrowLeftImg} alt="Hide" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{userContext.authType === AuthType.ResourceToken ? (
|
||||||
|
<div style={{ overflowY: "auto" }} data-bind="react:resourceTreeForResourceToken" />
|
||||||
|
) : (
|
||||||
|
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* Collections Window - End */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -73,7 +73,7 @@ export class Splitter {
|
|||||||
$(this.leftSide).resizable(splitterOptions);
|
$(this.leftSide).resizable(splitterOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResizeStart: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
private onResizeStart: JQueryUI.ResizableEvent = () => {
|
||||||
if (this.direction === SplitterDirection.Vertical) {
|
if (this.direction === SplitterDirection.Vertical) {
|
||||||
$(".ui-resizable-helper").height("100%");
|
$(".ui-resizable-helper").height("100%");
|
||||||
} else {
|
} else {
|
||||||
@@ -82,9 +82,7 @@ export class Splitter {
|
|||||||
$("iframe").css("pointer-events", "none");
|
$("iframe").css("pointer-events", "none");
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResizeStop: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
private onResizeStop: JQueryUI.ResizableEvent = () => $("iframe").css("pointer-events", "auto");
|
||||||
$("iframe").css("pointer-events", "auto");
|
|
||||||
};
|
|
||||||
|
|
||||||
public collapseLeft() {
|
public collapseLeft() {
|
||||||
this.lastX = $(this.splitter).position().left;
|
this.lastX = $(this.splitter).position().left;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
TextField,
|
TextField,
|
||||||
TooltipHost,
|
TooltipHost,
|
||||||
} from "office-ui-fabric-react";
|
} from "@fluentui/react";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import DeleteIcon from "../../images/delete.svg";
|
import DeleteIcon from "../../images/delete.svg";
|
||||||
import EditIcon from "../../images/Edit_entity.svg";
|
import EditIcon from "../../images/Edit_entity.svg";
|
||||||
@@ -32,6 +32,7 @@ export interface TableEntityProps {
|
|||||||
options: { key: string; text: string }[];
|
options: { key: string; text: string }[];
|
||||||
isPropertyTypeDisable: boolean;
|
isPropertyTypeDisable: boolean;
|
||||||
entityTimeValue: string;
|
entityTimeValue: string;
|
||||||
|
isEntityValueDisable?: boolean;
|
||||||
onDeleteEntity?: () => void;
|
onDeleteEntity?: () => void;
|
||||||
onEditEntity?: () => void;
|
onEditEntity?: () => void;
|
||||||
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
||||||
@@ -55,6 +56,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
isPropertyTypeDisable,
|
isPropertyTypeDisable,
|
||||||
isEntityTypeDate,
|
isEntityTypeDate,
|
||||||
entityTimeValue,
|
entityTimeValue,
|
||||||
|
isEntityValueDisable,
|
||||||
onEditEntity,
|
onEditEntity,
|
||||||
onDeleteEntity,
|
onDeleteEntity,
|
||||||
onEntityPropertyChange,
|
onEntityPropertyChange,
|
||||||
@@ -113,6 +115,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
<EntityValue
|
<EntityValue
|
||||||
entityValueLabel={entityValueLabel}
|
entityValueLabel={entityValueLabel}
|
||||||
entityValueType={getEntityValueType()}
|
entityValueType={getEntityValueType()}
|
||||||
|
isEntityValueDisable={isEntityValueDisable}
|
||||||
entityValuePlaceholder={entityValuePlaceholder}
|
entityValuePlaceholder={entityValuePlaceholder}
|
||||||
entityValue={entityValue}
|
entityValue={entityValue}
|
||||||
isEntityTypeDate={isEntityTypeDate}
|
isEntityTypeDate={isEntityTypeDate}
|
||||||
@@ -121,10 +124,11 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
onSelectDate={onSelectDate}
|
onSelectDate={onSelectDate}
|
||||||
onEntityTimeValueChange={onEntityTimeValueChange}
|
onEntityTimeValueChange={onEntityTimeValueChange}
|
||||||
/>
|
/>
|
||||||
<TooltipHost content="Edit property" id="editTooltip">
|
{!isEntityValueDisable && (
|
||||||
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
<TooltipHost content="Edit property" id="editTooltip">
|
||||||
</TooltipHost>
|
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
||||||
|
</TooltipHost>
|
||||||
|
)}
|
||||||
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
||||||
<TooltipHost content="Delete property" id="deleteTooltip">
|
<TooltipHost content="Delete property" id="deleteTooltip">
|
||||||
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
||||||
|
|||||||
16
src/Common/Tooltip/InfoTooltip.tsx
Normal file
16
src/Common/Tooltip/InfoTooltip.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Icon, TooltipHost } from "@fluentui/react";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export interface TooltipProps {
|
||||||
|
children: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }: TooltipProps) => {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<TooltipHost content={children}>
|
||||||
|
<Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" />
|
||||||
|
</TooltipHost>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { useId } from "@uifabric/react-hooks";
|
|
||||||
import { ITooltipHostStyles, TooltipHost } from "office-ui-fabric-react/lib/Tooltip";
|
|
||||||
import * as React from "react";
|
|
||||||
import InfoBubble from "../../../images/info-bubble.svg";
|
|
||||||
|
|
||||||
const calloutProps = { gapSpace: 0 };
|
|
||||||
const hostStyles: Partial<ITooltipHostStyles> = { root: { display: "inline-block" } };
|
|
||||||
|
|
||||||
export interface TooltipProps {
|
|
||||||
children: string;
|
|
||||||
}
|
|
||||||
export const Tooltip: React.FunctionComponent = ({ children }: TooltipProps) => {
|
|
||||||
const tooltipId = useId("tooltip");
|
|
||||||
|
|
||||||
return children ? (
|
|
||||||
<span>
|
|
||||||
<TooltipHost content={children} id={tooltipId} calloutProps={calloutProps} styles={hostStyles}>
|
|
||||||
<img className="infoImg" src={InfoBubble} alt="More information" />
|
|
||||||
</TooltipHost>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Image, Stack, TextField } from "office-ui-fabric-react";
|
import { Image, Stack, TextField } from "@fluentui/react";
|
||||||
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
|
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
|
||||||
import FolderIcon from "../../../images/folder_16x16.svg";
|
import FolderIcon from "../../../images/folder_16x16.svg";
|
||||||
import * as Constants from "../Constants";
|
import * as Constants from "../Constants";
|
||||||
import { Tooltip } from "../Tooltip/Tooltip";
|
import { InfoTooltip } from "../Tooltip/InfoTooltip";
|
||||||
|
|
||||||
interface UploadProps {
|
interface UploadProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -51,7 +51,7 @@ export const Upload: FunctionComponent<UploadProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="renewUploadItemsHeader">{label}</span>
|
<span className="renewUploadItemsHeader">{label}</span>
|
||||||
<Tooltip>{tooltip}</Tooltip>
|
{tooltip && <InfoTooltip>{tooltip}</InfoTooltip>}
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
|
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { createCollection, constructRpOptions } from "./createCollection";
|
import { constructRpOptions, createCollection } from "./createCollection";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("createCollection", () => {
|
describe("createCollection", () => {
|
||||||
const createCollectionParams: CreateCollectionParams = {
|
const createCollectionParams: CreateCollectionParams = {
|
||||||
@@ -22,7 +21,7 @@ describe("createCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
||||||
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { client } from "../CosmosClient";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
import { userContext } from "../../UserContext";
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateMongoDBCollection,
|
|
||||||
getMongoDBCollection,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinGraph,
|
createUpdateGremlinGraph,
|
||||||
getGremlinGraph,
|
getGremlinGraph,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import {
|
||||||
|
createUpdateMongoDBCollection,
|
||||||
|
getMongoDBCollection,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { userContext } from "../../UserContext";
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { createDatabase } from "./createDatabase";
|
import { client } from "../CosmosClient";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||||
|
import { createDatabase } from "./createDatabase";
|
||||||
|
|
||||||
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const clearMessage = logConsoleProgress(
|
const clearMessage = logConsoleProgress(
|
||||||
@@ -46,7 +45,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
await createDatabase(createDatabaseParams);
|
await createDatabase(createDatabaseParams);
|
||||||
}
|
}
|
||||||
collection = await createCollectionWithARM(params);
|
collection = await createCollectionWithARM(params);
|
||||||
} else if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
} else if (userContext.apiType === "Mongo") {
|
||||||
collection = await createMongoCollectionWithProxy(params);
|
collection = await createMongoCollectionWithProxy(params);
|
||||||
} else {
|
} else {
|
||||||
collection = await createCollectionWithSDK(params);
|
collection = await createCollectionWithSDK(params);
|
||||||
@@ -63,20 +62,20 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const { apiType } = userContext;
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return createSqlContainer(params);
|
return createSqlContainer(params);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return createMongoCollection(params);
|
return createMongoCollection(params);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return createCassandraTable(params);
|
return createCassandraTable(params);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return createGraph(params);
|
return createGraph(params);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return createTable(params);
|
return createTable(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseResponse } from "@azure/cosmos";
|
import { DatabaseResponse } from "@azure/cosmos";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { AuthType } from "../../AuthType";
|
||||||
import {
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
CassandraKeyspaceCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
GremlinDatabaseCreateUpdateParameters,
|
|
||||||
MongoDBDatabaseCreateUpdateParameters,
|
|
||||||
SqlDatabaseCreateUpdateParameters,
|
|
||||||
CreateUpdateOptions,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraKeyspace,
|
createUpdateCassandraKeyspace,
|
||||||
getCassandraKeyspace,
|
getCassandraKeyspace,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateMongoDBDatabase,
|
|
||||||
getMongoDBDatabase,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinDatabase,
|
createUpdateGremlinDatabase,
|
||||||
getGremlinDatabase,
|
getGremlinDatabase,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import {
|
||||||
|
createUpdateMongoDBDatabase,
|
||||||
|
getMongoDBDatabase,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import {
|
||||||
|
CassandraKeyspaceCreateUpdateParameters,
|
||||||
|
CreateUpdateOptions,
|
||||||
|
GremlinDatabaseCreateUpdateParameters,
|
||||||
|
MongoDBDatabaseCreateUpdateParameters,
|
||||||
|
SqlDatabaseCreateUpdateParameters,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
if (userContext.apiType === "Tables") {
|
||||||
throw new Error("Creating database resources is not allowed for tables accounts");
|
throw new Error("Creating database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||||
@@ -49,18 +48,19 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const { apiType } = userContext;
|
||||||
switch (defaultExperience) {
|
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
switch (apiType) {
|
||||||
|
case "SQL":
|
||||||
return createSqlDatabase(params);
|
return createSqlDatabase(params);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return createMongoDatabase(params);
|
return createMongoDatabase(params);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return createCassandraKeyspace(params);
|
return createCassandraKeyspace(params);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return createGremlineDatabase(params);
|
return createGremlineDatabase(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlStoredProcedureResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlStoredProcedure,
|
createUpdateSqlStoredProcedure,
|
||||||
getSqlStoredProcedure,
|
getSqlStoredProcedure,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
|
SqlStoredProcedureResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createStoredProcedure(
|
export async function createStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function createStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createTrigger(
|
export async function createTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -18,11 +17,7 @@ export async function createTrigger(
|
|||||||
): Promise<TriggerDefinition & Resource> {
|
): Promise<TriggerDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlUserDefinedFunctionResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlUserDefinedFunction,
|
createUpdateSqlUserDefinedFunction,
|
||||||
getSqlUserDefinedFunction,
|
getSqlUserDefinedFunction,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
|
SqlUserDefinedFunctionResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createUserDefinedFunction(
|
export async function createUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function createUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { deleteCollection } from "./deleteCollection";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteCollection } from "./deleteCollection";
|
||||||
|
|
||||||
describe("deleteCollection", () => {
|
describe("deleteCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -15,7 +14,7 @@ describe("deleteCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||||
@@ -28,23 +27,21 @@ export async function deleteCollection(databaseId: string, collectionId: string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> {
|
function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { deleteDatabase } from "./deleteDatabase";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteDatabase } from "./deleteDatabase";
|
||||||
|
|
||||||
describe("deleteDatabase", () => {
|
describe("deleteDatabase", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -15,7 +14,7 @@ describe("deleteDatabase", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteDatabase(databaseId: string): Promise<void> {
|
export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
if (userContext.apiType === "Tables") {
|
||||||
throw new Error("Deleting database resources is not allowed for tables accounts");
|
throw new Error("Deleting database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
@@ -31,21 +30,19 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteStoredProcedure(
|
export async function deleteStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,11 +12,7 @@ export async function deleteStoredProcedure(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlStoredProcedure(
|
await deleteSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlTrigger(
|
await deleteSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlUserDefinedFunction(
|
await deleteSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { configContext } from "../../ConfigContext";
|
import { configContext } from "../../ConfigContext";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
interface TimeSeriesData {
|
interface TimeSeriesData {
|
||||||
data: {
|
data: {
|
||||||
@@ -45,9 +45,9 @@ export const getCollectionUsageSizeInKB = async (databaseName: string, container
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`;
|
const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`;
|
||||||
const metricNames = "DataUsage,IndexUsage";
|
const metricNames = "DataUsage,IndexUsage";
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`;
|
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollection } from "./readCollection";
|
import { readCollection } from "./readCollection";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readCollection", () => {
|
describe("readCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,7 +12,7 @@ describe("readCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,15 +28,13 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
|
|||||||
};
|
};
|
||||||
|
|
||||||
const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => {
|
const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await getSqlContainerThroughput(
|
rpResponse = await getSqlContainerThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -50,7 +43,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await getMongoDBCollectionThroughput(
|
rpResponse = await getMongoDBCollectionThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -59,7 +52,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await getCassandraTableThroughput(
|
rpResponse = await getCassandraTableThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -68,7 +61,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await getGremlinGraphThroughput(
|
rpResponse = await getGremlinGraphThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -77,11 +70,11 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "NotFound") {
|
if (error.code !== "NotFound") {
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollections } from "./readCollections";
|
import { readCollections } from "./readCollections";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readCollections", () => {
|
describe("readCollections", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +13,7 @@ describe("readCollections", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
@@ -14,11 +13,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
|||||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readCollectionsWithARM(databaseId);
|
return await readCollectionsWithARM(databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,29 +29,28 @@ export async function readCollections(databaseId: string): Promise<DataModels.Co
|
|||||||
|
|
||||||
async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> {
|
async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
const subscriptionId = userContext.subscriptionId;
|
|
||||||
const resourceGroup = userContext.resourceGroup;
|
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
switch (defaultExperience) {
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
const accountName = databaseAccount.name;
|
||||||
|
|
||||||
|
switch (apiType) {
|
||||||
|
case "SQL":
|
||||||
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
|
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
||||||
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { userContext } from "../../UserContext";
|
||||||
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readDatabaseOfferWithARM(params.databaseId);
|
return await readDatabaseOfferWithARM(params.databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,28 +27,26 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
|
|||||||
};
|
};
|
||||||
|
|
||||||
const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "NotFound") {
|
if (error.code !== "NotFound") {
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readDatabases } from "./readDatabases";
|
import { readDatabases } from "./readDatabases";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readDatabases", () => {
|
describe("readDatabases", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +13,7 @@ describe("readDatabases", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export async function readDatabases(): Promise<DataModels.Database[]> {
|
export async function readDatabases(): Promise<DataModels.Database[]> {
|
||||||
let databases: DataModels.Database[];
|
let databases: DataModels.Database[];
|
||||||
const clearMessage = logConsoleProgress(`Querying databases`);
|
const clearMessage = logConsoleProgress(`Querying databases`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
databases = await readDatabasesWithARM();
|
databases = await readDatabasesWithARM();
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client().databases.readAll().fetchAll();
|
const sdkResponse = await client().databases.readAll().fetchAll();
|
||||||
@@ -34,26 +29,24 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
|
|||||||
|
|
||||||
async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);
|
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
|
|
||||||
export async function readMongoDBCollectionThroughRP(
|
export async function readMongoDBCollectionThroughRP(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,9 +13,9 @@ export async function readMongoDBCollectionThroughRP(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let collection: MongoDBCollectionResource;
|
let collection: MongoDBCollectionResource;
|
||||||
const subscriptionId = userContext.subscriptionId;
|
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = databaseAccount.name;
|
||||||
|
|
||||||
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readStoredProcedures(
|
export async function readStoredProcedures(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,11 +12,7 @@ export async function readStoredProcedures(
|
|||||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlStoredProcedures(
|
const rpResponse = await listSqlStoredProcedures(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readTriggers(
|
export async function readTriggers(
|
||||||
@@ -13,11 +12,7 @@ export async function readTriggers(
|
|||||||
): Promise<(TriggerDefinition & Resource)[]> {
|
): Promise<(TriggerDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlTriggers(
|
const rpResponse = await listSqlTriggers(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readUserDefinedFunctions(
|
export async function readUserDefinedFunctions(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string
|
collectionId: string
|
||||||
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
||||||
|
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
try {
|
try {
|
||||||
if (
|
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlUserDefinedFunctions(
|
const rpResponse = await listSqlUserDefinedFunctions(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { ContainerDefinition } from "@azure/cosmos";
|
|||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { Collection } from "../../Contracts/DataModels";
|
import { Collection } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
@@ -38,11 +37,7 @@ export async function updateCollection(
|
|||||||
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client()
|
const sdkResponse = await client()
|
||||||
@@ -68,21 +63,19 @@ async function updateCollectionWithARM(
|
|||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
const defaultExperience = userContext.defaultExperience;
|
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return updateMongoDBCollection(
|
return updateMongoDBCollection(
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
@@ -92,7 +85,7 @@ async function updateCollectionWithARM(
|
|||||||
newCollection
|
newCollection
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +1,53 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { HttpHeaders } from "../Constants";
|
|
||||||
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
|
||||||
import { OfferDefinition } from "@azure/cosmos";
|
import { OfferDefinition } from "@azure/cosmos";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { parseSDKOfferResponse } from "../OfferUtility";
|
|
||||||
import { readCollectionOffer } from "./readCollectionOffer";
|
|
||||||
import { readDatabaseOffer } from "./readDatabaseOffer";
|
|
||||||
import {
|
import {
|
||||||
updateSqlDatabaseThroughput,
|
|
||||||
migrateSqlDatabaseToAutoscale,
|
|
||||||
migrateSqlDatabaseToManualThroughput,
|
|
||||||
migrateSqlContainerToAutoscale,
|
|
||||||
migrateSqlContainerToManualThroughput,
|
|
||||||
updateSqlContainerThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
|
||||||
updateCassandraKeyspaceThroughput,
|
|
||||||
migrateCassandraKeyspaceToAutoscale,
|
migrateCassandraKeyspaceToAutoscale,
|
||||||
migrateCassandraKeyspaceToManualThroughput,
|
migrateCassandraKeyspaceToManualThroughput,
|
||||||
migrateCassandraTableToAutoscale,
|
migrateCassandraTableToAutoscale,
|
||||||
migrateCassandraTableToManualThroughput,
|
migrateCassandraTableToManualThroughput,
|
||||||
|
updateCassandraKeyspaceThroughput,
|
||||||
updateCassandraTableThroughput,
|
updateCassandraTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
updateMongoDBDatabaseThroughput,
|
|
||||||
migrateMongoDBDatabaseToAutoscale,
|
|
||||||
migrateMongoDBDatabaseToManualThroughput,
|
|
||||||
migrateMongoDBCollectionToAutoscale,
|
|
||||||
migrateMongoDBCollectionToManualThroughput,
|
|
||||||
updateMongoDBCollectionThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
|
||||||
updateGremlinDatabaseThroughput,
|
|
||||||
migrateGremlinDatabaseToAutoscale,
|
migrateGremlinDatabaseToAutoscale,
|
||||||
migrateGremlinDatabaseToManualThroughput,
|
migrateGremlinDatabaseToManualThroughput,
|
||||||
migrateGremlinGraphToAutoscale,
|
migrateGremlinGraphToAutoscale,
|
||||||
migrateGremlinGraphToManualThroughput,
|
migrateGremlinGraphToManualThroughput,
|
||||||
|
updateGremlinDatabaseThroughput,
|
||||||
updateGremlinGraphThroughput,
|
updateGremlinGraphThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { userContext } from "../../UserContext";
|
import {
|
||||||
|
migrateMongoDBCollectionToAutoscale,
|
||||||
|
migrateMongoDBCollectionToManualThroughput,
|
||||||
|
migrateMongoDBDatabaseToAutoscale,
|
||||||
|
migrateMongoDBDatabaseToManualThroughput,
|
||||||
|
updateMongoDBCollectionThroughput,
|
||||||
|
updateMongoDBDatabaseThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import {
|
||||||
|
migrateSqlContainerToAutoscale,
|
||||||
|
migrateSqlContainerToManualThroughput,
|
||||||
|
migrateSqlDatabaseToAutoscale,
|
||||||
|
migrateSqlDatabaseToManualThroughput,
|
||||||
|
updateSqlContainerThroughput,
|
||||||
|
updateSqlDatabaseThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
migrateTableToAutoscale,
|
migrateTableToAutoscale,
|
||||||
migrateTableToManualThroughput,
|
migrateTableToManualThroughput,
|
||||||
updateTableThroughput,
|
updateTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
|
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { HttpHeaders } from "../Constants";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { parseSDKOfferResponse } from "../OfferUtility";
|
||||||
|
import { readCollectionOffer } from "./readCollectionOffer";
|
||||||
|
import { readDatabaseOffer } from "./readDatabaseOffer";
|
||||||
|
|
||||||
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
let updatedOffer: Offer;
|
let updatedOffer: Offer;
|
||||||
@@ -61,7 +60,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
if (params.collectionId) {
|
if (params.collectionId) {
|
||||||
updatedOffer = await updateCollectionOfferWithARM(params);
|
updatedOffer = await updateCollectionOfferWithARM(params);
|
||||||
} else if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
} else if (userContext.apiType === "Tables") {
|
||||||
// update table's database offer with SDK since RP doesn't support it
|
// update table's database offer with SDK since RP doesn't support it
|
||||||
updatedOffer = await updateOfferWithSDK(params);
|
updatedOffer = await updateOfferWithSDK(params);
|
||||||
} else {
|
} else {
|
||||||
@@ -82,24 +81,24 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
|
|
||||||
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
await updateSqlContainerOffer(params);
|
await updateSqlContainerOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
await updateMongoCollectionOffer(params);
|
await updateMongoCollectionOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
await updateCassandraTableOffer(params);
|
await updateCassandraTableOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
await updateGremlinGraphOffer(params);
|
await updateGremlinGraphOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
await updateTableOffer(params);
|
await updateTableOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
@@ -116,21 +115,21 @@ const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<
|
|||||||
|
|
||||||
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
await updateSqlDatabaseOffer(params);
|
await updateSqlDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
await updateMongoDatabaseOffer(params);
|
await updateMongoDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
await updateCassandraKeyspaceOffer(params);
|
await updateCassandraKeyspaceOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
await updateGremlinDatabaseOffer(params);
|
await updateGremlinDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
@@ -145,9 +144,8 @@ const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Of
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateSqlContainerToAutoscale(
|
await migrateSqlContainerToAutoscale(
|
||||||
@@ -179,9 +177,8 @@ const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateMongoDBCollectionToAutoscale(
|
await migrateMongoDBCollectionToAutoscale(
|
||||||
@@ -213,9 +210,8 @@ const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<vo
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateCassandraTableToAutoscale(
|
await migrateCassandraTableToAutoscale(
|
||||||
@@ -247,9 +243,8 @@ const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<voi
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateGremlinGraphToAutoscale(
|
await migrateGremlinGraphToAutoscale(
|
||||||
@@ -281,9 +276,8 @@ const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateTableToAutoscale(subscriptionId, resourceGroup, accountName, params.collectionId);
|
await migrateTableToAutoscale(subscriptionId, resourceGroup, accountName, params.collectionId);
|
||||||
@@ -296,9 +290,8 @@ const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateSqlDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
await migrateSqlDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
||||||
@@ -311,9 +304,8 @@ const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateMongoDBDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
await migrateMongoDBDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
||||||
@@ -326,9 +318,8 @@ const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateCassandraKeyspaceToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
await migrateCassandraKeyspaceToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
||||||
@@ -341,9 +332,8 @@ const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateGremlinDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
const updateGremlinDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const accountName = databaseAccount.name;
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
if (params.migrateToAutoPilot) {
|
if (params.migrateToAutoPilot) {
|
||||||
await migrateGremlinDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
await migrateGremlinDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlStoredProcedureResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlStoredProcedure,
|
createUpdateSqlStoredProcedure,
|
||||||
getSqlStoredProcedure,
|
getSqlStoredProcedure,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
|
SqlStoredProcedureResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateStoredProcedure(
|
export async function updateStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,15 +20,13 @@ export async function updateStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
storedProcedure.id
|
storedProcedure.id
|
||||||
@@ -43,9 +40,9 @@ export async function updateStoredProcedure(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const rpResponse = await createUpdateSqlStoredProcedure(
|
const rpResponse = await createUpdateSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
storedProcedure.id,
|
storedProcedure.id,
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
|
import { TriggerDefinition } from "@azure/cosmos";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateTrigger(
|
export async function updateTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -17,16 +16,13 @@ export async function updateTrigger(
|
|||||||
trigger: TriggerDefinition
|
trigger: TriggerDefinition
|
||||||
): Promise<TriggerDefinition> {
|
): Promise<TriggerDefinition> {
|
||||||
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
||||||
|
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
try {
|
try {
|
||||||
if (
|
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
trigger.id
|
trigger.id
|
||||||
@@ -40,9 +36,9 @@ export async function updateTrigger(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const rpResponse = await createUpdateSqlTrigger(
|
const rpResponse = await createUpdateSqlTrigger(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
trigger.id,
|
trigger.id,
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlUserDefinedFunctionResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlUserDefinedFunction,
|
createUpdateSqlUserDefinedFunction,
|
||||||
getSqlUserDefinedFunction,
|
getSqlUserDefinedFunction,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
|
SqlUserDefinedFunctionResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateUserDefinedFunction(
|
export async function updateUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,16 +19,13 @@ export async function updateUserDefinedFunction(
|
|||||||
userDefinedFunction: UserDefinedFunctionDefinition
|
userDefinedFunction: UserDefinedFunctionDefinition
|
||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
||||||
|
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||||
try {
|
try {
|
||||||
if (
|
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
userDefinedFunction.id
|
userDefinedFunction.id
|
||||||
@@ -43,9 +39,9 @@ export async function updateUserDefinedFunction(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const rpResponse = await createUpdateSqlUserDefinedFunction(
|
const rpResponse = await createUpdateSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
subscriptionId,
|
||||||
userContext.resourceGroup,
|
resourceGroup,
|
||||||
userContext.databaseAccount.name,
|
databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
userDefinedFunction.id,
|
userDefinedFunction.id,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ export interface DatabaseAccount {
|
|||||||
location: string;
|
location: string;
|
||||||
type: string;
|
type: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
tags: any;
|
|
||||||
properties: DatabaseAccountExtendedProperties;
|
properties: DatabaseAccountExtendedProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,17 +206,14 @@ export enum NeighborType {
|
|||||||
BOTH,
|
BOTH,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface IGraphConfigUiData {
|
||||||
* Set of observable related to graph configuration by user
|
showNeighborType: NeighborType;
|
||||||
*/
|
nodeProperties: string[];
|
||||||
export interface GraphConfigUiData {
|
nodePropertiesWithNone: string[];
|
||||||
showNeighborType: ko.Observable<NeighborType>;
|
nodeCaptionChoice: string;
|
||||||
nodeProperties: ko.ObservableArray<string>;
|
nodeColorKeyChoice: string;
|
||||||
nodePropertiesWithNone: ko.ObservableArray<string>;
|
nodeIconChoice: string;
|
||||||
nodeCaptionChoice: ko.Observable<string>;
|
nodeIconSet: string;
|
||||||
nodeColorKeyChoice: ko.Observable<string>;
|
|
||||||
nodeIconChoice: ko.Observable<string>;
|
|
||||||
nodeIconSet: ko.Observable<string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
export enum DefaultAccountExperienceType {
|
|
||||||
DocumentDB = "DocumentDB",
|
|
||||||
Graph = "Graph",
|
|
||||||
MongoDB = "MongoDB",
|
|
||||||
Table = "Table",
|
|
||||||
Cassandra = "Cassandra",
|
|
||||||
ApiForMongoDB = "Azure Cosmos DB for MongoDB API",
|
|
||||||
}
|
|
||||||
@@ -4,79 +4,10 @@ import * as ko from "knockout";
|
|||||||
import "./ComponentRegisterer";
|
import "./ComponentRegisterer";
|
||||||
|
|
||||||
describe("Component Registerer", () => {
|
describe("Component Registerer", () => {
|
||||||
it("should register input-typeahead component", () => {
|
|
||||||
expect(ko.components.isRegistered("input-typeahead")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register error-display component", () => {
|
|
||||||
expect(ko.components.isRegistered("error-display")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register graph-style component", () => {
|
|
||||||
expect(ko.components.isRegistered("graph-style")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register json-editor component", () => {
|
it("should register json-editor component", () => {
|
||||||
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should register documents-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("documents-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register stored-procedure-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("stored-procedure-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register trigger-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("trigger-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register user-defined-function-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("user-defined-function-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register settings-tab-v2 component", () => {
|
|
||||||
expect(ko.components.isRegistered("database-settings-tab-v2")).toBe(true);
|
|
||||||
expect(ko.components.isRegistered("collection-settings-tab-v2")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register query-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("query-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register tables-query-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("tables-query-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register graph-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("graph-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register notebookv2-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("notebookv2-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register terminal-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("terminal-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register mongo-shell-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("mongo-shell-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should registeradd-collection-pane component", () => {
|
|
||||||
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register graph-styling-pane component", () => {
|
|
||||||
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register string-input-pane component", () => {
|
|
||||||
expect(ko.components.isRegistered("string-input-pane")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register dynamic-list component", () => {
|
it("should register dynamic-list component", () => {
|
||||||
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,63 +2,15 @@ import * as ko from "knockout";
|
|||||||
import { DiffEditorComponent } from "./Controls/DiffEditor/DiffEditorComponent";
|
import { DiffEditorComponent } from "./Controls/DiffEditor/DiffEditorComponent";
|
||||||
import { DynamicListComponent } from "./Controls/DynamicList/DynamicListComponent";
|
import { DynamicListComponent } from "./Controls/DynamicList/DynamicListComponent";
|
||||||
import { EditorComponent } from "./Controls/Editor/EditorComponent";
|
import { EditorComponent } from "./Controls/Editor/EditorComponent";
|
||||||
import { ErrorDisplayComponent } from "./Controls/ErrorDisplayComponent/ErrorDisplayComponent";
|
|
||||||
import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahead";
|
|
||||||
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
|
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
|
||||||
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
||||||
import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
|
|
||||||
import * as PaneComponents from "./Panes/PaneComponents";
|
import * as PaneComponents from "./Panes/PaneComponents";
|
||||||
import ConflictsTab from "./Tabs/ConflictsTab";
|
|
||||||
import DocumentsTab from "./Tabs/DocumentsTab";
|
|
||||||
import GalleryTab from "./Tabs/GalleryTab";
|
|
||||||
import GraphTab from "./Tabs/GraphTab";
|
|
||||||
import MongoShellTab from "./Tabs/MongoShellTab";
|
|
||||||
import NotebookTabV2 from "./Tabs/NotebookV2Tab";
|
|
||||||
import NotebookViewerTab from "./Tabs/NotebookViewerTab";
|
|
||||||
import QueryTab from "./Tabs/QueryTab";
|
|
||||||
import QueryTablesTab from "./Tabs/QueryTablesTab";
|
|
||||||
import SchemaAnalyzerTab from "./Tabs/SchemaAnalyzerTab";
|
|
||||||
import { DatabaseSettingsTabV2, SettingsTabV2 } from "./Tabs/SettingsTabV2";
|
|
||||||
import StoredProcedureTab from "./Tabs/StoredProcedureTab";
|
|
||||||
import TerminalTab from "./Tabs/TerminalTab";
|
|
||||||
import TriggerTab from "./Tabs/TriggerTab";
|
|
||||||
import UserDefinedFunctionTab from "./Tabs/UserDefinedFunctionTab";
|
|
||||||
|
|
||||||
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
|
||||||
ko.components.register("error-display", new ErrorDisplayComponent());
|
|
||||||
ko.components.register("graph-style", GraphStyleComponent);
|
|
||||||
ko.components.register("editor", new EditorComponent());
|
ko.components.register("editor", new EditorComponent());
|
||||||
ko.components.register("json-editor", new JsonEditorComponent());
|
ko.components.register("json-editor", new JsonEditorComponent());
|
||||||
ko.components.register("diff-editor", new DiffEditorComponent());
|
ko.components.register("diff-editor", new DiffEditorComponent());
|
||||||
ko.components.register("dynamic-list", DynamicListComponent);
|
ko.components.register("dynamic-list", DynamicListComponent);
|
||||||
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
||||||
|
|
||||||
// Collection Tabs
|
|
||||||
[
|
|
||||||
DocumentsTab,
|
|
||||||
StoredProcedureTab,
|
|
||||||
TriggerTab,
|
|
||||||
UserDefinedFunctionTab,
|
|
||||||
SettingsTabV2,
|
|
||||||
QueryTab,
|
|
||||||
QueryTablesTab,
|
|
||||||
GraphTab,
|
|
||||||
MongoShellTab,
|
|
||||||
ConflictsTab,
|
|
||||||
NotebookTabV2,
|
|
||||||
TerminalTab,
|
|
||||||
GalleryTab,
|
|
||||||
NotebookViewerTab,
|
|
||||||
DatabaseSettingsTabV2,
|
|
||||||
SchemaAnalyzerTab,
|
|
||||||
].forEach(({ component: { name, template } }) => ko.components.register(name, { template }));
|
|
||||||
|
|
||||||
// Panes
|
// Panes
|
||||||
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
|
||||||
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
|
||||||
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
|
||||||
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
|
||||||
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
|
||||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
|
||||||
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import DeleteTriggerIcon from "../../images/DeleteTrigger.svg";
|
|||||||
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
||||||
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
||||||
import Explorer from "./Explorer";
|
import Explorer from "./Explorer";
|
||||||
@@ -30,16 +29,16 @@ export interface DatabaseContextMenuButtonParams {
|
|||||||
* New resource tree (in ReactJS)
|
* New resource tree (in ReactJS)
|
||||||
*/
|
*/
|
||||||
export class ResourceTreeContextMenuButtonFactory {
|
export class ResourceTreeContextMenuButtonFactory {
|
||||||
public static createDatabaseContextMenu(container: Explorer): TreeNodeMenuItem[] {
|
public static createDatabaseContextMenu(container: Explorer, databaseId: string): TreeNodeMenuItem[] {
|
||||||
const items: TreeNodeMenuItem[] = [
|
const items: TreeNodeMenuItem[] = [
|
||||||
{
|
{
|
||||||
iconSrc: AddCollectionIcon,
|
iconSrc: AddCollectionIcon,
|
||||||
onClick: () => container.onNewCollectionClicked(),
|
onClick: () => container.onNewCollectionClicked(databaseId),
|
||||||
label: container.addCollectionText(),
|
label: container.addCollectionText(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (userContext.defaultExperience !== DefaultAccountExperienceType.Table) {
|
if (userContext.apiType !== "Tables") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: DeleteDatabaseIcon,
|
iconSrc: DeleteDatabaseIcon,
|
||||||
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
||||||
@@ -63,7 +62,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import { DefaultButton, IButtonStyles, IContextualMenuItem, IContextualMenuProps } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ArcadiaWorkspace, SparkPool } from "../../../Contracts/DataModels";
|
|
||||||
import { DefaultButton, IButtonStyles } from "office-ui-fabric-react/lib/Button";
|
|
||||||
import { IContextualMenuItem, IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
|
|
||||||
import * as Logger from "../../../Common/Logger";
|
|
||||||
import { getErrorMessage } from "../../../Common/ErrorHandlingUtils";
|
import { getErrorMessage } from "../../../Common/ErrorHandlingUtils";
|
||||||
|
import * as Logger from "../../../Common/Logger";
|
||||||
|
import { ArcadiaWorkspace, SparkPool } from "../../../Contracts/DataModels";
|
||||||
|
|
||||||
export interface ArcadiaMenuPickerProps {
|
export interface ArcadiaMenuPickerProps {
|
||||||
selectText?: string;
|
selectText?: string;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Icon, Label, Stack } from "office-ui-fabric-react";
|
import { Icon, Label, Stack } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { accordionStackTokens } from "../Settings/SettingsRenderUtils";
|
import { accordionStackTokens } from "../Settings/SettingsRenderUtils";
|
||||||
|
|
||||||
export interface CollapsibleSectionProps {
|
export interface CollapsibleSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
isExpandedByDefault: boolean;
|
isExpandedByDefault: boolean;
|
||||||
|
onExpand?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollapsibleSectionState {
|
export interface CollapsibleSectionState {
|
||||||
@@ -23,6 +24,12 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
this.setState({ isExpanded: !this.state.isExpanded });
|
this.setState({ isExpanded: !this.state.isExpanded });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public componentDidUpdate(): void {
|
||||||
|
if (this.state.isExpanded && this.props.onExpand) {
|
||||||
|
this.props.onExpand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
ChoiceGroup,
|
ChoiceGroup,
|
||||||
|
DefaultButton,
|
||||||
|
Dialog as FluentDialog,
|
||||||
|
DialogFooter,
|
||||||
|
DialogType,
|
||||||
FontIcon,
|
FontIcon,
|
||||||
|
IButtonProps,
|
||||||
IChoiceGroupProps,
|
IChoiceGroupProps,
|
||||||
|
IDialogProps,
|
||||||
IProgressIndicatorProps,
|
IProgressIndicatorProps,
|
||||||
|
ITextFieldProps,
|
||||||
|
Link,
|
||||||
|
PrimaryButton,
|
||||||
ProgressIndicator,
|
ProgressIndicator,
|
||||||
} from "office-ui-fabric-react";
|
TextField,
|
||||||
import { DefaultButton, IButtonProps, PrimaryButton } from "office-ui-fabric-react/lib/Button";
|
} from "@fluentui/react";
|
||||||
import { Dialog as FluentDialog, DialogFooter, DialogType, IDialogProps } from "office-ui-fabric-react/lib/Dialog";
|
|
||||||
import { Link } from "office-ui-fabric-react/lib/Link";
|
|
||||||
import { ITextFieldProps, TextField } from "office-ui-fabric-react/lib/TextField";
|
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
export interface TextFieldProps extends ITextFieldProps {
|
export interface TextFieldProps extends ITextFieldProps {
|
||||||
@@ -97,7 +103,7 @@ export const Dialog: FunctionComponent<DialogProps> = ({
|
|||||||
text: secondaryButtonText,
|
text: secondaryButtonText,
|
||||||
onClick: onSecondaryButtonClick,
|
onClick: onSecondaryButtonClick,
|
||||||
}
|
}
|
||||||
: undefined;
|
: {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FluentDialog {...dialogProps}>
|
<FluentDialog {...dialogProps}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import template from "./diff-editor-component.html";
|
import template from "./diff-editor-component.html";
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -92,7 +92,7 @@ export class DiffEditorViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor on diff mode and attach to DOM
|
* Create the monaco editor on diff mode and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected createDiffEditor(
|
protected async createDiffEditor(
|
||||||
originalContent: string,
|
originalContent: string,
|
||||||
modifiedContent: string,
|
modifiedContent: string,
|
||||||
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
||||||
@@ -111,7 +111,7 @@ export class DiffEditorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const language = this.params.editorLanguage || "json";
|
const language = this.params.editorLanguage || "json";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
const originalModel = monaco.editor.createModel(originalContent, language);
|
const originalModel = monaco.editor.createModel(originalContent, language);
|
||||||
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
||||||
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
* React component for Switch Directory
|
* React component for Switch Directory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from "underscore";
|
import { Dropdown, IDropdownOption, IDropdownProps } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Dropdown, IDropdownOption, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown";
|
import _ from "underscore";
|
||||||
import { Tenant } from "../../../Contracts/DataModels";
|
import { Tenant } from "../../../Contracts/DataModels";
|
||||||
|
|
||||||
export interface DefaultDirectoryDropdownProps {
|
export interface DefaultDirectoryDropdownProps {
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import _ from "underscore";
|
import {
|
||||||
|
DefaultButton,
|
||||||
|
IButtonProps,
|
||||||
|
ITextFieldProps,
|
||||||
|
List,
|
||||||
|
ScrollablePane,
|
||||||
|
Sticky,
|
||||||
|
StickyPositionType,
|
||||||
|
TextField,
|
||||||
|
} from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import _ from "underscore";
|
||||||
import { DefaultButton, IButtonProps } from "office-ui-fabric-react/lib/Button";
|
|
||||||
import { List } from "office-ui-fabric-react/lib/List";
|
|
||||||
import { ScrollablePane } from "office-ui-fabric-react/lib/ScrollablePane";
|
|
||||||
import { Sticky, StickyPositionType } from "office-ui-fabric-react/lib/Sticky";
|
|
||||||
import { TextField, ITextFieldProps } from "office-ui-fabric-react/lib/TextField";
|
|
||||||
import { Tenant } from "../../../Contracts/DataModels";
|
import { Tenant } from "../../../Contracts/DataModels";
|
||||||
|
|
||||||
export interface DirectoryListProps {
|
export interface DirectoryListProps {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`test render renders with directories and default 1`] = `
|
exports[`test render renders with directories and default 1`] = `
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
className="defaultDirectoryDropdown"
|
className="defaultDirectoryDropdown"
|
||||||
defaultSelectedKey="asdfghjklzxcvbnm9876543210"
|
defaultSelectedKey="asdfghjklzxcvbnm9876543210"
|
||||||
label="Set your default directory"
|
label="Set your default directory"
|
||||||
@@ -26,7 +26,7 @@ exports[`test render renders with directories and default 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`test render renders with directories and last visit default 1`] = `
|
exports[`test render renders with directories and last visit default 1`] = `
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
className="defaultDirectoryDropdown"
|
className="defaultDirectoryDropdown"
|
||||||
defaultSelectedKey="lastVisited"
|
defaultSelectedKey="lastVisited"
|
||||||
label="Set your default directory"
|
label="Set your default directory"
|
||||||
@@ -51,7 +51,7 @@ exports[`test render renders with directories and last visit default 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`test render renders with directories but no default 1`] = `
|
exports[`test render renders with directories but no default 1`] = `
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
className="defaultDirectoryDropdown"
|
className="defaultDirectoryDropdown"
|
||||||
defaultSelectedKey="lastVisited"
|
defaultSelectedKey="lastVisited"
|
||||||
label="Set your default directory"
|
label="Set your default directory"
|
||||||
@@ -76,7 +76,7 @@ exports[`test render renders with directories but no default 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`test render renders with no directories 1`] = `
|
exports[`test render renders with no directories 1`] = `
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
className="defaultDirectoryDropdown"
|
className="defaultDirectoryDropdown"
|
||||||
defaultSelectedKey="lastVisited"
|
defaultSelectedKey="lastVisited"
|
||||||
label="Set your default directory"
|
label="Set your default directory"
|
||||||
|
|||||||
@@ -350,11 +350,11 @@ exports[`test render renders with filters 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-ScrollablePane root-40"
|
className="ms-ScrollablePane root-53"
|
||||||
data-is-scrollable="true"
|
data-is-scrollable="true"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="stickyAbove-42"
|
className="stickyAbove-55"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@@ -365,7 +365,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="ms-ScrollablePane--contentContainer contentContainer-41"
|
className="ms-ScrollablePane--contentContainer contentContainer-54"
|
||||||
data-is-scrollable={true}
|
data-is-scrollable={true}
|
||||||
>
|
>
|
||||||
<Sticky
|
<Sticky
|
||||||
@@ -408,7 +408,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
>
|
>
|
||||||
<TextFieldBase
|
<TextFieldBase
|
||||||
ariaLabel="Directory filter text box"
|
ariaLabel="Directory filter text box"
|
||||||
canRevealPassword={false}
|
|
||||||
className="directoryListFilterTextBox"
|
className="directoryListFilterTextBox"
|
||||||
deferredValidationTime={200}
|
deferredValidationTime={200}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -691,18 +690,18 @@ exports[`test render renders with filters 1`] = `
|
|||||||
validateOnLoad={true}
|
validateOnLoad={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField directoryListFilterTextBox root-46"
|
className="ms-TextField directoryListFilterTextBox root-59"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-wrapper"
|
className="ms-TextField-wrapper"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-fieldGroup fieldGroup-47"
|
className="ms-TextField-fieldGroup fieldGroup-60"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
aria-label="Directory filter text box"
|
aria-label="Directory filter text box"
|
||||||
className="ms-TextField-field field-48"
|
className="ms-TextField-field field-61"
|
||||||
id="TextField0"
|
id="TextField0"
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -1266,7 +1265,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"borderColor": "#f3f2f1",
|
"borderColor": "#f3f2f1",
|
||||||
"color": "#a19f9d",
|
"color": "#a19f9d",
|
||||||
"cursor": "default",
|
"cursor": "default",
|
||||||
"pointerEvents": "none",
|
|
||||||
"selectors": Object {
|
"selectors": Object {
|
||||||
":focus": Object {
|
":focus": Object {
|
||||||
"outline": 0,
|
"outline": 0,
|
||||||
@@ -1611,6 +1609,35 @@ exports[`test render renders with filters 1`] = `
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"splitButtonMenuFocused": Object {
|
||||||
|
"outline": "transparent",
|
||||||
|
"position": "relative",
|
||||||
|
"selectors": Object {
|
||||||
|
".ms-Fabric--isFocusVisible &:focus:after": Object {
|
||||||
|
"border": "1px solid #ffffff",
|
||||||
|
"bottom": 3,
|
||||||
|
"content": "\\"\\"",
|
||||||
|
"left": 3,
|
||||||
|
"outline": "1px solid #605e5c",
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 3,
|
||||||
|
"selectors": Object {
|
||||||
|
"@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object {
|
||||||
|
"border": "none",
|
||||||
|
"bottom": -2,
|
||||||
|
"left": -2,
|
||||||
|
"right": -2,
|
||||||
|
"top": -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"top": 3,
|
||||||
|
"zIndex": 1,
|
||||||
|
},
|
||||||
|
"::-moz-focus-inner": Object {
|
||||||
|
"border": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"splitButtonMenuIcon": Object {
|
"splitButtonMenuIcon": Object {
|
||||||
"color": "#323130",
|
"color": "#323130",
|
||||||
},
|
},
|
||||||
@@ -1900,7 +1927,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled={true}
|
aria-disabled={true}
|
||||||
className="ms-Button ms-Button--default is-disabled directoryListButton root-57"
|
className="ms-Button ms-Button--default is-disabled directoryListButton root-70"
|
||||||
data-is-focusable={false}
|
data-is-focusable={false}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -1912,7 +1939,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-flexContainer flexContainer-58"
|
className="ms-Button-flexContainer flexContainer-71"
|
||||||
data-automationid="splitbuttonprimary"
|
data-automationid="splitbuttonprimary"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -1932,7 +1959,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<Component />
|
<FocusRects />
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</DefaultButton>
|
</DefaultButton>
|
||||||
</CustomizedDefaultButton>
|
</CustomizedDefaultButton>
|
||||||
@@ -1943,7 +1970,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="stickyBelow-43"
|
className="stickyBelow-56"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"bottom": "0px",
|
"bottom": "0px",
|
||||||
@@ -1954,7 +1981,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="stickyBelowItems-44"
|
className="stickyBelowItems-57"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
||||||
import template from "./editor-component.html";
|
import template from "./editor-component.html";
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
import { SqlCompletionItemProvider, ErrorMarkProvider } from "@azure/cosmos-language-service";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -49,15 +48,17 @@ class EditorViewModel extends JsonEditorViewModel {
|
|||||||
return this.params.contentType;
|
return this.params.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected registerCompletionItemProvider() {
|
protected async registerCompletionItemProvider() {
|
||||||
let sqlCompletionItemProvider = new SqlCompletionItemProvider();
|
|
||||||
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
||||||
monaco.languages.registerCompletionItemProvider("sql", sqlCompletionItemProvider);
|
const { SqlCompletionItemProvider } = await import("@azure/cosmos-language-service");
|
||||||
|
const monaco = await loadMonaco();
|
||||||
|
monaco.languages.registerCompletionItemProvider("sql", new SqlCompletionItemProvider());
|
||||||
EditorViewModel.providerRegistered.push("sql");
|
EditorViewModel.providerRegistered.push("sql");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
protected async getErrorMarkers(input: string): Promise<monaco.editor.IMarkerData[]> {
|
||||||
|
const { ErrorMarkProvider } = await import("@azure/cosmos-language-service");
|
||||||
return ErrorMarkProvider.getErrorMark(input);
|
return ErrorMarkProvider.getErrorMark(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as monaco from "monaco-editor";
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
|
|
||||||
export interface EditorReactProps {
|
export interface EditorReactProps {
|
||||||
language: string;
|
language: string;
|
||||||
@@ -61,7 +61,7 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
private createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
value: this.props.content,
|
value: this.props.content,
|
||||||
language: this.props.language,
|
language: this.props.language,
|
||||||
@@ -74,6 +74,7 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.rootNode.innerHTML = "";
|
this.rootNode.innerHTML = "";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
createCallback(monaco.editor.create(this.rootNode, options));
|
createCallback(monaco.editor.create(this.rootNode, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
import template from "./error-display-component.html";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for ko component registration
|
|
||||||
* This component displays an error as designed in:
|
|
||||||
* https://microsoft.sharepoint.com/teams/DPX/Modern/DocDB/_layouts/15/WopiFrame.aspx?sourcedoc={66864d4a-f925-4cbe-9eb4-79f8d191a115}&action=edit&wd=target%28DocumentDB%20emulator%2Eone%7CE617D0A7-F77C-4968-B75A-1451049F4FEA%2FError%20notification%7CAA1E4BC9-4D72-472C-B40C-2437FA217226%2F%29
|
|
||||||
* TODO: support "More details"
|
|
||||||
*/
|
|
||||||
export class ErrorDisplayComponent {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
viewModel: ErrorDisplayViewModel,
|
|
||||||
template,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for this component
|
|
||||||
*/
|
|
||||||
interface ErrorDisplayParams {
|
|
||||||
errorMsg: ko.Observable<string>; // Primary message
|
|
||||||
}
|
|
||||||
|
|
||||||
class ErrorDisplayViewModel {
|
|
||||||
public constructor(public params: ErrorDisplayParams) {}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<div class="warningErrorContainer" data-bind="visible: !!params.errorMsg()">
|
|
||||||
<div class="warningErrorContent">
|
|
||||||
<span><img src="/error_red.svg" alt="Error" /></span>
|
|
||||||
<span class="settingErrorMsg warningErrorDetailsLinkContainer" data-bind="text: params.errorMsg()"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import {
|
||||||
|
Checkbox,
|
||||||
|
DefaultButton,
|
||||||
|
Dropdown,
|
||||||
|
IDropdownOption,
|
||||||
|
IDropdownStyles,
|
||||||
|
ITextFieldStyles,
|
||||||
|
Stack,
|
||||||
|
TextField,
|
||||||
|
} from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
|
||||||
import { Dropdown, IDropdownOption, IDropdownStyles } from "office-ui-fabric-react/lib/Dropdown";
|
|
||||||
import { Checkbox } from "office-ui-fabric-react/lib/Checkbox";
|
|
||||||
import { TextField, ITextFieldStyles } from "office-ui-fabric-react/lib/TextField";
|
|
||||||
import { DefaultButton } from "office-ui-fabric-react";
|
|
||||||
import "./FeaturePanelComponent.less";
|
import "./FeaturePanelComponent.less";
|
||||||
|
|
||||||
export const FeaturePanelComponent: React.FunctionComponent = () => {
|
export const FeaturePanelComponent: React.FunctionComponent = () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { FeaturePanelComponent } from "./FeaturePanelComponent";
|
import { FeaturePanelComponent } from "./FeaturePanelComponent";
|
||||||
import { getTheme, mergeStyleSets, FontWeights, Modal, IconButton, IIconProps } from "office-ui-fabric-react";
|
import { getTheme, mergeStyleSets, FontWeights, Modal, IconButton, IIconProps } from "@fluentui/react";
|
||||||
import "./FeaturePanelLauncher.less";
|
import "./FeaturePanelLauncher.less";
|
||||||
|
|
||||||
// Modal wrapper
|
// Modal wrapper
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ exports[`Feature panel renders all flags 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
label="Base Url"
|
label="Base Url"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
options={
|
options={
|
||||||
@@ -85,7 +85,7 @@ exports[`Feature panel renders all flags 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StyledWithResponsiveMode
|
<Dropdown
|
||||||
label="Platform"
|
label="Platform"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
options={
|
options={
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "office-ui-fabric-react";
|
import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
import {
|
import { ChoiceGroup, IButtonProps, IChoiceGroupProps, PrimaryButton, IChoiceGroupOption } from "@fluentui/react";
|
||||||
ChoiceGroup,
|
|
||||||
IButtonProps,
|
|
||||||
IChoiceGroupProps,
|
|
||||||
PrimaryButton,
|
|
||||||
IChoiceGroupOption,
|
|
||||||
} from "office-ui-fabric-react";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ChildrenMargin } from "./GitHubStyleConstants";
|
import { ChildrenMargin } from "./GitHubStyleConstants";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DefaultButton, IButtonProps, Link, PrimaryButton } from "office-ui-fabric-react";
|
import { DefaultButton, IButtonProps, Link, PrimaryButton } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IGitHubBranch, IGitHubRepo } from "../../../GitHub/GitHubClient";
|
import { IGitHubBranch, IGitHubRepo } from "../../../GitHub/GitHubClient";
|
||||||
import { AddRepoComponent, AddRepoComponentProps } from "./AddRepoComponent";
|
import { AddRepoComponent, AddRepoComponentProps } from "./AddRepoComponent";
|
||||||
@@ -23,8 +23,6 @@ export interface RepoListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class GitHubReposComponent extends React.Component<GitHubReposComponentProps> {
|
export class GitHubReposComponent extends React.Component<GitHubReposComponentProps> {
|
||||||
public static readonly ConnectToGitHubTitle = "Connect to GitHub";
|
|
||||||
public static readonly ManageGitHubRepoTitle = "Manage GitHub settings";
|
|
||||||
private static readonly ManageGitHubRepoDescription =
|
private static readonly ManageGitHubRepoDescription =
|
||||||
"Select your GitHub repos and branch(es) to pin to your notebooks workspace.";
|
"Select your GitHub repos and branch(es) to pin to your notebooks workspace.";
|
||||||
private static readonly ManageGitHubRepoResetConnection = "View or change your GitHub authorization settings.";
|
private static readonly ManageGitHubRepoResetConnection = "View or change your GitHub authorization settings.";
|
||||||
@@ -32,14 +30,6 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
|
|||||||
private static readonly CancelButtonText = "Cancel";
|
private static readonly CancelButtonText = "Cancel";
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const header: JSX.Element = (
|
|
||||||
<p>
|
|
||||||
{this.props.showAuthorizeAccess
|
|
||||||
? GitHubReposComponent.ConnectToGitHubTitle
|
|
||||||
: GitHubReposComponent.ManageGitHubRepoTitle}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
|
|
||||||
const content: JSX.Element = this.props.showAuthorizeAccess ? (
|
const content: JSX.Element = this.props.showAuthorizeAccess ? (
|
||||||
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
|
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
|
||||||
) : (
|
) : (
|
||||||
@@ -66,9 +56,6 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={"firstdivbg headerline"} role="heading" aria-level={2}>
|
|
||||||
{header}
|
|
||||||
</div>
|
|
||||||
<div className={"paneMainContent"}>{content}</div>
|
<div className={"paneMainContent"}>{content}</div>
|
||||||
{!this.props.showAuthorizeAccess && (
|
{!this.props.showAuthorizeAccess && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
IStyleFunctionOrObject,
|
|
||||||
ICheckboxStyleProps,
|
ICheckboxStyleProps,
|
||||||
ICheckboxStyles,
|
ICheckboxStyles,
|
||||||
IDropdownStyles,
|
|
||||||
IDropdownStyleProps,
|
IDropdownStyleProps,
|
||||||
} from "office-ui-fabric-react";
|
IDropdownStyles,
|
||||||
|
IStyleFunctionOrObject,
|
||||||
|
} from "@fluentui/react";
|
||||||
|
|
||||||
export const ButtonsFooterStyle: React.CSSProperties = {
|
export const ButtonsFooterStyle: React.CSSProperties = {
|
||||||
padding: 14,
|
paddingTop: 14,
|
||||||
height: "auto",
|
height: "auto",
|
||||||
|
borderTop: "2px solid lightGray",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ContentFooterStyle: React.CSSProperties = {
|
export const ContentFooterStyle: React.CSSProperties = {
|
||||||
padding: "10px 24px 10px 24px",
|
paddingTop: "10px",
|
||||||
height: "auto",
|
height: "auto",
|
||||||
|
borderTop: "2px solid lightGray",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ChildrenMargin = 10;
|
export const ChildrenMargin = 10;
|
||||||
@@ -53,6 +55,11 @@ export const BranchesDropdownOptionContainerStyle: React.CSSProperties = {
|
|||||||
padding: 8,
|
padding: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ContentMainStyle: React.CSSProperties = {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
};
|
||||||
|
|
||||||
export const ReposListRepoColumnMinWidth = 192;
|
export const ReposListRepoColumnMinWidth = 192;
|
||||||
export const ReposListBranchesColumnWidth = 116;
|
export const ReposListBranchesColumnWidth = 116;
|
||||||
export const BranchesDropdownWidth = 200;
|
export const BranchesDropdownWidth = 200;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
ResponsiveMode,
|
ResponsiveMode,
|
||||||
SelectionMode,
|
SelectionMode,
|
||||||
Text,
|
Text,
|
||||||
} from "office-ui-fabric-react";
|
} from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IGitHubBranch, IGitHubPageInfo } from "../../../GitHub/GitHubClient";
|
import { IGitHubBranch, IGitHubPageInfo } from "../../../GitHub/GitHubClient";
|
||||||
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { CommandButton, FontIcon, FontWeights, ITextProps, Separator, Stack, Text } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Stack, Text, Separator, FontIcon, CommandButton, FontWeights, ITextProps } from "office-ui-fabric-react";
|
|
||||||
|
|
||||||
export class GalleryHeaderComponent extends React.Component {
|
export class GalleryHeaderComponent extends React.Component {
|
||||||
private static readonly azureText = "Microsoft Azure";
|
private static readonly azureText = "Microsoft Azure";
|
||||||
@@ -61,7 +61,7 @@ export class GalleryHeaderComponent extends React.Component {
|
|||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
{this.renderHeaderItem(
|
{this.renderHeaderItem(
|
||||||
GalleryHeaderComponent.galleryText,
|
GalleryHeaderComponent.galleryText,
|
||||||
undefined,
|
() => "",
|
||||||
GalleryHeaderComponent.headerItemTextProps
|
GalleryHeaderComponent.headerItemTextProps
|
||||||
)}
|
)}
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
/**
|
|
||||||
* How to use this component:
|
|
||||||
*
|
|
||||||
* In your html markup, use:
|
|
||||||
* <input-typeahead params="{
|
|
||||||
choices:choices,
|
|
||||||
selection:selection,
|
|
||||||
inputValue:inputValue,
|
|
||||||
placeholder:'Enter source',
|
|
||||||
typeaheadOverrideOptions:typeaheadOverrideOptions
|
|
||||||
}"></input-typeahead>
|
|
||||||
* The parameters are documented below.
|
|
||||||
*
|
|
||||||
* Notes:
|
|
||||||
* - dynamic:true by default, this allows choices to change after initialization.
|
|
||||||
* To turn it off, use:
|
|
||||||
* typeaheadOverrideOptions: { dynamic:false }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "jquery-typeahead";
|
|
||||||
import template from "./input-typeahead.html";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for ko component registration
|
|
||||||
*/
|
|
||||||
export class InputTypeaheadComponent {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
viewModel: InputTypeaheadViewModel,
|
|
||||||
template,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Item {
|
|
||||||
caption: string;
|
|
||||||
value: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for this component
|
|
||||||
*/
|
|
||||||
interface InputTypeaheadParams {
|
|
||||||
/**
|
|
||||||
* List of choices available in the dropdown.
|
|
||||||
*/
|
|
||||||
choices: ko.ObservableArray<Item>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets updated when user clicks on the choice in the dropdown
|
|
||||||
*/
|
|
||||||
selection?: ko.Observable<Item>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current string value of <input>
|
|
||||||
*/
|
|
||||||
inputValue?: ko.Observable<string>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define what text you want as the input placeholder
|
|
||||||
*/
|
|
||||||
placeholder: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override default jquery-typeahead options
|
|
||||||
* WARNING: do not override input, source or callback to avoid breaking the components behavior.
|
|
||||||
*/
|
|
||||||
typeaheadOverrideOptions?: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function gets called when pressing ENTER on the input box
|
|
||||||
*/
|
|
||||||
submitFct?: (inputValue: string | null, selection: Item | null) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typehead comes with a Search button that we normally remove.
|
|
||||||
* If you want to use it, turn this on
|
|
||||||
*/
|
|
||||||
showSearchButton?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OnClickItem {
|
|
||||||
matchedKey: string;
|
|
||||||
value: any;
|
|
||||||
caption: string;
|
|
||||||
group: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Cache {
|
|
||||||
inputValue: string | null;
|
|
||||||
selection: Item | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class InputTypeaheadViewModel {
|
|
||||||
private static instanceCount = 0; // Generate unique id for each component's typeahead instance
|
|
||||||
private instanceNumber: number;
|
|
||||||
private params: InputTypeaheadParams;
|
|
||||||
|
|
||||||
private cache: Cache;
|
|
||||||
|
|
||||||
public constructor(params: InputTypeaheadParams) {
|
|
||||||
this.instanceNumber = InputTypeaheadViewModel.instanceCount++;
|
|
||||||
this.params = params;
|
|
||||||
|
|
||||||
this.params.choices.subscribe(this.initializeTypeahead.bind(this));
|
|
||||||
this.cache = {
|
|
||||||
inputValue: null,
|
|
||||||
selection: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Must execute once ko is rendered, so that it can find the input element by id
|
|
||||||
*/
|
|
||||||
private initializeTypeahead() {
|
|
||||||
let params = this.params;
|
|
||||||
let cache = this.cache;
|
|
||||||
let options: any = {
|
|
||||||
input: `#${this.getComponentId()}`, //'.input-typeahead',
|
|
||||||
order: "asc",
|
|
||||||
minLength: 0,
|
|
||||||
searchOnFocus: true,
|
|
||||||
source: {
|
|
||||||
display: "caption",
|
|
||||||
data: () => {
|
|
||||||
return this.params.choices();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
callback: {
|
|
||||||
onClick: (node: any, a: any, item: OnClickItem, event: any) => {
|
|
||||||
cache.selection = item;
|
|
||||||
|
|
||||||
if (params.selection) {
|
|
||||||
params.selection(item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onResult(node: any, query: any, result: any, resultCount: any, resultCountPerGroup: any) {
|
|
||||||
cache.inputValue = query;
|
|
||||||
if (params.inputValue) {
|
|
||||||
params.inputValue(query);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
template: (query: string, item: any) => {
|
|
||||||
// Don't display id if caption *IS* the id
|
|
||||||
return item.caption === item.value
|
|
||||||
? "<span>{{caption}}</span>"
|
|
||||||
: "<span><div>{{caption}}</div><div><small>{{value}}</small></div></span>";
|
|
||||||
},
|
|
||||||
dynamic: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Override options
|
|
||||||
if (params.typeaheadOverrideOptions) {
|
|
||||||
for (let p in params.typeaheadOverrideOptions) {
|
|
||||||
options[p] = params.typeaheadOverrideOptions[p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
($ as any).typeahead(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get this component id
|
|
||||||
* @return unique id per instance
|
|
||||||
*/
|
|
||||||
private getComponentId(): string {
|
|
||||||
return `input-typeahead${this.instanceNumber}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executed once ko is done rendering bindings
|
|
||||||
* Use ko's "template: afterRender" callback to do that without actually using any template.
|
|
||||||
* Another way is to call it within setTimeout() in constructor.
|
|
||||||
*/
|
|
||||||
public afterRender(): void {
|
|
||||||
this.initializeTypeahead();
|
|
||||||
}
|
|
||||||
|
|
||||||
public submit(): void {
|
|
||||||
if (this.params.submitFct) {
|
|
||||||
this.params.submitFct(this.cache.inputValue, this.cache.selection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<span class="input-typeahead-container">
|
|
||||||
<form class="input-typehead" data-bind="submit:submit">
|
|
||||||
<div class="typeahead__container">
|
|
||||||
<div class="typeahead__field">
|
|
||||||
<span class="typeahead__query">
|
|
||||||
<input
|
|
||||||
name="q"
|
|
||||||
type="search"
|
|
||||||
autocomplete="off"
|
|
||||||
data-bind="attr: { placeholder: params.placeholder, id:getComponentId() }, value:params.inputValue, template: { afterRender:afterRender() }"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="typeahead__button" data-bind="visible:params.showSearchButton">
|
|
||||||
<button type="submit"><span class="typeahead__search-icon"></span></button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</span>
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import Q from "q";
|
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
||||||
import template from "./json-editor-component.html";
|
import template from "./json-editor-component.html";
|
||||||
|
|
||||||
@@ -88,7 +87,7 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
protected async createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
this.registerCompletionItemProvider();
|
this.registerCompletionItemProvider();
|
||||||
this.editorContainer = document.getElementById(this.getEditorId());
|
this.editorContainer = document.getElementById(this.getEditorId());
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
@@ -102,6 +101,7 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.editorContainer.innerHTML = "";
|
this.editorContainer.innerHTML = "";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
createCallback(monaco.editor.create(this.editorContainer, options));
|
createCallback(monaco.editor.create(this.editorContainer, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,15 +109,16 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
protected registerCompletionItemProvider() {}
|
protected registerCompletionItemProvider() {}
|
||||||
|
|
||||||
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
||||||
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
protected async getErrorMarkers(_: string): Promise<monaco.editor.IMarkerData[]> {
|
||||||
return Q.Promise(() => {});
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getEditorLanguage(): string {
|
protected getEditorLanguage(): string {
|
||||||
return "json";
|
return "json";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
protected async configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
||||||
|
const monaco = await loadMonaco();
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
const queryEditorModel = this.editor.getModel();
|
const queryEditorModel = this.editor.getModel();
|
||||||
if (!this.params.isReadOnly && this.params.updatedContent) {
|
if (!this.params.isReadOnly && this.params.updatedContent) {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const createTestDatabaseAccount = (): DataModels.DatabaseAccount => {
|
|||||||
gremlinEndpoint: null,
|
gremlinEndpoint: null,
|
||||||
tableEndpoint: null,
|
tableEndpoint: null,
|
||||||
},
|
},
|
||||||
tags: "testTags",
|
|
||||||
type: "testType",
|
type: "testType",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -30,7 +29,6 @@ const createTestMongo32DatabaseAccount = (): DataModels.DatabaseAccount => {
|
|||||||
gremlinEndpoint: null,
|
gremlinEndpoint: null,
|
||||||
tableEndpoint: null,
|
tableEndpoint: null,
|
||||||
},
|
},
|
||||||
tags: "testTags",
|
|
||||||
type: "testType",
|
type: "testType",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -48,7 +46,6 @@ const createTestMongo36DatabaseAccount = (): DataModels.DatabaseAccount => {
|
|||||||
tableEndpoint: null,
|
tableEndpoint: null,
|
||||||
mongoEndpoint: "https://testMongoEndpoint.azure.com/",
|
mongoEndpoint: "https://testMongoEndpoint.azure.com/",
|
||||||
},
|
},
|
||||||
tags: "testTags",
|
|
||||||
type: "testType",
|
type: "testType",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -65,7 +62,6 @@ const createTestCassandraDatabaseAccount = (): DataModels.DatabaseAccount => {
|
|||||||
gremlinEndpoint: null,
|
gremlinEndpoint: null,
|
||||||
tableEndpoint: null,
|
tableEndpoint: null,
|
||||||
},
|
},
|
||||||
tags: "testTags",
|
|
||||||
type: "testType",
|
type: "testType",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
import { Card } from "@uifabric/react-cards";
|
|
||||||
import {
|
import {
|
||||||
FontWeights,
|
|
||||||
Icon,
|
|
||||||
IconButton,
|
|
||||||
Image,
|
|
||||||
ImageFit,
|
|
||||||
Persona,
|
|
||||||
Text,
|
|
||||||
Link,
|
|
||||||
BaseButton,
|
BaseButton,
|
||||||
Button,
|
Button,
|
||||||
LinkBase,
|
DocumentCard,
|
||||||
|
DocumentCardActivity,
|
||||||
|
DocumentCardDetails,
|
||||||
|
DocumentCardPreview,
|
||||||
|
DocumentCardTitle,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
IDocumentCardPreviewProps,
|
||||||
|
IDocumentCardStyles,
|
||||||
|
ImageFit,
|
||||||
|
Link,
|
||||||
Separator,
|
Separator,
|
||||||
TooltipHost,
|
|
||||||
Spinner,
|
Spinner,
|
||||||
SpinnerSize,
|
SpinnerSize,
|
||||||
} from "office-ui-fabric-react";
|
Text,
|
||||||
import * as React from "react";
|
TooltipHost,
|
||||||
|
} from "@fluentui/react";
|
||||||
|
import React, { FunctionComponent, useState } from "react";
|
||||||
|
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
||||||
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
||||||
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
||||||
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
|
||||||
|
|
||||||
export interface GalleryCardComponentProps {
|
export interface GalleryCardComponentProps {
|
||||||
data: IGalleryItem;
|
data: IGalleryItem;
|
||||||
@@ -34,166 +36,47 @@ export interface GalleryCardComponentProps {
|
|||||||
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GalleryCardComponentState {
|
export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps> = ({
|
||||||
isDeletingPublishedNotebook: boolean;
|
data,
|
||||||
}
|
isFavorite,
|
||||||
|
showDownload,
|
||||||
|
showDelete,
|
||||||
|
onClick,
|
||||||
|
onTagClick,
|
||||||
|
onFavoriteClick,
|
||||||
|
onUnfavoriteClick,
|
||||||
|
onDownloadClick,
|
||||||
|
onDeleteClick,
|
||||||
|
}: GalleryCardComponentProps) => {
|
||||||
|
const CARD_WIDTH = 256;
|
||||||
|
const cardImageHeight = 144;
|
||||||
|
const cardDescriptionMaxChars = 80;
|
||||||
|
const cardItemGapSmall = 8;
|
||||||
|
const cardDeleteSpinnerHeight = 360;
|
||||||
|
const smallTextLineHeight = 18;
|
||||||
|
|
||||||
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps, GalleryCardComponentState> {
|
const [isDeletingPublishedNotebook, setIsDeletingPublishedNotebook] = useState<boolean>(false);
|
||||||
public static readonly CARD_WIDTH = 256;
|
|
||||||
private static readonly cardImageHeight = 144;
|
|
||||||
public static readonly cardHeightToWidthRatio =
|
|
||||||
GalleryCardComponent.cardImageHeight / GalleryCardComponent.CARD_WIDTH;
|
|
||||||
private static readonly cardDescriptionMaxChars = 80;
|
|
||||||
private static readonly cardItemGapBig = 10;
|
|
||||||
private static readonly cardItemGapSmall = 8;
|
|
||||||
private static readonly cardDeleteSpinnerHeight = 360;
|
|
||||||
private static readonly smallTextLineHeight = 18;
|
|
||||||
|
|
||||||
constructor(props: GalleryCardComponentProps) {
|
const cardButtonsVisible = isFavorite !== undefined || showDownload || showDelete;
|
||||||
super(props);
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
this.state = {
|
year: "numeric",
|
||||||
isDeletingPublishedNotebook: false,
|
month: "short",
|
||||||
};
|
day: "numeric",
|
||||||
}
|
};
|
||||||
|
const dateString = new Date(data.created).toLocaleString("default", options);
|
||||||
|
const cardTitle = FileSystemUtil.stripExtension(data.name, "ipynb");
|
||||||
|
|
||||||
public render(): JSX.Element {
|
const renderTruncated = (text: string, totalLength: number): string => {
|
||||||
const cardButtonsVisible = this.props.isFavorite !== undefined || this.props.showDownload || this.props.showDelete;
|
let truncatedDescription = text.substr(0, totalLength);
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
if (text.length > totalLength) {
|
||||||
year: "numeric",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
};
|
|
||||||
const dateString = new Date(this.props.data.created).toLocaleString("default", options);
|
|
||||||
const cardTitle = FileSystemUtil.stripExtension(this.props.data.name, "ipynb");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
style={{ background: "white" }}
|
|
||||||
aria-label={cardTitle}
|
|
||||||
data-is-focusable="true"
|
|
||||||
tokens={{ width: GalleryCardComponent.CARD_WIDTH, childrenGap: 0 }}
|
|
||||||
onClick={(event) => this.onClick(event, this.props.onClick)}
|
|
||||||
>
|
|
||||||
{this.state.isDeletingPublishedNotebook && (
|
|
||||||
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
|
||||||
<Spinner
|
|
||||||
size={SpinnerSize.large}
|
|
||||||
label={`Deleting '${cardTitle}'`}
|
|
||||||
styles={{ root: { height: GalleryCardComponent.cardDeleteSpinnerHeight } }}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
)}
|
|
||||||
{!this.state.isDeletingPublishedNotebook && (
|
|
||||||
<>
|
|
||||||
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
|
||||||
<Persona
|
|
||||||
imageUrl={this.props.data.isSample && CosmosDBLogo}
|
|
||||||
text={this.props.data.author}
|
|
||||||
secondaryText={dateString}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
|
|
||||||
<Card.Item>
|
|
||||||
<Image
|
|
||||||
src={this.props.data.thumbnailUrl}
|
|
||||||
width={GalleryCardComponent.CARD_WIDTH}
|
|
||||||
height={GalleryCardComponent.cardImageHeight}
|
|
||||||
imageFit={ImageFit.cover}
|
|
||||||
alt={`${cardTitle} cover image`}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
|
|
||||||
<Card.Section styles={{ root: { padding: GalleryCardComponent.cardItemGapBig } }}>
|
|
||||||
<Text variant="small" nowrap styles={{ root: { height: GalleryCardComponent.smallTextLineHeight } }}>
|
|
||||||
{this.props.data.tags ? (
|
|
||||||
this.props.data.tags.map((tag, index, array) => (
|
|
||||||
<span key={tag}>
|
|
||||||
<Link onClick={(event) => this.onClick(event, () => this.props.onTagClick(tag))}>{tag}</Link>
|
|
||||||
{index === array.length - 1 ? <></> : ", "}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<br />
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
fontWeight: FontWeights.semibold,
|
|
||||||
paddingTop: GalleryCardComponent.cardItemGapSmall,
|
|
||||||
paddingBottom: GalleryCardComponent.cardItemGapSmall,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
nowrap
|
|
||||||
>
|
|
||||||
{cardTitle}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text variant="small" styles={{ root: { height: GalleryCardComponent.smallTextLineHeight * 2 } }}>
|
|
||||||
{this.renderTruncatedDescription()}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{this.props.data.views !== undefined &&
|
|
||||||
this.generateIconText("RedEye", this.props.data.views.toString())}
|
|
||||||
{this.props.data.downloads !== undefined &&
|
|
||||||
this.generateIconText("Download", this.props.data.downloads.toString())}
|
|
||||||
{this.props.data.favorites !== undefined &&
|
|
||||||
this.generateIconText("Heart", this.props.data.favorites.toString())}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
|
|
||||||
{cardButtonsVisible && (
|
|
||||||
<Card.Section
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
marginLeft: GalleryCardComponent.cardItemGapBig,
|
|
||||||
marginRight: GalleryCardComponent.cardItemGapBig,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{this.props.isFavorite !== undefined &&
|
|
||||||
this.generateIconButtonWithTooltip(
|
|
||||||
this.props.isFavorite ? "HeartFill" : "Heart",
|
|
||||||
this.props.isFavorite ? "Unfavorite" : "Favorite",
|
|
||||||
"left",
|
|
||||||
this.props.isFavorite ? this.props.onUnfavoriteClick : this.props.onFavoriteClick
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.props.showDownload &&
|
|
||||||
this.generateIconButtonWithTooltip("Download", "Download", "left", this.props.onDownloadClick)}
|
|
||||||
|
|
||||||
{this.props.showDelete &&
|
|
||||||
this.generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
|
||||||
this.props.onDeleteClick(
|
|
||||||
() => this.setState({ isDeletingPublishedNotebook: true }),
|
|
||||||
() => this.setState({ isDeletingPublishedNotebook: false })
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderTruncatedDescription = (): string => {
|
|
||||||
let truncatedDescription = this.props.data.description.substr(0, GalleryCardComponent.cardDescriptionMaxChars);
|
|
||||||
if (this.props.data.description.length > GalleryCardComponent.cardDescriptionMaxChars) {
|
|
||||||
truncatedDescription = `${truncatedDescription} ...`;
|
truncatedDescription = `${truncatedDescription} ...`;
|
||||||
}
|
}
|
||||||
return truncatedDescription;
|
return truncatedDescription;
|
||||||
};
|
};
|
||||||
|
|
||||||
private generateIconText = (iconName: string, text: string): JSX.Element => {
|
const generateIconText = (iconName: string, text: string): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: GalleryCardComponent.cardItemGapSmall } }}>
|
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: cardItemGapSmall } }}>
|
||||||
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -203,7 +86,7 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
||||||
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
||||||
*/
|
*/
|
||||||
private generateIconButtonWithTooltip = (
|
const generateIconButtonWithTooltip = (
|
||||||
iconName: string,
|
iconName: string,
|
||||||
title: string,
|
title: string,
|
||||||
horizontalAlign: "right" | "left",
|
horizontalAlign: "right" | "left",
|
||||||
@@ -220,15 +103,15 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
iconProps={{ iconName }}
|
iconProps={{ iconName }}
|
||||||
title={title}
|
title={title}
|
||||||
ariaLabel={title}
|
ariaLabel={title}
|
||||||
onClick={(event) => this.onClick(event, activate)}
|
onClick={(event) => handlerOnClick(event, activate)}
|
||||||
/>
|
/>
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClick = (
|
const handlerOnClick = (
|
||||||
event:
|
event:
|
||||||
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent>
|
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | MouseEvent>
|
||||||
| React.MouseEvent<
|
| React.MouseEvent<
|
||||||
HTMLAnchorElement | HTMLButtonElement | HTMLDivElement | BaseButton | Button | HTMLSpanElement,
|
HTMLAnchorElement | HTMLButtonElement | HTMLDivElement | BaseButton | Button | HTMLSpanElement,
|
||||||
MouseEvent
|
MouseEvent
|
||||||
@@ -239,4 +122,84 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
activate();
|
activate();
|
||||||
};
|
};
|
||||||
}
|
const DocumentCardActivityPeople = [{ name: data.author, profileImageSrc: data.isSample && CosmosDBLogo }];
|
||||||
|
const previewProps: IDocumentCardPreviewProps = {
|
||||||
|
previewImages: [
|
||||||
|
{
|
||||||
|
previewImageSrc: data.thumbnailUrl,
|
||||||
|
imageFit: ImageFit.cover,
|
||||||
|
width: CARD_WIDTH,
|
||||||
|
height: cardImageHeight,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const cardStyles: IDocumentCardStyles = {
|
||||||
|
root: { display: "inline-block", marginRight: 20, width: CARD_WIDTH },
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<DocumentCard aria-label={cardTitle} styles={cardStyles} onClick={onClick}>
|
||||||
|
{isDeletingPublishedNotebook && (
|
||||||
|
<Spinner
|
||||||
|
size={SpinnerSize.large}
|
||||||
|
label={`Deleting '${cardTitle}'`}
|
||||||
|
styles={{ root: { height: cardDeleteSpinnerHeight } }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!isDeletingPublishedNotebook && (
|
||||||
|
<>
|
||||||
|
<DocumentCardActivity activity={dateString} people={DocumentCardActivityPeople} />
|
||||||
|
<DocumentCardPreview {...previewProps} />
|
||||||
|
<DocumentCardDetails>
|
||||||
|
<Text variant="small" nowrap styles={{ root: { height: smallTextLineHeight, padding: "2px 16px" } }}>
|
||||||
|
{data.tags ? (
|
||||||
|
data.tags.map((tag, index, array) => (
|
||||||
|
<span key={tag}>
|
||||||
|
<Link onClick={(event) => handlerOnClick(event, () => onTagClick(tag))}>{tag}</Link>
|
||||||
|
{index === array.length - 1 ? <></> : ", "}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<br />
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<DocumentCardTitle title={renderTruncated(cardTitle, 20)} shouldTruncate />
|
||||||
|
<DocumentCardTitle
|
||||||
|
title={renderTruncated(data.description, cardDescriptionMaxChars)}
|
||||||
|
showAsSecondaryTitle
|
||||||
|
/>
|
||||||
|
<span style={{ padding: "8px 16px" }}>
|
||||||
|
{data.views !== undefined && generateIconText("RedEye", data.views.toString())}
|
||||||
|
{data.downloads !== undefined && generateIconText("Download", data.downloads.toString())}
|
||||||
|
{data.favorites !== undefined && generateIconText("Heart", data.favorites.toString())}
|
||||||
|
</span>
|
||||||
|
</DocumentCardDetails>
|
||||||
|
{cardButtonsVisible && (
|
||||||
|
<DocumentCardDetails>
|
||||||
|
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
||||||
|
|
||||||
|
<span style={{ padding: "0px 16px" }}>
|
||||||
|
{isFavorite !== undefined &&
|
||||||
|
generateIconButtonWithTooltip(
|
||||||
|
isFavorite ? "HeartFill" : "Heart",
|
||||||
|
isFavorite ? "Unfavorite" : "Favorite",
|
||||||
|
"left",
|
||||||
|
isFavorite ? onUnfavoriteClick : onFavoriteClick
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showDownload && generateIconButtonWithTooltip("Download", "Download", "left", onDownloadClick)}
|
||||||
|
|
||||||
|
{showDelete &&
|
||||||
|
generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
||||||
|
onDeleteClick(
|
||||||
|
() => setIsDeletingPublishedNotebook(true),
|
||||||
|
() => setIsDeletingPublishedNotebook(false)
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</DocumentCardDetails>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</DocumentCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,59 +1,49 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`GalleryCardComponent renders 1`] = `
|
exports[`GalleryCardComponent renders 1`] = `
|
||||||
<Card
|
<StyledDocumentCardBase
|
||||||
aria-label="name"
|
aria-label="name"
|
||||||
data-is-focusable="true"
|
styles={
|
||||||
onClick={[Function]}
|
|
||||||
style={
|
|
||||||
Object {
|
Object {
|
||||||
"background": "white",
|
"root": Object {
|
||||||
}
|
"display": "inline-block",
|
||||||
}
|
"marginRight": 20,
|
||||||
tokens={
|
"width": 256,
|
||||||
Object {
|
},
|
||||||
"childrenGap": 0,
|
|
||||||
"width": 256,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CardItem
|
<StyledDocumentCardActivityBase
|
||||||
tokens={
|
activity="Invalid Date"
|
||||||
Object {
|
people={
|
||||||
"padding": 10,
|
Array [
|
||||||
}
|
Object {
|
||||||
}
|
"name": "author",
|
||||||
>
|
"profileImageSrc": false,
|
||||||
<StyledPersonaBase
|
|
||||||
imageUrl={false}
|
|
||||||
secondaryText="Invalid Date"
|
|
||||||
text="author"
|
|
||||||
/>
|
|
||||||
</CardItem>
|
|
||||||
<CardItem>
|
|
||||||
<StyledImageBase
|
|
||||||
alt="name cover image"
|
|
||||||
height={144}
|
|
||||||
imageFit={2}
|
|
||||||
src="thumbnailUrl"
|
|
||||||
width={256}
|
|
||||||
/>
|
|
||||||
</CardItem>
|
|
||||||
<CardSection
|
|
||||||
styles={
|
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"padding": 10,
|
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
>
|
/>
|
||||||
|
<StyledDocumentCardPreviewBase
|
||||||
|
previewImages={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"height": 144,
|
||||||
|
"imageFit": 2,
|
||||||
|
"previewImageSrc": "thumbnailUrl",
|
||||||
|
"width": 256,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<StyledDocumentCardDetailsBase>
|
||||||
<Text
|
<Text
|
||||||
nowrap={true}
|
nowrap={true}
|
||||||
styles={
|
styles={
|
||||||
Object {
|
Object {
|
||||||
"root": Object {
|
"root": Object {
|
||||||
"height": 18,
|
"height": 18,
|
||||||
|
"padding": "2px 16px",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,33 +59,21 @@ exports[`GalleryCardComponent renders 1`] = `
|
|||||||
</StyledLinkBase>
|
</StyledLinkBase>
|
||||||
</span>
|
</span>
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<StyledDocumentCardTitleBase
|
||||||
nowrap={true}
|
shouldTruncate={true}
|
||||||
styles={
|
title="name"
|
||||||
|
/>
|
||||||
|
<StyledDocumentCardTitleBase
|
||||||
|
showAsSecondaryTitle={true}
|
||||||
|
title="description"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
Object {
|
Object {
|
||||||
"root": Object {
|
"padding": "8px 16px",
|
||||||
"fontWeight": 600,
|
|
||||||
"paddingBottom": 8,
|
|
||||||
"paddingTop": 8,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
name
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
styles={
|
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"height": 36,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
variant="small"
|
|
||||||
>
|
|
||||||
description
|
|
||||||
</Text>
|
|
||||||
<span>
|
|
||||||
<Text
|
<Text
|
||||||
styles={
|
styles={
|
||||||
Object {
|
Object {
|
||||||
@@ -169,17 +147,8 @@ exports[`GalleryCardComponent renders 1`] = `
|
|||||||
0
|
0
|
||||||
</Text>
|
</Text>
|
||||||
</span>
|
</span>
|
||||||
</CardSection>
|
</StyledDocumentCardDetailsBase>
|
||||||
<CardSection
|
<StyledDocumentCardDetailsBase>
|
||||||
styles={
|
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"marginLeft": 10,
|
|
||||||
"marginRight": 10,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Separator
|
<Separator
|
||||||
styles={
|
styles={
|
||||||
Object {
|
Object {
|
||||||
@@ -190,7 +159,13 @@ exports[`GalleryCardComponent renders 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span>
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"padding": "0px 16px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
<StyledTooltipHostBase
|
<StyledTooltipHostBase
|
||||||
calloutProps={
|
calloutProps={
|
||||||
Object {
|
Object {
|
||||||
@@ -276,6 +251,6 @@ exports[`GalleryCardComponent renders 1`] = `
|
|||||||
/>
|
/>
|
||||||
</StyledTooltipHostBase>
|
</StyledTooltipHostBase>
|
||||||
</span>
|
</span>
|
||||||
</CardSection>
|
</StyledDocumentCardDetailsBase>
|
||||||
</Card>
|
</StyledDocumentCardBase>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
jest.mock("../../../Juno/JunoClient");
|
jest.mock("../../../../Juno/JunoClient");
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CodeOfConductComponent, CodeOfConductComponentProps } from "./CodeOfConductComponent";
|
import { HttpStatusCodes } from "../../../../Common/Constants";
|
||||||
import { JunoClient } from "../../../Juno/JunoClient";
|
import { JunoClient } from "../../../../Juno/JunoClient";
|
||||||
import { HttpStatusCodes } from "../../../Common/Constants";
|
import { CodeOfConduct, CodeOfConductProps } from "./CodeOfConduct";
|
||||||
|
|
||||||
describe("CodeOfConductComponent", () => {
|
describe("CodeOfConduct", () => {
|
||||||
let codeOfConductProps: CodeOfConductComponentProps;
|
let codeOfConductProps: CodeOfConductProps;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const junoClient = new JunoClient(undefined);
|
const junoClient = new JunoClient();
|
||||||
junoClient.acceptCodeOfConduct = jest.fn().mockReturnValue({
|
junoClient.acceptCodeOfConduct = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
data: true,
|
data: true,
|
||||||
@@ -21,12 +21,12 @@ describe("CodeOfConductComponent", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
const wrapper = shallow(<CodeOfConductComponent {...codeOfConductProps} />);
|
const wrapper = shallow(<CodeOfConduct {...codeOfConductProps} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("onAcceptedCodeOfConductCalled", async () => {
|
it("onAcceptedCodeOfConductCalled", async () => {
|
||||||
const wrapper = shallow(<CodeOfConductComponent {...codeOfConductProps} />);
|
const wrapper = shallow(<CodeOfConduct {...codeOfConductProps} />);
|
||||||
wrapper.find(".genericPaneSubmitBtn").first().simulate("click");
|
wrapper.find(".genericPaneSubmitBtn").first().simulate("click");
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
expect(codeOfConductProps.onAcceptCodeOfConduct).toBeCalled();
|
expect(codeOfConductProps.onAcceptCodeOfConduct).toBeCalled();
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { Checkbox, Link, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||||
|
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||||
|
import { CodeOfConductEndpoints, HttpStatusCodes } from "../../../../Common/Constants";
|
||||||
|
import { getErrorMessage, getErrorStack, handleError } from "../../../../Common/ErrorHandlingUtils";
|
||||||
|
import { JunoClient } from "../../../../Juno/JunoClient";
|
||||||
|
import { Action } from "../../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { trace, traceFailure, traceStart, traceSuccess } from "../../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
|
||||||
|
export interface CodeOfConductProps {
|
||||||
|
junoClient: JunoClient;
|
||||||
|
onAcceptCodeOfConduct: (result: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeOfConduct: FunctionComponent<CodeOfConductProps> = ({
|
||||||
|
junoClient,
|
||||||
|
onAcceptCodeOfConduct,
|
||||||
|
}: CodeOfConductProps) => {
|
||||||
|
const descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
||||||
|
const descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
||||||
|
const descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
||||||
|
const link1: { label: string; url: string } = {
|
||||||
|
label: "code of conduct.",
|
||||||
|
url: CodeOfConductEndpoints.codeOfConduct,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [readCodeOfConduct, setReadCodeOfConduct] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const acceptCodeOfConduct = async (): Promise<void> => {
|
||||||
|
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await junoClient.acceptCodeOfConduct();
|
||||||
|
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
||||||
|
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
||||||
|
}
|
||||||
|
|
||||||
|
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
||||||
|
|
||||||
|
onAcceptCodeOfConduct(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
traceFailure(
|
||||||
|
Action.NotebooksGalleryAcceptCodeOfConduct,
|
||||||
|
{
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
errorStack: getErrorStack(error),
|
||||||
|
},
|
||||||
|
startKey
|
||||||
|
);
|
||||||
|
|
||||||
|
handleError(error, "CodeOfConduct/acceptCodeOfConduct", "Failed to accept code of conduct");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeCheckbox = (): void => {
|
||||||
|
setReadCodeOfConduct(!readCodeOfConduct);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack tokens={{ childrenGap: 20 }}>
|
||||||
|
<Stack.Item>
|
||||||
|
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{descriptionPara1}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>{descriptionPara2}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>
|
||||||
|
{descriptionPara3}
|
||||||
|
<Link href={link1.url} target="_blank">
|
||||||
|
{link1.label}
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Checkbox
|
||||||
|
styles={{
|
||||||
|
label: {
|
||||||
|
margin: 0,
|
||||||
|
padding: "2 0 2 0",
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label="I have read and accept the code of conduct."
|
||||||
|
onChange={onChangeCheckbox}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<PrimaryButton
|
||||||
|
ariaLabel="Continue"
|
||||||
|
title="Continue"
|
||||||
|
onClick={async () => await acceptCodeOfConduct()}
|
||||||
|
tabIndex={0}
|
||||||
|
className="genericPaneSubmitBtn"
|
||||||
|
text="Continue"
|
||||||
|
disabled={!readCodeOfConduct}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`CodeOfConductComponent renders 1`] = `
|
exports[`CodeOfConduct renders 1`] = `
|
||||||
<Stack
|
<Stack
|
||||||
tokens={
|
tokens={
|
||||||
Object {
|
Object {
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { JunoClient } from "../../../Juno/JunoClient";
|
|
||||||
import { HttpStatusCodes, CodeOfConductEndpoints } from "../../../Common/Constants";
|
|
||||||
import { Stack, Text, Checkbox, PrimaryButton, Link } from "office-ui-fabric-react";
|
|
||||||
import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils";
|
|
||||||
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
|
|
||||||
export interface CodeOfConductComponentProps {
|
|
||||||
junoClient: JunoClient;
|
|
||||||
onAcceptCodeOfConduct: (result: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CodeOfConductComponentState {
|
|
||||||
readCodeOfConduct: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CodeOfConductComponent extends React.Component<CodeOfConductComponentProps, CodeOfConductComponentState> {
|
|
||||||
private viewCodeOfConductTraced: boolean;
|
|
||||||
private descriptionPara1: string;
|
|
||||||
private descriptionPara2: string;
|
|
||||||
private descriptionPara3: string;
|
|
||||||
private link1: { label: string; url: string };
|
|
||||||
|
|
||||||
constructor(props: CodeOfConductComponentProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
readCodeOfConduct: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
|
||||||
this.descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
|
||||||
this.descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
|
||||||
this.link1 = { label: "code of conduct.", url: CodeOfConductEndpoints.codeOfConduct };
|
|
||||||
}
|
|
||||||
|
|
||||||
private async acceptCodeOfConduct(): Promise<void> {
|
|
||||||
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await this.props.junoClient.acceptCodeOfConduct();
|
|
||||||
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
|
||||||
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
|
||||||
}
|
|
||||||
|
|
||||||
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
|
||||||
|
|
||||||
this.props.onAcceptCodeOfConduct(response.data);
|
|
||||||
} catch (error) {
|
|
||||||
traceFailure(
|
|
||||||
Action.NotebooksGalleryAcceptCodeOfConduct,
|
|
||||||
{
|
|
||||||
error: getErrorMessage(error),
|
|
||||||
errorStack: getErrorStack(error),
|
|
||||||
},
|
|
||||||
startKey
|
|
||||||
);
|
|
||||||
|
|
||||||
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onChangeCheckbox = (): void => {
|
|
||||||
this.setState({ readCodeOfConduct: !this.state.readCodeOfConduct });
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
if (!this.viewCodeOfConductTraced) {
|
|
||||||
this.viewCodeOfConductTraced = true;
|
|
||||||
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack tokens={{ childrenGap: 20 }}>
|
|
||||||
<Stack.Item>
|
|
||||||
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{this.descriptionPara1}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>{this.descriptionPara2}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>
|
|
||||||
{this.descriptionPara3}
|
|
||||||
<Link href={this.link1.url} target="_blank">
|
|
||||||
{this.link1.label}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Checkbox
|
|
||||||
styles={{
|
|
||||||
label: {
|
|
||||||
margin: 0,
|
|
||||||
padding: "2 0 2 0",
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
fontSize: 12,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
label="I have read and accept the code of conduct."
|
|
||||||
onChange={this.onChangeCheckbox}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<PrimaryButton
|
|
||||||
ariaLabel="Continue"
|
|
||||||
title="Continue"
|
|
||||||
onClick={async () => await this.acceptCodeOfConduct()}
|
|
||||||
tabIndex={0}
|
|
||||||
className="genericPaneSubmitBtn"
|
|
||||||
text="Continue"
|
|
||||||
disabled={!this.state.readCodeOfConduct}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user