Compare commits

..

45 Commits

Author SHA1 Message Date
sunilyadav840
88ef4ea9ed updated snapshot 2021-05-14 14:24:31 +05:30
sunilyadav840
6a28bd4898 Merge branch 'configure-eslint-plugin-jsx-a11y' of https://github.com/Azure/cosmos-explorer into configure-eslint-plugin-jsx-a11y 2021-05-14 13:25:43 +05:30
sunilyadav840
2a2f55ff28 Merge branch 'master' 2021-05-14 13:25:03 +05:30
Steve Faulkner
f9e8b5eaaa Remove Unused Knockout Components (#783) 2021-05-13 18:03:29 -05:00
vaidankarswapnil
a6b82c8340 Migrate graph style panel to react (#619)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-13 15:45:00 -05:00
Tanuj Mittal
404b1fc0f1 Prep Schema Analyzer for flighting (#760)
* Prepare for flighting Schema Analyzer

* Rename SchemaAnalyzerComponent -> SchemaAnalyzer

* Only show Schema option if notebooks enabled
2021-05-13 10:34:09 -07:00
Sunil Kumar Yadav
d7c62ac7f1 Migrate Collapse/Open Resource Tree to React (#733)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-12 20:03:52 -05:00
Sunil Kumar Yadav
8e6d274b11 Add Files to TypeScript Strict (#776)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-12 19:56:48 -05:00
Sunil Kumar Yadav
2d506f0312 Add Files to TypeScript Strict Mode (#777) 2021-05-12 19:23:10 -05:00
victor-meng
d76aaca0dd Improve lazy load database/collection offer logic (#768) 2021-05-12 19:13:15 -05:00
victor-meng
14e58e5519 Batch of small fixes for RightPaneForm and AddDatabasePane components (#780) 2021-05-12 19:12:03 -05:00
Steve Faulkner
ac743d9efc Merge branch 'master' into configure-eslint-plugin-jsx-a11y 2021-05-12 15:09:39 -05:00
victor-meng
2f6dbd83f3 Fix throughput input component and add database panel (#773) 2021-05-12 13:56:24 -05:00
Steve Faulkner
0a6c7c0ff9 Add Mongo 3.2 End to End Test (#779) 2021-05-12 13:41:44 -05:00
Steve Faulkner
66281447df Pass undefined analyticalTTL if Synapse is disabled (#778) 2021-05-12 11:49:25 -05:00
victor-meng
c5f76ac2a9 Fix isFixedCollectionWithSharedThroughputSupported flag (#774) 2021-05-12 09:16:13 -05:00
sunilyadav840
8a5f8cb31e updated snapshot 2021-05-12 10:09:53 +05:30
sunilyadav840
f0fe29a3b0 Merge branch 'master' of https://github.com/Azure/cosmos-explorer into configure-eslint-plugin-jsx-a11y 2021-05-12 09:58:25 +05:30
Laurent Nguyen
861042c27e Fix bug publish screenshot (#762)
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/762?feature.someFeatureFlagYouMightNeed=true)

The main change in this PR fixes the snapshot functionality in the Publish pane-related components. Because the code cell outputs are now rendered in their own iframes for security reasons, a single snapshot of the notebook is no longer possible: each cell output takes its own snapshot and the snapshots are collated on the main notebook snapshot.
- Move the snapshot functionality to notebook components: this removes the reference of the notebook DOM node that we must pass to the Publish pane via explorer.
- Add slice in the state and actions in notebook redux for notebook snapshot requests and result
- Add post robot message to take snapshots and receive results
- Add logic in `NotebookRenderer` to wait for all output snapshots done before taking the main one collating.
- Use `zustand` to share snapshot between Redux world and React world. This solves the issue of keeping the `PanelContainer` component generic, while being able to update its children (`PublishPanel` component) with the new snapshot.

Additional changes:
- Add `local()` in `@font-face` to check if font is already installed before downloading the font (must be done for Safari, but not Edge/Chrome)
- Add "Export output to image" menu item in notebook cell, since each cell output can take its own snapshot (which can be downloaded)
![image](https://user-images.githubusercontent.com/21954022/117454706-b5f16600-af46-11eb-8535-6bf99f3d9170.png)
2021-05-11 18:24:05 +00:00
sunilyadav840
00f649643b Merge branch 'master' 2021-05-11 20:16:07 +05:30
sunilyadav840
aae4036e80 Fixed eslint-jsx-a11 issue 2021-05-11 18:02:04 +05:30
victor-meng
4ed8fe9e7d Remove old add collection pane (#767) 2021-05-10 20:10:48 -05:00
Srinath Narayanan
4c506da7b9 Added metrics blade link and fixed SelfServe bugs (#764)
* Added metrics blade link

* fixed lint error
2021-05-10 17:36:50 -07:00
Hardikkumar Nai
a81b1a40a3 Use @fluentui/react DocumentCard (#715)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-10 14:17:37 -05:00
Hardikkumar Nai
9d5c9d6296 Migrate Add Database Panel to React (#597)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-10 14:02:14 -05:00
sunilyadav840
ff3ea402d7 configure eslint-plugin-jsx-a11y 2021-05-10 19:17:57 +05:30
Steve Faulkner
7efa8ca58f Remove unused Switch Directory Pane (#766) 2021-05-09 22:37:18 -05:00
Hardikkumar Nai
487fbf2072 Remove genericRightPaneComponent and create RightPaneWrapper with form (#679)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-09 19:22:44 -05:00
Sunil Kumar Yadav
aa308b3e4d Enable TypeScript noImplicitThis (#761) 2021-05-07 10:25:19 -05:00
Steve Faulkner
db227084be Remove IE11 from Coding Guidelines 2021-05-07 10:04:47 -05:00
victor-meng
d62baf327b Change create wildcard index default value to false for mongo 3.2 (#759)
* Change create wildcard index default value to false for mongo 3.2

* Update snapshots
2021-05-06 21:27:47 -05:00
Jordi Bunster
78eafe1aec Remove NotebookViewerTab (#749)
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/749)
2021-05-07 00:20:25 +00:00
Sunil Kumar Yadav
a91ea6c1e4 Remove old Add/Edit Table Entity code (#755) 2021-05-06 18:51:45 -05:00
victor-meng
5606ef3266 Fix table edit entity bug and add collection panel bug for connection string users (#757)
* Fix table edit entity bug and add collection panel bug for connection string users

* Remove parseInt for int64
2021-05-06 18:51:22 -05:00
Steve Faulkner
503f044a70 Update strict mode files (#753) 2021-05-06 12:35:24 -05:00
Hardikkumar Nai
23223cfb23 Upgrade Fluent UI v8 (#688)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-05 18:26:03 -05:00
Steve Faulkner
bd47e5ed49 Remove unused Explorer methods (#750) 2021-05-05 17:35:35 -05:00
Hardikkumar Nai
8c05ac740c Remove Explorer.databaseAccount (#717)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-05 16:54:50 -05:00
Hardikkumar Nai
fdd12b41c4 Remove Explorer.defaultExperience (#680)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-05 13:00:01 -05:00
Tanuj Mittal
d1d28885d0 Use CellOutputViewer for SchemaAnalyzer (#747) 2021-05-05 11:12:27 +05:30
Hardikkumar Nai
aab624e241 Create End to End Graph Test (#745) 2021-05-04 23:01:13 -05:00
Tanuj Mittal
181b53c858 Disable HTML in markdown cell for NotebookReadOnlyRenderer (#746)
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/746)

We have a custom implementation of `Markdown` cell that we use in `NotebookRenderer`. This custom implementation disables HTML rendering in markdown cells. This change uses the same for `NotebookReadOnlyRenderer` which we use for Gallery.
2021-05-04 21:43:39 +00:00
Srinath Narayanan
1fdb339fbf Enable the "Enable notebooks" button (#734)
* enable notebooks initial commit

* use only first write location

* addressed PR comments

* Minor edits
2021-05-04 13:06:27 -07:00
Jordi Bunster
b7579d5c8b eslint switch/case exhaustiveness check rule (#739) 2021-05-04 09:12:54 -07:00
vaidankarswapnil
038f3ee684 Move GitHub repos panel to react (#638)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-03 19:56:47 -05:00
298 changed files with 19210 additions and 45234 deletions

View File

@@ -1,4 +1,5 @@
**/node_modules/ **/node_modules/
src/**/__mocks__/**/*
dist/ dist/
Contracts/ Contracts/
src/Api/Apis.ts src/Api/Apis.ts
@@ -53,7 +54,6 @@ src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts
src/Explorer/Controls/InputTypeahead/InputTypeahead.ts src/Explorer/Controls/InputTypeahead/InputTypeahead.ts
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts
src/Explorer/Controls/ThroughputInput/ThroughputInput.test.ts
src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts
src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts
src/Explorer/Controls/Toolbar/IToolbarAction.ts src/Explorer/Controls/Toolbar/IToolbarAction.ts
@@ -84,8 +84,8 @@ src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts # src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts # src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
@@ -108,24 +108,19 @@ src/Explorer/Notebook/NotebookUtil.ts
src/Explorer/OpenActions.test.ts src/Explorer/OpenActions.test.ts
src/Explorer/OpenActions.ts src/Explorer/OpenActions.ts
src/Explorer/OpenActionsStubs.ts src/Explorer/OpenActionsStubs.ts
src/Explorer/Panes/AddCollectionPane.test.ts
src/Explorer/Panes/AddCollectionPane.ts
src/Explorer/Panes/AddDatabasePane.test.ts
src/Explorer/Panes/AddDatabasePane.ts src/Explorer/Panes/AddDatabasePane.ts
src/Explorer/Panes/AddDatabasePane.test.ts
src/Explorer/Panes/BrowseQueriesPane.ts src/Explorer/Panes/BrowseQueriesPane.ts
src/Explorer/Panes/CassandraAddCollectionPane.ts src/Explorer/Panes/CassandraAddCollectionPane.ts
src/Explorer/Panes/ContextualPaneBase.ts src/Explorer/Panes/ContextualPaneBase.ts
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
src/Explorer/Panes/GraphStylingPane.ts # src/Explorer/Panes/GraphStylingPane.ts
# src/Explorer/Panes/NewVertexPane.ts # src/Explorer/Panes/NewVertexPane.ts
src/Explorer/Panes/PaneComponents.ts src/Explorer/Panes/PaneComponents.ts
src/Explorer/Panes/RenewAdHocAccessPane.ts src/Explorer/Panes/RenewAdHocAccessPane.ts
src/Explorer/Panes/SetupNotebooksPane.ts src/Explorer/Panes/SetupNotebooksPane.ts
src/Explorer/Panes/SwitchDirectoryPane.ts src/Explorer/Panes/SwitchDirectoryPane.ts
src/Explorer/Panes/Tables/EditTableEntityPane.ts
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
src/Explorer/Panes/Tables/TableEntityPane.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts

View File

@@ -3,14 +3,15 @@ module.exports = {
browser: true, browser: true,
es6: true, es6: true,
}, },
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks"], plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks", "jsx-a11y"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jsx-a11y/recommended"],
globals: { globals: {
Atomics: "readonly", Atomics: "readonly",
SharedArrayBuffer: "readonly", SharedArrayBuffer: "readonly",
}, },
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
parserOptions: { parserOptions: {
project: ["./tsconfig.json", "./tsconfig.test.json"],
ecmaFeatures: { ecmaFeatures: {
jsx: true, jsx: true,
}, },
@@ -33,8 +34,10 @@ module.exports = {
}, },
], ],
rules: { rules: {
"jsx-a11y/anchor-is-valid": 1,
"no-console": ["error", { allow: ["error", "warn", "dir"] }], "no-console": ["error", { allow: ["error", "warn", "dir"] }],
curly: "error", curly: "error",
"@typescript-eslint/switch-exhaustiveness-check": "error",
"@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-extraneous-class": "error", "@typescript-eslint/no-extraneous-class": "error",
"no-null/no-null": "error", "no-null/no-null": "error",

View File

@@ -138,8 +138,10 @@ jobs:
matrix: matrix:
test-file: test-file:
- ./test/cassandra/container.spec.ts - ./test/cassandra/container.spec.ts
- ./test/graph/container.spec.ts
- ./test/sql/container.spec.ts - ./test/sql/container.spec.ts
- ./test/mongo/container.spec.ts - ./test/mongo/container.spec.ts
- ./test/mongo/container32.spec.ts
- ./test/selfServe/selfServeExample.spec.ts - ./test/selfServe/selfServeExample.spec.ts
- ./test/notebooks/upload.spec.ts - ./test/notebooks/upload.spec.ts
- ./test/sql/resourceToken.spec.ts - ./test/sql/resourceToken.spec.ts

View File

@@ -188,7 +188,3 @@ Cosmos Explorer has been under constant development for over 5 years. As a resul
✅ DO ✅ DO
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices) - Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
- Support IE11
- In practice, this should not need to be considered as part of a normal development workflow
- Polyfills and transpilation are already provided by our engineering systems.
- This requirement will be removed on March 30th, 2021 when Azure drops IE11 support.

View File

@@ -69,7 +69,8 @@ module.exports = {
moduleNameMapper: { moduleNameMapper: {
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule", "^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule", "@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1", // https://github.com/OfficeDev/office-ui-fabric-react/wiki/Fabric-6-Release-Notes "@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes
"monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor",
"^dnd-core$": "dnd-core/dist/cjs", "^dnd-core$": "dnd-core/dist/cjs",
"^react-dnd$": "react-dnd/dist/cjs", "^react-dnd$": "react-dnd/dist/cjs",
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs", "^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",

View File

@@ -4,7 +4,7 @@
@font-face { @font-face {
font-family: wf_segoe-ui_normal; font-family: wf_segoe-ui_normal;
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff"); src: local("Segoe UI"), url("../../fonts/segoe-ui/west-european/normal/latest.woff");
} }
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif; @DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;

View File

@@ -1757,7 +1757,7 @@ input::-webkit-calendar-picker-indicator {
cursor: pointer; cursor: pointer;
} }
.contextual-pane .paneMainContent { .paneMainContent {
flex: 1; flex: 1;
padding-left: 34px; padding-left: 34px;
padding-right: 34px; padding-right: 34px;
@@ -2099,7 +2099,7 @@ a:link {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
overflow-x: auto; overflow-x: auto;
overflow-y: auto; overflow-y: hidden;
height: 100%; height: 100%;
} }
@@ -3085,3 +3085,7 @@ settings-pane {
padding-left: @SmallSpace; padding-left: @SmallSpace;
} }
} }
.hiddenMain {
visibility: hidden;
height: 0px;
}

View File

@@ -3,6 +3,7 @@
.resourceTree { .resourceTree {
height: 100%; height: 100%;
width: 20%;
flex: 0 0 auto; flex: 0 0 auto;
.main { .main {
height: 100%; height: 100%;

31615
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
"@azure/ms-rest-nodeauth": "3.0.7", "@azure/ms-rest-nodeauth": "3.0.7",
"@babel/plugin-proposal-class-properties": "7.12.1", "@babel/plugin-proposal-class-properties": "7.12.1",
"@babel/plugin-proposal-decorators": "7.12.12", "@babel/plugin-proposal-decorators": "7.12.12",
"@fluentui/react": "8.14.3",
"@jupyterlab/services": "6.0.2", "@jupyterlab/services": "6.0.2",
"@jupyterlab/terminal": "3.0.3", "@jupyterlab/terminal": "3.0.3",
"@microsoft/applicationinsights-web": "2.6.1", "@microsoft/applicationinsights-web": "2.6.1",
@@ -42,8 +43,6 @@
"@testing-library/jest-dom": "5.11.9", "@testing-library/jest-dom": "5.11.9",
"@types/mkdirp": "1.0.1", "@types/mkdirp": "1.0.1",
"@types/node-fetch": "2.5.7", "@types/node-fetch": "2.5.7",
"@uifabric/react-cards": "0.109.110",
"@uifabric/styling": "7.13.7",
"applicationinsights": "1.8.0", "applicationinsights": "1.8.0",
"bootstrap": "3.4.1", "bootstrap": "3.4.1",
"canvas": "file:./canvas", "canvas": "file:./canvas",
@@ -57,6 +56,7 @@
"datatables.net-dt": "1.10.19", "datatables.net-dt": "1.10.19",
"date-fns": "1.29.0", "date-fns": "1.29.0",
"dayjs": "1.8.19", "dayjs": "1.8.19",
"dom-to-image": "2.6.0",
"dotenv": "8.2.0", "dotenv": "8.2.0",
"eslint-plugin-jest": "23.13.2", "eslint-plugin-jest": "23.13.2",
"eslint-plugin-react": "7.20.0", "eslint-plugin-react": "7.20.0",
@@ -76,7 +76,6 @@
"monaco-editor": "0.18.1", "monaco-editor": "0.18.1",
"ms": "2.1.3", "ms": "2.1.3",
"msal": "1.4.4", "msal": "1.4.4",
"office-ui-fabric-react": "7.164.2",
"p-retry": "4.2.0", "p-retry": "4.2.0",
"plotly.js-cartesian-dist-min": "1.52.3", "plotly.js-cartesian-dist-min": "1.52.3",
"post-robot": "10.0.42", "post-robot": "10.0.42",
@@ -99,7 +98,8 @@
"swr": "0.4.0", "swr": "0.4.0",
"terser-webpack-plugin": "3.1.0", "terser-webpack-plugin": "3.1.0",
"underscore": "1.9.1", "underscore": "1.9.1",
"utility-types": "3.10.0" "utility-types": "3.10.0",
"zustand": "3.5.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.9.0", "@babel/core": "7.9.0",
@@ -111,6 +111,7 @@
"@types/codemirror": "0.0.56", "@types/codemirror": "0.0.56",
"@types/crossroads": "0.0.30", "@types/crossroads": "0.0.30",
"@types/d3": "5.9.2", "@types/d3": "5.9.2",
"@types/dom-to-image": "2.6.2",
"@types/enzyme": "3.10.7", "@types/enzyme": "3.10.7",
"@types/enzyme-adapter-react-16": "1.0.6", "@types/enzyme-adapter-react-16": "1.0.6",
"@types/hasher": "0.0.31", "@types/hasher": "0.0.31",
@@ -128,8 +129,8 @@
"@types/sinon": "2.3.3", "@types/sinon": "2.3.3",
"@types/styled-components": "5.1.1", "@types/styled-components": "5.1.1",
"@types/underscore": "1.7.36", "@types/underscore": "1.7.36",
"@typescript-eslint/eslint-plugin": "4.0.1", "@typescript-eslint/eslint-plugin": "4.22.0",
"@typescript-eslint/parser": "4.0.1", "@typescript-eslint/parser": "4.22.0",
"babel-jest": "24.9.0", "babel-jest": "24.9.0",
"babel-loader": "8.1.0", "babel-loader": "8.1.0",
"buffer": "5.1.0", "buffer": "5.1.0",
@@ -141,6 +142,7 @@
"enzyme-to-json": "3.6.1", "enzyme-to-json": "3.6.1",
"eslint": "7.8.1", "eslint": "7.8.1",
"eslint-cli": "1.1.1", "eslint-cli": "1.1.1",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-no-null": "1.0.2", "eslint-plugin-no-null": "1.0.2",
"eslint-plugin-prefer-arrow": "1.2.2", "eslint-plugin-prefer-arrow": "1.2.2",
"eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-react-hooks": "4.2.0",
@@ -191,11 +193,11 @@
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress", "pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
"copyToConsumers": "node copyToConsumers", "copyToConsumers": "node copyToConsumers",
"test": "rimraf coverage && jest", "test": "rimraf coverage && jest",
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles", "test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
"watch": "npm run start", "watch": "npm run start",
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/", "wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
"build:ase": "gulp build:ase", "build:ase": "gulp build:ase",
"compile": "tsc -p ./tsconfig.build.json", "compile": "tsc",
"compile:contracts": "tsc -p ./tsconfig.contracts.json", "compile:contracts": "tsc -p ./tsconfig.contracts.json",
"compile:strict": "tsc -p ./tsconfig.strict.json", "compile:strict": "tsc -p ./tsconfig.strict.json",
"format": "prettier --write \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"", "format": "prettier --write \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
@@ -204,7 +206,7 @@
"build:contracts": "npm run compile:contracts", "build:contracts": "npm run compile:contracts",
"strict:find": "node ./strict-null-checks/find.js", "strict:find": "node ./strict-null-checks/find.js",
"strict:add": "node ./strict-null-checks/auto-add.js", "strict:add": "node ./strict-null-checks/auto-add.js",
"compile:fullStrict": "tsc", "compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts" "generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
}, },
"repository": { "repository": {

View File

@@ -0,0 +1,15 @@
.schema-analyzer-cell-outputs {
padding: 10px 2px;
}
// Mimic FluentUI8's DocumentCard style
.schema-analyzer-cell-output {
margin-bottom: 20px;
padding: 14px 20px;
border: 1px solid rgb(237, 235, 233);
}
.schema-analyzer-cell-output:hover {
border-color: rgb(200, 198, 196);
box-shadow: inset 0 0 0 1px rgb(200, 198, 196)
}

View File

@@ -9,15 +9,22 @@ import postRobot from "post-robot";
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work
import { SnapshotRequest } from "../Explorer/Notebook/NotebookComponent/types";
import "../Explorer/Notebook/NotebookRenderer/base.css"; import "../Explorer/Notebook/NotebookRenderer/base.css";
import "../Explorer/Notebook/NotebookRenderer/default.css"; import "../Explorer/Notebook/NotebookRenderer/default.css";
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
import "./CellOutputViewer.less";
import { TransformMedia } from "./TransformMedia"; import { TransformMedia } from "./TransformMedia";
export interface SnapshotResponse {
imageSrc: string;
requestId: string;
}
export interface CellOutputViewerProps { export interface CellOutputViewerProps {
id: string; id: string;
contentRef: ContentRef; contentRef: ContentRef;
hidden: boolean; outputsContainerClassName: string;
expanded: boolean; outputClassName: string;
outputs: OnDiskOutput[]; outputs: OnDiskOutput[];
onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void; onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void;
} }
@@ -34,27 +41,26 @@ const onInit = async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const props = (event as any).data as CellOutputViewerProps; const props = (event as any).data as CellOutputViewerProps;
const outputs = ( const outputs = (
<div <div data-iframe-height className={props.outputsContainerClassName}>
data-iframe-height
className={`nteract-cell-outputs ${props.hidden ? "hidden" : ""} ${props.expanded ? "expanded" : ""}`}
>
{props.outputs?.map((output, index) => ( {props.outputs?.map((output, index) => (
<Output output={createImmutableOutput(output)} key={index}> <div className={props.outputClassName} key={index}>
<TransformMedia <Output output={createImmutableOutput(output)} key={index}>
output_type={"display_data"} <TransformMedia
id={props.id} output_type={"display_data"}
contentRef={props.contentRef} id={props.id}
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)} contentRef={props.contentRef}
/> onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
<TransformMedia />
output_type={"execute_result"} <TransformMedia
id={props.id} output_type={"execute_result"}
contentRef={props.contentRef} id={props.id}
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)} contentRef={props.contentRef}
/> onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
<KernelOutputError /> />
<StreamText /> <KernelOutputError />
</Output> <StreamText />
</Output>
</div>
))} ))}
</div> </div>
); );
@@ -62,6 +68,36 @@ const onInit = async () => {
ReactDOM.render(outputs, document.getElementById("cellOutput")); ReactDOM.render(outputs, document.getElementById("cellOutput"));
} }
); );
postRobot.on(
"snapshotRequest",
{
window: window.parent,
domain: window.location.origin,
},
async (event): Promise<SnapshotResponse> => {
const topNode = document.getElementById("cellOutput");
if (!topNode) {
const errorMsg = "No top node to snapshot";
return Promise.reject(new Error(errorMsg));
}
// Typescript definition for event is wrong. So read props by casting to <any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const snapshotRequest = (event as any).data as SnapshotRequest;
const result = await NotebookUtil.takeScreenshotDomToImage(
topNode,
snapshotRequest.aspectRatio,
undefined,
snapshotRequest.downloadFilename
);
return {
imageSrc: result.imageSrc,
requestId: snapshotRequest.requestId,
};
}
);
}; };
// Entry point // Entry point

View File

@@ -0,0 +1,41 @@
import React, { FunctionComponent } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
export interface CollapsedResourceTreeProps {
toggleLeftPaneExpanded: () => void;
isLeftPaneExpanded: boolean;
}
export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps> = ({
toggleLeftPaneExpanded,
isLeftPaneExpanded,
}: CollapsedResourceTreeProps): JSX.Element => {
return (
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
<div className="main-nav nav">
<ul className="nav">
<li className="resourceTreeCollapse" id="collapseToggleLeftPaneButton" aria-label="Expand Tree">
<span
className="leftarrowCollapsed"
onClick={toggleLeftPaneExpanded}
role="button"
tabIndex={0}
onKeyDown={toggleLeftPaneExpanded}
>
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
</span>
<span
className="collectionCollapsed"
onClick={toggleLeftPaneExpanded}
role="button"
tabIndex={0}
onKeyDown={toggleLeftPaneExpanded}
>
<span data-bind="text: collectionTitle" />
</span>
</li>
</ul>
</div>
</div>
);
};

View File

@@ -65,28 +65,18 @@ export class ClientDefaults {
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000; public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
} }
export class AccountKind { export enum AccountKind {
public static DocumentDB: string = "DocumentDB"; DocumentDB = "DocumentDB",
public static MongoDB: string = "MongoDB"; MongoDB = "MongoDB",
public static Parse: string = "Parse"; Parse = "Parse",
public static GlobalDocumentDB: string = "GlobalDocumentDB"; GlobalDocumentDB = "GlobalDocumentDB",
public static Default: string = AccountKind.DocumentDB; Default = "DocumentDB",
} }
export class CorrelationBackend { export class CorrelationBackend {
public static Url: string = "https://aka.ms/cosmosdbanalytics"; public static Url: string = "https://aka.ms/cosmosdbanalytics";
} }
export class DefaultAccountExperience {
public static DocumentDB: string = "DocumentDB";
public static Graph: string = "Graph";
public static MongoDB: string = "MongoDB";
public static ApiForMongoDB: string = "Azure Cosmos DB for MongoDB API";
public static Table: string = "Table";
public static Cassandra: string = "Cassandra";
public static Default: string = DefaultAccountExperience.DocumentDB;
}
export class CapabilityNames { export class CapabilityNames {
public static EnableTable: string = "EnableTable"; public static EnableTable: string = "EnableTable";
public static EnableGremlin: string = "EnableGremlin"; public static EnableGremlin: string = "EnableGremlin";
@@ -104,6 +94,7 @@ export class Flights {
public static readonly MongoIndexEditor = "mongoindexeditor"; public static readonly MongoIndexEditor = "mongoindexeditor";
public static readonly MongoIndexing = "mongoindexing"; public static readonly MongoIndexing = "mongoindexing";
public static readonly AutoscaleTest = "autoscaletest"; public static readonly AutoscaleTest = "autoscaletest";
public static readonly SchemaAnalyzer = "schemaanalyzer";
} }
export class AfecFeatures { export class AfecFeatures {

View File

@@ -1,5 +1,5 @@
import { ResourceType } from "@azure/cosmos/dist-esm/common/constants"; import { ResourceType } from "@azure/cosmos/dist-esm/common/constants";
import { configContext, Platform, updateConfigContext, resetConfigContext } from "../ConfigContext"; import { Platform, resetConfigContext, updateConfigContext } from "../ConfigContext";
import { updateUserContext } from "../UserContext"; import { updateUserContext } from "../UserContext";
import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient"; import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient";
@@ -91,7 +91,6 @@ describe("endpoint", () => {
location: "foo", location: "foo",
type: "foo", type: "foo",
kind: "foo", kind: "foo",
tags: [],
properties: { properties: {
documentEndpoint: "bar", documentEndpoint: "bar",
gremlinEndpoint: "foo", gremlinEndpoint: "foo",

View File

@@ -43,12 +43,7 @@ export const endpoint = () => {
const location = _global.parent ? _global.parent.location : _global.location; const location = _global.parent ? _global.parent.location : _global.location;
return configContext.EMULATOR_ENDPOINT || location.origin; return configContext.EMULATOR_ENDPOINT || location.origin;
} }
return ( return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
userContext.endpoint ||
(userContext.databaseAccount &&
userContext.databaseAccount.properties &&
userContext.databaseAccount.properties.documentEndpoint)
);
}; };
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> { export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {

View File

@@ -1,4 +1,4 @@
import { DatePicker, TextField } from "office-ui-fabric-react"; import { DatePicker, TextField } from "@fluentui/react";
import React, { FunctionComponent } from "react"; import React, { FunctionComponent } from "react";
export interface TableEntityProps { export interface TableEntityProps {
@@ -40,7 +40,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
<TextField <TextField
label={entityValueLabel && entityValueLabel} label={entityValueLabel && entityValueLabel}
id="entityTimeId" id="entityTimeId"
autoFocus
type="time" type="time"
value={entityTimeValue} value={entityTimeValue}
onChange={onEntityTimeValueChange} onChange={onEntityTimeValueChange}
@@ -55,7 +54,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
label={entityValueLabel && entityValueLabel} label={entityValueLabel && entityValueLabel}
className="addEntityTextField" className="addEntityTextField"
id="entityValueId" id="entityValueId"
autoFocus
disabled={isEntityValueDisable} disabled={isEntityValueDisable}
type={entityValueType} type={entityValueType}
placeholder={entityValuePlaceholder} placeholder={entityValuePlaceholder}

View File

@@ -61,7 +61,7 @@ export function queryDocuments(
query: string, query: string,
continuationToken?: string continuationToken?: string
): Promise<QueryResponse> { ): Promise<QueryResponse> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const params = { const params = {
db: databaseId, db: databaseId,
@@ -121,7 +121,7 @@ export function readDocument(
collection: Collection, collection: Collection,
documentId: DocumentId documentId: DocumentId
): Promise<DataModels.DocumentId> { ): Promise<DataModels.DocumentId> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const idComponents = documentId.self.split("/"); const idComponents = documentId.self.split("/");
const path = idComponents.slice(0, 4).join("/"); const path = idComponents.slice(0, 4).join("/");
@@ -167,7 +167,7 @@ export function createDocument(
partitionKeyProperty: string, partitionKeyProperty: string,
documentContent: unknown documentContent: unknown
): Promise<DataModels.DocumentId> { ): Promise<DataModels.DocumentId> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const params = { const params = {
db: databaseId, db: databaseId,
@@ -206,7 +206,7 @@ export function updateDocument(
documentId: DocumentId, documentId: DocumentId,
documentContent: string documentContent: string
): Promise<DataModels.DocumentId> { ): Promise<DataModels.DocumentId> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const idComponents = documentId.self.split("/"); const idComponents = documentId.self.split("/");
const path = idComponents.slice(0, 5).join("/"); const path = idComponents.slice(0, 5).join("/");
@@ -247,7 +247,7 @@ export function updateDocument(
} }
export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> { export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const idComponents = documentId.self.split("/"); const idComponents = documentId.self.split("/");
const path = idComponents.slice(0, 5).join("/"); const path = idComponents.slice(0, 5).join("/");
@@ -289,7 +289,7 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
export function createMongoCollectionWithProxy( export function createMongoCollectionWithProxy(
params: DataModels.CreateCollectionParams params: DataModels.CreateCollectionParams
): Promise<DataModels.Collection> { ): Promise<DataModels.Collection> {
const databaseAccount = userContext.databaseAccount; const { databaseAccount } = userContext;
const shardKey: string = params.partitionKey?.paths[0]; const shardKey: string = params.partitionKey?.paths[0];
const mongoParams: DataModels.MongoParameters = { const mongoParams: DataModels.MongoParameters = {
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint, resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,

View File

@@ -1,8 +1,8 @@
import { configContext, Platform } from "../ConfigContext";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { userContext } from "../UserContext"; import { userContext } from "../UserContext";
import { configContext, Platform } from "../ConfigContext"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
const notificationsPath = () => { const notificationsPath = () => {
switch (configContext.platform) { switch (configContext.platform) {
@@ -20,9 +20,7 @@ export const fetchPortalNotifications = async (): Promise<DataModels.Notificatio
return []; return [];
} }
const databaseAccount = userContext.databaseAccount; const { databaseAccount, resourceGroup, subscriptionId } = userContext;
const subscriptionId = userContext.subscriptionId;
const resourceGroup = userContext.resourceGroup;
const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${ const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${
databaseAccount.name databaseAccount.name
}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`; }&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;

View File

@@ -182,11 +182,8 @@ export class QueriesClient {
} }
public getResourceId(): string { public getResourceId(): string {
const databaseAccount = userContext.databaseAccount; const { databaseAccount, subscriptionId = "", resourceGroup = "" } = userContext;
const databaseAccountName = (databaseAccount && databaseAccount.name) || ""; const databaseAccountName = databaseAccount?.name || "";
const subscriptionId = userContext.subscriptionId || "";
const resourceGroup = userContext.resourceGroup || "";
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`; return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`;
} }

View File

@@ -0,0 +1,60 @@
import React, { FunctionComponent } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
import refreshImg from "../../images/refresh-cosmos.svg";
import { AuthType } from "../AuthType";
import { userContext } from "../UserContext";
export interface ResourceTreeProps {
toggleLeftPaneExpanded: () => void;
isLeftPaneExpanded: boolean;
}
export const ResourceTree: FunctionComponent<ResourceTreeProps> = ({
toggleLeftPaneExpanded,
isLeftPaneExpanded,
}: ResourceTreeProps): JSX.Element => {
return (
<div id="main" className={isLeftPaneExpanded ? "main" : "hiddenMain"}>
{/* Collections Window - - Start */}
<div id="mainslide" className="flexContainer">
{/* Collections Window Title/Command Bar - Start */}
<div className="collectiontitle">
<div className="coltitle">
<span className="titlepadcol" data-bind="text: collectionTitle" />
<div className="float-right">
<span
className="padimgcolrefresh"
data-test="refreshTree"
role="button"
data-bind="click: onRefreshResourcesClick, clickBubble: false, event: { keypress: onRefreshDatabasesKeyPress }"
tabIndex={0}
aria-label="Refresh tree"
title="Refresh tree"
>
<img className="refreshcol" src={refreshImg} alt="Refresh tree" />
</span>
<span
className="padimgcolrefresh1"
id="expandToggleLeftPaneButton"
role="button"
onClick={toggleLeftPaneExpanded}
tabIndex={0}
aria-label="Collapse Tree"
title="Collapse Tree"
onKeyDown={toggleLeftPaneExpanded}
>
<img className="refreshcol1" src={arrowLeftImg} alt="Hide" />
</span>
</div>
</div>
</div>
{userContext.authType === AuthType.ResourceToken ? (
<div style={{ overflowY: "auto" }} data-bind="react:resourceTreeForResourceToken" />
) : (
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
)}
</div>
{/* Collections Window - End */}
</div>
);
};

View File

@@ -8,7 +8,7 @@ import {
Stack, Stack,
TextField, TextField,
TooltipHost, TooltipHost,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import React, { FunctionComponent } from "react"; import React, { FunctionComponent } from "react";
import DeleteIcon from "../../images/delete.svg"; import DeleteIcon from "../../images/delete.svg";
import EditIcon from "../../images/Edit_entity.svg"; import EditIcon from "../../images/Edit_entity.svg";
@@ -96,7 +96,6 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
<TextField <TextField
label={entityPropertyLabel && entityPropertyLabel} label={entityPropertyLabel && entityPropertyLabel}
id="entityPropertyId" id="entityPropertyId"
autoFocus
disabled={isPropertyTypeDisable} disabled={isPropertyTypeDisable}
placeholder={entityPropertyPlaceHolder} placeholder={entityPropertyPlaceHolder}
value={entityProperty} value={entityProperty}

View File

@@ -0,0 +1,16 @@
import { Icon, TooltipHost } from "@fluentui/react";
import * as React from "react";
export interface TooltipProps {
children: string;
}
export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }: TooltipProps) => {
return (
<span>
<TooltipHost content={children}>
<Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" />
</TooltipHost>
</span>
);
};

View File

@@ -1,24 +0,0 @@
import { useId } from "@uifabric/react-hooks";
import { ITooltipHostStyles, TooltipHost } from "office-ui-fabric-react/lib/Tooltip";
import * as React from "react";
import InfoBubble from "../../../images/info-bubble.svg";
const calloutProps = { gapSpace: 0 };
const hostStyles: Partial<ITooltipHostStyles> = { root: { display: "inline-block" } };
export interface TooltipProps {
children: string;
}
export const Tooltip: React.FunctionComponent = ({ children }: TooltipProps) => {
const tooltipId = useId("tooltip");
return children ? (
<span>
<TooltipHost content={children} id={tooltipId} calloutProps={calloutProps} styles={hostStyles}>
<img className="infoImg" src={InfoBubble} alt="More information" />
</TooltipHost>
</span>
) : (
<></>
);
};

View File

@@ -1,8 +1,8 @@
import { Image, Stack, TextField } from "office-ui-fabric-react"; import { Image, Stack, TextField } from "@fluentui/react";
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react"; import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
import FolderIcon from "../../../images/folder_16x16.svg"; import FolderIcon from "../../../images/folder_16x16.svg";
import * as Constants from "../Constants"; import * as Constants from "../Constants";
import { Tooltip } from "../Tooltip/Tooltip"; import { InfoTooltip } from "../Tooltip/InfoTooltip";
interface UploadProps { interface UploadProps {
label: string; label: string;
@@ -47,11 +47,11 @@ export const Upload: FunctionComponent<UploadProps> = ({
props.onUpload(event); props.onUpload(event);
} }
}; };
const title = label + " to upload";
return ( return (
<div> <div>
<span className="renewUploadItemsHeader">{label}</span> <span className="renewUploadItemsHeader">{label}</span>
<Tooltip>{tooltip}</Tooltip> {tooltip && <InfoTooltip>{tooltip}</InfoTooltip>}
<Stack horizontal> <Stack horizontal>
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} /> <TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
<input <input
@@ -67,7 +67,7 @@ export const Upload: FunctionComponent<UploadProps> = ({
role="button" role="button"
/> />
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}> <a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} /> <Image className="fileImportImg" src={FolderIcon} alt={label} title={label} />
</a> </a>
</Stack> </Stack>
</div> </div>

View File

@@ -62,8 +62,8 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
}; };
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => { const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
const defaultExperience = userContext.apiType; const { apiType } = userContext;
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
return createSqlContainer(params); return createSqlContainer(params);
case "Mongo": case "Mongo":
@@ -75,7 +75,7 @@ const createCollectionWithARM = async (params: DataModels.CreateCollectionParams
case "Tables": case "Tables":
return createTable(params); return createTable(params);
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
}; };

View File

@@ -48,8 +48,9 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
} }
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> { async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
const defaultExperience = userContext.apiType; const { apiType } = userContext;
switch (defaultExperience) {
switch (apiType) {
case "SQL": case "SQL":
return createSqlDatabase(params); return createSqlDatabase(params);
case "Mongo": case "Mongo":
@@ -59,7 +60,7 @@ async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): P
case "Gremlin": case "Gremlin":
return createGremlineDatabase(params); return createGremlineDatabase(params);
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} }

View File

@@ -27,12 +27,10 @@ export async function deleteCollection(databaseId: string, collectionId: string)
} }
function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> { function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId); return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
case "Mongo": case "Mongo":
@@ -44,6 +42,6 @@ function deleteCollectionWithARM(databaseId: string, collectionId: string): Prom
case "Tables": case "Tables":
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId); return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} }

View File

@@ -30,12 +30,10 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
} }
function deleteDatabaseWithARM(databaseId: string): Promise<void> { function deleteDatabaseWithARM(databaseId: string): Promise<void> {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId); return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
case "Mongo": case "Mongo":
@@ -45,6 +43,6 @@ function deleteDatabaseWithARM(databaseId: string): Promise<void> {
case "Gremlin": case "Gremlin":
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId); return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} }

View File

@@ -1,8 +1,8 @@
import { AuthType } from "../../AuthType"; import { AuthType } from "../../AuthType";
import { armRequest } from "../../Utils/arm/request";
import { configContext } from "../../ConfigContext"; import { configContext } from "../../ConfigContext";
import { handleError } from "../ErrorHandlingUtils";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { armRequest } from "../../Utils/arm/request";
import { handleError } from "../ErrorHandlingUtils";
interface TimeSeriesData { interface TimeSeriesData {
data: { data: {
@@ -45,9 +45,9 @@ export const getCollectionUsageSizeInKB = async (databaseName: string, container
return undefined; return undefined;
} }
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`; const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`;
const metricNames = "DataUsage,IndexUsage"; const metricNames = "DataUsage,IndexUsage";
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`; const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`;

View File

@@ -28,14 +28,12 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
}; };
const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => { const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
let rpResponse; let rpResponse;
try { try {
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
rpResponse = await getSqlContainerThroughput( rpResponse = await getSqlContainerThroughput(
subscriptionId, subscriptionId,
@@ -76,7 +74,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId); rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
break; break;
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} catch (error) { } catch (error) {
if (error.code !== "NotFound") { if (error.code !== "NotFound") {

View File

@@ -29,12 +29,11 @@ export async function readCollections(databaseId: string): Promise<DataModels.Co
async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> { async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> {
let rpResponse; let rpResponse;
const subscriptionId = userContext.subscriptionId;
const resourceGroup = userContext.resourceGroup;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
switch (defaultExperience) { const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const accountName = databaseAccount.name;
switch (apiType) {
case "SQL": case "SQL":
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId); rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
break; break;
@@ -51,7 +50,7 @@ async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Co
rpResponse = await listTables(subscriptionId, resourceGroup, accountName); rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
break; break;
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection); return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);

View File

@@ -27,14 +27,12 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
}; };
const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => { const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
let rpResponse; let rpResponse;
try { try {
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId); rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
break; break;
@@ -48,7 +46,7 @@ const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId); rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
break; break;
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} catch (error) { } catch (error) {
if (error.code !== "NotFound") { if (error.code !== "NotFound") {

View File

@@ -29,12 +29,10 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
async function readDatabasesWithARM(): Promise<DataModels.Database[]> { async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
let rpResponse; let rpResponse;
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName); rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
break; break;
@@ -48,7 +46,7 @@ async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName); rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
break; break;
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database); return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);

View File

@@ -1,9 +1,9 @@
import { AuthType } from "../../AuthType";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources"; import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types"; import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types";
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
import { handleError } from "../ErrorHandlingUtils"; import { handleError } from "../ErrorHandlingUtils";
import { AuthType } from "../../AuthType";
export async function readMongoDBCollectionThroughRP( export async function readMongoDBCollectionThroughRP(
databaseId: string, databaseId: string,
@@ -13,9 +13,9 @@ export async function readMongoDBCollectionThroughRP(
return undefined; return undefined;
} }
let collection: MongoDBCollectionResource; let collection: MongoDBCollectionResource;
const subscriptionId = userContext.subscriptionId;
const resourceGroup = userContext.resourceGroup; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const accountName = userContext.databaseAccount.name; const accountName = databaseAccount.name;
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`); const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
try { try {

View File

@@ -11,12 +11,13 @@ export async function readUserDefinedFunctions(
collectionId: string collectionId: string
): Promise<(UserDefinedFunctionDefinition & Resource)[]> { ): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const rpResponse = await listSqlUserDefinedFunctions( const rpResponse = await listSqlUserDefinedFunctions(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId collectionId
); );

View File

@@ -63,12 +63,10 @@ async function updateCollectionWithARM(
collectionId: string, collectionId: string,
newCollection: Partial<Collection> newCollection: Partial<Collection>
): Promise<Collection> { ): Promise<Collection> {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
const defaultExperience = userContext.apiType;
switch (defaultExperience) { switch (apiType) {
case "SQL": case "SQL":
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection); return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
case "Cassandra": case "Cassandra":
@@ -87,7 +85,7 @@ async function updateCollectionWithARM(
newCollection newCollection
); );
default: default:
throw new Error(`Unsupported default experience type: ${defaultExperience}`); throw new Error(`Unsupported default experience type: ${apiType}`);
} }
} }

View File

@@ -144,9 +144,8 @@ const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Of
}; };
const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void> => { const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateSqlContainerToAutoscale( await migrateSqlContainerToAutoscale(
@@ -178,9 +177,8 @@ const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void>
}; };
const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<void> => { const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateMongoDBCollectionToAutoscale( await migrateMongoDBCollectionToAutoscale(
@@ -212,9 +210,8 @@ const updateMongoCollectionOffer = async (params: UpdateOfferParams): Promise<vo
}; };
const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<void> => { const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateCassandraTableToAutoscale( await migrateCassandraTableToAutoscale(
@@ -246,9 +243,8 @@ const updateCassandraTableOffer = async (params: UpdateOfferParams): Promise<voi
}; };
const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void> => { const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateGremlinGraphToAutoscale( await migrateGremlinGraphToAutoscale(
@@ -280,9 +276,8 @@ const updateGremlinGraphOffer = async (params: UpdateOfferParams): Promise<void>
}; };
const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => { const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateTableToAutoscale(subscriptionId, resourceGroup, accountName, params.collectionId); await migrateTableToAutoscale(subscriptionId, resourceGroup, accountName, params.collectionId);
@@ -295,9 +290,8 @@ const updateTableOffer = async (params: UpdateOfferParams): Promise<void> => {
}; };
const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => { const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateSqlDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId); await migrateSqlDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
@@ -310,9 +304,8 @@ const updateSqlDatabaseOffer = async (params: UpdateOfferParams): Promise<void>
}; };
const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => { const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateMongoDBDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId); await migrateMongoDBDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
@@ -325,9 +318,8 @@ const updateMongoDatabaseOffer = async (params: UpdateOfferParams): Promise<void
}; };
const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<void> => { const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateCassandraKeyspaceToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId); await migrateCassandraKeyspaceToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);
@@ -340,9 +332,8 @@ const updateCassandraKeyspaceOffer = async (params: UpdateOfferParams): Promise<
}; };
const updateGremlinDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => { const updateGremlinDatabaseOffer = async (params: UpdateOfferParams): Promise<void> => {
const subscriptionId = userContext.subscriptionId; const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const resourceGroup = userContext.resourceGroup; const accountName = databaseAccount.name;
const accountName = userContext.databaseAccount.name;
if (params.migrateToAutoPilot) { if (params.migrateToAutoPilot) {
await migrateGremlinDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId); await migrateGremlinDatabaseToAutoscale(subscriptionId, resourceGroup, accountName, params.databaseId);

View File

@@ -20,11 +20,13 @@ export async function updateStoredProcedure(
): Promise<StoredProcedureDefinition & Resource> { ): Promise<StoredProcedureDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`); const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlStoredProcedure( const getResponse = await getSqlStoredProcedure(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
storedProcedure.id storedProcedure.id
@@ -38,9 +40,9 @@ export async function updateStoredProcedure(
}, },
}; };
const rpResponse = await createUpdateSqlStoredProcedure( const rpResponse = await createUpdateSqlStoredProcedure(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
storedProcedure.id, storedProcedure.id,

View File

@@ -16,12 +16,13 @@ export async function updateTrigger(
trigger: TriggerDefinition trigger: TriggerDefinition
): Promise<TriggerDefinition> { ): Promise<TriggerDefinition> {
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`); const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlTrigger( const getResponse = await getSqlTrigger(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
trigger.id trigger.id
@@ -35,9 +36,9 @@ export async function updateTrigger(
}, },
}; };
const rpResponse = await createUpdateSqlTrigger( const rpResponse = await createUpdateSqlTrigger(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
trigger.id, trigger.id,

View File

@@ -19,12 +19,13 @@ export async function updateUserDefinedFunction(
userDefinedFunction: UserDefinedFunctionDefinition userDefinedFunction: UserDefinedFunctionDefinition
): Promise<UserDefinedFunctionDefinition & Resource> { ): Promise<UserDefinedFunctionDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`); const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlUserDefinedFunction( const getResponse = await getSqlUserDefinedFunction(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
userDefinedFunction.id userDefinedFunction.id
@@ -38,9 +39,9 @@ export async function updateUserDefinedFunction(
}, },
}; };
const rpResponse = await createUpdateSqlUserDefinedFunction( const rpResponse = await createUpdateSqlUserDefinedFunction(
userContext.subscriptionId, subscriptionId,
userContext.resourceGroup, resourceGroup,
userContext.databaseAccount.name, databaseAccount.name,
databaseId, databaseId,
collectionId, collectionId,
userDefinedFunction.id, userDefinedFunction.id,

View File

@@ -4,7 +4,6 @@ export interface DatabaseAccount {
location: string; location: string;
type: string; type: string;
kind: string; kind: string;
tags: any;
properties: DatabaseAccountExtendedProperties; properties: DatabaseAccountExtendedProperties;
} }

View File

@@ -206,17 +206,14 @@ export enum NeighborType {
BOTH, BOTH,
} }
/** export interface IGraphConfigUiData {
* Set of observable related to graph configuration by user showNeighborType: NeighborType;
*/ nodeProperties: string[];
export interface GraphConfigUiData { nodePropertiesWithNone: string[];
showNeighborType: ko.Observable<NeighborType>; nodeCaptionChoice: string;
nodeProperties: ko.ObservableArray<string>; nodeColorKeyChoice: string;
nodePropertiesWithNone: ko.ObservableArray<string>; nodeIconChoice: string;
nodeCaptionChoice: ko.Observable<string>; nodeIconSet: string;
nodeColorKeyChoice: ko.Observable<string>;
nodeIconChoice: ko.Observable<string>;
nodeIconSet: ko.Observable<string>;
} }
/** /**

View File

@@ -4,30 +4,10 @@ import * as ko from "knockout";
import "./ComponentRegisterer"; import "./ComponentRegisterer";
describe("Component Registerer", () => { describe("Component Registerer", () => {
it("should register input-typeahead component", () => {
expect(ko.components.isRegistered("input-typeahead")).toBe(true);
});
it("should register error-display component", () => {
expect(ko.components.isRegistered("error-display")).toBe(true);
});
it("should register graph-style component", () => {
expect(ko.components.isRegistered("graph-style")).toBe(true);
});
it("should register json-editor component", () => { it("should register json-editor component", () => {
expect(ko.components.isRegistered("json-editor")).toBe(true); expect(ko.components.isRegistered("json-editor")).toBe(true);
}); });
it("should registeradd-collection-pane component", () => {
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
});
it("should register graph-styling-pane component", () => {
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
});
it("should register dynamic-list component", () => { it("should register dynamic-list component", () => {
expect(ko.components.isRegistered("dynamic-list")).toBe(true); expect(ko.components.isRegistered("dynamic-list")).toBe(true);
}); });

View File

@@ -2,16 +2,10 @@ import * as ko from "knockout";
import { DiffEditorComponent } from "./Controls/DiffEditor/DiffEditorComponent"; import { DiffEditorComponent } from "./Controls/DiffEditor/DiffEditorComponent";
import { DynamicListComponent } from "./Controls/DynamicList/DynamicListComponent"; import { DynamicListComponent } from "./Controls/DynamicList/DynamicListComponent";
import { EditorComponent } from "./Controls/Editor/EditorComponent"; import { EditorComponent } from "./Controls/Editor/EditorComponent";
import { ErrorDisplayComponent } from "./Controls/ErrorDisplayComponent/ErrorDisplayComponent";
import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahead";
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent"; import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3"; import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
import * as PaneComponents from "./Panes/PaneComponents"; import * as PaneComponents from "./Panes/PaneComponents";
ko.components.register("input-typeahead", new InputTypeaheadComponent());
ko.components.register("error-display", new ErrorDisplayComponent());
ko.components.register("graph-style", GraphStyleComponent);
ko.components.register("editor", new EditorComponent()); ko.components.register("editor", new EditorComponent());
ko.components.register("json-editor", new JsonEditorComponent()); ko.components.register("json-editor", new JsonEditorComponent());
ko.components.register("diff-editor", new DiffEditorComponent()); ko.components.register("diff-editor", new DiffEditorComponent());
@@ -19,10 +13,6 @@ ko.components.register("dynamic-list", DynamicListComponent);
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3); ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
// Panes // Panes
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent()); ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent()); ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());

View File

@@ -1,9 +1,8 @@
import { DefaultButton, IButtonStyles, IContextualMenuItem, IContextualMenuProps } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { ArcadiaWorkspace, SparkPool } from "../../../Contracts/DataModels";
import { DefaultButton, IButtonStyles } from "office-ui-fabric-react/lib/Button";
import { IContextualMenuItem, IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
import * as Logger from "../../../Common/Logger";
import { getErrorMessage } from "../../../Common/ErrorHandlingUtils"; import { getErrorMessage } from "../../../Common/ErrorHandlingUtils";
import * as Logger from "../../../Common/Logger";
import { ArcadiaWorkspace, SparkPool } from "../../../Contracts/DataModels";
export interface ArcadiaMenuPickerProps { export interface ArcadiaMenuPickerProps {
selectText?: string; selectText?: string;

View File

@@ -1,4 +1,4 @@
import { Icon, Label, Stack } from "office-ui-fabric-react"; import { Icon, Label, Stack } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { accordionStackTokens } from "../Settings/SettingsRenderUtils"; import { accordionStackTokens } from "../Settings/SettingsRenderUtils";

View File

@@ -1,14 +1,20 @@
import { import {
ChoiceGroup, ChoiceGroup,
DefaultButton,
Dialog as FluentDialog,
DialogFooter,
DialogType,
FontIcon, FontIcon,
IButtonProps,
IChoiceGroupProps, IChoiceGroupProps,
IDialogProps,
IProgressIndicatorProps, IProgressIndicatorProps,
ITextFieldProps,
Link,
PrimaryButton,
ProgressIndicator, ProgressIndicator,
} from "office-ui-fabric-react"; TextField,
import { DefaultButton, IButtonProps, PrimaryButton } from "office-ui-fabric-react/lib/Button"; } from "@fluentui/react";
import { Dialog as FluentDialog, DialogFooter, DialogType, IDialogProps } from "office-ui-fabric-react/lib/Dialog";
import { Link } from "office-ui-fabric-react/lib/Link";
import { ITextFieldProps, TextField } from "office-ui-fabric-react/lib/TextField";
import React, { FunctionComponent } from "react"; import React, { FunctionComponent } from "react";
export interface TextFieldProps extends ITextFieldProps { export interface TextFieldProps extends ITextFieldProps {
@@ -97,7 +103,7 @@ export const Dialog: FunctionComponent<DialogProps> = ({
text: secondaryButtonText, text: secondaryButtonText,
onClick: onSecondaryButtonClick, onClick: onSecondaryButtonClick,
} }
: undefined; : {};
return ( return (
<FluentDialog {...dialogProps}> <FluentDialog {...dialogProps}>

View File

@@ -2,9 +2,9 @@
* React component for Switch Directory * React component for Switch Directory
*/ */
import _ from "underscore"; import { Dropdown, IDropdownOption, IDropdownProps } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { Dropdown, IDropdownOption, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown"; import _ from "underscore";
import { Tenant } from "../../../Contracts/DataModels"; import { Tenant } from "../../../Contracts/DataModels";
export interface DefaultDirectoryDropdownProps { export interface DefaultDirectoryDropdownProps {

View File

@@ -1,11 +1,15 @@
import _ from "underscore"; import {
DefaultButton,
IButtonProps,
ITextFieldProps,
List,
ScrollablePane,
Sticky,
StickyPositionType,
TextField,
} from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import _ from "underscore";
import { DefaultButton, IButtonProps } from "office-ui-fabric-react/lib/Button";
import { List } from "office-ui-fabric-react/lib/List";
import { ScrollablePane } from "office-ui-fabric-react/lib/ScrollablePane";
import { Sticky, StickyPositionType } from "office-ui-fabric-react/lib/Sticky";
import { TextField, ITextFieldProps } from "office-ui-fabric-react/lib/TextField";
import { Tenant } from "../../../Contracts/DataModels"; import { Tenant } from "../../../Contracts/DataModels";
export interface DirectoryListProps { export interface DirectoryListProps {

View File

@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`test render renders with directories and default 1`] = ` exports[`test render renders with directories and default 1`] = `
<StyledWithResponsiveMode <Dropdown
className="defaultDirectoryDropdown" className="defaultDirectoryDropdown"
defaultSelectedKey="asdfghjklzxcvbnm9876543210" defaultSelectedKey="asdfghjklzxcvbnm9876543210"
label="Set your default directory" label="Set your default directory"
@@ -26,7 +26,7 @@ exports[`test render renders with directories and default 1`] = `
`; `;
exports[`test render renders with directories and last visit default 1`] = ` exports[`test render renders with directories and last visit default 1`] = `
<StyledWithResponsiveMode <Dropdown
className="defaultDirectoryDropdown" className="defaultDirectoryDropdown"
defaultSelectedKey="lastVisited" defaultSelectedKey="lastVisited"
label="Set your default directory" label="Set your default directory"
@@ -51,7 +51,7 @@ exports[`test render renders with directories and last visit default 1`] = `
`; `;
exports[`test render renders with directories but no default 1`] = ` exports[`test render renders with directories but no default 1`] = `
<StyledWithResponsiveMode <Dropdown
className="defaultDirectoryDropdown" className="defaultDirectoryDropdown"
defaultSelectedKey="lastVisited" defaultSelectedKey="lastVisited"
label="Set your default directory" label="Set your default directory"
@@ -76,7 +76,7 @@ exports[`test render renders with directories but no default 1`] = `
`; `;
exports[`test render renders with no directories 1`] = ` exports[`test render renders with no directories 1`] = `
<StyledWithResponsiveMode <Dropdown
className="defaultDirectoryDropdown" className="defaultDirectoryDropdown"
defaultSelectedKey="lastVisited" defaultSelectedKey="lastVisited"
label="Set your default directory" label="Set your default directory"

View File

@@ -350,11 +350,11 @@ exports[`test render renders with filters 1`] = `
} }
> >
<div <div
className="ms-ScrollablePane root-40" className="ms-ScrollablePane root-53"
data-is-scrollable="true" data-is-scrollable="true"
> >
<div <div
className="stickyAbove-42" className="stickyAbove-55"
style={ style={
Object { Object {
"height": 0, "height": 0,
@@ -365,7 +365,7 @@ exports[`test render renders with filters 1`] = `
} }
/> />
<div <div
className="ms-ScrollablePane--contentContainer contentContainer-41" className="ms-ScrollablePane--contentContainer contentContainer-54"
data-is-scrollable={true} data-is-scrollable={true}
> >
<Sticky <Sticky
@@ -408,7 +408,6 @@ exports[`test render renders with filters 1`] = `
> >
<TextFieldBase <TextFieldBase
ariaLabel="Directory filter text box" ariaLabel="Directory filter text box"
canRevealPassword={false}
className="directoryListFilterTextBox" className="directoryListFilterTextBox"
deferredValidationTime={200} deferredValidationTime={200}
onChange={[Function]} onChange={[Function]}
@@ -691,18 +690,18 @@ exports[`test render renders with filters 1`] = `
validateOnLoad={true} validateOnLoad={true}
> >
<div <div
className="ms-TextField directoryListFilterTextBox root-46" className="ms-TextField directoryListFilterTextBox root-59"
> >
<div <div
className="ms-TextField-wrapper" className="ms-TextField-wrapper"
> >
<div <div
className="ms-TextField-fieldGroup fieldGroup-47" className="ms-TextField-fieldGroup fieldGroup-60"
> >
<input <input
aria-invalid={false} aria-invalid={false}
aria-label="Directory filter text box" aria-label="Directory filter text box"
className="ms-TextField-field field-48" className="ms-TextField-field field-61"
id="TextField0" id="TextField0"
onBlur={[Function]} onBlur={[Function]}
onChange={[Function]} onChange={[Function]}
@@ -1266,7 +1265,6 @@ exports[`test render renders with filters 1`] = `
"borderColor": "#f3f2f1", "borderColor": "#f3f2f1",
"color": "#a19f9d", "color": "#a19f9d",
"cursor": "default", "cursor": "default",
"pointerEvents": "none",
"selectors": Object { "selectors": Object {
":focus": Object { ":focus": Object {
"outline": 0, "outline": 0,
@@ -1611,6 +1609,35 @@ exports[`test render renders with filters 1`] = `
}, },
}, },
}, },
"splitButtonMenuFocused": Object {
"outline": "transparent",
"position": "relative",
"selectors": Object {
".ms-Fabric--isFocusVisible &:focus:after": Object {
"border": "1px solid #ffffff",
"bottom": 3,
"content": "\\"\\"",
"left": 3,
"outline": "1px solid #605e5c",
"position": "absolute",
"right": 3,
"selectors": Object {
"@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object {
"border": "none",
"bottom": -2,
"left": -2,
"right": -2,
"top": -2,
},
},
"top": 3,
"zIndex": 1,
},
"::-moz-focus-inner": Object {
"border": "0",
},
},
},
"splitButtonMenuIcon": Object { "splitButtonMenuIcon": Object {
"color": "#323130", "color": "#323130",
}, },
@@ -1900,7 +1927,7 @@ exports[`test render renders with filters 1`] = `
> >
<button <button
aria-disabled={true} aria-disabled={true}
className="ms-Button ms-Button--default is-disabled directoryListButton root-57" className="ms-Button ms-Button--default is-disabled directoryListButton root-70"
data-is-focusable={false} data-is-focusable={false}
disabled={true} disabled={true}
onClick={[Function]} onClick={[Function]}
@@ -1912,7 +1939,7 @@ exports[`test render renders with filters 1`] = `
type="button" type="button"
> >
<span <span
className="ms-Button-flexContainer flexContainer-58" className="ms-Button-flexContainer flexContainer-71"
data-automationid="splitbuttonprimary" data-automationid="splitbuttonprimary"
> >
<div <div
@@ -1932,7 +1959,7 @@ exports[`test render renders with filters 1`] = `
</div> </div>
</span> </span>
</button> </button>
<Component /> <FocusRects />
</BaseButton> </BaseButton>
</DefaultButton> </DefaultButton>
</CustomizedDefaultButton> </CustomizedDefaultButton>
@@ -1943,7 +1970,7 @@ exports[`test render renders with filters 1`] = `
</List> </List>
</div> </div>
<div <div
className="stickyBelow-43" className="stickyBelow-56"
style={ style={
Object { Object {
"bottom": "0px", "bottom": "0px",
@@ -1954,7 +1981,7 @@ exports[`test render renders with filters 1`] = `
} }
> >
<div <div
className="stickyBelowItems-44" className="stickyBelowItems-57"
/> />
</div> </div>
</div> </div>

View File

@@ -32,6 +32,9 @@
.errorLink { .errorLink {
cursor: pointer; cursor: pointer;
} }
.errorLinkColor {
color: @AccentMediumHigh;
}
} }
.paneErrorIcon { .paneErrorIcon {

View File

@@ -1,27 +0,0 @@
import template from "./error-display-component.html";
/**
* Helper class for ko component registration
* This component displays an error as designed in:
* https://microsoft.sharepoint.com/teams/DPX/Modern/DocDB/_layouts/15/WopiFrame.aspx?sourcedoc={66864d4a-f925-4cbe-9eb4-79f8d191a115}&action=edit&wd=target%28DocumentDB%20emulator%2Eone%7CE617D0A7-F77C-4968-B75A-1451049F4FEA%2FError%20notification%7CAA1E4BC9-4D72-472C-B40C-2437FA217226%2F%29
* TODO: support "More details"
*/
export class ErrorDisplayComponent {
constructor() {
return {
viewModel: ErrorDisplayViewModel,
template,
};
}
}
/**
* Parameters for this component
*/
interface ErrorDisplayParams {
errorMsg: ko.Observable<string>; // Primary message
}
class ErrorDisplayViewModel {
public constructor(public params: ErrorDisplayParams) {}
}

View File

@@ -1,6 +0,0 @@
<div class="warningErrorContainer" data-bind="visible: !!params.errorMsg()">
<div class="warningErrorContent">
<span><img src="/error_red.svg" alt="Error" /></span>
<span class="settingErrorMsg warningErrorDetailsLinkContainer" data-bind="text: params.errorMsg()"></span>
</div>
</div>

View File

@@ -1,9 +1,14 @@
import {
Checkbox,
DefaultButton,
Dropdown,
IDropdownOption,
IDropdownStyles,
ITextFieldStyles,
Stack,
TextField,
} from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { Stack } from "office-ui-fabric-react/lib/Stack";
import { Dropdown, IDropdownOption, IDropdownStyles } from "office-ui-fabric-react/lib/Dropdown";
import { Checkbox } from "office-ui-fabric-react/lib/Checkbox";
import { TextField, ITextFieldStyles } from "office-ui-fabric-react/lib/TextField";
import { DefaultButton } from "office-ui-fabric-react";
import "./FeaturePanelComponent.less"; import "./FeaturePanelComponent.less";
export const FeaturePanelComponent: React.FunctionComponent = () => { export const FeaturePanelComponent: React.FunctionComponent = () => {

View File

@@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { FeaturePanelComponent } from "./FeaturePanelComponent"; import { FeaturePanelComponent } from "./FeaturePanelComponent";
import { getTheme, mergeStyleSets, FontWeights, Modal, IconButton, IIconProps } from "office-ui-fabric-react"; import { getTheme, mergeStyleSets, FontWeights, Modal, IconButton, IIconProps } from "@fluentui/react";
import "./FeaturePanelLauncher.less"; import "./FeaturePanelLauncher.less";
// Modal wrapper // Modal wrapper

View File

@@ -57,7 +57,7 @@ exports[`Feature panel renders all flags 1`] = `
} }
} }
> >
<StyledWithResponsiveMode <Dropdown
label="Base Url" label="Base Url"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -85,7 +85,7 @@ exports[`Feature panel renders all flags 1`] = `
} }
} }
/> />
<StyledWithResponsiveMode <Dropdown
label="Platform" label="Platform"
onChange={[Function]} onChange={[Function]}
options={ options={

View File

@@ -1,4 +1,4 @@
import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "office-ui-fabric-react"; import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import * as Constants from "../../../Common/Constants"; import * as Constants from "../../../Common/Constants";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants"; import { Action } from "../../../Shared/Telemetry/TelemetryConstants";

View File

@@ -1,10 +1,4 @@
import { import { ChoiceGroup, IButtonProps, IChoiceGroupProps, PrimaryButton, IChoiceGroupOption } from "@fluentui/react";
ChoiceGroup,
IButtonProps,
IChoiceGroupProps,
PrimaryButton,
IChoiceGroupOption,
} from "office-ui-fabric-react";
import * as React from "react"; import * as React from "react";
import { ChildrenMargin } from "./GitHubStyleConstants"; import { ChildrenMargin } from "./GitHubStyleConstants";

View File

@@ -1,4 +1,4 @@
import { DefaultButton, IButtonProps, Link, PrimaryButton } from "office-ui-fabric-react"; import { DefaultButton, IButtonProps, Link, PrimaryButton } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { IGitHubBranch, IGitHubRepo } from "../../../GitHub/GitHubClient"; import { IGitHubBranch, IGitHubRepo } from "../../../GitHub/GitHubClient";
import { AddRepoComponent, AddRepoComponentProps } from "./AddRepoComponent"; import { AddRepoComponent, AddRepoComponentProps } from "./AddRepoComponent";
@@ -23,8 +23,6 @@ export interface RepoListItem {
} }
export class GitHubReposComponent extends React.Component<GitHubReposComponentProps> { export class GitHubReposComponent extends React.Component<GitHubReposComponentProps> {
public static readonly ConnectToGitHubTitle = "Connect to GitHub";
public static readonly ManageGitHubRepoTitle = "Manage GitHub settings";
private static readonly ManageGitHubRepoDescription = private static readonly ManageGitHubRepoDescription =
"Select your GitHub repos and branch(es) to pin to your notebooks workspace."; "Select your GitHub repos and branch(es) to pin to your notebooks workspace.";
private static readonly ManageGitHubRepoResetConnection = "View or change your GitHub authorization settings."; private static readonly ManageGitHubRepoResetConnection = "View or change your GitHub authorization settings.";
@@ -32,14 +30,6 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
private static readonly CancelButtonText = "Cancel"; private static readonly CancelButtonText = "Cancel";
public render(): JSX.Element { public render(): JSX.Element {
const header: JSX.Element = (
<p>
{this.props.showAuthorizeAccess
? GitHubReposComponent.ConnectToGitHubTitle
: GitHubReposComponent.ManageGitHubRepoTitle}
</p>
);
const content: JSX.Element = this.props.showAuthorizeAccess ? ( const content: JSX.Element = this.props.showAuthorizeAccess ? (
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} /> <AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
) : ( ) : (
@@ -66,9 +56,6 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
return ( return (
<> <>
<div className={"firstdivbg headerline"} role="heading" aria-level={2}>
{header}
</div>
<div className={"paneMainContent"}>{content}</div> <div className={"paneMainContent"}>{content}</div>
{!this.props.showAuthorizeAccess && ( {!this.props.showAuthorizeAccess && (
<> <>

View File

@@ -1,19 +1,21 @@
import { import {
IStyleFunctionOrObject,
ICheckboxStyleProps, ICheckboxStyleProps,
ICheckboxStyles, ICheckboxStyles,
IDropdownStyles,
IDropdownStyleProps, IDropdownStyleProps,
} from "office-ui-fabric-react"; IDropdownStyles,
IStyleFunctionOrObject,
} from "@fluentui/react";
export const ButtonsFooterStyle: React.CSSProperties = { export const ButtonsFooterStyle: React.CSSProperties = {
padding: 14, paddingTop: 14,
height: "auto", height: "auto",
borderTop: "2px solid lightGray",
}; };
export const ContentFooterStyle: React.CSSProperties = { export const ContentFooterStyle: React.CSSProperties = {
padding: "10px 24px 10px 24px", paddingTop: "10px",
height: "auto", height: "auto",
borderTop: "2px solid lightGray",
}; };
export const ChildrenMargin = 10; export const ChildrenMargin = 10;
@@ -53,6 +55,11 @@ export const BranchesDropdownOptionContainerStyle: React.CSSProperties = {
padding: 8, padding: 8,
}; };
export const ContentMainStyle: React.CSSProperties = {
display: "flex",
flexDirection: "column",
};
export const ReposListRepoColumnMinWidth = 192; export const ReposListRepoColumnMinWidth = 192;
export const ReposListBranchesColumnWidth = 116; export const ReposListBranchesColumnWidth = 116;
export const BranchesDropdownWidth = 200; export const BranchesDropdownWidth = 200;

View File

@@ -16,7 +16,7 @@ import {
ResponsiveMode, ResponsiveMode,
SelectionMode, SelectionMode,
Text, Text,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { IGitHubBranch, IGitHubPageInfo } from "../../../GitHub/GitHubClient"; import { IGitHubBranch, IGitHubPageInfo } from "../../../GitHub/GitHubClient";
import * as GitHubUtils from "../../../Utils/GitHubUtils"; import * as GitHubUtils from "../../../Utils/GitHubUtils";

View File

@@ -1,5 +1,5 @@
import { CommandButton, FontIcon, FontWeights, ITextProps, Separator, Stack, Text } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { Stack, Text, Separator, FontIcon, CommandButton, FontWeights, ITextProps } from "office-ui-fabric-react";
export class GalleryHeaderComponent extends React.Component { export class GalleryHeaderComponent extends React.Component {
private static readonly azureText = "Microsoft Azure"; private static readonly azureText = "Microsoft Azure";
@@ -61,7 +61,7 @@ export class GalleryHeaderComponent extends React.Component {
<Stack.Item> <Stack.Item>
{this.renderHeaderItem( {this.renderHeaderItem(
GalleryHeaderComponent.galleryText, GalleryHeaderComponent.galleryText,
undefined, () => "",
GalleryHeaderComponent.headerItemTextProps GalleryHeaderComponent.headerItemTextProps
)} )}
</Stack.Item> </Stack.Item>

View File

@@ -1,186 +0,0 @@
/**
* How to use this component:
*
* In your html markup, use:
* <input-typeahead params="{
choices:choices,
selection:selection,
inputValue:inputValue,
placeholder:'Enter source',
typeaheadOverrideOptions:typeaheadOverrideOptions
}"></input-typeahead>
* The parameters are documented below.
*
* Notes:
* - dynamic:true by default, this allows choices to change after initialization.
* To turn it off, use:
* typeaheadOverrideOptions: { dynamic:false }
*
*/
import "jquery-typeahead";
import template from "./input-typeahead.html";
/**
* Helper class for ko component registration
*/
export class InputTypeaheadComponent {
constructor() {
return {
viewModel: InputTypeaheadViewModel,
template,
};
}
}
export interface Item {
caption: string;
value: any;
}
/**
* Parameters for this component
*/
interface InputTypeaheadParams {
/**
* List of choices available in the dropdown.
*/
choices: ko.ObservableArray<Item>;
/**
* Gets updated when user clicks on the choice in the dropdown
*/
selection?: ko.Observable<Item>;
/**
* The current string value of <input>
*/
inputValue?: ko.Observable<string>;
/**
* Define what text you want as the input placeholder
*/
placeholder: string;
/**
* Override default jquery-typeahead options
* WARNING: do not override input, source or callback to avoid breaking the components behavior.
*/
typeaheadOverrideOptions?: any;
/**
* This function gets called when pressing ENTER on the input box
*/
submitFct?: (inputValue: string | null, selection: Item | null) => void;
/**
* Typehead comes with a Search button that we normally remove.
* If you want to use it, turn this on
*/
showSearchButton?: boolean;
}
interface OnClickItem {
matchedKey: string;
value: any;
caption: string;
group: string;
}
interface Cache {
inputValue: string | null;
selection: Item | null;
}
class InputTypeaheadViewModel {
private static instanceCount = 0; // Generate unique id for each component's typeahead instance
private instanceNumber: number;
private params: InputTypeaheadParams;
private cache: Cache;
public constructor(params: InputTypeaheadParams) {
this.instanceNumber = InputTypeaheadViewModel.instanceCount++;
this.params = params;
this.params.choices.subscribe(this.initializeTypeahead.bind(this));
this.cache = {
inputValue: null,
selection: null,
};
}
/**
* Must execute once ko is rendered, so that it can find the input element by id
*/
private initializeTypeahead() {
let params = this.params;
let cache = this.cache;
let options: any = {
input: `#${this.getComponentId()}`, //'.input-typeahead',
order: "asc",
minLength: 0,
searchOnFocus: true,
source: {
display: "caption",
data: () => {
return this.params.choices();
},
},
callback: {
onClick: (_node: unknown, _a: unknown, item: OnClickItem) => {
cache.selection = item;
if (params.selection) {
params.selection(item);
}
},
onResult(_node: unknown, query: any) {
cache.inputValue = query;
if (params.inputValue) {
params.inputValue(query);
}
},
},
template: (_query: string, item: any) => {
// Don't display id if caption *IS* the id
return item.caption === item.value
? "<span>{{caption}}</span>"
: "<span><div>{{caption}}</div><div><small>{{value}}</small></div></span>";
},
dynamic: true,
};
// Override options
if (params.typeaheadOverrideOptions) {
for (let p in params.typeaheadOverrideOptions) {
options[p] = params.typeaheadOverrideOptions[p];
}
}
($ as any).typeahead(options);
}
/**
* Get this component id
* @return unique id per instance
*/
private getComponentId(): string {
return `input-typeahead${this.instanceNumber}`;
}
/**
* Executed once ko is done rendering bindings
* Use ko's "template: afterRender" callback to do that without actually using any template.
* Another way is to call it within setTimeout() in constructor.
*/
public afterRender(): void {
this.initializeTypeahead();
}
public submit(): void {
if (this.params.submitFct) {
this.params.submitFct(this.cache.inputValue, this.cache.selection);
}
}
}

View File

@@ -1,19 +0,0 @@
<span class="input-typeahead-container">
<form class="input-typehead" data-bind="submit:submit">
<div class="typeahead__container">
<div class="typeahead__field">
<span class="typeahead__query">
<input
name="q"
type="search"
autocomplete="off"
data-bind="attr: { placeholder: params.placeholder, id:getComponentId() }, value:params.inputValue, template: { afterRender:afterRender() }"
/>
</span>
<span class="typeahead__button" data-bind="visible:params.showSearchButton">
<button type="submit"><span class="typeahead__search-icon"></span></button>
</span>
</div>
</div>
</form>
</span>

View File

@@ -13,7 +13,6 @@ const createTestDatabaseAccount = (): DataModels.DatabaseAccount => {
gremlinEndpoint: null, gremlinEndpoint: null,
tableEndpoint: null, tableEndpoint: null,
}, },
tags: "testTags",
type: "testType", type: "testType",
}; };
}; };
@@ -30,7 +29,6 @@ const createTestMongo32DatabaseAccount = (): DataModels.DatabaseAccount => {
gremlinEndpoint: null, gremlinEndpoint: null,
tableEndpoint: null, tableEndpoint: null,
}, },
tags: "testTags",
type: "testType", type: "testType",
}; };
}; };
@@ -48,7 +46,6 @@ const createTestMongo36DatabaseAccount = (): DataModels.DatabaseAccount => {
tableEndpoint: null, tableEndpoint: null,
mongoEndpoint: "https://testMongoEndpoint.azure.com/", mongoEndpoint: "https://testMongoEndpoint.azure.com/",
}, },
tags: "testTags",
type: "testType", type: "testType",
}; };
}; };
@@ -65,7 +62,6 @@ const createTestCassandraDatabaseAccount = (): DataModels.DatabaseAccount => {
gremlinEndpoint: null, gremlinEndpoint: null,
tableEndpoint: null, tableEndpoint: null,
}, },
tags: "testTags",
type: "testType", type: "testType",
}; };
}; };

View File

@@ -1,21 +1,23 @@
import { Card } from "@uifabric/react-cards";
import { import {
BaseButton, BaseButton,
Button, Button,
FontWeights, DocumentCard,
DocumentCardActivity,
DocumentCardDetails,
DocumentCardPreview,
DocumentCardTitle,
Icon, Icon,
IconButton, IconButton,
Image, IDocumentCardPreviewProps,
IDocumentCardStyles,
ImageFit, ImageFit,
Link, Link,
LinkBase,
Persona,
Separator, Separator,
Spinner, Spinner,
SpinnerSize, SpinnerSize,
Text, Text,
TooltipHost, TooltipHost,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import React, { FunctionComponent, useState } from "react"; import React, { FunctionComponent, useState } from "react";
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg"; import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
import { IGalleryItem } from "../../../../Juno/JunoClient"; import { IGalleryItem } from "../../../../Juno/JunoClient";
@@ -49,7 +51,6 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
const CARD_WIDTH = 256; const CARD_WIDTH = 256;
const cardImageHeight = 144; const cardImageHeight = 144;
const cardDescriptionMaxChars = 80; const cardDescriptionMaxChars = 80;
const cardItemGapBig = 10;
const cardItemGapSmall = 8; const cardItemGapSmall = 8;
const cardDeleteSpinnerHeight = 360; const cardDeleteSpinnerHeight = 360;
const smallTextLineHeight = 18; const smallTextLineHeight = 18;
@@ -65,9 +66,9 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
const dateString = new Date(data.created).toLocaleString("default", options); const dateString = new Date(data.created).toLocaleString("default", options);
const cardTitle = FileSystemUtil.stripExtension(data.name, "ipynb"); const cardTitle = FileSystemUtil.stripExtension(data.name, "ipynb");
const renderTruncatedDescription = (): string => { const renderTruncated = (text: string, totalLength: number): string => {
let truncatedDescription = data.description.substr(0, cardDescriptionMaxChars); let truncatedDescription = text.substr(0, totalLength);
if (data.description.length > cardDescriptionMaxChars) { if (text.length > totalLength) {
truncatedDescription = `${truncatedDescription} ...`; truncatedDescription = `${truncatedDescription} ...`;
} }
return truncatedDescription; return truncatedDescription;
@@ -110,7 +111,7 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
const handlerOnClick = ( const handlerOnClick = (
event: event:
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent> | React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | MouseEvent>
| React.MouseEvent< | React.MouseEvent<
HTMLAnchorElement | HTMLButtonElement | HTMLDivElement | BaseButton | Button | HTMLSpanElement, HTMLAnchorElement | HTMLButtonElement | HTMLDivElement | BaseButton | Button | HTMLSpanElement,
MouseEvent MouseEvent
@@ -121,42 +122,35 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
event.preventDefault(); event.preventDefault();
activate(); activate();
}; };
const DocumentCardActivityPeople = [{ name: data.author, profileImageSrc: data.isSample && CosmosDBLogo }];
const previewProps: IDocumentCardPreviewProps = {
previewImages: [
{
previewImageSrc: data.thumbnailUrl,
imageFit: ImageFit.cover,
width: CARD_WIDTH,
height: cardImageHeight,
},
],
};
const cardStyles: IDocumentCardStyles = {
root: { display: "inline-block", marginRight: 20, width: CARD_WIDTH },
};
return ( return (
<Card <DocumentCard aria-label={cardTitle} styles={cardStyles} onClick={onClick}>
style={{ background: "white" }}
aria-label={cardTitle}
data-is-focusable="true"
tokens={{ width: CARD_WIDTH, childrenGap: 0 }}
onClick={(event) => handlerOnClick(event, onClick)}
>
{isDeletingPublishedNotebook && ( {isDeletingPublishedNotebook && (
<Card.Item tokens={{ padding: cardItemGapBig }}> <Spinner
<Spinner size={SpinnerSize.large}
size={SpinnerSize.large} label={`Deleting '${cardTitle}'`}
label={`Deleting '${cardTitle}'`} styles={{ root: { height: cardDeleteSpinnerHeight } }}
styles={{ root: { height: cardDeleteSpinnerHeight } }} />
/>
</Card.Item>
)} )}
{!isDeletingPublishedNotebook && ( {!isDeletingPublishedNotebook && (
<> <>
<Card.Item tokens={{ padding: cardItemGapBig }}> <DocumentCardActivity activity={dateString} people={DocumentCardActivityPeople} />
<Persona imageUrl={data.isSample && CosmosDBLogo} text={data.author} secondaryText={dateString} /> <DocumentCardPreview {...previewProps} />
</Card.Item> <DocumentCardDetails>
<Text variant="small" nowrap styles={{ root: { height: smallTextLineHeight, padding: "2px 16px" } }}>
<Card.Item>
<Image
src={data.thumbnailUrl}
width={CARD_WIDTH}
height={cardImageHeight}
imageFit={ImageFit.cover}
alt={`${cardTitle} cover image`}
/>
</Card.Item>
<Card.Section styles={{ root: { padding: cardItemGapBig } }}>
<Text variant="small" nowrap styles={{ root: { height: smallTextLineHeight } }}>
{data.tags ? ( {data.tags ? (
data.tags.map((tag, index, array) => ( data.tags.map((tag, index, array) => (
<span key={tag}> <span key={tag}>
@@ -168,43 +162,22 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
<br /> <br />
)} )}
</Text> </Text>
<DocumentCardTitle title={renderTruncated(cardTitle, 20)} shouldTruncate />
<Text <DocumentCardTitle
styles={{ title={renderTruncated(data.description, cardDescriptionMaxChars)}
root: { showAsSecondaryTitle
fontWeight: FontWeights.semibold, />
paddingTop: cardItemGapSmall, <span style={{ padding: "8px 16px" }}>
paddingBottom: cardItemGapSmall,
},
}}
nowrap
>
{cardTitle}
</Text>
<Text variant="small" styles={{ root: { height: smallTextLineHeight * 2 } }}>
{renderTruncatedDescription()}
</Text>
<span>
{data.views !== undefined && generateIconText("RedEye", data.views.toString())} {data.views !== undefined && generateIconText("RedEye", data.views.toString())}
{data.downloads !== undefined && generateIconText("Download", data.downloads.toString())} {data.downloads !== undefined && generateIconText("Download", data.downloads.toString())}
{data.favorites !== undefined && generateIconText("Heart", data.favorites.toString())} {data.favorites !== undefined && generateIconText("Heart", data.favorites.toString())}
</span> </span>
</Card.Section> </DocumentCardDetails>
{cardButtonsVisible && ( {cardButtonsVisible && (
<Card.Section <DocumentCardDetails>
styles={{
root: {
marginLeft: cardItemGapBig,
marginRight: cardItemGapBig,
},
}}
>
<Separator styles={{ root: { padding: 0, height: 1 } }} /> <Separator styles={{ root: { padding: 0, height: 1 } }} />
<span> <span style={{ padding: "0px 16px" }}>
{isFavorite !== undefined && {isFavorite !== undefined &&
generateIconButtonWithTooltip( generateIconButtonWithTooltip(
isFavorite ? "HeartFill" : "Heart", isFavorite ? "HeartFill" : "Heart",
@@ -223,10 +196,10 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
) )
)} )}
</span> </span>
</Card.Section> </DocumentCardDetails>
)} )}
</> </>
)} )}
</Card> </DocumentCard>
); );
}; };

View File

@@ -1,59 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`GalleryCardComponent renders 1`] = ` exports[`GalleryCardComponent renders 1`] = `
<Card <StyledDocumentCardBase
aria-label="name" aria-label="name"
data-is-focusable="true" styles={
onClick={[Function]}
style={
Object { Object {
"background": "white", "root": Object {
} "display": "inline-block",
} "marginRight": 20,
tokens={ "width": 256,
Object { },
"childrenGap": 0,
"width": 256,
} }
} }
> >
<CardItem <StyledDocumentCardActivityBase
tokens={ activity="Invalid Date"
Object { people={
"padding": 10, Array [
} Object {
} "name": "author",
> "profileImageSrc": false,
<StyledPersonaBase
imageUrl={false}
secondaryText="Invalid Date"
text="author"
/>
</CardItem>
<CardItem>
<StyledImageBase
alt="name cover image"
height={144}
imageFit={2}
src="thumbnailUrl"
width={256}
/>
</CardItem>
<CardSection
styles={
Object {
"root": Object {
"padding": 10,
}, },
} ]
} }
> />
<StyledDocumentCardPreviewBase
previewImages={
Array [
Object {
"height": 144,
"imageFit": 2,
"previewImageSrc": "thumbnailUrl",
"width": 256,
},
]
}
/>
<StyledDocumentCardDetailsBase>
<Text <Text
nowrap={true} nowrap={true}
styles={ styles={
Object { Object {
"root": Object { "root": Object {
"height": 18, "height": 18,
"padding": "2px 16px",
}, },
} }
} }
@@ -69,33 +59,21 @@ exports[`GalleryCardComponent renders 1`] = `
</StyledLinkBase> </StyledLinkBase>
</span> </span>
</Text> </Text>
<Text <StyledDocumentCardTitleBase
nowrap={true} shouldTruncate={true}
styles={ title="name"
/>
<StyledDocumentCardTitleBase
showAsSecondaryTitle={true}
title="description"
/>
<span
style={
Object { Object {
"root": Object { "padding": "8px 16px",
"fontWeight": 600,
"paddingBottom": 8,
"paddingTop": 8,
},
} }
} }
> >
name
</Text>
<Text
styles={
Object {
"root": Object {
"height": 36,
},
}
}
variant="small"
>
description
</Text>
<span>
<Text <Text
styles={ styles={
Object { Object {
@@ -169,17 +147,8 @@ exports[`GalleryCardComponent renders 1`] = `
0 0
</Text> </Text>
</span> </span>
</CardSection> </StyledDocumentCardDetailsBase>
<CardSection <StyledDocumentCardDetailsBase>
styles={
Object {
"root": Object {
"marginLeft": 10,
"marginRight": 10,
},
}
}
>
<Separator <Separator
styles={ styles={
Object { Object {
@@ -190,7 +159,13 @@ exports[`GalleryCardComponent renders 1`] = `
} }
} }
/> />
<span> <span
style={
Object {
"padding": "0px 16px",
}
}
>
<StyledTooltipHostBase <StyledTooltipHostBase
calloutProps={ calloutProps={
Object { Object {
@@ -276,6 +251,6 @@ exports[`GalleryCardComponent renders 1`] = `
/> />
</StyledTooltipHostBase> </StyledTooltipHostBase>
</span> </span>
</CardSection> </StyledDocumentCardDetailsBase>
</Card> </StyledDocumentCardBase>
`; `;

View File

@@ -0,0 +1,123 @@
import * as React from "react";
import { JunoClient } from "../../../Juno/JunoClient";
import { HttpStatusCodes, CodeOfConductEndpoints } from "../../../Common/Constants";
import { Stack, Text, Checkbox, PrimaryButton, Link } from "@fluentui/react";
import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils";
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
export interface CodeOfConductComponentProps {
junoClient: JunoClient;
onAcceptCodeOfConduct: (result: boolean) => void;
}
interface CodeOfConductComponentState {
readCodeOfConduct: boolean;
}
export class CodeOfConductComponent extends React.Component<CodeOfConductComponentProps, CodeOfConductComponentState> {
private viewCodeOfConductTraced: boolean;
private descriptionPara1: string;
private descriptionPara2: string;
private descriptionPara3: string;
private link1: { label: string; url: string };
constructor(props: CodeOfConductComponentProps) {
super(props);
this.state = {
readCodeOfConduct: false,
};
this.descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
this.descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
this.descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
this.link1 = { label: "code of conduct.", url: CodeOfConductEndpoints.codeOfConduct };
}
private async acceptCodeOfConduct(): Promise<void> {
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
try {
const response = await this.props.junoClient.acceptCodeOfConduct();
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
}
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
this.props.onAcceptCodeOfConduct(response.data);
} catch (error) {
traceFailure(
Action.NotebooksGalleryAcceptCodeOfConduct,
{
error: getErrorMessage(error),
errorStack: getErrorStack(error),
},
startKey
);
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
}
}
private onChangeCheckbox = (): void => {
this.setState({ readCodeOfConduct: !this.state.readCodeOfConduct });
};
public render(): JSX.Element {
if (!this.viewCodeOfConductTraced) {
this.viewCodeOfConductTraced = true;
trace(Action.NotebooksGalleryViewCodeOfConduct);
}
return (
<Stack tokens={{ childrenGap: 20 }}>
<Stack.Item>
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{this.descriptionPara1}</Text>
</Stack.Item>
<Stack.Item>
<Text>{this.descriptionPara2}</Text>
</Stack.Item>
<Stack.Item>
<Text>
{this.descriptionPara3}
<Link href={this.link1.url} target="_blank">
{this.link1.label}
</Link>
</Text>
</Stack.Item>
<Stack.Item>
<Checkbox
styles={{
label: {
margin: 0,
padding: "2 0 2 0",
},
text: {
fontSize: 12,
},
}}
label="I have read and accept the code of conduct."
onChange={this.onChangeCheckbox}
/>
</Stack.Item>
<Stack.Item>
<PrimaryButton
ariaLabel="Continue"
title="Continue"
onClick={async () => await this.acceptCodeOfConduct()}
tabIndex={0}
className="genericPaneSubmitBtn"
text="Continue"
disabled={!this.state.readCodeOfConduct}
/>
</Stack.Item>
</Stack>
);
}
}

View File

@@ -9,7 +9,7 @@ describe("CodeOfConductComponent", () => {
let codeOfConductProps: CodeOfConductComponentProps; let codeOfConductProps: CodeOfConductComponentProps;
beforeEach(() => { beforeEach(() => {
const junoClient = new JunoClient(undefined); const junoClient = new JunoClient();
junoClient.acceptCodeOfConduct = jest.fn().mockReturnValue({ junoClient.acceptCodeOfConduct = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK, status: HttpStatusCodes.OK,
data: true, data: true,

View File

@@ -1,4 +1,4 @@
import { Checkbox, Link, PrimaryButton, Stack, Text } from "office-ui-fabric-react"; import { Checkbox, Link, PrimaryButton, Stack, Text } from "@fluentui/react";
import React, { FunctionComponent, useEffect, useState } from "react"; import React, { FunctionComponent, useEffect, useState } from "react";
import { CodeOfConductEndpoints, HttpStatusCodes } from "../../../../Common/Constants"; import { CodeOfConductEndpoints, HttpStatusCodes } from "../../../../Common/Constants";
import { getErrorMessage, getErrorStack, handleError } from "../../../../Common/ErrorHandlingUtils"; import { getErrorMessage, getErrorStack, handleError } from "../../../../Common/ErrorHandlingUtils";

View File

@@ -19,7 +19,7 @@ import {
SpinnerSize, SpinnerSize,
Stack, Stack,
Text, Text,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { HttpStatusCodes } from "../../../Common/Constants"; import { HttpStatusCodes } from "../../../Common/Constants";
import { handleError } from "../../../Common/ErrorHandlingUtils"; import { handleError } from "../../../Common/ErrorHandlingUtils";
@@ -34,7 +34,6 @@ import { CodeOfConductComponent } from "./CodeOfConductComponent";
import "./GalleryViewerComponent.less"; import "./GalleryViewerComponent.less";
import { InfoComponent } from "./InfoComponent/InfoComponent"; import { InfoComponent } from "./InfoComponent/InfoComponent";
const CARD_WIDTH = 256;
export interface GalleryViewerComponentProps { export interface GalleryViewerComponentProps {
container?: Explorer; container?: Explorer;
junoClient: JunoClient; junoClient: JunoClient;
@@ -87,7 +86,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
public static readonly PublishedTitle = "My published work"; public static readonly PublishedTitle = "My published work";
private static readonly rowsPerPage = 5; private static readonly rowsPerPage = 5;
private static readonly CARD_WIDTH = 256;
private static readonly mostViewedText = "Most viewed"; private static readonly mostViewedText = "Most viewed";
private static readonly mostDownloadedText = "Most downloaded"; private static readonly mostDownloadedText = "Most downloaded";
private static readonly mostFavoritedText = "Most favorited"; private static readonly mostFavoritedText = "Most favorited";
@@ -644,7 +643,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
private getPageSpecification = (itemIndex?: number, visibleRect?: IRectangle): IPageSpecification => { private getPageSpecification = (itemIndex?: number, visibleRect?: IRectangle): IPageSpecification => {
if (itemIndex === 0) { if (itemIndex === 0) {
this.columnCount = Math.floor(visibleRect.width / CARD_WIDTH) || this.columnCount; this.columnCount = Math.floor(visibleRect.width / GalleryViewerComponent.CARD_WIDTH) || this.columnCount;
this.rowCount = GalleryViewerComponent.rowsPerPage; this.rowCount = GalleryViewerComponent.rowsPerPage;
} }
@@ -672,7 +671,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
}; };
return ( return (
<div style={{ float: "left", padding: 10 }}> <div style={{ float: "left", padding: 5 }}>
<GalleryCardComponent {...props} /> <GalleryCardComponent {...props} />
</div> </div>
); );

View File

@@ -1,5 +1,5 @@
import * as React from "react"; import * as React from "react";
import { Icon, Label, Stack, HoverCard, HoverCardType, Link } from "office-ui-fabric-react"; import { Icon, Label, Stack, HoverCard, HoverCardType, Link } from "@fluentui/react";
import { CodeOfConductEndpoints } from "../../../../Common/Constants"; import { CodeOfConductEndpoints } from "../../../../Common/Constants";
import "./InfoComponent.less"; import "./InfoComponent.less";

View File

@@ -4,7 +4,7 @@ exports[`GalleryViewerComponent renders 1`] = `
<div <div
className="galleryContainer" className="galleryContainer"
> >
<StyledPivotBase <StyledPivot
onLinkClick={[Function]} onLinkClick={[Function]}
selectedKey="OfficialSamples" selectedKey="OfficialSamples"
> >
@@ -41,7 +41,7 @@ exports[`GalleryViewerComponent renders 1`] = `
<StackItem <StackItem
grow={true} grow={true}
> >
<StyledSearchBoxBase <StyledSearchBox
onChange={[Function]} onChange={[Function]}
placeholder="Search" placeholder="Search"
/> />
@@ -60,7 +60,7 @@ exports[`GalleryViewerComponent renders 1`] = `
} }
} }
> >
<StyledWithResponsiveMode <Dropdown
onChange={[Function]} onChange={[Function]}
options={ options={
Array [ Array [
@@ -127,7 +127,7 @@ exports[`GalleryViewerComponent renders 1`] = `
<StackItem <StackItem
grow={true} grow={true}
> >
<StyledSearchBoxBase <StyledSearchBox
onChange={[Function]} onChange={[Function]}
placeholder="Search" placeholder="Search"
/> />
@@ -146,7 +146,7 @@ exports[`GalleryViewerComponent renders 1`] = `
} }
} }
> >
<StyledWithResponsiveMode <Dropdown
onChange={[Function]} onChange={[Function]}
options={ options={
Array [ Array [
@@ -182,6 +182,6 @@ exports[`GalleryViewerComponent renders 1`] = `
</StackItem> </StackItem>
</Stack> </Stack>
</PivotItem> </PivotItem>
</StyledPivotBase> </StyledPivot>
</div> </div>
`; `;

View File

@@ -1,17 +1,7 @@
/** /**
* Wrapper around Notebook metadata * Wrapper around Notebook metadata
*/ */
import { import { FontWeights, Icon, IconButton, Link, Persona, PersonaSize, PrimaryButton, Stack, Text } from "@fluentui/react";
FontWeights,
Icon,
IconButton,
Link,
Persona,
PersonaSize,
PrimaryButton,
Stack,
Text,
} from "office-ui-fabric-react";
import * as React from "react"; import * as React from "react";
import { IGalleryItem } from "../../../Juno/JunoClient"; import { IGalleryItem } from "../../../Juno/JunoClient";
import * as FileSystemUtil from "../../Notebook/FileSystemUtil"; import * as FileSystemUtil from "../../Notebook/FileSystemUtil";

View File

@@ -3,7 +3,7 @@
*/ */
import { Notebook } from "@nteract/commutable"; import { Notebook } from "@nteract/commutable";
import { createContentRef } from "@nteract/core"; import { createContentRef } from "@nteract/core";
import { IChoiceGroupProps, Icon, IProgressIndicatorProps, Link, ProgressIndicator } from "office-ui-fabric-react"; import { IChoiceGroupProps, Icon, IProgressIndicatorProps, Link, ProgressIndicator } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { contents } from "rx-jupyter"; import { contents } from "rx-jupyter";
import { IGalleryItem, JunoClient } from "../../../Juno/JunoClient"; import { IGalleryItem, JunoClient } from "../../../Juno/JunoClient";

View File

@@ -1,22 +1,24 @@
import { IButtonProps, IconButton } from "office-ui-fabric-react/lib/Button";
import { ContextualMenu, IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
import { import {
ContextualMenu,
DetailsList, DetailsList,
DetailsListLayoutMode, DetailsListLayoutMode,
DetailsRow, DetailsRow,
FocusZone,
IButtonProps,
IColumn, IColumn,
IconButton,
IContextualMenuProps,
IDetailsListProps, IDetailsListProps,
IDetailsRowProps, IDetailsRowProps,
} from "office-ui-fabric-react/lib/DetailsList";
import { FocusZone } from "office-ui-fabric-react/lib/FocusZone";
import { ITextField, ITextFieldProps, TextField } from "office-ui-fabric-react/lib/TextField";
import {
IObjectWithKey, IObjectWithKey,
ISelectionZoneProps, ISelectionZoneProps,
ITextField,
ITextFieldProps,
Selection, Selection,
SelectionMode, SelectionMode,
SelectionZone, SelectionZone,
} from "office-ui-fabric-react/lib/utilities/selection/index"; TextField,
} from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import * as _ from "underscore"; import * as _ from "underscore";
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png"; import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";

View File

@@ -2,10 +2,10 @@
* Horizontal switch component * Horizontal switch component
*/ */
import { Icon } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import "./RadioSwitchComponent.less";
import { Icon } from "office-ui-fabric-react/lib/Icon";
import { NormalizedEventKey } from "../../../Common/Constants"; import { NormalizedEventKey } from "../../../Common/Constants";
import "./RadioSwitchComponent.less";
export interface Choice { export interface Choice {
key: string; key: string;
@@ -25,6 +25,7 @@ export class RadioSwitchComponent extends React.Component<RadioSwitchComponentPr
<div className="radioSwitchComponent"> <div className="radioSwitchComponent">
{this.props.choices.map((choice: Choice) => ( {this.props.choices.map((choice: Choice) => (
<span <span
role="button"
tabIndex={0} tabIndex={0}
key={choice.key} key={choice.key}
onClick={() => this.onSelect(choice)} onClick={() => this.onSelect(choice)}

View File

@@ -154,19 +154,20 @@ describe("SettingsComponent", () => {
expect(settingsComponentInstance.hasConflictResolution()).toEqual(undefined); expect(settingsComponentInstance.hasConflictResolution()).toEqual(undefined);
const newContainer = new Explorer(); const newContainer = new Explorer();
newContainer.databaseAccount = ko.observable({ updateUserContext({
id: undefined, databaseAccount: {
name: undefined, id: undefined,
location: undefined, name: undefined,
type: undefined, location: undefined,
kind: undefined, type: undefined,
tags: undefined, kind: undefined,
properties: { properties: {
documentEndpoint: undefined, documentEndpoint: undefined,
tableEndpoint: undefined, tableEndpoint: undefined,
gremlinEndpoint: undefined, gremlinEndpoint: undefined,
cassandraEndpoint: undefined, cassandraEndpoint: undefined,
enableMultipleWriteLocations: true, enableMultipleWriteLocations: true,
},
}, },
}); });
const newCollection = { ...collection }; const newCollection = { ...collection };

View File

@@ -1,4 +1,4 @@
import { IPivotItemProps, IPivotProps, Pivot, PivotItem } from "office-ui-fabric-react"; import { IPivotItemProps, IPivotProps, Pivot, PivotItem } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import DiscardIcon from "../../../../images/discard.svg"; import DiscardIcon from "../../../../images/discard.svg";
import SaveIcon from "../../../../images/save-cosmos.svg"; import SaveIcon from "../../../../images/save-cosmos.svg";
@@ -233,11 +233,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
} }
public loadMongoIndexes = async (): Promise<void> => { public loadMongoIndexes = async (): Promise<void> => {
if ( if (userContext.apiType === "Mongo" && userContext?.databaseAccount) {
userContext.apiType === "Mongo" &&
this.container.isEnableMongoCapabilityPresent() &&
this.container.databaseAccount()
) {
this.mongoDBCollectionResource = await readMongoDBCollectionThroughRP( this.mongoDBCollectionResource = await readMongoDBCollectionThroughRP(
this.collection.databaseId, this.collection.databaseId,
this.collection.id() this.collection.id()
@@ -300,8 +296,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.container && userContext.apiType === "Cassandra" && hasDatabaseSharedThroughput(this.collection); this.container && userContext.apiType === "Cassandra" && hasDatabaseSharedThroughput(this.collection);
public hasConflictResolution = (): boolean => public hasConflictResolution = (): boolean =>
this.container?.databaseAccount && userContext?.databaseAccount?.properties?.enableMultipleWriteLocations &&
this.container.databaseAccount()?.properties?.enableMultipleWriteLocations &&
this.collection.conflictResolutionPolicy && this.collection.conflictResolutionPolicy &&
!!this.collection.conflictResolutionPolicy(); !!this.collection.conflictResolutionPolicy();
@@ -876,7 +871,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
mongoIndexingPolicyComponentProps: MongoIndexingPolicyComponentProps mongoIndexingPolicyComponentProps: MongoIndexingPolicyComponentProps
): JSX.Element => { ): JSX.Element => {
if (userContext.authType === AuthType.AAD) { if (userContext.authType === AuthType.AAD) {
if (this.container.isEnableMongoCapabilityPresent()) { if (userContext.apiType === "Mongo") {
return <MongoIndexingPolicyComponent {...mongoIndexingPolicyComponentProps} />; return <MongoIndexingPolicyComponent {...mongoIndexingPolicyComponentProps} />;
} }
return undefined; return undefined;

View File

@@ -1,6 +1,6 @@
import { shallow } from "enzyme"; import { shallow } from "enzyme";
import React from "react"; import React from "react";
import { IColumn, Text } from "office-ui-fabric-react"; import { IColumn, Text } from "@fluentui/react";
import { import {
getAutoPilotV3SpendElement, getAutoPilotV3SpendElement,
getEstimatedSpendingElement, getEstimatedSpendingElement,

View File

@@ -38,7 +38,7 @@ import {
IDetailsRowProps, IDetailsRowProps,
DetailsRow, DetailsRow,
IDetailsColumnStyles, IDetailsColumnStyles,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import { isDirtyTypes, isDirty } from "./SettingsUtils"; import { isDirtyTypes, isDirty } from "./SettingsUtils";
export interface EstimatedSpendingDisplayProps { export interface EstimatedSpendingDisplayProps {

View File

@@ -9,7 +9,7 @@ import {
subComponentStackProps, subComponentStackProps,
getChoiceGroupStyles, getChoiceGroupStyles,
} from "../SettingsRenderUtils"; } from "../SettingsRenderUtils";
import { TextField, ITextFieldProps, Stack, IChoiceGroupOption, ChoiceGroup } from "office-ui-fabric-react"; import { TextField, ITextFieldProps, Stack, IChoiceGroupOption, ChoiceGroup } from "@fluentui/react";
import { ToolTipLabelComponent } from "./ToolTipLabelComponent"; import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
import { isDirty } from "../SettingsUtils"; import { isDirty } from "../SettingsUtils";

View File

@@ -1,7 +1,8 @@
import { MessageBar, MessageBarType, Stack } from "office-ui-fabric-react"; import { MessageBar, MessageBarType, Stack } from "@fluentui/react";
import * as monaco from "monaco-editor";
import * as React from "react"; import * as React from "react";
import * as DataModels from "../../../../Contracts/DataModels"; import * as DataModels from "../../../../Contracts/DataModels";
import { loadMonaco, monaco } from "../../../LazyMonaco"; import { loadMonaco } from "../../../LazyMonaco";
import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils"; import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils";
import { isDirty, isIndexTransforming } from "../SettingsUtils"; import { isDirty, isIndexTransforming } from "../SettingsUtils";
import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent"; import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent";
@@ -121,7 +122,7 @@ export class IndexingPolicyComponent extends React.Component<
{isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && ( {isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && (
<MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar> <MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar>
)} )}
<div className="settingsV2IndexingPolicyEditor" tabIndex={0} ref={this.indexingPolicyDiv}></div> <div className="settingsV2IndexingPolicyEditor" role="button" tabIndex={0} ref={this.indexingPolicyDiv}></div>
</Stack> </Stack>
); );
} }

View File

@@ -1,5 +1,5 @@
import * as React from "react"; import * as React from "react";
import { MessageBar, MessageBarType } from "office-ui-fabric-react"; import { MessageBar, MessageBarType } from "@fluentui/react";
import { import {
mongoIndexTransformationRefreshingMessage, mongoIndexTransformationRefreshingMessage,
renderMongoIndexTransformationRefreshMessage, renderMongoIndexTransformationRefreshMessage,

View File

@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`IndexingPolicyRefreshComponent renders 1`] = ` exports[`IndexingPolicyRefreshComponent renders 1`] = `
<StyledMessageBarBase <StyledMessageBar
messageBarType={5} messageBarType={5}
> >
<Text <Text
@@ -20,5 +20,5 @@ exports[`IndexingPolicyRefreshComponent renders 1`] = `
Refresh to check the progress. Refresh to check the progress.
</StyledLinkBase> </StyledLinkBase>
</Text> </Text>
</StyledMessageBarBase> </StyledMessageBar>
`; `;

View File

@@ -8,7 +8,7 @@ import {
Dropdown, Dropdown,
IDropdownOption, IDropdownOption,
ITextField, ITextField,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import { import {
addMongoIndexSubElementsTokens, addMongoIndexSubElementsTokens,
mongoErrorMessageStyles, mongoErrorMessageStyles,

View File

@@ -12,7 +12,7 @@ import {
Spinner, Spinner,
SpinnerSize, SpinnerSize,
Separator, Separator,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import { import {
addMongoIndexStackProps, addMongoIndexStackProps,
customDetailsListStyles, customDetailsListStyles,

View File

@@ -30,7 +30,7 @@ exports[`AddMongoIndexComponent renders 1`] = `
} }
value="sample_key" value="sample_key"
/> />
<StyledWithResponsiveMode <Dropdown
ariaLabel="Index Type 1" ariaLabel="Index Type 1"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -67,7 +67,7 @@ exports[`AddMongoIndexComponent renders 1`] = `
onClick={[Function]} onClick={[Function]}
/> />
</Stack> </Stack>
<StyledMessageBarBase <StyledMessageBar
messageBarType={1} messageBarType={1}
styles={ styles={
Object { Object {
@@ -78,6 +78,6 @@ exports[`AddMongoIndexComponent renders 1`] = `
} }
> >
sample error sample error
</StyledMessageBarBase> </StyledMessageBar>
</Stack> </Stack>
`; `;

View File

@@ -1,14 +1,15 @@
import { shallow } from "enzyme"; import { shallow } from "enzyme";
import ko from "knockout";
import React from "react"; import React from "react";
import { ScaleComponent, ScaleComponentProps } from "./ScaleComponent";
import { container, collection } from "../TestUtils";
import { ThroughputInputAutoPilotV3Component } from "./ThroughputInputComponents/ThroughputInputAutoPilotV3Component";
import Explorer from "../../../Explorer";
import * as Constants from "../../../../Common/Constants"; import * as Constants from "../../../../Common/Constants";
import * as DataModels from "../../../../Contracts/DataModels"; import * as DataModels from "../../../../Contracts/DataModels";
import { throughputUnit } from "../SettingsRenderUtils";
import * as SharedConstants from "../../../../Shared/Constants"; import * as SharedConstants from "../../../../Shared/Constants";
import ko from "knockout"; import { updateUserContext } from "../../../../UserContext";
import Explorer from "../../../Explorer";
import { throughputUnit } from "../SettingsRenderUtils";
import { collection, container } from "../TestUtils";
import { ScaleComponent, ScaleComponentProps } from "./ScaleComponent";
import { ThroughputInputAutoPilotV3Component } from "./ThroughputInputComponents/ThroughputInputAutoPilotV3Component";
describe("ScaleComponent", () => { describe("ScaleComponent", () => {
const nonNationalCloudContainer = new Explorer(); const nonNationalCloudContainer = new Explorer();
@@ -80,25 +81,25 @@ describe("ScaleComponent", () => {
it("autoScale enabled", () => { it("autoScale enabled", () => {
const newContainer = new Explorer(); const newContainer = new Explorer();
updateUserContext({
newContainer.databaseAccount({ databaseAccount: {
id: undefined, id: undefined,
name: undefined, name: undefined,
location: undefined, location: undefined,
type: undefined, type: undefined,
kind: "documentdb", kind: "documentdb",
tags: undefined, properties: {
properties: { documentEndpoint: undefined,
documentEndpoint: undefined, tableEndpoint: undefined,
tableEndpoint: undefined, gremlinEndpoint: undefined,
gremlinEndpoint: undefined, cassandraEndpoint: undefined,
cassandraEndpoint: undefined, capabilities: [
capabilities: [ {
{ name: Constants.CapabilityNames.EnableAutoScale.toLowerCase(),
name: Constants.CapabilityNames.EnableAutoScale.toLowerCase(), description: undefined,
description: undefined, },
}, ],
], },
}, },
}); });
const props = { ...baseProps, container: newContainer }; const props = { ...baseProps, container: newContainer };

View File

@@ -1,4 +1,4 @@
import { Label, Link, MessageBar, MessageBarType, Stack, Text, TextField } from "office-ui-fabric-react"; import { Label, Link, MessageBar, MessageBarType, Stack, Text, TextField } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import * as Constants from "../../../../Common/Constants"; import * as Constants from "../../../../Common/Constants";
import { configContext, Platform } from "../../../../ConfigContext"; import { configContext, Platform } from "../../../../ConfigContext";
@@ -54,8 +54,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
} }
public isAutoScaleEnabled = (): boolean => { public isAutoScaleEnabled = (): boolean => {
const accountCapabilities: DataModels.Capability[] = this.props.container?.databaseAccount()?.properties const accountCapabilities: DataModels.Capability[] = userContext?.databaseAccount?.properties?.capabilities;
?.capabilities;
const enableAutoScaleCapability = const enableAutoScaleCapability =
accountCapabilities && accountCapabilities &&
accountCapabilities.find((capability: DataModels.Capability) => { accountCapabilities.find((capability: DataModels.Capability) => {
@@ -170,7 +169,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
private getThroughputInputComponent = (): JSX.Element => ( private getThroughputInputComponent = (): JSX.Element => (
<ThroughputInputAutoPilotV3Component <ThroughputInputAutoPilotV3Component
databaseAccount={this.props.container.databaseAccount()} databaseAccount={userContext?.databaseAccount}
databaseName={this.databaseId} databaseName={this.databaseId}
collectionName={this.collectionId} collectionName={this.collectionId}
throughput={this.props.throughput} throughput={this.props.throughput}
@@ -199,8 +198,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
); );
private isFreeTierAccount(): boolean { private isFreeTierAccount(): boolean {
const databaseAccount = this.props.container?.databaseAccount(); return userContext?.databaseAccount?.properties?.enableFreeTier;
return databaseAccount?.properties?.enableFreeTier;
} }
private getFreeTierInfoMessage(): JSX.Element { private getFreeTierInfoMessage(): JSX.Element {

View File

@@ -1,13 +1,4 @@
import { import { ChoiceGroup, IChoiceGroupOption, Label, Link, MessageBar, Stack, Text, TextField } from "@fluentui/react";
ChoiceGroup,
IChoiceGroupOption,
Label,
Link,
MessageBar,
Stack,
Text,
TextField,
} from "office-ui-fabric-react";
import * as React from "react"; import * as React from "react";
import * as ViewModels from "../../../../Contracts/ViewModels"; import * as ViewModels from "../../../../Contracts/ViewModels";
import { userContext } from "../../../../UserContext"; import { userContext } from "../../../../UserContext";

View File

@@ -10,7 +10,7 @@ import {
Stack, Stack,
Text, Text,
TextField, TextField,
} from "office-ui-fabric-react"; } from "@fluentui/react";
import React from "react"; import React from "react";
import * as DataModels from "../../../../../Contracts/DataModels"; import * as DataModels from "../../../../../Contracts/DataModels";
import { SubscriptionType } from "../../../../../Contracts/SubscriptionType"; import { SubscriptionType } from "../../../../../Contracts/SubscriptionType";

View File

@@ -8,7 +8,7 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
} }
} }
> >
<StyledMessageBarBase <StyledMessageBar
messageBarIconProps={ messageBarIconProps={
Object { Object {
"className": "messageBarWarningIcon", "className": "messageBarWarningIcon",
@@ -27,7 +27,7 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
> >
Your bill will be affected as you update your throughput settings. Please review the updated cost estimate below before saving your changes Your bill will be affected as you update your throughput settings. Please review the updated cost estimate below before saving your changes
</Text> </Text>
</StyledMessageBarBase> </StyledMessageBar>
<Stack> <Stack>
<StyledLabelBase <StyledLabelBase
id="settingsV2RadioButtonLabelId" id="settingsV2RadioButtonLabelId"
@@ -49,7 +49,7 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledMessageBarBase <StyledMessageBar
messageBarIconProps={ messageBarIconProps={
Object { Object {
"className": "messageBarInfoIcon", "className": "messageBarInfoIcon",
@@ -86,8 +86,8 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
Learn more Learn more
</a> </a>
</Text> </Text>
</StyledMessageBarBase> </StyledMessageBar>
<StyledChoiceGroupBase <StyledChoiceGroup
ariaLabelledBy="settingsV2RadioButtonLabelId" ariaLabelledBy="settingsV2RadioButtonLabelId"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -196,7 +196,7 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
ariaLabelledBy="settingsV2RadioButtonLabelId" ariaLabelledBy="settingsV2RadioButtonLabelId"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -252,7 +252,7 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
> >
capacity calculator capacity calculator
<Component <FontIcon
iconName="NavigateExternalInline" iconName="NavigateExternalInline"
/> />
</StyledLinkBase> </StyledLinkBase>
@@ -470,7 +470,7 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
ariaLabelledBy="settingsV2RadioButtonLabelId" ariaLabelledBy="settingsV2RadioButtonLabelId"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -526,7 +526,7 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
> >
capacity calculator capacity calculator
<Component <FontIcon
iconName="NavigateExternalInline" iconName="NavigateExternalInline"
/> />
</StyledLinkBase> </StyledLinkBase>

View File

@@ -1,5 +1,5 @@
import * as React from "react"; import * as React from "react";
import { Stack, Text, IIconStyles, Icon, TooltipHost, DirectionalHint } from "office-ui-fabric-react"; import { Stack, Text, IIconStyles, Icon, TooltipHost, DirectionalHint } from "@fluentui/react";
import { toolTipLabelStackTokens } from "../SettingsRenderUtils"; import { toolTipLabelStackTokens } from "../SettingsRenderUtils";
export interface ToolTipLabelComponentProps { export interface ToolTipLabelComponentProps {

View File

@@ -8,7 +8,7 @@ exports[`ConflictResolutionComponent Path text field displayed 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
label="Mode" label="Mode"
onChange={[Function]} onChange={[Function]}
options={ options={
@@ -80,7 +80,7 @@ exports[`ConflictResolutionComponent Sproc text field displayed 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
label="Mode" label="Mode"
onChange={[Function]} onChange={[Function]}
options={ options={

View File

@@ -13,6 +13,7 @@ exports[`IndexingPolicyComponent renders 1`] = `
/> />
<div <div
className="settingsV2IndexingPolicyEditor" className="settingsV2IndexingPolicyEditor"
role="button"
tabIndex={0} tabIndex={0}
/> />
</Stack> </Stack>

View File

@@ -8,7 +8,7 @@ exports[`ScaleComponent renders with correct initial notification 1`] = `
} }
} }
> >
<StyledMessageBarBase <StyledMessageBar
messageBarType={5} messageBarType={5}
> >
<Text <Text
@@ -26,7 +26,7 @@ exports[`ScaleComponent renders with correct initial notification 1`] = `
Database: test, Container: test Database: test, Container: test
, Current autoscale throughput: 100 - 1000 RU/s, Target autoscale throughput: 600 - 6000 RU/s , Current autoscale throughput: 100 - 1000 RU/s, Target autoscale throughput: 600 - 6000 RU/s
</Text> </Text>
</StyledMessageBarBase> </StyledMessageBar>
<Stack <Stack
tokens={ tokens={
Object { Object {

View File

@@ -15,7 +15,7 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="timeToLive" id="timeToLive"
label="Time to Live" label="Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -85,7 +85,7 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
value="1000" value="1000"
/> />
</Stack> </Stack>
<StyledChoiceGroupBase <StyledChoiceGroup
id="geoSpatialConfig" id="geoSpatialConfig"
label="Geospatial Configuration" label="Geospatial Configuration"
onChange={[Function]} onChange={[Function]}
@@ -146,7 +146,7 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
aria-labelledby="settingsV2ChangeFeedLabelId" aria-labelledby="settingsV2ChangeFeedLabelId"
id="changeFeedPolicy" id="changeFeedPolicy"
onChange={[Function]} onChange={[Function]}
@@ -238,7 +238,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="timeToLive" id="timeToLive"
label="Time to Live" label="Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -308,7 +308,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
value="1000" value="1000"
/> />
</Stack> </Stack>
<StyledChoiceGroupBase <StyledChoiceGroup
id="geoSpatialConfig" id="geoSpatialConfig"
label="Geospatial Configuration" label="Geospatial Configuration"
onChange={[Function]} onChange={[Function]}
@@ -355,7 +355,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="analyticalStorageTimeToLive" id="analyticalStorageTimeToLive"
label="Analytical Storage Time to Live" label="Analytical Storage Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -422,7 +422,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
aria-labelledby="settingsV2ChangeFeedLabelId" aria-labelledby="settingsV2ChangeFeedLabelId"
id="changeFeedPolicy" id="changeFeedPolicy"
onChange={[Function]} onChange={[Function]}
@@ -514,7 +514,7 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="timeToLive" id="timeToLive"
label="Time to Live" label="Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -584,7 +584,7 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
value="1000" value="1000"
/> />
</Stack> </Stack>
<StyledChoiceGroupBase <StyledChoiceGroup
id="geoSpatialConfig" id="geoSpatialConfig"
label="Geospatial Configuration" label="Geospatial Configuration"
onChange={[Function]} onChange={[Function]}
@@ -631,7 +631,7 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="analyticalStorageTimeToLive" id="analyticalStorageTimeToLive"
label="Analytical Storage Time to Live" label="Analytical Storage Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -753,7 +753,7 @@ exports[`SubSettingsComponent renders 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="timeToLive" id="timeToLive"
label="Time to Live" label="Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -823,7 +823,7 @@ exports[`SubSettingsComponent renders 1`] = `
value="1000" value="1000"
/> />
</Stack> </Stack>
<StyledChoiceGroupBase <StyledChoiceGroup
id="geoSpatialConfig" id="geoSpatialConfig"
label="Geospatial Configuration" label="Geospatial Configuration"
onChange={[Function]} onChange={[Function]}
@@ -870,7 +870,7 @@ exports[`SubSettingsComponent renders 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="analyticalStorageTimeToLive" id="analyticalStorageTimeToLive"
label="Analytical Storage Time to Live" label="Analytical Storage Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -962,7 +962,7 @@ exports[`SubSettingsComponent renders 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
aria-labelledby="settingsV2ChangeFeedLabelId" aria-labelledby="settingsV2ChangeFeedLabelId"
id="changeFeedPolicy" id="changeFeedPolicy"
onChange={[Function]} onChange={[Function]}
@@ -1054,7 +1054,7 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="timeToLive" id="timeToLive"
label="Time to Live" label="Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -1099,7 +1099,7 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
} }
/> />
</Stack> </Stack>
<StyledChoiceGroupBase <StyledChoiceGroup
id="geoSpatialConfig" id="geoSpatialConfig"
label="Geospatial Configuration" label="Geospatial Configuration"
onChange={[Function]} onChange={[Function]}
@@ -1146,7 +1146,7 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
} }
} }
> >
<StyledChoiceGroupBase <StyledChoiceGroup
id="analyticalStorageTimeToLive" id="analyticalStorageTimeToLive"
label="Analytical Storage Time to Live" label="Analytical Storage Time to Live"
onChange={[Function]} onChange={[Function]}
@@ -1238,7 +1238,7 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
} }
/> />
</StyledLabelBase> </StyledLabelBase>
<StyledChoiceGroupBase <StyledChoiceGroup
aria-labelledby="settingsV2ChangeFeedLabelId" aria-labelledby="settingsV2ChangeFeedLabelId"
id="changeFeedPolicy" id="changeFeedPolicy"
onChange={[Function]} onChange={[Function]}

Some files were not shown because too many files have changed in this diff Show More