From 9d5c9d6296c316c03e56f34e443aa03a6144ad49 Mon Sep 17 00:00:00 2001 From: Hardikkumar Nai <80053762+hardiknai-techm@users.noreply.github.com> Date: Tue, 11 May 2021 00:32:14 +0530 Subject: [PATCH] Migrate Add Database Panel to React (#597) Co-authored-by: Steve Faulkner --- .eslintignore | 3 +- less/documentDB.less | 2 +- package-lock.json | 290 +- src/Common/Tooltip/InfoTooltip.tsx | 16 + src/Common/Tooltip/Tooltip.tsx | 24 - src/Common/Upload/Upload.tsx | 4 +- src/Explorer/ComponentRegisterer.ts | 1 + .../CostEstimateText.test.tsx | 13 + .../CostEstimateText/CostEstimateText.tsx | 77 + .../CostEstimateText.test.tsx.snap | 3 + .../ThroughputInput/ThroughputInput.test.tsx | 36 + .../ThroughputInput/ThroughputInput.tsx | 450 +-- .../ThroughputInput.test.tsx.snap | 1991 +++++++++++ src/Explorer/Explorer.tsx | 26 +- .../CommandBarComponentButtonFactory.tsx | 3 +- src/Explorer/Panes/AddCollectionPanel.tsx | 4 + src/Explorer/Panes/AddDatabasePane.html | 52 +- .../AddDatabasePanel.test.tsx | 17 + .../AddDatabasePanel/AddDatabasePanel.tsx | 342 ++ .../AddDatabasePanel.test.tsx.snap | 104 + src/Explorer/Panes/PaneComponents.ts | 1 - src/Explorer/Panes/PanelFooterComponent.tsx | 8 +- .../Panes/PanelInfoErrorComponent.tsx | 10 +- .../RightPaneForm/RightPaneForm.test.tsx | 20 +- .../Panes/RightPaneForm/RightPaneForm.tsx | 62 +- .../__snapshots__/RightPaneForm.test.tsx.snap | 2960 +++++------------ .../Panes/SettingsPane/SettingsPane.tsx | 34 +- .../__snapshots__/SettingsPane.test.tsx.snap | 34 +- .../Panes/UploadFilePane/UploadFilePane.tsx | 17 +- .../Panes/UploadItemsPane/UploadItemsPane.tsx | 20 +- .../UploadItemsPane.test.tsx.snap | 3 - ...eteDatabaseConfirmationPanel.test.tsx.snap | 20 +- src/Explorer/SplashScreen/SplashScreen.tsx | 2 +- src/Main.tsx | 1 - src/Utils/APITypeUtils.ts | 27 + test/mongo/container.spec.ts | 2 +- 36 files changed, 4010 insertions(+), 2669 deletions(-) create mode 100644 src/Common/Tooltip/InfoTooltip.tsx delete mode 100644 src/Common/Tooltip/Tooltip.tsx create mode 100644 src/Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText.test.tsx create mode 100644 src/Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText.tsx create mode 100644 src/Explorer/Controls/ThroughputInput/CostEstimateText/__snapshots__/CostEstimateText.test.tsx.snap create mode 100644 src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx create mode 100644 src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap create mode 100644 src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.test.tsx create mode 100644 src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx create mode 100644 src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap diff --git a/.eslintignore b/.eslintignore index 050bbc0dc..ee3f2bfb5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -54,7 +54,6 @@ src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts src/Explorer/Controls/InputTypeahead/InputTypeahead.ts src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts -src/Explorer/Controls/ThroughputInput/ThroughputInput.test.ts src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts src/Explorer/Controls/Toolbar/IToolbarAction.ts @@ -111,8 +110,8 @@ src/Explorer/OpenActions.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.test.ts src/Explorer/Panes/BrowseQueriesPane.ts src/Explorer/Panes/CassandraAddCollectionPane.ts src/Explorer/Panes/ContextualPaneBase.ts diff --git a/less/documentDB.less b/less/documentDB.less index 97a7be384..e58206818 100644 --- a/less/documentDB.less +++ b/less/documentDB.less @@ -1757,7 +1757,7 @@ input::-webkit-calendar-picker-indicator { cursor: pointer; } -.contextual-pane .paneMainContent { +.paneMainContent { flex: 1; padding-left: 34px; padding-right: 34px; diff --git a/package-lock.json b/package-lock.json index 4aa886979..41e933711 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2297,6 +2297,15 @@ } } }, + "@fluentui/react-window-provider": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-1.0.2.tgz", + "integrity": "sha512-fGSgL3Vp/+6t1Ysfz21FWZmqsU+iFVxOigvHnm5uKVyyRPwtaabv/F6kQ2y5isLMI2YmJaUd2i0cDJKu8ggrvw==", + "requires": { + "@uifabric/set-version": "^7.0.24", + "tslib": "^1.10.0" + } + }, "@fluentui/set-version": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.1.0.tgz", @@ -3090,9 +3099,9 @@ } }, "react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -3258,9 +3267,9 @@ }, "dependencies": { "react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -3574,18 +3583,18 @@ } }, "@npmcli/move-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.0.tgz", - "integrity": "sha512-Iv2iq0JuyYjKeFkSR4LPaCdDZwlGK9X2cP/01nJcp3yMJ1FjNd9vpiEYvLUgzBxKPg2SFmaOhizoQsPc0LWeOQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "requires": { "mkdirp": "^1.0.4", - "rimraf": "^2.7.1" + "rimraf": "^3.0.2" }, "dependencies": { "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { "glob": "^7.1.3" } @@ -6193,6 +6202,18 @@ } } }, + "@uifabric/foundation": { + "version": "7.9.26", + "resolved": "https://registry.npmjs.org/@uifabric/foundation/-/foundation-7.9.26.tgz", + "integrity": "sha512-1FLTb+jlH/Tuel2L9wT/zLl5ZW6W4Lbjrs5VUVjv81vWxzznvPnTf8+Ew0qkzaH7xDuMNMl7okswhV0IfJyheg==", + "requires": { + "@uifabric/merge-styles": "^7.19.2", + "@uifabric/set-version": "^7.0.24", + "@uifabric/styling": "^7.19.0", + "@uifabric/utilities": "^7.33.5", + "tslib": "^1.10.0" + } + }, "@uifabric/icons": { "version": "7.5.23", "resolved": "https://registry.npmjs.org/@uifabric/icons/-/icons-7.5.23.tgz", @@ -6327,6 +6348,17 @@ } } }, + "@uifabric/react-hooks": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.14.0.tgz", + "integrity": "sha512-Ndu/DEKHF4gFXEZa2AGgSkdWaj+njVrsSyXbkWRh2UZReFWnH1LMko9p/ZCwk1i9kAd5CUmyIfURUzIEya9YCg==", + "requires": { + "@fluentui/react-window-provider": "^1.0.2", + "@uifabric/set-version": "^7.0.24", + "@uifabric/utilities": "^7.33.5", + "tslib": "^1.10.0" + } + }, "@uifabric/set-version": { "version": "7.0.24", "resolved": "https://registry.npmjs.org/@uifabric/set-version/-/set-version-7.0.24.tgz", @@ -6335,6 +6367,32 @@ "tslib": "^1.10.0" } }, + "@uifabric/styling": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@uifabric/styling/-/styling-7.19.0.tgz", + "integrity": "sha512-fXComDtGV7dHF4rP4cLHwI6fC+1f/nvPavpMBz4IQdySwixta9TVMKbzt0OA6i0mJztqZCVAd27F/sl9R/JmcQ==", + "requires": { + "@fluentui/theme": "^1.7.4", + "@microsoft/load-themed-styles": "^1.10.26", + "@uifabric/merge-styles": "^7.19.2", + "@uifabric/set-version": "^7.0.24", + "@uifabric/utilities": "^7.33.5", + "tslib": "^1.10.0" + }, + "dependencies": { + "@fluentui/theme": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-1.7.4.tgz", + "integrity": "sha512-o4eo7lstLxxXl1g2RR9yz18Yt8yjQO/LbQuZjsiAfv/4Bf0CRnb+3j1F7gxIdBWAchKj9gzaMpIFijfI98pvYQ==", + "requires": { + "@uifabric/merge-styles": "^7.19.2", + "@uifabric/set-version": "^7.0.24", + "@uifabric/utilities": "^7.33.5", + "tslib": "^1.10.0" + } + } + } + }, "@uifabric/theme-samples": { "version": "7.2.34", "resolved": "https://registry.npmjs.org/@uifabric/theme-samples/-/theme-samples-7.2.34.tgz", @@ -6380,42 +6438,6 @@ "tslib": "^1.10.0" } }, - "@uifabric/foundation": { - "version": "7.9.26", - "resolved": "https://registry.npmjs.org/@uifabric/foundation/-/foundation-7.9.26.tgz", - "integrity": "sha512-1FLTb+jlH/Tuel2L9wT/zLl5ZW6W4Lbjrs5VUVjv81vWxzznvPnTf8+Ew0qkzaH7xDuMNMl7okswhV0IfJyheg==", - "requires": { - "@uifabric/merge-styles": "^7.19.2", - "@uifabric/set-version": "^7.0.24", - "@uifabric/styling": "^7.19.0", - "@uifabric/utilities": "^7.33.5", - "tslib": "^1.10.0" - } - }, - "@uifabric/react-hooks": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.14.0.tgz", - "integrity": "sha512-Ndu/DEKHF4gFXEZa2AGgSkdWaj+njVrsSyXbkWRh2UZReFWnH1LMko9p/ZCwk1i9kAd5CUmyIfURUzIEya9YCg==", - "requires": { - "@fluentui/react-window-provider": "^1.0.2", - "@uifabric/set-version": "^7.0.24", - "@uifabric/utilities": "^7.33.5", - "tslib": "^1.10.0" - } - }, - "@uifabric/styling": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@uifabric/styling/-/styling-7.19.0.tgz", - "integrity": "sha512-fXComDtGV7dHF4rP4cLHwI6fC+1f/nvPavpMBz4IQdySwixta9TVMKbzt0OA6i0mJztqZCVAd27F/sl9R/JmcQ==", - "requires": { - "@fluentui/theme": "^1.7.4", - "@microsoft/load-themed-styles": "^1.10.26", - "@uifabric/merge-styles": "^7.19.2", - "@uifabric/set-version": "^7.0.24", - "@uifabric/utilities": "^7.33.5", - "tslib": "^1.10.0" - } - }, "@uifabric/utilities": { "version": "7.33.5", "resolved": "https://registry.npmjs.org/@uifabric/utilities/-/utilities-7.33.5.tgz", @@ -6429,9 +6451,9 @@ } }, "office-ui-fabric-react": { - "version": "7.168.2", - "resolved": "https://registry.npmjs.org/office-ui-fabric-react/-/office-ui-fabric-react-7.168.2.tgz", - "integrity": "sha512-ssN6/6K4Z/PdT2ExE1q61B34w6LqfQrqTvrlq/NfSvDk7USxXvP3+rd7HQAUrynSsWx2MnNeYt23d34sSHLCKw==", + "version": "7.170.0", + "resolved": "https://registry.npmjs.org/office-ui-fabric-react/-/office-ui-fabric-react-7.170.0.tgz", + "integrity": "sha512-N348H5dS56oMrnKeZP1p7h2o+lO9wUY9YEHiVZ0FYpB8gmRwgJVq8/d2hSfZEgQH14IMbhdLYNE8RFziYyHFsw==", "requires": { "@fluentui/date-time-utilities": "^7.9.1", "@fluentui/react-focus": "^7.17.6", @@ -6450,6 +6472,18 @@ } } }, + "@uifabric/utilities": { + "version": "7.33.5", + "resolved": "https://registry.npmjs.org/@uifabric/utilities/-/utilities-7.33.5.tgz", + "integrity": "sha512-I+Oi0deD/xltSluFY8l2EVd/J4mvOaMljxKO2knSD9/KoGDlo/o5GN4gbnVo8nIt76HWHLAk3KtlJKJm6BhbIQ==", + "requires": { + "@fluentui/dom-utilities": "^1.1.2", + "@uifabric/merge-styles": "^7.19.2", + "@uifabric/set-version": "^7.0.24", + "prop-types": "^15.7.2", + "tslib": "^1.10.0" + } + }, "@uifabric/variants": { "version": "7.2.35", "resolved": "https://registry.npmjs.org/@uifabric/variants/-/variants-7.2.35.tgz", @@ -6470,18 +6504,6 @@ "@uifabric/utilities": "^7.33.5", "tslib": "^1.10.0" } - }, - "@uifabric/utilities": { - "version": "7.33.5", - "resolved": "https://registry.npmjs.org/@uifabric/utilities/-/utilities-7.33.5.tgz", - "integrity": "sha512-I+Oi0deD/xltSluFY8l2EVd/J4mvOaMljxKO2knSD9/KoGDlo/o5GN4gbnVo8nIt76HWHLAk3KtlJKJm6BhbIQ==", - "requires": { - "@fluentui/dom-utilities": "^1.1.2", - "@uifabric/merge-styles": "^7.19.2", - "@uifabric/set-version": "^7.0.24", - "prop-types": "^15.7.2", - "tslib": "^1.10.0" - } } } }, @@ -7135,6 +7157,14 @@ "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "assert": { @@ -7436,6 +7466,11 @@ "regenerator-runtime": "^0.11.0" }, "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -7626,9 +7661,9 @@ "dev": true }, "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", "dev": true }, "body-parser": { @@ -7843,14 +7878,6 @@ "requires": { "bn.js": "^5.0.0", "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", - "dev": true - } } }, "browserify-sign": { @@ -7870,12 +7897,6 @@ "safe-buffer": "^5.2.0" }, "dependencies": { - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", - "dev": true - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -7984,9 +8005,9 @@ "dev": true }, "cacache": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", - "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz", + "integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==", "requires": { "@npmcli/move-file": "^1.0.1", "chownr": "^2.0.0", @@ -8002,7 +8023,7 @@ "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", - "ssri": "^8.0.0", + "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" }, @@ -8330,7 +8351,8 @@ "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true }, "chrome-trace-event": { "version": "1.0.2", @@ -8819,22 +8841,9 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } } } }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, "core-js-compat": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz", @@ -8871,6 +8880,14 @@ "requires": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "create-file-webpack": { @@ -10024,6 +10041,14 @@ "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "dir-glob": { @@ -10302,18 +10327,26 @@ "integrity": "sha512-vhGNxT87PdZA6Ak4E0QhArwGzNcSPUwSN7n9wCFLeBlY2NNuuiwguQuQIp7P5oB65PLJ892yKcHiqz1xLWeiug==" }, "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", + "bn.js": "^4.11.9", + "brorand": "^1.1.0", "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "emitter-listener": { @@ -11045,9 +11078,9 @@ "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" }, "eventsource": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", - "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", "dev": true, "requires": { "original": "^1.0.0" @@ -12316,9 +12349,9 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -19298,6 +19331,14 @@ "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "mime": { @@ -20617,7 +20658,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "requires": { "p-try": "^2.0.0" } @@ -20947,9 +20987,9 @@ } }, "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dev": true, "requires": { "create-hash": "^1.1.2", @@ -21520,6 +21560,14 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } } }, "pump": { @@ -25544,6 +25592,12 @@ "y18n": "^4.0.0" } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", diff --git a/src/Common/Tooltip/InfoTooltip.tsx b/src/Common/Tooltip/InfoTooltip.tsx new file mode 100644 index 000000000..c16e22ce8 --- /dev/null +++ b/src/Common/Tooltip/InfoTooltip.tsx @@ -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 = ({ children }: TooltipProps) => { + return ( + + + + + + ); +}; diff --git a/src/Common/Tooltip/Tooltip.tsx b/src/Common/Tooltip/Tooltip.tsx deleted file mode 100644 index ee7b69425..000000000 --- a/src/Common/Tooltip/Tooltip.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { ITooltipHostStyles, TooltipHost } from "@fluentui/react"; -import { useId } from "@fluentui/react-hooks"; -import * as React from "react"; -import InfoBubble from "../../../images/info-bubble.svg"; - -const calloutProps = { gapSpace: 0 }; -const hostStyles: Partial = { root: { display: "inline-block" } }; - -export interface TooltipProps { - children: string; -} -export const Tooltip: React.FunctionComponent = ({ children }: TooltipProps) => { - const tooltipId = useId("tooltip"); - - return children ? ( - - - More information - - - ) : ( - <> - ); -}; diff --git a/src/Common/Upload/Upload.tsx b/src/Common/Upload/Upload.tsx index b8d8767c6..3feb4fdfd 100644 --- a/src/Common/Upload/Upload.tsx +++ b/src/Common/Upload/Upload.tsx @@ -2,7 +2,7 @@ import { Image, Stack, TextField } from "@fluentui/react"; import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react"; import FolderIcon from "../../../images/folder_16x16.svg"; import * as Constants from "../Constants"; -import { Tooltip } from "../Tooltip/Tooltip"; +import { InfoTooltip } from "../Tooltip/InfoTooltip"; interface UploadProps { label: string; @@ -51,7 +51,7 @@ export const Upload: FunctionComponent = ({ return (
{label} - {tooltip} + {tooltip && {tooltip}} { + it("should render Default properly", () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/src/Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText.tsx b/src/Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText.tsx new file mode 100644 index 000000000..51aaae619 --- /dev/null +++ b/src/Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText.tsx @@ -0,0 +1,77 @@ +import { Text } from "@fluentui/react"; +import React, { FunctionComponent } from "react"; +import { InfoTooltip } from "../../../../Common/Tooltip/InfoTooltip"; +import * as SharedConstants from "../../../../Shared/Constants"; +import { userContext } from "../../../../UserContext"; +import { + calculateEstimateNumber, + computeRUUsagePriceHourly, + getAutoscalePricePerRu, + getCurrencySign, + getMultimasterMultiplier, + getPriceCurrency, + getPricePerRu, +} from "../../../../Utils/PricingUtils"; + +interface CostEstimateTextProps { + requestUnits: number; + isAutoscale: boolean; +} + +export const CostEstimateText: FunctionComponent = ({ + requestUnits, + isAutoscale, +}: CostEstimateTextProps) => { + const { databaseAccount } = userContext; + if (!databaseAccount?.properties) { + return <>; + } + + const serverId: string = userContext.portalEnv; + const numberOfRegions: number = databaseAccount.properties.readLocations?.length || 1; + const multimasterEnabled: boolean = databaseAccount.properties.enableMultipleWriteLocations; + const hourlyPrice: number = computeRUUsagePriceHourly({ + serverId, + requestUnits, + numberOfRegions, + multimasterEnabled, + isAutoscale, + }); + const dailyPrice: number = hourlyPrice * 24; + const monthlyPrice: number = hourlyPrice * SharedConstants.hoursInAMonth; + const currency: string = getPriceCurrency(serverId); + const currencySign: string = getCurrencySign(serverId); + const multiplier = getMultimasterMultiplier(numberOfRegions, multimasterEnabled); + const pricePerRu = isAutoscale + ? getAutoscalePricePerRu(serverId, multiplier) * multiplier + : getPricePerRu(serverId) * multiplier; + + const iconWithEstimatedCostDisclaimer: JSX.Element = PricingUtils.estimatedCostDisclaimer; + + if (isAutoscale) { + return ( + + Estimated monthly cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "} + + {currencySign + calculateEstimateNumber(monthlyPrice / 10)} -{" "} + {currencySign + calculateEstimateNumber(monthlyPrice)}{" "} + + ({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits / 10} - {requestUnits}{" "} + RU/s, {currencySign + pricePerRu}/RU) + + ); + } + + return ( + + Estimated cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "} + + {currencySign + calculateEstimateNumber(hourlyPrice)} hourly /{" "} + {currencySign + calculateEstimateNumber(dailyPrice)} daily /{" "} + {currencySign + calculateEstimateNumber(monthlyPrice)} monthly{" "} + + ({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits}RU/s,{" "} + {currencySign + pricePerRu}/RU) + + ); +}; diff --git a/src/Explorer/Controls/ThroughputInput/CostEstimateText/__snapshots__/CostEstimateText.test.tsx.snap b/src/Explorer/Controls/ThroughputInput/CostEstimateText/__snapshots__/CostEstimateText.test.tsx.snap new file mode 100644 index 000000000..cd4efbdc6 --- /dev/null +++ b/src/Explorer/Controls/ThroughputInput/CostEstimateText/__snapshots__/CostEstimateText.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CostEstimateText Pane should render Default properly 1`] = ``; diff --git a/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx b/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx new file mode 100644 index 000000000..7b59ae003 --- /dev/null +++ b/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx @@ -0,0 +1,36 @@ +import { mount, ReactWrapper } from "enzyme"; +import React from "react"; +import { ThroughputInput } from "./ThroughputInput"; +const props = { + isDatabase: false, + showFreeTierExceedThroughputTooltip: true, + isSharded: false, + setThroughputValue: () => jest.fn(), + setIsAutoscale: () => jest.fn(), + onCostAcknowledgeChange: () => jest.fn(), +}; +describe("ThroughputInput Pane", () => { + let wrapper: ReactWrapper; + + beforeEach(() => { + wrapper = mount(); + }); + + it("should render Default properly", () => { + expect(wrapper).toMatchSnapshot(); + }); + + it("test Autoscale Mode select", () => { + wrapper.setProps({ isAutoscaleSelected: true }); + expect(wrapper.find('[aria-label="ruDescription"]').at(0).text()).toBe( + "Estimate your required RU/s with capacity calculator." + ); + expect(wrapper.find('[aria-label="maxRUDescription"]').at(0).text()).toContain("Max RU/s"); + }); + + it("test Manual Mode select", () => { + wrapper.setProps({ isAutoscaleSelected: false }); + expect(wrapper.find('[aria-label="ruDescription"]').at(0).text()).toContain("Estimate your required RU/s with"); + expect(wrapper.find('[aria-label="capacityLink"]').at(0).text()).toContain("capacity calculator"); + }); +}); diff --git a/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx b/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx index 8d1321500..3991c0cbd 100644 --- a/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx +++ b/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx @@ -1,11 +1,14 @@ -import { Checkbox, DirectionalHint, Icon, Link, Stack, Text, TextField, TooltipHost } from "@fluentui/react"; -import React from "react"; +import { Checkbox, DirectionalHint, Link, Stack, Text, TextField, TooltipHost } from "@fluentui/react"; +import React, { FunctionComponent, useState } from "react"; import * as Constants from "../../../Common/Constants"; +import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip"; import * as SharedConstants from "../../../Shared/Constants"; import { userContext } from "../../../UserContext"; import { getCollectionName } from "../../../Utils/APITypeUtils"; import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils"; import * as PricingUtils from "../../../Utils/PricingUtils"; +import { CostEstimateText } from "./CostEstimateText/CostEstimateText"; +import "./ThroughputInput.less"; export interface ThroughputInputProps { isDatabase: boolean; @@ -14,178 +17,25 @@ export interface ThroughputInputProps { setThroughputValue: (throughput: number) => void; setIsAutoscale: (isAutoscale: boolean) => void; onCostAcknowledgeChange: (isAcknowledged: boolean) => void; + isAutoscaleSelected?: boolean; + throughput?: number; } -export interface ThroughputInputState { - isAutoscaleSelected: boolean; - throughput: number; - isCostAcknowledged: boolean; - throughputError: string; -} - -export class ThroughputInput extends React.Component { - constructor(props: ThroughputInputProps) { - super(props); - - this.state = { - isAutoscaleSelected: true, - throughput: AutoPilotUtils.minAutoPilotThroughput, - isCostAcknowledged: false, - throughputError: undefined, - }; - - this.props.setThroughputValue(AutoPilotUtils.minAutoPilotThroughput); - this.props.setIsAutoscale(true); - } - - render(): JSX.Element { - return ( -
- - - - {this.getThroughputLabelText()} - - - - - - - - - Autoscale - - - Manual - - - {this.state.isAutoscaleSelected && ( - - - Estimate your required RU/s with  - - capacity calculator - - . - - - - - {this.props.isDatabase ? "Database" : getCollectionName()} max RU/s - - - - - - - this.onThroughputValueChange(newInput)} - step={AutoPilotUtils.autoPilotIncrementStep} - min={AutoPilotUtils.minAutoPilotThroughput} - value={this.state.throughput.toString()} - aria-label="Max request units per second" - errorMessage={this.state.throughputError} - /> - - - Your {this.props.isDatabase ? "database" : getCollectionName().toLocaleLowerCase()} throughput will - automatically scale from{" "} - - {AutoPilotUtils.getMinRUsBasedOnUserInput(this.state.throughput)} RU/s (10% of max RU/s) -{" "} - {this.state.throughput} RU/s - {" "} - based on usage. - - - )} - - {!this.state.isAutoscaleSelected && ( - - - Estimate your required RU/s with  - - capacity calculator - - . - - - SharedConstants.CollectionCreation.DefaultCollectionRUs400 - ? "The first 400 RU/s in this account are free. Billing will apply to any throughput beyond 400 RU/s." - : undefined - } - > - this.onThroughputValueChange(newInput)} - step={100} - min={SharedConstants.CollectionCreation.DefaultCollectionRUs400} - max={userContext.isTryCosmosDBSubscription ? Constants.TryCosmosExperience.maxRU : Infinity} - value={this.state.throughput.toString()} - aria-label="Max request units per second" - required={true} - errorMessage={this.state.throughputError} - /> - - - )} - - - - {this.state.throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && ( - - - , isChecked: boolean) => { - this.setState({ isCostAcknowledged: isChecked }); - this.props.onCostAcknowledgeChange(isChecked); - }} - /> - - {this.getCostAcknowledgeText()} - - - )} -
- ); - } - - private getThroughputLabelText(): string { +export const ThroughputInput: FunctionComponent = ({ + isDatabase, + showFreeTierExceedThroughputTooltip, + setThroughputValue, + setIsAutoscale, + isSharded, + isAutoscaleSelected = true, + throughput = AutoPilotUtils.minAutoPilotThroughput, + onCostAcknowledgeChange, +}: ThroughputInputProps) => { + const [isCostAcknowledged, setIsCostAcknowledged] = useState(false); + const [throughputError, setThroughputError] = useState(""); + const getThroughputLabelText = (): string => { let throughputHeaderText: string; - if (this.state.isAutoscaleSelected) { + if (isAutoscaleSelected) { throughputHeaderText = AutoPilotUtils.getAutoPilotHeaderText().toLocaleLowerCase(); } else { const minRU: string = SharedConstants.CollectionCreation.DefaultCollectionRUs400.toLocaleString(); @@ -194,29 +44,26 @@ export class ThroughputInput extends React.Component { const newThroughput = parseInt(newInput); - this.setState({ throughput: newThroughput }); - this.props.setThroughputValue(newThroughput); - - if (!this.props.isSharded && newThroughput > 10000) { - this.setState({ throughputError: "Unsharded collections support up to 10,000 RUs" }); + setThroughputValue(newThroughput); + if (!isSharded && newThroughput > 10000) { + setThroughputError("Unsharded collections support up to 10,000 RUs"); } else { - this.setState({ throughputError: undefined }); + setThroughputError(""); } - } + }; - private getAutoScaleTooltip(): string { + const getAutoScaleTooltip = (): string => { const collectionName = getCollectionName().toLocaleLowerCase(); return `Set the max RU/s to the highest RU/s you want your ${collectionName} to scale to. The ${collectionName} will scale between 10% of max RU/s to the max RU/s based on usage.`; - } + }; - private getCostAcknowledgeText(): string { - const { databaseAccount } = userContext; + const getCostAcknowledgeText = (): string => { + const databaseAccount = userContext.databaseAccount; if (!databaseAccount || !databaseAccount.properties) { return ""; } @@ -225,98 +72,159 @@ export class ThroughputInput extends React.Component): void { - if (event.target.checked && !this.state.isAutoscaleSelected) { - this.setState({ isAutoscaleSelected: true, throughput: AutoPilotUtils.minAutoPilotThroughput }); - this.props.setIsAutoscale(true); + const handleOnChangeMode = (event: React.ChangeEvent, mode: string): void => { + if (mode === "Autoscale") { + setThroughputValue(AutoPilotUtils.minAutoPilotThroughput); + setIsAutoscale(true); + } else { + setThroughputValue(SharedConstants.CollectionCreation.DefaultCollectionRUs400); + setIsAutoscale(false); } - } - - private onManualRadioBtnChange(event: React.ChangeEvent): void { - if (event.target.checked && this.state.isAutoscaleSelected) { - this.setState({ - isAutoscaleSelected: false, - throughput: SharedConstants.CollectionCreation.DefaultCollectionRUs400, - }); - this.props.setIsAutoscale(false); - this.props.setThroughputValue(SharedConstants.CollectionCreation.DefaultCollectionRUs400); - } - } -} - -interface CostEstimateTextProps { - requestUnits: number; - isAutoscale: boolean; -} - -const CostEstimateText: React.FunctionComponent = (props: CostEstimateTextProps) => { - const { requestUnits, isAutoscale } = props; - const { databaseAccount } = userContext; - if (!databaseAccount?.properties) { - return <>; - } - - const serverId: string = userContext.portalEnv; - const numberOfRegions: number = databaseAccount.properties.readLocations?.length || 1; - const multimasterEnabled: boolean = databaseAccount.properties.enableMultipleWriteLocations; - const hourlyPrice: number = PricingUtils.computeRUUsagePriceHourly({ - serverId, - requestUnits, - numberOfRegions, - multimasterEnabled, - isAutoscale, - }); - const dailyPrice: number = hourlyPrice * 24; - const monthlyPrice: number = hourlyPrice * SharedConstants.hoursInAMonth; - const currency: string = PricingUtils.getPriceCurrency(serverId); - const currencySign: string = PricingUtils.getCurrencySign(serverId); - const multiplier = PricingUtils.getMultimasterMultiplier(numberOfRegions, multimasterEnabled); - const pricePerRu = isAutoscale - ? PricingUtils.getAutoscalePricePerRu(serverId, multiplier) * multiplier - : PricingUtils.getPricePerRu(serverId) * multiplier; - - const iconWithEstimatedCostDisclaimer: JSX.Element = ( - - - - ); - - if (isAutoscale) { - return ( - - Estimated monthly cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "} - - {currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice / 10)} -{" "} - {currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice)}{" "} - - ({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits / 10} - {requestUnits}{" "} - RU/s, {currencySign + pricePerRu}/RU) - - ); - } + }; return ( - - Estimated cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "} - - {currencySign + PricingUtils.calculateEstimateNumber(hourlyPrice)} hourly /{" "} - {currencySign + PricingUtils.calculateEstimateNumber(dailyPrice)} daily /{" "} - {currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice)} monthly{" "} - - ({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits}RU/s,{" "} - {currencySign + pricePerRu}/RU) - +
+ + + + {getThroughputLabelText()} + + {PricingUtils.getRuToolTipText()} + + + + handleOnChangeMode(e, "Autoscale")} + /> + Autoscale + + handleOnChangeMode(e, "Manual")} + /> + Manual + + + {isAutoscaleSelected && ( + + + Estimate your required RU/s with{" "} + + capacity calculator + + . + + + + + {isDatabase ? "Database" : getCollectionName()} Max RU/s + + {getAutoScaleTooltip()} + + + onThroughputValueChange(newInput)} + step={AutoPilotUtils.autoPilotIncrementStep} + min={AutoPilotUtils.minAutoPilotThroughput} + value={throughput.toString()} + aria-label="Max request units per second" + required={true} + errorMessage={throughputError} + /> + + + Your {isDatabase ? "database" : getCollectionName().toLocaleLowerCase()} throughput will automatically scale + from{" "} + + {AutoPilotUtils.getMinRUsBasedOnUserInput(throughput)} RU/s (10% of max RU/s) - {throughput} RU/s + {" "} + based on usage. + + + )} + + {!isAutoscaleSelected && ( + + + Estimate your required RU/s with  + + capacity calculator + + . + + + SharedConstants.CollectionCreation.DefaultCollectionRUs400 + ? "The first 400 RU/s in this account are free. Billing will apply to any throughput beyond 400 RU/s." + : undefined + } + > + onThroughputValueChange(newInput)} + step={100} + min={SharedConstants.CollectionCreation.DefaultCollectionRUs400} + max={userContext.isTryCosmosDBSubscription ? Constants.TryCosmosExperience.maxRU : Infinity} + value={throughput.toString()} + aria-label="Max request units per second" + required={true} + errorMessage={throughputError} + /> + + + )} + + + + {throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && ( + + , isChecked: boolean) => { + setIsCostAcknowledged(isChecked); + onCostAcknowledgeChange(isChecked); + }} + /> + + {getCostAcknowledgeText()} + + + )} +
); }; diff --git a/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap b/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap new file mode 100644 index 000000000..cf430a1e0 --- /dev/null +++ b/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap @@ -0,0 +1,1991 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ThroughputInput Pane should render Default properly 1`] = ` + +
+ +
+ + *  + + + + Container throughput (autoscale) + + + + + + +
+ + + +  + + + +
+
+
+
+
+
+
+ +
+ + + Autoscale + + + + Manual + +
+
+ +
+ + + Estimate your required RU/s with + + + + + capacity calculator + + + + . + + + +
+ + + Container + Max RU/s + + + + + + +
+ + + +  + + + +
+
+
+
+
+
+
+ + +
+
+
+ +
+
+
+
+
+ + + Your + container + throughput will automatically scale from + + + 400 + RU/s (10% of max RU/s) - + 4000 + RU/s + + + based on usage. + + +
+
+ +
+
+`; diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index 223ab657c..dee398749 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -31,7 +31,7 @@ import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants" import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor"; import { ArcadiaResourceManager } from "../SparkClusterManager/ArcadiaResourceManager"; import { updateUserContext, userContext } from "../UserContext"; -import { getCollectionName } from "../Utils/APITypeUtils"; +import { getCollectionName, getDatabaseName, getUploadName } from "../Utils/APITypeUtils"; import { decryptJWTToken, getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { stringToBlob } from "../Utils/BlobUtils"; import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils"; @@ -52,6 +52,7 @@ import { NotebookUtil } from "./Notebook/NotebookUtil"; import AddCollectionPane from "./Panes/AddCollectionPane"; import { AddCollectionPanel } from "./Panes/AddCollectionPanel"; import AddDatabasePane from "./Panes/AddDatabasePane"; +import { AddDatabasePanel } from "./Panes/AddDatabasePanel/AddDatabasePanel"; import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane/BrowseQueriesPane"; import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane"; import { ContextualPaneBase } from "./Panes/ContextualPaneBase"; @@ -1961,7 +1962,7 @@ export default class Explorer { public openDeleteDatabaseConfirmationPane(): void { this.openSidePanel( - "Delete Database", + "Delete " + getDatabaseName(), ); + this.openSidePanel("Upload " + getUploadName(), ); } public openSettingPane(): void { this.openSidePanel( - "Settings", + "Setting", this.expandConsole()} closePanel={this.closeSidePanel} /> ); } @@ -2005,6 +2006,21 @@ export default class Explorer { /> ); } + public openAddDatabasePane(): void { + if (userContext.features.enableKOPanel) { + this.addDatabasePane.open(); + document.getElementById("linkAddDatabase").focus(); + } else { + this.openSidePanel( + "Add " + getDatabaseName(), + + ); + } + } public openBrowseQueriesPanel(): void { this.openSidePanel("Open Saved Queries", ); @@ -2021,7 +2037,7 @@ export default class Explorer { public openUploadFilePanel(parent?: NotebookContentItem): void { parent = parent || this.resourceTree.myNotebooksContentRoot; this.openSidePanel( - "Upload File", + "Upload file to notebook server", this.expandConsole()} closePanel={this.closeSidePanel} diff --git a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx index 8f0715988..b5040d8a6 100644 --- a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx +++ b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx @@ -266,8 +266,7 @@ function createNewDatabase(container: Explorer): CommandButtonComponentProps { iconSrc: AddDatabaseIcon, iconAlt: label, onCommandClick: () => { - container.addDatabasePane.open(); - document.getElementById("linkAddDatabase").focus(); + container.openAddDatabasePane(); }, commandButtonLabel: label, ariaLabel: label, diff --git a/src/Explorer/Panes/AddCollectionPanel.tsx b/src/Explorer/Panes/AddCollectionPanel.tsx index 89cf46d6c..1837133b5 100644 --- a/src/Explorer/Panes/AddCollectionPanel.tsx +++ b/src/Explorer/Panes/AddCollectionPanel.tsx @@ -213,6 +213,8 @@ export class AddCollectionPanel extends React.Component (this.newDatabaseThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)} @@ -442,6 +444,8 @@ export class AddCollectionPanel extends React.Component (this.collectionThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)} diff --git a/src/Explorer/Panes/AddDatabasePane.html b/src/Explorer/Panes/AddDatabasePane.html index 0166ab7cb..2a598ade6 100644 --- a/src/Explorer/Panes/AddDatabasePane.html +++ b/src/Explorer/Panes/AddDatabasePane.html @@ -1,4 +1,4 @@ -
+
@@ -126,31 +126,31 @@

diff --git a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.test.tsx b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.test.tsx new file mode 100644 index 000000000..4206eb723 --- /dev/null +++ b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.test.tsx @@ -0,0 +1,17 @@ +import { shallow } from "enzyme"; +import React from "react"; +import Explorer from "../../Explorer"; +import { AddDatabasePanel } from "./AddDatabasePanel"; + +const props = { + explorer: new Explorer(), + closePanel: (): void => undefined, + openNotificationConsole: (): void => undefined, +}; + +describe("AddDatabasePane Pane", () => { + it("should render Default properly", () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx new file mode 100644 index 000000000..c525f927d --- /dev/null +++ b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx @@ -0,0 +1,342 @@ +import { Checkbox, Text, TextField } from "@fluentui/react"; +import React, { FunctionComponent, useEffect, useState } from "react"; +import * as Constants from "../../../Common/Constants"; +import { createDatabase } from "../../../Common/dataAccess/createDatabase"; +import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils"; +import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip"; +import { configContext, Platform } from "../../../ConfigContext"; +import * as DataModels from "../../../Contracts/DataModels"; +import { SubscriptionType } from "../../../Contracts/SubscriptionType"; +import * as SharedConstants from "../../../Shared/Constants"; +import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants"; +import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; +import { userContext } from "../../../UserContext"; +import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils"; +import * as PricingUtils from "../../../Utils/PricingUtils"; +import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput"; +import Explorer from "../../Explorer"; +import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent"; +import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm"; + +export interface AddDatabasePaneProps { + explorer: Explorer; + closePanel: () => void; + openNotificationConsole: () => void; +} + +export const AddDatabasePanel: FunctionComponent = ({ + explorer: container, + closePanel, + openNotificationConsole, +}: AddDatabasePaneProps) => { + const { subscriptionType } = userContext; + const getSharedThroughputDefault = !(subscriptionType === SubscriptionType.EA || container.isServerlessEnabled()); + const _isAutoPilotSelectedAndWhatTier = (): DataModels.AutoPilotCreationSettings => { + if (isAutoPilotSelected && maxAutoPilotThroughputSet) { + return { + maxThroughput: maxAutoPilotThroughputSet * 1, + }; + } + return undefined; + }; + + const isCassandraAccount: boolean = userContext.apiType === "Cassandra"; + const databaseLabel: string = isCassandraAccount ? "keyspace" : "database"; + const collectionsLabel: string = isCassandraAccount ? "tables" : "collections"; + const databaseIdLabel: string = isCassandraAccount ? "Keyspace id" : "Database id"; + const databaseIdPlaceHolder: string = isCassandraAccount ? "Type a new keyspace id" : "Type a new database id"; + + const [databaseId, setDatabaseId] = useState(""); + const databaseIdTooltipText = `A ${ + isCassandraAccount ? "keyspace" : "database" + } is a logical container of one or more ${isCassandraAccount ? "tables" : "collections"}`; + + const databaseLevelThroughputTooltipText = `Provisioned throughput at the ${databaseLabel} level will be shared across all ${collectionsLabel} within the ${databaseLabel}.`; + const [databaseCreateNewShared, setDatabaseCreateNewShared] = useState(getSharedThroughputDefault); + const [formErrorsDetails, setFormErrorsDetails] = useState(); + const [formErrors, setFormErrors] = useState(""); + + const [isAutoPilotSelected, setIsAutoPilotSelected] = useState(container.isAutoscaleDefaultEnabled()); + + const throughputDefaults = container.collectionCreationDefaults.throughput; + const [throughput, setThroughput] = useState( + isAutoPilotSelected ? AutoPilotUtils.minAutoPilotThroughput : throughputDefaults.shared + ); + + const [throughputSpendAck, setThroughputSpendAck] = useState(false); + + const canRequestSupport = () => { + if ( + configContext.platform !== Platform.Emulator && + !userContext.isTryCosmosDBSubscription && + configContext.platform !== Platform.Portal + ) { + const offerThroughput: number = throughput; + return offerThroughput <= 100000; + } + + return false; + }; + const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier; + const upsellMessage: string = PricingUtils.getUpsellMessage( + userContext.portalEnv, + isFreeTierAccount, + container.isFirstResourceCreated(), + false + ); + + const upsellAnchorUrl: string = isFreeTierAccount ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing; + + const upsellAnchorText: string = isFreeTierAccount ? "Learn more" : "More details"; + const maxAutoPilotThroughputSet = AutoPilotUtils.minAutoPilotThroughput; + + const canConfigureThroughput = !container.isServerlessEnabled(); + const showUpsellMessage = () => { + if (container.isServerlessEnabled()) { + return false; + } + + if (isFreeTierAccount) { + return databaseCreateNewShared; + } + + return true; + }; + const [isExecuting, setIsExecuting] = useState(false); + + useEffect(() => { + setDatabaseCreateNewShared(getSharedThroughputDefault); + }, [subscriptionType]); + + const addDatabasePaneMessage = { + database: { + id: databaseId, + shared: databaseCreateNewShared, + }, + subscriptionType: SubscriptionType[subscriptionType], + subscriptionQuotaId: userContext.quotaId, + defaultsCheck: { + flight: userContext.addCollectionFlight, + }, + dataExplorerArea: Constants.Areas.ContextualPane, + }; + + useEffect(() => { + const addDatabasePaneOpenMessage = { + subscriptionType: SubscriptionType[subscriptionType], + subscriptionQuotaId: userContext.quotaId, + defaultsCheck: { + throughput: throughput, + flight: userContext.addCollectionFlight, + }, + dataExplorerArea: Constants.Areas.ContextualPane, + }; + TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage); + }, []); + + const onSubmit = () => { + if (!_isValid()) { + return; + } + + const offerThroughput: number = _computeOfferThroughput(); + + const addDatabasePaneStartMessage = { + ...addDatabasePaneMessage, + offerThroughput, + }; + const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage); + setFormErrors(""); + setIsExecuting(true); + + const createDatabaseParams: DataModels.CreateDatabaseParams = { + databaseId: addDatabasePaneStartMessage.database.id, + databaseLevelThroughput: addDatabasePaneStartMessage.database.shared, + }; + if (isAutoPilotSelected) { + createDatabaseParams.autoPilotMaxThroughput = addDatabasePaneStartMessage.offerThroughput; + } else { + createDatabaseParams.offerThroughput = addDatabasePaneStartMessage.offerThroughput; + } + + createDatabase(createDatabaseParams).then( + () => { + _onCreateDatabaseSuccess(offerThroughput, startKey); + }, + (error: string) => { + _onCreateDatabaseFailure(error, offerThroughput, startKey); + } + ); + }; + + const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => { + setIsExecuting(false); + closePanel(); + container.refreshAllDatabases(); + const addDatabasePaneSuccessMessage = { + ...addDatabasePaneMessage, + offerThroughput, + }; + TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey); + }; + + const _onCreateDatabaseFailure = (error: string, offerThroughput: number, startKey: number): void => { + setIsExecuting(false); + const errorMessage = getErrorMessage(error); + setFormErrors(errorMessage); + setFormErrorsDetails(errorMessage); + const addDatabasePaneFailedMessage = { + ...addDatabasePaneMessage, + offerThroughput, + error: errorMessage, + errorStack: getErrorStack(error), + }; + TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey); + }; + + const _getThroughput = (): number => { + return isNaN(throughput) ? 0 : Number(throughput); + }; + + const _computeOfferThroughput = (): number => { + if (!canConfigureThroughput) { + return undefined; + } + + return _getThroughput(); + }; + + const _isValid = (): boolean => { + // TODO add feature flag that disables validation for customers with custom accounts + if (isAutoPilotSelected) { + const autoPilot = _isAutoPilotSelectedAndWhatTier(); + if ( + !autoPilot || + !autoPilot.maxThroughput || + !AutoPilotUtils.isValidAutoPilotThroughput(autoPilot.maxThroughput) + ) { + setFormErrors( + `Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput` + ); + return false; + } + } + const throughput = _getThroughput(); + + if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !throughputSpendAck) { + setFormErrors(`Please acknowledge the estimated daily spend.`); + return false; + } + + const autoscaleThroughput = maxAutoPilotThroughputSet * 1; + + if ( + isAutoPilotSelected && + autoscaleThroughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && + !throughputSpendAck + ) { + setFormErrors(`Please acknowledge the estimated monthly spend.`); + return false; + } + + return true; + }; + + const handleonChangeDBId = React.useCallback( + (event: React.FormEvent, newValue?: string) => { + setDatabaseId(newValue || ""); + }, + [] + ); + + const props: RightPaneFormProps = { + expandConsole: container.expandConsole, + formError: formErrors, + formErrorDetail: formErrorsDetails, + isExecuting, + submitButtonText: "OK", + onSubmit, + }; + + return ( + +

+ {showUpsellMessage && formErrors === "" && ( + + )} +
+
+

+ * + {databaseIdLabel} + {databaseIdTooltipText} +

+ + + +
+ setDatabaseCreateNewShared(!databaseCreateNewShared)} + />{" "} + {databaseLevelThroughputTooltipText} +
+ {databaseCreateNewShared && ( +
+ setThroughput(throughput)} + setIsAutoscale={(isAutoscale: boolean) => setIsAutoPilotSelected(isAutoscale)} + onCostAcknowledgeChange={(isAcknowledged: boolean) => setThroughputSpendAck(isAcknowledged)} + /> + + {canRequestSupport() && ( +

+ + Contact support{" "} + + for more than {throughputDefaults.unlimitedmax?.toLocaleString()} RU/s. +

+ )} +
+ )} +
+
+
+ + ); +}; diff --git a/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap new file mode 100644 index 000000000..bdc4f1526 --- /dev/null +++ b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap @@ -0,0 +1,104 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AddDatabasePane Pane should render Default properly 1`] = ` + +
+ +
+
+

+ + * + + + Database id + + + A database is a logical container of one or more collections + +

+ +
+ + + + Provisioned throughput at the database level will be shared across all collections within the database. + +
+
+ +
+
+
+
+
+`; diff --git a/src/Explorer/Panes/PaneComponents.ts b/src/Explorer/Panes/PaneComponents.ts index 9d730887d..34ff76ed3 100644 --- a/src/Explorer/Panes/PaneComponents.ts +++ b/src/Explorer/Panes/PaneComponents.ts @@ -17,7 +17,6 @@ export class AddDatabasePaneComponent { }; } } - export class AddCollectionPaneComponent { constructor() { return { diff --git a/src/Explorer/Panes/PanelFooterComponent.tsx b/src/Explorer/Panes/PanelFooterComponent.tsx index ba74b0dd7..d007a5e36 100644 --- a/src/Explorer/Panes/PanelFooterComponent.tsx +++ b/src/Explorer/Panes/PanelFooterComponent.tsx @@ -9,12 +9,6 @@ export const PanelFooterComponent: React.FunctionComponent = ( buttonLabel, }: PanelFooterProps): JSX.Element => (
- +
); diff --git a/src/Explorer/Panes/PanelInfoErrorComponent.tsx b/src/Explorer/Panes/PanelInfoErrorComponent.tsx index 8e15596ed..2ae836f64 100644 --- a/src/Explorer/Panes/PanelInfoErrorComponent.tsx +++ b/src/Explorer/Panes/PanelInfoErrorComponent.tsx @@ -22,19 +22,19 @@ export const PanelInfoErrorComponent: React.FunctionComponent { let icon: JSX.Element; if (messageType === "error") { - icon = ; + icon = ; } else if (messageType === "warning") { - icon = ; + icon = ; } else if (messageType === "info") { - icon = ; + icon = ; } return ( formError && ( - + {icon} - + {message} {link && linkText && ( diff --git a/src/Explorer/Panes/RightPaneForm/RightPaneForm.test.tsx b/src/Explorer/Panes/RightPaneForm/RightPaneForm.test.tsx index 79bcf43d0..a2f3423e1 100644 --- a/src/Explorer/Panes/RightPaneForm/RightPaneForm.test.tsx +++ b/src/Explorer/Panes/RightPaneForm/RightPaneForm.test.tsx @@ -3,48 +3,38 @@ import { mount, ReactWrapper } from "enzyme"; import React from "react"; import { RightPaneForm } from "./RightPaneForm"; -const onClose = jest.fn(); const onSubmit = jest.fn(); const expandConsole = jest.fn(); const props = { - closePanel: (): void => undefined, expandConsole, formError: "", formErrorDetail: "", - id: "loadQueryPane", isExecuting: false, - title: "Load Query Pane", submitButtonText: "Load", - onClose, onSubmit, }; -describe("Load Query Pane", () => { +describe("Right Pane Form", () => { let wrapper: ReactWrapper; it("should render Default properly", () => { wrapper = mount(); expect(wrapper).toMatchSnapshot(); }); - it("should call close method click cancel icon", () => { - render(); - fireEvent.click(screen.getByTestId("closePaneBtn")); - expect(onClose).toHaveBeenCalled(); - }); it("should call submit method enter in form", () => { render(); - fireEvent.click(screen.getByTestId("submit")); + fireEvent.click(screen.getByLabelText("Load")); expect(onSubmit).toHaveBeenCalled(); }); it("should call submit method click on submit button", () => { render(); - fireEvent.click(screen.getByTestId("submit")); + fireEvent.click(screen.getByLabelText("Load")); expect(onSubmit).toHaveBeenCalled(); }); it("should render error in header", () => { render(); - expect(screen.getByTestId("errorIcon")).toBeDefined(); - expect(screen.getByTestId("panelmessage").innerHTML).toEqual("file already Exist"); + expect(screen.getByLabelText("error")).toBeDefined(); + expect(screen.getByLabelText("message").innerHTML).toEqual("file already Exist"); }); }); diff --git a/src/Explorer/Panes/RightPaneForm/RightPaneForm.tsx b/src/Explorer/Panes/RightPaneForm/RightPaneForm.tsx index 40120ff76..774399b23 100644 --- a/src/Explorer/Panes/RightPaneForm/RightPaneForm.tsx +++ b/src/Explorer/Panes/RightPaneForm/RightPaneForm.tsx @@ -1,6 +1,4 @@ -import { IconButton } from "@fluentui/react"; import React, { FunctionComponent, ReactNode } from "react"; -import { KeyCodes } from "../../../Common/Constants"; import { PanelFooterComponent } from "../PanelFooterComponent"; import { PanelInfoErrorComponent, PanelInfoErrorProps } from "../PanelInfoErrorComponent"; import { PanelLoadingScreen } from "../PanelLoadingScreen"; @@ -9,12 +7,9 @@ export interface RightPaneFormProps { expandConsole: () => void; formError: string; formErrorDetail: string; - id: string; isExecuting: boolean; - onClose: () => void; onSubmit: () => void; submitButtonText: string; - title: string; isSubmitButtonHidden?: boolean; children?: ReactNode; } @@ -23,51 +18,16 @@ export const RightPaneForm: FunctionComponent = ({ expandConsole, formError, formErrorDetail, - id, isExecuting, - onClose, onSubmit, submitButtonText, - title, isSubmitButtonHidden = false, children, }: RightPaneFormProps) => { - const getPanelHeight = (): number => { - const notificationConsoleElement: HTMLElement = document.getElementById("explorerNotificationConsole"); - return window.innerHeight - $(notificationConsoleElement).height(); - }; - - const panelHeight: number = getPanelHeight(); - const handleOnSubmit = (event: React.FormEvent) => { event.preventDefault(); onSubmit(); }; - const renderPanelHeader = (): JSX.Element => { - return ( -
- - {title} - - -
- ); - }; - - const onKeyDown = (event: React.KeyboardEvent): void => { - if (event.keyCode === KeyCodes.Escape) { - onClose(); - event.stopPropagation(); - } - }; const panelInfoErrorProps: PanelInfoErrorProps = { messageType: "error", @@ -78,19 +38,13 @@ export const RightPaneForm: FunctionComponent = ({ }; return ( -
-
-
-
- {renderPanelHeader()} - -
- {children} - {!isSubmitButtonHidden && } - -
- {isExecuting && } -
-
+ <> + +
+ {children} + {!isSubmitButtonHidden && } + + {isExecuting && } + ); }; diff --git a/src/Explorer/Panes/RightPaneForm/__snapshots__/RightPaneForm.test.tsx.snap b/src/Explorer/Panes/RightPaneForm/__snapshots__/RightPaneForm.test.tsx.snap index f11ff705e..90b9189f3 100644 --- a/src/Explorer/Panes/RightPaneForm/__snapshots__/RightPaneForm.test.tsx.snap +++ b/src/Explorer/Panes/RightPaneForm/__snapshots__/RightPaneForm.test.tsx.snap @@ -1,73 +1,322 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Load Query Pane should render Default properly 1`] = ` +exports[`Right Pane Form should render Default properly 1`] = ` -
+
-
-
-
- - Load Query Pane - - - - *": Object { - "left": 0, - "position": "relative", - "top": 0, - }, - }, - "textAlign": "center", - "textDecoration": "none", - "userSelect": "none", - }, - Object { - "backgroundColor": "transparent", - "border": "none", - "color": "#0078d4", - "height": "32px", - "padding": "0 4px", - "width": "32px", - }, - ], - "rootChecked": Object { - "backgroundColor": "#edebe9", - "color": "#005a9e", - }, - "rootCheckedHovered": Object { - "backgroundColor": "#e1dfdd", - "color": "#005a9e", - }, - "rootDisabled": Array [ - Object { - "outline": "transparent", - "position": "relative", - "selectors": Object { - ".ms-Fabric--isFocusVisible &:focus:after": Object { - "border": "1px solid transparent", - "bottom": 2, - "content": "\\"\\"", - "left": 2, - "outline": "1px solid #605e5c", - "position": "absolute", - "right": 2, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "bottom": -2, - "left": -2, - "outlineColor": "ButtonText", - "right": -2, - "top": -2, - }, - }, - "top": 2, - "zIndex": 1, - }, - "::-moz-focus-inner": Object { - "border": "0", - }, - }, - }, - Object { - "backgroundColor": "#f3f2f1", - "borderColor": "#f3f2f1", - "color": "#a19f9d", - "cursor": "default", - "selectors": Object { - ":focus": Object { - "outline": 0, - }, - ":hover": Object { - "outline": 0, - }, - }, - }, - Object { - "color": "#c8c6c4", - }, - ], - "rootExpanded": Object { - "backgroundColor": "#edebe9", - "color": "#005a9e", - }, - "rootHasMenu": Object { - "width": "auto", - }, - "rootHovered": Object { - "backgroundColor": "#f3f2f1", - "color": "#106ebe", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "borderColor": "Highlight", - "color": "Highlight", - }, - }, - }, - "rootPressed": Object { - "backgroundColor": "#edebe9", - "color": "#005a9e", - }, - "screenReaderText": Object { - "border": 0, - "height": 1, - "margin": -1, - "overflow": "hidden", - "padding": 0, - "position": "absolute", - "width": 1, - }, - "splitButtonContainer": Array [ - 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", - }, - }, - }, - Object { - "display": "inline-flex", - "selectors": Object { - ".ms-Button--default": Object { - "borderBottomRightRadius": "0", - "borderRight": "none", - "borderTopRightRadius": "0", - }, - ".ms-Button--primary": Object { - "border": "none", - "borderBottomRightRadius": "0", - "borderTopRightRadius": "0", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "Window", - "border": "1px solid WindowText", - "borderRightWidth": "0", - "color": "WindowText", - "forcedColorAdjust": "none", - }, - }, - }, - ".ms-Button--primary + .ms-Button": Object { - "border": "none", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "border": "1px solid WindowText", - "borderLeftWidth": "0", - }, - }, - }, - }, - }, - ], - "splitButtonContainerChecked": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - }, - }, - "splitButtonContainerCheckedHovered": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - }, - }, - "splitButtonContainerDisabled": Object { - "border": "none", - "outline": "none", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - "forcedColorAdjust": "none", - }, - }, - }, - "splitButtonContainerFocused": Object { - "outline": "none!important", - }, - "splitButtonContainerHovered": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Highlight", - "color": "Window", - }, - }, - }, - ".ms-Button.is-disabled": Object { - "color": "#a19f9d", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - }, - }, - }, - }, - }, - "splitButtonDivider": Object { - "bottom": 8, - "position": "absolute", - "right": 31, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "WindowText", - }, - }, - "top": 8, - "width": 1, - }, - "splitButtonDividerDisabled": Object { - "bottom": 8, - "position": "absolute", - "right": 31, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "GrayText", - }, - }, - "top": 8, - "width": 1, - }, - "splitButtonFlexContainer": Object { - "alignItems": "center", - "display": "flex", - "flexWrap": "nowrap", - "height": "100%", - "justifyContent": "center", - }, - "splitButtonMenuButton": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - ".ms-Button-menuIcon": Object { - "color": "WindowText", - }, - }, - "border": "1px solid #8a8886", - "borderBottomRightRadius": "2px", - "borderLeft": "none", - "borderRadius": 0, - "borderTopRightRadius": "2px", - "boxSizing": "border-box", - "cursor": "pointer", - "display": "inline-block", - "height": "auto", - "marginBottom": 0, - "marginLeft": -1, - "marginRight": 0, - "marginTop": 0, - "outline": "transparent", - "padding": 6, - "textAlign": "center", - "textDecoration": "none", - "userSelect": "none", - "verticalAlign": "top", - "width": 32, - }, - "splitButtonMenuButtonDisabled": Object { - "border": "none", - "pointerEvents": "none", - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - }, - }, - }, - ".ms-Button-menuIcon": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "color": "GrayText", - }, - }, - }, - ":hover": Object { - "cursor": "default", - }, - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "border": "1px solid GrayText", - "color": "GrayText", - }, - }, - }, - "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", - }, - }, - }, - "textContainer": Object { - "display": "block", - "flexGrow": 1, - }, - } - } - tabIndex={0} + primary={true} + text="Load" theme={ Object { "disableGlobalClassNames": false, @@ -1084,80 +871,586 @@ exports[`Load Query Pane should render Default properly 1`] = ` }, } } - title="Close pane" - variantClassName="ms-Button--icon" - > - - - - - -
- - - -
- - *": Object { + "left": 0, + "position": "relative", + "top": 0, + }, + }, + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + }, + Object { + "height": "32px", + "minWidth": "80px", + }, + Object { + "backgroundColor": "#0078d4", + "border": "1px solid #0078d4", + "color": "#ffffff", + "selectors": Object { + ".ms-Fabric--isFocusVisible &:focus": Object { + "selectors": Object { + ":after": Object { + "border": "none", + "outlineColor": "#ffffff", + }, + }, + }, + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "borderColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + ], + "rootChecked": Object { + "backgroundColor": "#005a9e", + "color": "#ffffff", + }, + "rootCheckedHovered": Object { + "backgroundColor": "#005a9e", + "color": "#ffffff", + }, + "rootDisabled": Array [ + Object { + "outline": "transparent", + "position": "relative", + "selectors": Object { + ".ms-Fabric--isFocusVisible &:focus:after": Object { + "border": "1px solid transparent", + "bottom": 2, + "content": "\\"\\"", + "left": 2, + "outline": "1px solid #605e5c", + "position": "absolute", + "right": 2, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "bottom": -2, + "left": -2, + "outlineColor": "ButtonText", + "right": -2, + "top": -2, + }, + }, + "top": 2, + "zIndex": 1, + }, + "::-moz-focus-inner": Object { + "border": "0", + }, + }, + }, + Object { + "backgroundColor": "#f3f2f1", + "borderColor": "#f3f2f1", + "color": "#a19f9d", + "cursor": "default", + "selectors": Object { + ":focus": Object { + "outline": 0, + }, + ":hover": Object { + "outline": 0, + }, + }, + }, + Object { + "backgroundColor": "#f3f2f1", + "color": "#d2d0ce", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + }, + ], + "rootExpanded": Object { + "backgroundColor": "#005a9e", + "color": "#ffffff", + }, + "rootHovered": Object { + "backgroundColor": "#106ebe", + "border": "1px solid #106ebe", + "color": "#ffffff", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Highlight", + "borderColor": "Highlight", + "color": "Window", + }, + }, + }, + "rootPressed": Object { + "backgroundColor": "#005a9e", + "border": "1px solid #005a9e", + "color": "#ffffff", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "borderColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + "screenReaderText": Object { + "border": 0, + "height": 1, + "margin": -1, + "overflow": "hidden", + "padding": 0, + "position": "absolute", + "width": 1, + }, + "splitButtonContainer": Array [ + Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "border": "none", + }, + }, + }, + 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", + }, + }, + }, + Object { + "display": "inline-flex", + "selectors": Object { + ".ms-Button--default": Object { + "borderBottomRightRadius": "0", + "borderRight": "none", + "borderTopRightRadius": "0", + }, + ".ms-Button--primary": Object { + "border": "none", + "borderBottomRightRadius": "0", + "borderTopRightRadius": "0", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "border": "1px solid WindowText", + "borderRightWidth": "0", + "color": "WindowText", + "forcedColorAdjust": "none", + }, + }, + }, + ".ms-Button--primary + .ms-Button": Object { + "border": "none", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "border": "1px solid WindowText", + "borderLeftWidth": "0", + }, + }, + }, + }, + }, + ], + "splitButtonContainerChecked": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + }, + }, + "splitButtonContainerCheckedHovered": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + }, + }, + "splitButtonContainerDisabled": Object { + "border": "none", + "outline": "none", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + "forcedColorAdjust": "none", + }, + }, + }, + "splitButtonContainerFocused": Object { + "outline": "none!important", + }, + "splitButtonContainerHovered": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Highlight", + "color": "Window", + }, + }, + }, + ".ms-Button.is-disabled": Object { + "color": "#a19f9d", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + }, + }, + }, + "splitButtonDivider": Array [ + Object { + "backgroundColor": "#ffffff", + "bottom": 8, + "position": "absolute", + "right": 31, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + }, + }, + "top": 8, + "width": 1, + }, + Object { + "bottom": 8, + "position": "absolute", + "right": 31, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "WindowText", + }, + }, + "top": 8, + "width": 1, + }, + ], + "splitButtonDividerDisabled": Object { + "bottom": 8, + "position": "absolute", + "right": 31, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "GrayText", + }, + }, + "top": 8, + "width": 1, + }, + "splitButtonFlexContainer": Object { + "alignItems": "center", + "display": "flex", + "flexWrap": "nowrap", + "height": "100%", + "justifyContent": "center", + }, + "splitButtonMenuButton": Array [ + Object { + "backgroundColor": "#0078d4", + "color": "#ffffff", + "selectors": Object { + ":hover": Object { + "backgroundColor": "#106ebe", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "color": "Highlight", + }, + }, + }, + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "WindowText", + }, + }, + }, + Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + ".ms-Button-menuIcon": Object { + "color": "WindowText", + }, + }, + "border": "1px solid #8a8886", + "borderBottomRightRadius": "2px", + "borderLeft": "none", + "borderRadius": 0, + "borderTopRightRadius": "2px", + "boxSizing": "border-box", + "cursor": "pointer", + "display": "inline-block", + "height": "auto", + "marginBottom": 0, + "marginLeft": -1, + "marginRight": 0, + "marginTop": 0, + "outline": "transparent", + "padding": 6, + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + "verticalAlign": "top", + "width": 32, + }, + ], + "splitButtonMenuButtonChecked": Object { + "backgroundColor": "#005a9e", + "selectors": Object { + ":hover": Object { + "backgroundColor": "#005a9e", + }, + }, + }, + "splitButtonMenuButtonDisabled": Array [ + Object { + "backgroundColor": "#f3f2f1", + "selectors": Object { + ":hover": Object { + "backgroundColor": "#f3f2f1", + }, + }, + }, + Object { + "border": "none", + "pointerEvents": "none", + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + }, + ".ms-Button-menuIcon": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "color": "GrayText", + }, + }, + }, + ":hover": Object { + "cursor": "default", + }, + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "border": "1px solid GrayText", + "color": "GrayText", + }, + }, + }, + ], + "splitButtonMenuButtonExpanded": Object { + "backgroundColor": "#005a9e", + "selectors": Object { + ":hover": Object { + "backgroundColor": "#005a9e", + }, + }, + }, + "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 { + "color": "#ffffff", + }, + "splitButtonMenuIconDisabled": Object { + "color": "#a19f9d", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "color": "GrayText", + }, + }, + }, + "textContainer": Object { + "display": "block", + "flexGrow": 1, + }, + } + } text="Load" theme={ Object { @@ -1433,1469 +1726,46 @@ exports[`Load Query Pane should render Default properly 1`] = ` } } type="submit" + variantClassName="ms-Button--primary" > - - - *": Object { - "left": 0, - "position": "relative", - "top": 0, - }, - }, - "textAlign": "center", - "textDecoration": "none", - "userSelect": "none", - }, - Object { - "height": "32px", - "minWidth": "80px", - }, - Object { - "backgroundColor": "#0078d4", - "border": "1px solid #0078d4", - "color": "#ffffff", - "selectors": Object { - ".ms-Fabric--isFocusVisible &:focus": Object { - "selectors": Object { - ":after": Object { - "border": "none", - "outlineColor": "#ffffff", - }, - }, - }, - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "borderColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - ], - "rootChecked": Object { - "backgroundColor": "#005a9e", - "color": "#ffffff", - }, - "rootCheckedHovered": Object { - "backgroundColor": "#005a9e", - "color": "#ffffff", - }, - "rootDisabled": Array [ - Object { - "outline": "transparent", - "position": "relative", - "selectors": Object { - ".ms-Fabric--isFocusVisible &:focus:after": Object { - "border": "1px solid transparent", - "bottom": 2, - "content": "\\"\\"", - "left": 2, - "outline": "1px solid #605e5c", - "position": "absolute", - "right": 2, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "bottom": -2, - "left": -2, - "outlineColor": "ButtonText", - "right": -2, - "top": -2, - }, - }, - "top": 2, - "zIndex": 1, - }, - "::-moz-focus-inner": Object { - "border": "0", - }, - }, - }, - Object { - "backgroundColor": "#f3f2f1", - "borderColor": "#f3f2f1", - "color": "#a19f9d", - "cursor": "default", - "selectors": Object { - ":focus": Object { - "outline": 0, - }, - ":hover": Object { - "outline": 0, - }, - }, - }, - Object { - "backgroundColor": "#f3f2f1", - "color": "#d2d0ce", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - }, - }, - }, - ], - "rootExpanded": Object { - "backgroundColor": "#005a9e", - "color": "#ffffff", - }, - "rootHovered": Object { - "backgroundColor": "#106ebe", - "border": "1px solid #106ebe", - "color": "#ffffff", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Highlight", - "borderColor": "Highlight", - "color": "Window", - }, - }, - }, - "rootPressed": Object { - "backgroundColor": "#005a9e", - "border": "1px solid #005a9e", - "color": "#ffffff", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "borderColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - "screenReaderText": Object { - "border": 0, - "height": 1, - "margin": -1, - "overflow": "hidden", - "padding": 0, - "position": "absolute", - "width": 1, - }, - "splitButtonContainer": Array [ - Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "border": "none", - }, - }, - }, - 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", - }, - }, - }, - Object { - "display": "inline-flex", - "selectors": Object { - ".ms-Button--default": Object { - "borderBottomRightRadius": "0", - "borderRight": "none", - "borderTopRightRadius": "0", - }, - ".ms-Button--primary": Object { - "border": "none", - "borderBottomRightRadius": "0", - "borderTopRightRadius": "0", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "Window", - "border": "1px solid WindowText", - "borderRightWidth": "0", - "color": "WindowText", - "forcedColorAdjust": "none", - }, - }, - }, - ".ms-Button--primary + .ms-Button": Object { - "border": "none", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "border": "1px solid WindowText", - "borderLeftWidth": "0", - }, - }, - }, - }, - }, - ], - "splitButtonContainerChecked": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - }, - }, - "splitButtonContainerCheckedHovered": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "WindowText", - "color": "Window", - "forcedColorAdjust": "none", - }, - }, - }, - }, - }, - "splitButtonContainerDisabled": Object { - "border": "none", - "outline": "none", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "MsHighContrastAdjust": "none", - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - "forcedColorAdjust": "none", - }, - }, - }, - "splitButtonContainerFocused": Object { - "outline": "none!important", - }, - "splitButtonContainerHovered": Object { - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Highlight", - "color": "Window", - }, - }, - }, - ".ms-Button.is-disabled": Object { - "color": "#a19f9d", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - }, - }, - }, - }, - }, - "splitButtonDivider": Array [ - Object { - "backgroundColor": "#ffffff", - "bottom": 8, - "position": "absolute", - "right": 31, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - }, - }, - "top": 8, - "width": 1, - }, - Object { - "bottom": 8, - "position": "absolute", - "right": 31, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "WindowText", - }, - }, - "top": 8, - "width": 1, - }, - ], - "splitButtonDividerDisabled": Object { - "bottom": 8, - "position": "absolute", - "right": 31, - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "GrayText", - }, - }, - "top": 8, - "width": 1, - }, - "splitButtonFlexContainer": Object { - "alignItems": "center", - "display": "flex", - "flexWrap": "nowrap", - "height": "100%", - "justifyContent": "center", - }, - "splitButtonMenuButton": Array [ - Object { - "backgroundColor": "#0078d4", - "color": "#ffffff", - "selectors": Object { - ":hover": Object { - "backgroundColor": "#106ebe", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "color": "Highlight", - }, - }, - }, - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "WindowText", - }, - }, - }, - Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - ".ms-Button-menuIcon": Object { - "color": "WindowText", - }, - }, - "border": "1px solid #8a8886", - "borderBottomRightRadius": "2px", - "borderLeft": "none", - "borderRadius": 0, - "borderTopRightRadius": "2px", - "boxSizing": "border-box", - "cursor": "pointer", - "display": "inline-block", - "height": "auto", - "marginBottom": 0, - "marginLeft": -1, - "marginRight": 0, - "marginTop": 0, - "outline": "transparent", - "padding": 6, - "textAlign": "center", - "textDecoration": "none", - "userSelect": "none", - "verticalAlign": "top", - "width": 32, - }, - ], - "splitButtonMenuButtonChecked": Object { - "backgroundColor": "#005a9e", - "selectors": Object { - ":hover": Object { - "backgroundColor": "#005a9e", - }, - }, - }, - "splitButtonMenuButtonDisabled": Array [ - Object { - "backgroundColor": "#f3f2f1", - "selectors": Object { - ":hover": Object { - "backgroundColor": "#f3f2f1", - }, - }, - }, - Object { - "border": "none", - "pointerEvents": "none", - "selectors": Object { - ".ms-Button--primary": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "borderColor": "GrayText", - "color": "GrayText", - }, - }, - }, - ".ms-Button-menuIcon": Object { - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "color": "GrayText", - }, - }, - }, - ":hover": Object { - "cursor": "default", - }, - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "backgroundColor": "Window", - "border": "1px solid GrayText", - "color": "GrayText", - }, - }, - }, - ], - "splitButtonMenuButtonExpanded": Object { - "backgroundColor": "#005a9e", - "selectors": Object { - ":hover": Object { - "backgroundColor": "#005a9e", - }, - }, - }, - "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 { - "color": "#ffffff", - }, - "splitButtonMenuIconDisabled": Object { - "color": "#a19f9d", - "selectors": Object { - "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { - "color": "GrayText", - }, - }, - }, - "textContainer": Object { - "display": "block", - "flexGrow": 1, - }, - } - } - text="Load" - theme={ - Object { - "disableGlobalClassNames": false, - "effects": Object { - "elevation16": "0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108)", - "elevation4": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", - "elevation64": "0 25.6px 57.6px 0 rgba(0, 0, 0, 0.22), 0 4.8px 14.4px 0 rgba(0, 0, 0, 0.18)", - "elevation8": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", - "roundedCorner2": "2px", - "roundedCorner4": "4px", - "roundedCorner6": "6px", - }, - "fonts": Object { - "large": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "18px", - "fontWeight": 400, - }, - "medium": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "14px", - "fontWeight": 400, - }, - "mediumPlus": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "16px", - "fontWeight": 400, - }, - "mega": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "68px", - "fontWeight": 600, - }, - "small": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "12px", - "fontWeight": 400, - }, - "smallPlus": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "12px", - "fontWeight": 400, - }, - "superLarge": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "42px", - "fontWeight": 600, - }, - "tiny": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "10px", - "fontWeight": 400, - }, - "xLarge": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "20px", - "fontWeight": 600, - }, - "xLargePlus": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "24px", - "fontWeight": 600, - }, - "xSmall": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "10px", - "fontWeight": 400, - }, - "xxLarge": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "28px", - "fontWeight": 600, - }, - "xxLargePlus": Object { - "MozOsxFontSmoothing": "grayscale", - "WebkitFontSmoothing": "antialiased", - "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", - "fontSize": "32px", - "fontWeight": 600, - }, - }, - "isInverted": false, - "palette": Object { - "accent": "#0078d4", - "black": "#000000", - "blackTranslucent40": "rgba(0,0,0,.4)", - "blue": "#0078d4", - "blueDark": "#002050", - "blueLight": "#00bcf2", - "blueMid": "#00188f", - "green": "#107c10", - "greenDark": "#004b1c", - "greenLight": "#bad80a", - "magenta": "#b4009e", - "magentaDark": "#5c005c", - "magentaLight": "#e3008c", - "neutralDark": "#201f1e", - "neutralLight": "#edebe9", - "neutralLighter": "#f3f2f1", - "neutralLighterAlt": "#faf9f8", - "neutralPrimary": "#323130", - "neutralPrimaryAlt": "#3b3a39", - "neutralQuaternary": "#d2d0ce", - "neutralQuaternaryAlt": "#e1dfdd", - "neutralSecondary": "#605e5c", - "neutralSecondaryAlt": "#8a8886", - "neutralTertiary": "#a19f9d", - "neutralTertiaryAlt": "#c8c6c4", - "orange": "#d83b01", - "orangeLight": "#ea4300", - "orangeLighter": "#ff8c00", - "purple": "#5c2d91", - "purpleDark": "#32145a", - "purpleLight": "#b4a0ff", - "red": "#e81123", - "redDark": "#a4262c", - "teal": "#008272", - "tealDark": "#004b50", - "tealLight": "#00b294", - "themeDark": "#005a9e", - "themeDarkAlt": "#106ebe", - "themeDarker": "#004578", - "themeLight": "#c7e0f4", - "themeLighter": "#deecf9", - "themeLighterAlt": "#eff6fc", - "themePrimary": "#0078d4", - "themeSecondary": "#2b88d8", - "themeTertiary": "#71afe5", - "white": "#ffffff", - "whiteTranslucent40": "rgba(255,255,255,.4)", - "yellow": "#ffb900", - "yellowDark": "#d29200", - "yellowLight": "#fff100", - }, - "rtl": undefined, - "semanticColors": Object { - "accentButtonBackground": "#0078d4", - "accentButtonText": "#ffffff", - "actionLink": "#323130", - "actionLinkHovered": "#201f1e", - "blockingBackground": "#FDE7E9", - "blockingIcon": "#FDE7E9", - "bodyBackground": "#ffffff", - "bodyBackgroundChecked": "#edebe9", - "bodyBackgroundHovered": "#f3f2f1", - "bodyDivider": "#edebe9", - "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodySubtext": "#605e5c", - "bodyText": "#323130", - "bodyTextChecked": "#000000", - "buttonBackground": "#ffffff", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundCheckedHovered": "#edebe9", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#f3f2f1", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextCheckedHovered": "#000000", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", - "cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", - "cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", - "cardStandoutBackground": "#ffffff", - "defaultStateBackground": "#faf9f8", - "disabledBackground": "#f3f2f1", - "disabledBodySubtext": "#c8c6c4", - "disabledBodyText": "#a19f9d", - "disabledBorder": "#c8c6c4", - "disabledSubtext": "#d2d0ce", - "disabledText": "#a19f9d", - "errorBackground": "#FDE7E9", - "errorIcon": "#A80000", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "infoBackground": "#f3f2f1", - "infoIcon": "#605e5c", - "inputBackground": "#ffffff", - "inputBackgroundChecked": "#0078d4", - "inputBackgroundCheckedHovered": "#005a9e", - "inputBorder": "#605e5c", - "inputBorderHovered": "#323130", - "inputFocusBorderAlt": "#0078d4", - "inputForegroundChecked": "#ffffff", - "inputIcon": "#0078d4", - "inputIconDisabled": "#a19f9d", - "inputIconHovered": "#005a9e", - "inputPlaceholderBackgroundChecked": "#deecf9", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", - "inputTextHovered": "#201f1e", - "link": "#0078d4", - "linkHovered": "#004578", - "listBackground": "#ffffff", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", - "listItemBackgroundChecked": "#edebe9", - "listItemBackgroundCheckedHovered": "#e1dfdd", - "listItemBackgroundHovered": "#f3f2f1", - "listText": "#323130", - "listTextColor": "#323130", - "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuHeader": "#0078d4", - "menuIcon": "#0078d4", - "menuItemBackgroundChecked": "#edebe9", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", - "messageLink": "#005A9E", - "messageLinkHovered": "#004578", - "messageText": "#323130", - "primaryButtonBackground": "#0078d4", - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": "#106ebe", - "primaryButtonBackgroundPressed": "#005a9e", - "primaryButtonBorder": "transparent", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", - "primaryButtonTextHovered": "#ffffff", - "primaryButtonTextPressed": "#ffffff", - "severeWarningBackground": "#FED9CC", - "severeWarningIcon": "#D83B01", - "smallInputBorder": "#605e5c", - "successBackground": "#DFF6DD", - "successIcon": "#107C10", - "successText": "#107C10", - "variantBorder": "#edebe9", - "variantBorderHovered": "#a19f9d", - "warningBackground": "#FFF4CE", - "warningHighlight": "#ffb900", - "warningIcon": "#797775", - "warningText": "#323130", - }, - "spacing": Object { - "l1": "20px", - "l2": "32px", - "m": "16px", - "s1": "8px", - "s2": "4px", - }, - } - } - type="submit" - variantClassName="ms-Button--primary" + - - - - - - - -
-
- + Load + + + + + + + + + +
-
-
+ + `; diff --git a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx index 85331ec65..88fb10cf0 100644 --- a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx +++ b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx @@ -1,16 +1,13 @@ import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react"; import React, { FunctionComponent, MouseEvent, useState } from "react"; import * as Constants from "../../../Common/Constants"; -import { Tooltip } from "../../../Common/Tooltip/Tooltip"; +import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip"; import { configContext } from "../../../ConfigContext"; import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility"; import * as StringUtility from "../../../Shared/StringUtility"; import { userContext } from "../../../UserContext"; import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils"; -import { - GenericRightPaneComponent, - GenericRightPaneProps, -} from "../GenericRightPaneComponent/GenericRightPaneComponent"; +import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm"; export interface SettingsPaneProps { expandConsole: () => void; @@ -105,15 +102,12 @@ export const SettingsPane: FunctionComponent = ({ setGraphAutoVizDisabled(option.key); }; - const genericPaneProps: GenericRightPaneProps = { + const genericPaneProps: RightPaneFormProps = { expandConsole, formError: formErrors, formErrorDetail: "", - id: "settingspane", isExecuting, - title: "Setting", submitButtonText: "Apply", - onClose: () => closePanel(), onSubmit: () => handlerOnSubmit(undefined), }; const pageOptionList: IChoiceGroupOption[] = [ @@ -130,17 +124,17 @@ export const SettingsPane: FunctionComponent = ({ setPageOption(option.key); }; return ( - +
{shouldShowQueryPageOptions && (
Page options - + Choose Custom to specify a fixed amount of query results to show, or choose Unlimited to show as many query results per page. - +
@@ -149,7 +143,7 @@ export const SettingsPane: FunctionComponent = ({
Query results per page - Enter the number of query results that should be shown per page. + Enter the number of query results that should be shown per page.
= ({
Enable cross-partition query - + Send more than one request while executing a query. More than one request is necessary if the query is not scoped to single partition key value. - +
= ({
Max degree of parallelism - + Gets or sets the number of concurrent operations run client side during parallel query execution. A positive property value limits the number of concurrent operations to the set value. If it is set to less than 0, the system automatically decides the number of concurrent operations to run. - +
= ({
Display Gremlin query results as:  - + Select Graph to automatically visualize the query results as a Graph or JSON to display the results as JSON. - +
= ({
- + ); }; diff --git a/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap b/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap index 851d97dc9..a7eb35a83 100644 --- a/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap +++ b/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap @@ -1,16 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Settings Pane should render Default properly 1`] = ` -
Page options - + Choose Custom to specify a fixed amount of query results to show, or choose Unlimited to show as many query results per page. - +
Query results per page - + Enter the number of query results that should be shown per page. - +
Enable cross-partition query - + Send more than one request while executing a query. More than one request is necessary if the query is not scoped to single partition key value. - +
Max degree of parallelism - + Gets or sets the number of concurrent operations run client side during parallel query execution. A positive property value limits the number of concurrent operations to the set value. If it is set to less than 0, the system automatically decides the number of concurrent operations to run. - +
- + `; exports[`Settings Pane should render Gremlin properly 1`] = ` -
Display Gremlin query results as:  - + Select Graph to automatically visualize the query results as a Graph or JSON to display the results as JSON. - +
- + `; diff --git a/src/Explorer/Panes/UploadFilePane/UploadFilePane.tsx b/src/Explorer/Panes/UploadFilePane/UploadFilePane.tsx index 279e088d0..aa804cb52 100644 --- a/src/Explorer/Panes/UploadFilePane/UploadFilePane.tsx +++ b/src/Explorer/Panes/UploadFilePane/UploadFilePane.tsx @@ -15,9 +15,6 @@ export const UploadFilePane: FunctionComponent = ({ closePanel, uploadFile, }: UploadFilePanelProps) => { - const title = "Upload file to notebook server"; - const submitButtonLabel = "Upload"; - const selectFileInputLabel = "Select file to upload"; const extensions: string = undefined; //ex. ".ipynb" const errorMessage = "Could not upload file"; const inProgressMessage = "Uploading file to notebook server"; @@ -39,11 +36,8 @@ export const UploadFilePane: FunctionComponent = ({ } const file: File = files.item(0); - // const id: string = logConsoleProgress( - // `${inProgressMessage}: ${file.name}` - // ); - logConsoleProgress(`${inProgressMessage}: ${file.name}`); + const clearMessage = logConsoleProgress(`${inProgressMessage}: ${file.name}`); setIsExecuting(true); @@ -61,7 +55,7 @@ export const UploadFilePane: FunctionComponent = ({ ) .finally(() => { setIsExecuting(false); - // clearInProgressMessageWithId(id); + clearMessage(); }); }; @@ -92,18 +86,15 @@ export const UploadFilePane: FunctionComponent = ({ expandConsole, formError: formErrors, formErrorDetail: formErrorsDetails, - id: "uploadFilePane", isExecuting: isExecuting, - title, - submitButtonText: submitButtonLabel, - onClose: closePanel, + submitButtonText: "Upload", onSubmit: submit, }; return (
- +
); diff --git a/src/Explorer/Panes/UploadItemsPane/UploadItemsPane.tsx b/src/Explorer/Panes/UploadItemsPane/UploadItemsPane.tsx index 33d00c833..e2ef3ddbc 100644 --- a/src/Explorer/Panes/UploadItemsPane/UploadItemsPane.tsx +++ b/src/Explorer/Panes/UploadItemsPane/UploadItemsPane.tsx @@ -2,7 +2,6 @@ import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@flu import React, { ChangeEvent, FunctionComponent, useState } from "react"; import { Upload } from "../../../Common/Upload/Upload"; import { UploadDetailsRecord } from "../../../Contracts/ViewModels"; -import { userContext } from "../../../UserContext"; import { logConsoleError } from "../../../Utils/NotificationConsoleUtils"; import Explorer from "../../Explorer"; import { getErrorMessage } from "../../Tables/Utilities"; @@ -10,23 +9,9 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor export interface UploadItemsPaneProps { explorer: Explorer; - closePanel: () => void; } -const getTitle = (): string => { - if (userContext.apiType === "Cassandra" || userContext.apiType === "Tables") { - return "Upload Tables"; - } else if (userContext.apiType === "Gremlin") { - return "Upload Graph"; - } else { - return "Upload Items"; - } -}; - -export const UploadItemsPane: FunctionComponent = ({ - explorer, - closePanel, -}: UploadItemsPaneProps) => { +export const UploadItemsPane: FunctionComponent = ({ explorer }: UploadItemsPaneProps) => { const [files, setFiles] = useState(); const [uploadFileData, setUploadFileData] = useState([]); const [formError, setFormError] = useState(""); @@ -71,11 +56,8 @@ export const UploadItemsPane: FunctionComponent = ({ expandConsole: () => explorer.expandConsole(), formError, formErrorDetail, - id: "uploaditemspane", isExecuting: isExecuting, - title: getTitle(), submitButtonText: "Upload", - onClose: closePanel, onSubmit, }; diff --git a/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap b/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap index 352cc7707..c635538f7 100644 --- a/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap +++ b/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap @@ -5,11 +5,8 @@ exports[`Upload Items Pane should render Default properly 1`] = ` expandConsole={[Function]} formError="" formErrorDetail="" - id="uploaditemspane" - onClose={[Function]} onSubmit={[Function]} submitButtonText="Upload" - title="Upload Items" >
@@ -1593,13 +1593,13 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database key=".0:$.1" > Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources. @@ -2303,14 +2303,12 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database > { iconSrc: AddDatabaseIcon, title: this.container.addDatabaseText(), description: null, - onClick: () => this.container.addDatabasePane.open(), + onClick: () => this.container.openAddDatabasePane(), }); } diff --git a/src/Main.tsx b/src/Main.tsx index 66894dbcc..d2789bbbe 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -35,7 +35,6 @@ import "./Explorer/Controls/DynamicList/DynamicListComponent.less"; import "./Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.less"; import "./Explorer/Controls/JsonEditor/JsonEditorComponent.less"; import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less"; -import "./Explorer/Controls/ThroughputInput/ThroughputInput.less"; import "./Explorer/Controls/TreeComponent/treeComponent.less"; import { ExplorerParams } from "./Explorer/Explorer"; import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less"; diff --git a/src/Utils/APITypeUtils.ts b/src/Utils/APITypeUtils.ts index c321bd98b..7c71dcf4d 100644 --- a/src/Utils/APITypeUtils.ts +++ b/src/Utils/APITypeUtils.ts @@ -28,3 +28,30 @@ export const getCollectionName = (isPlural?: boolean): string => { return collectionName; }; + +export const getDatabaseName = (): string => { + const { apiType } = userContext; + switch (apiType) { + case "SQL": + case "Mongo": + case "Gremlin": + case "Tables": + return "Database"; + case "Cassandra": + return "Keyspace"; + default: + throw new Error(`Unknown API type: ${apiType}`); + } +}; + +export const getUploadName = (): string => { + switch (userContext.apiType) { + case "Cassandra": + case "Tables": + return "Tables"; + case "Gremlin": + return "Graph"; + default: + return "Items"; + } +}; diff --git a/test/mongo/container.spec.ts b/test/mongo/container.spec.ts index 02ca87d52..3b8c944d7 100644 --- a/test/mongo/container.spec.ts +++ b/test/mongo/container.spec.ts @@ -23,7 +23,7 @@ test("Mongo CRUD", async () => { await safeClick(explorer, `.nodeItem >> text=${databaseId}`); await safeClick(explorer, `.nodeItem >> text=${containerId}`); // Create indexing policy - await safeClick(explorer, ".nodeItem >> text=Settings"); + await safeClick(explorer, ".nodeItem >> text=Setting"); await explorer.click('button[role="tab"]:has-text("Indexing Policy")'); await explorer.click('[aria-label="Index Field Name 0"]'); await explorer.fill('[aria-label="Index Field Name 0"]', "foo");