mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-06 03:00:23 +00:00
Compare commits
4 Commits
jbunster/s
...
languy-upg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d94849c7b | ||
|
|
8285f1fc37 | ||
|
|
ad1d5add96 | ||
|
|
c9be25b1e8 |
@@ -5,6 +5,7 @@ src/Api/Apis.ts
|
|||||||
src/AuthType.ts
|
src/AuthType.ts
|
||||||
src/Bindings/BindingHandlersRegisterer.ts
|
src/Bindings/BindingHandlersRegisterer.ts
|
||||||
src/Bindings/ReactBindingHandler.ts
|
src/Bindings/ReactBindingHandler.ts
|
||||||
|
src/Common/ArrayHashMap.ts
|
||||||
src/Common/Constants.ts
|
src/Common/Constants.ts
|
||||||
src/Common/CosmosClient.test.ts
|
src/Common/CosmosClient.test.ts
|
||||||
src/Common/CosmosClient.ts
|
src/Common/CosmosClient.ts
|
||||||
@@ -12,12 +13,15 @@ src/Common/DataAccessUtilityBase.test.ts
|
|||||||
src/Common/DataAccessUtilityBase.ts
|
src/Common/DataAccessUtilityBase.ts
|
||||||
src/Common/EditableUtility.ts
|
src/Common/EditableUtility.ts
|
||||||
src/Common/HashMap.test.ts
|
src/Common/HashMap.test.ts
|
||||||
|
src/Common/HashMap.ts
|
||||||
src/Common/Logger.test.ts
|
src/Common/Logger.test.ts
|
||||||
src/Common/MessageHandler.test.ts
|
src/Common/MessageHandler.test.ts
|
||||||
src/Common/MessageHandler.ts
|
src/Common/MessageHandler.ts
|
||||||
src/Common/MongoProxyClient.test.ts
|
src/Common/MongoProxyClient.test.ts
|
||||||
src/Common/MongoUtility.ts
|
src/Common/MongoUtility.ts
|
||||||
src/Common/NotificationsClientBase.ts
|
src/Common/NotificationsClientBase.ts
|
||||||
|
src/Common/ObjectCache.test.ts
|
||||||
|
src/Common/ObjectCache.ts
|
||||||
src/Common/QueriesClient.ts
|
src/Common/QueriesClient.ts
|
||||||
src/Common/Splitter.ts
|
src/Common/Splitter.ts
|
||||||
src/Config.ts
|
src/Config.ts
|
||||||
@@ -41,6 +45,7 @@ src/Definitions/jquery.d.ts
|
|||||||
src/Definitions/plotly.js-cartesian-dist.d-min.ts
|
src/Definitions/plotly.js-cartesian-dist.d-min.ts
|
||||||
src/Definitions/png.d.ts
|
src/Definitions/png.d.ts
|
||||||
src/Definitions/svg.d.ts
|
src/Definitions/svg.d.ts
|
||||||
|
src/Definitions/worker.d.ts
|
||||||
src/Explorer/ComponentRegisterer.test.ts
|
src/Explorer/ComponentRegisterer.test.ts
|
||||||
src/Explorer/ComponentRegisterer.ts
|
src/Explorer/ComponentRegisterer.ts
|
||||||
src/Explorer/ContextMenuButtonFactory.ts
|
src/Explorer/ContextMenuButtonFactory.ts
|
||||||
@@ -86,7 +91,8 @@ 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/Graph/NewVertexComponent/NewVertex.test.ts
|
||||||
|
src/Explorer/Graph/NewVertexComponent/NewVertexComponent.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
|
||||||
src/Explorer/Menus/ContextMenu.ts
|
src/Explorer/Menus/ContextMenu.ts
|
||||||
@@ -115,14 +121,18 @@ src/Explorer/Panes/AddDatabasePane.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/DeleteCollectionConfirmationPane.test.ts
|
||||||
|
src/Explorer/Panes/DeleteCollectionConfirmationPane.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/StringInputPane.ts
|
||||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||||
|
src/Explorer/Panes/Tables/AddTableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||||
src/Explorer/Panes/Tables/TableEntityPane.ts
|
src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||||
@@ -240,6 +250,7 @@ src/Utils/QueryUtils.test.ts
|
|||||||
src/applyExplorerBindings.ts
|
src/applyExplorerBindings.ts
|
||||||
src/global.d.ts
|
src/global.d.ts
|
||||||
src/setupTests.ts
|
src/setupTests.ts
|
||||||
|
src/workers/upload/index.ts
|
||||||
src/Explorer/Controls/AccessibleElement/AccessibleElement.tsx
|
src/Explorer/Controls/AccessibleElement/AccessibleElement.tsx
|
||||||
src/Explorer/Controls/Accordion/AccordionComponent.tsx
|
src/Explorer/Controls/Accordion/AccordionComponent.tsx
|
||||||
src/Explorer/Controls/AccountSwitch/AccountSwitchComponent.test.tsx
|
src/Explorer/Controls/AccountSwitch/AccountSwitchComponent.test.tsx
|
||||||
|
|||||||
71
.github/workflows/ci.yml
vendored
71
.github/workflows/ci.yml
vendored
@@ -101,8 +101,7 @@ jobs:
|
|||||||
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
||||||
endtoendemulator:
|
endtoendemulator:
|
||||||
name: "End To End Emulator Tests"
|
name: "End To End Emulator Tests"
|
||||||
# Temporarily disabled. This test needs to be rewritten in playwright
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
if: false
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -127,21 +126,58 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: screenshots
|
name: screenshots
|
||||||
path: failed-*
|
path: failed-*
|
||||||
endtoend:
|
accessibility:
|
||||||
name: "E2E"
|
name: "Accessibility | Hosted"
|
||||||
|
needs: [lint, format, compile, unittest]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js 14.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 14.x
|
||||||
|
- name: Accessibility Check
|
||||||
|
run: |
|
||||||
|
# Ubuntu gets mad when webpack runs too many files watchers
|
||||||
|
cat /proc/sys/fs/inotify/max_user_watches
|
||||||
|
sudo sysctl fs.inotify.max_user_watches=524288
|
||||||
|
sudo sysctl -p
|
||||||
|
npm ci
|
||||||
|
npm start &
|
||||||
|
npx wait-on -i 5000 https-get://0.0.0.0:1234/
|
||||||
|
node utils/accesibilityCheck.js
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
||||||
|
endtoendhosted:
|
||||||
|
name: "End to End Tests"
|
||||||
|
needs: [cleanupaccounts]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
||||||
|
PORTAL_RUNNER_SUBSCRIPTION: ${{ secrets.PORTAL_RUNNER_SUBSCRIPTION }}
|
||||||
|
PORTAL_RUNNER_RESOURCE_GROUP: ${{ secrets.PORTAL_RUNNER_RESOURCE_GROUP }}
|
||||||
|
PORTAL_RUNNER_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT }}
|
||||||
|
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT_KEY }}
|
||||||
|
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT }}
|
||||||
|
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_TENANT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_TENANT_ID }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
||||||
|
PORTAL_RUNNER_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_SQL }}
|
||||||
|
MONGO_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_MONGO }}
|
||||||
|
CASSANDRA_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_CASSANDRA }}
|
||||||
|
TABLES_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_TABLE }}
|
||||||
|
DATA_EXPLORER_ENDPOINT: "https://localhost:1234/hostedExplorer.html"
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
test-file:
|
test-file:
|
||||||
- ./test/cassandra/container.spec.ts
|
- ./test/cassandra/container.spec.ts
|
||||||
- ./test/sql/container.spec.ts
|
- ./test/mongo/mongoIndexPolicy.spec.ts
|
||||||
- ./test/mongo/container.spec.ts
|
- ./test/notebooks/uploadAndOpenNotebook.spec.ts
|
||||||
- ./test/selfServe/selfServeExample.spec.ts
|
- ./test/selfServe/selfServeExample.spec.ts
|
||||||
- ./test/notebooks/upload.spec.ts
|
- ./test/sql/container.spec.ts
|
||||||
- ./test/sql/resourceToken.spec.ts
|
- ./test/sql/resourceToken.spec.ts
|
||||||
- ./test/tables/container.spec.ts
|
- ./test/tables/container.spec.ts
|
||||||
steps:
|
steps:
|
||||||
@@ -152,17 +188,30 @@ jobs:
|
|||||||
node-version: 14.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm start &
|
- run: npm start &
|
||||||
|
- run: node utils/cleanupDBs.js
|
||||||
- run: npm run wait-for-server
|
- run: npm run wait-for-server
|
||||||
- name: ${{ matrix['test-file'] }}
|
- name: ${{ matrix['test-file'] }}
|
||||||
run: |
|
run: npx jest -c ./jest.config.e2e.js --detectOpenHandles ${{ matrix['test-file'] }}
|
||||||
# Run tests up to three times
|
|
||||||
for i in $(seq 1 3); do npx jest -c ./jest.config.playwright.js ${{ matrix['test-file'] }} && s=0 && break || s=$? && sleep 1; done; (exit $s)
|
|
||||||
shell: bash
|
shell: bash
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: screenshots
|
name: screenshots
|
||||||
path: screenshots/
|
path: failed-*
|
||||||
|
cleanupaccounts:
|
||||||
|
name: "Cleanup Test Database Accounts"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js 14.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 14.x
|
||||||
|
- run: npm ci
|
||||||
|
- run: node utils/cleanupDBs.js
|
||||||
nuget:
|
nuget:
|
||||||
name: Publish Nuget
|
name: Publish Nuget
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
|
|||||||
28
.github/workflows/cleanup.yml
vendored
28
.github/workflows/cleanup.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
# This is a basic workflow to help you get started with Actions
|
|
||||||
|
|
||||||
name: Cleanup End to End Account Resources
|
|
||||||
|
|
||||||
on:
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Once every hour
|
|
||||||
- cron: "0 * * * *"
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
# This workflow contains a single job called "build"
|
|
||||||
cleanupaccounts:
|
|
||||||
name: "Cleanup Test Database Accounts"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
|
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js 14.x
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 14.x
|
|
||||||
- run: npm ci
|
|
||||||
- run: node utils/cleanupDBs.js
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -14,6 +14,4 @@ Contracts/*
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.cache/
|
.cache/
|
||||||
.env
|
.env
|
||||||
failure.png
|
failure.png
|
||||||
screenshots/*
|
|
||||||
GettingStarted-ignore*.ipynb
|
|
||||||
@@ -153,7 +153,7 @@ Cosmos Explorer has been under constant development for over 5 years. As a resul
|
|||||||
|
|
||||||
✅ DO
|
✅ DO
|
||||||
|
|
||||||
- Use [Playwright](https://github.com/microsoft/playwright) and [Jest](https://jestjs.io/)
|
- Use [Puppeteer](https://developers.google.com/web/tools/puppeteer) and [Jest](https://jestjs.io/)
|
||||||
- Write or modify an existing E2E test that covers the primary use case of any major feature.
|
- Write or modify an existing E2E test that covers the primary use case of any major feature.
|
||||||
- Use caution. Do not try to cover every case. End to End tests can be slow and brittle.
|
- Use caution. Do not try to cover every case. End to End tests can be slow and brittle.
|
||||||
|
|
||||||
|
|||||||
10
externals/iframeResizer.contentWindow.min.js
vendored
10
externals/iframeResizer.contentWindow.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,13 +0,0 @@
|
|||||||
const isCI = require("is-ci");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
exitOnPageError: false,
|
|
||||||
launchOptions: {
|
|
||||||
headless: isCI,
|
|
||||||
slowMo: 10,
|
|
||||||
timeout: 60000,
|
|
||||||
},
|
|
||||||
contextOptions: {
|
|
||||||
ignoreHTTPSErrors: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
12
jest-puppeteer.config.js
Normal file
12
jest-puppeteer.config.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
const isCI = require("is-ci");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
launch: {
|
||||||
|
headless: isCI,
|
||||||
|
slowMo: 55,
|
||||||
|
defaultViewport: null,
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
args: ["--disable-web-security"],
|
||||||
|
exitOnPageError: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
5
jest.config.e2e.js
Normal file
5
jest.config.e2e.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: "jest-puppeteer",
|
||||||
|
testMatch: ["<rootDir>/test/**/*.spec.[jt]s?(x)"],
|
||||||
|
setupFiles: ["dotenv/config"],
|
||||||
|
};
|
||||||
@@ -69,6 +69,7 @@ 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",
|
||||||
|
"worker-loader": "<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
|
"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
|
||||||
"^dnd-core$": "dnd-core/dist/cjs",
|
"^dnd-core$": "dnd-core/dist/cjs",
|
||||||
"^react-dnd$": "react-dnd/dist/cjs",
|
"^react-dnd$": "react-dnd/dist/cjs",
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
preset: "jest-playwright-preset",
|
|
||||||
testMatch: ["<rootDir>/test/**/*.spec.[jt]s?(x)"],
|
|
||||||
setupFiles: ["dotenv/config"],
|
|
||||||
testEnvironment: "./test/playwrightEnv.js",
|
|
||||||
setupFilesAfterEnv: ["expect-playwright"],
|
|
||||||
};
|
|
||||||
41327
package-lock.json
generated
41327
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -5,7 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/arm-cosmosdb": "9.1.0",
|
"@azure/arm-cosmosdb": "9.1.0",
|
||||||
"@azure/cosmos": "3.10.5",
|
"@azure/cosmos": "3.9.0",
|
||||||
"@azure/cosmos-language-service": "0.0.5",
|
"@azure/cosmos-language-service": "0.0.5",
|
||||||
"@azure/identity": "1.2.1",
|
"@azure/identity": "1.2.1",
|
||||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
"@nteract/iron-icons": "1.0.0",
|
"@nteract/iron-icons": "1.0.0",
|
||||||
"@nteract/jupyter-widgets": "2.0.0",
|
"@nteract/jupyter-widgets": "2.0.0",
|
||||||
"@nteract/logos": "1.0.0",
|
"@nteract/logos": "1.0.0",
|
||||||
"@nteract/markdown": "4.6.0",
|
"@nteract/markdown": "4.6.1",
|
||||||
"@nteract/monaco-editor": "3.2.2",
|
"@nteract/monaco-editor": "3.2.2",
|
||||||
"@nteract/octicons": "2.0.0",
|
"@nteract/octicons": "2.0.0",
|
||||||
"@nteract/outputs": "3.0.9",
|
"@nteract/outputs": "3.0.9",
|
||||||
"@nteract/presentational-components": "3.0.7",
|
"@nteract/presentational-components": "3.0.7",
|
||||||
"@nteract/stateful-components": "1.7.0",
|
"@nteract/stateful-components": "1.7.7",
|
||||||
"@nteract/styles": "2.0.2",
|
"@nteract/styles": "2.0.2",
|
||||||
"@nteract/transform-geojson": "5.1.8",
|
"@nteract/transform-geojson": "5.1.8",
|
||||||
"@nteract/transform-model-debug": "5.0.1",
|
"@nteract/transform-model-debug": "5.0.1",
|
||||||
@@ -65,7 +65,6 @@
|
|||||||
"i18next": "19.8.4",
|
"i18next": "19.8.4",
|
||||||
"i18next-browser-languagedetector": "6.0.1",
|
"i18next-browser-languagedetector": "6.0.1",
|
||||||
"i18next-http-backend": "1.0.23",
|
"i18next-http-backend": "1.0.23",
|
||||||
"iframe-resizer-react": "1.1.0",
|
|
||||||
"immutable": "4.0.0-rc.12",
|
"immutable": "4.0.0-rc.12",
|
||||||
"is-ci": "2.0.0",
|
"is-ci": "2.0.0",
|
||||||
"jquery": "3.5.1",
|
"jquery": "3.5.1",
|
||||||
@@ -79,7 +78,6 @@
|
|||||||
"office-ui-fabric-react": "7.164.2",
|
"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",
|
|
||||||
"q": "1.5.1",
|
"q": "1.5.1",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
"react-animate-height": "2.0.8",
|
"react-animate-height": "2.0.8",
|
||||||
@@ -94,7 +92,6 @@
|
|||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"rx-jupyter": "5.5.12",
|
"rx-jupyter": "5.5.12",
|
||||||
"rxjs": "6.6.3",
|
"rxjs": "6.6.3",
|
||||||
"sanitize-html": "2.3.3",
|
|
||||||
"styled-components": "4.3.2",
|
"styled-components": "4.3.2",
|
||||||
"swr": "0.4.0",
|
"swr": "0.4.0",
|
||||||
"terser-webpack-plugin": "3.1.0",
|
"terser-webpack-plugin": "3.1.0",
|
||||||
@@ -113,23 +110,26 @@
|
|||||||
"@types/d3": "5.9.2",
|
"@types/d3": "5.9.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/expect-puppeteer": "4.4.5",
|
||||||
"@types/hasher": "0.0.31",
|
"@types/hasher": "0.0.31",
|
||||||
"@types/jest": "26.0.20",
|
"@types/jest": "26.0.20",
|
||||||
|
"@types/jest-environment-puppeteer": "4.4.1",
|
||||||
"@types/memoize-one": "4.1.1",
|
"@types/memoize-one": "4.1.1",
|
||||||
"@types/node": "12.11.1",
|
"@types/node": "12.11.1",
|
||||||
"@types/post-robot": "10.0.1",
|
|
||||||
"@types/promise.prototype.finally": "2.0.3",
|
"@types/promise.prototype.finally": "2.0.3",
|
||||||
|
"@types/prop-types": "15.5.8",
|
||||||
|
"@types/puppeteer": "5.4.3",
|
||||||
"@types/q": "1.5.1",
|
"@types/q": "1.5.1",
|
||||||
"@types/react": "17.0.3",
|
"@types/react": "17.0.0",
|
||||||
"@types/react-dom": "17.0.3",
|
"@types/react-dom": "17.0.0",
|
||||||
"@types/react-notification-system": "0.2.39",
|
"@types/react-notification-system": "0.2.39",
|
||||||
"@types/react-redux": "7.1.7",
|
"@types/react-redux": "7.1.7",
|
||||||
"@types/sanitize-html": "1.27.2",
|
|
||||||
"@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.0.1",
|
||||||
"@typescript-eslint/parser": "4.0.1",
|
"@typescript-eslint/parser": "4.0.1",
|
||||||
|
"axe-puppeteer": "1.1.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",
|
||||||
@@ -144,18 +144,16 @@
|
|||||||
"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",
|
||||||
"expect-playwright": "0.3.3",
|
|
||||||
"expose-loader": "0.7.5",
|
"expose-loader": "0.7.5",
|
||||||
"fast-glob": "3.2.5",
|
"fast-glob": "3.2.5",
|
||||||
"file-loader": "2.0.0",
|
"file-loader": "2.0.0",
|
||||||
"fs-extra": "7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"html-inline-css-webpack-plugin": "1.11.0",
|
|
||||||
"html-loader": "0.5.5",
|
"html-loader": "0.5.5",
|
||||||
"html-loader-jest": "0.2.1",
|
"html-loader-jest": "0.2.1",
|
||||||
"html-webpack-plugin": "4.5.2",
|
"html-webpack-plugin": "3.2.0",
|
||||||
"jest": "25.5.4",
|
"jest": "25.5.4",
|
||||||
"jest-canvas-mock": "2.1.0",
|
"jest-canvas-mock": "2.1.0",
|
||||||
"jest-playwright-preset": "1.5.1",
|
"jest-puppeteer": "4.4.0",
|
||||||
"jest-trx-results-processor": "0.0.7",
|
"jest-trx-results-processor": "0.0.7",
|
||||||
"less": "3.8.1",
|
"less": "3.8.1",
|
||||||
"less-loader": "4.1.0",
|
"less-loader": "4.1.0",
|
||||||
@@ -163,23 +161,23 @@
|
|||||||
"mini-css-extract-plugin": "0.4.3",
|
"mini-css-extract-plugin": "0.4.3",
|
||||||
"monaco-editor-webpack-plugin": "1.7.0",
|
"monaco-editor-webpack-plugin": "1.7.0",
|
||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"playwright": "1.10.0",
|
|
||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
|
"puppeteer": "8.0.0",
|
||||||
"raw-loader": "0.5.1",
|
"raw-loader": "0.5.1",
|
||||||
"react-dev-utils": "11.0.4",
|
|
||||||
"rimraf": "3.0.0",
|
"rimraf": "3.0.0",
|
||||||
"sinon": "3.2.1",
|
"sinon": "3.2.1",
|
||||||
"style-loader": "0.23.0",
|
"style-loader": "0.23.0",
|
||||||
"ts-loader": "6.2.2",
|
"ts-loader": "6.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
"tslint-microsoft-contrib": "6.0.0",
|
"tslint-microsoft-contrib": "6.0.0",
|
||||||
"typescript": "4.2.4",
|
"typescript": "4.2.3",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"wait-on": "4.0.2",
|
"wait-on": "4.0.2",
|
||||||
"webpack": "4.46.0",
|
"webpack": "4.43.0",
|
||||||
"webpack-bundle-analyzer": "3.6.1",
|
"webpack-bundle-analyzer": "3.6.1",
|
||||||
"webpack-cli": "3.3.10",
|
"webpack-cli": "3.3.10",
|
||||||
"webpack-dev-server": "3.11.0"
|
"webpack-dev-server": "3.11.0",
|
||||||
|
"worker-loader": "2.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --max-old-space-size=10196 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
"start": "node --max-old-space-size=10196 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
||||||
@@ -195,7 +193,7 @@
|
|||||||
"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 +202,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": {
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ app.get("/pull/:pr(\\d+)", (req, res) => {
|
|||||||
|
|
||||||
const portal = new URL("https://ms.portal.azure.com/");
|
const portal = new URL("https://ms.portal.azure.com/");
|
||||||
portal.searchParams.set("dataExplorerSource", explorer.href);
|
portal.searchParams.set("dataExplorerSource", explorer.href);
|
||||||
|
portal.hash =
|
||||||
|
"@microsoft.onmicrosoft.com/resource/subscriptions/b9c77f10-b438-4c32-9819-eef8a654e478/resourceGroups/stfaul/providers/Microsoft.DocumentDb/databaseAccounts/stfaul-sql/dataExplorer";
|
||||||
|
|
||||||
return res.redirect(portal.href);
|
return res.redirect(portal.href);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ export interface ReactAdapter {
|
|||||||
export class Registerer {
|
export class Registerer {
|
||||||
public static register(): void {
|
public static register(): void {
|
||||||
ko.bindingHandlers.react = {
|
ko.bindingHandlers.react = {
|
||||||
init: (element: any, wrappedValueAccessor: () => any) => {
|
init: (
|
||||||
|
element: any,
|
||||||
|
wrappedValueAccessor: () => any,
|
||||||
|
allBindings?: ko.AllBindings,
|
||||||
|
viewModel?: any,
|
||||||
|
bindingContext?: ko.BindingContext
|
||||||
|
) => {
|
||||||
const adapter: ReactAdapter = wrappedValueAccessor();
|
const adapter: ReactAdapter = wrappedValueAccessor();
|
||||||
|
|
||||||
if (adapter.setElement) {
|
if (adapter.setElement) {
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import { createImmutableOutput, JSONObject, OnDiskOutput } from "@nteract/commutable";
|
|
||||||
// import outputs individually to avoid increasing the bundle size
|
|
||||||
import { KernelOutputError } from "@nteract/outputs/lib/components/kernel-output-error";
|
|
||||||
import { Output } from "@nteract/outputs/lib/components/output";
|
|
||||||
import { StreamText } from "@nteract/outputs/lib/components/stream-text";
|
|
||||||
import { ContentRef } from "@nteract/types";
|
|
||||||
import "bootstrap/dist/css/bootstrap.css";
|
|
||||||
import postRobot from "post-robot";
|
|
||||||
import * as React from "react";
|
|
||||||
import * as ReactDOM from "react-dom";
|
|
||||||
import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work
|
|
||||||
import "../Explorer/Notebook/NotebookRenderer/base.css";
|
|
||||||
import "../Explorer/Notebook/NotebookRenderer/default.css";
|
|
||||||
import { TransformMedia } from "./TransformMedia";
|
|
||||||
|
|
||||||
export interface CellOutputViewerProps {
|
|
||||||
id: string;
|
|
||||||
contentRef: ContentRef;
|
|
||||||
hidden: boolean;
|
|
||||||
expanded: boolean;
|
|
||||||
outputs: OnDiskOutput[];
|
|
||||||
onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onInit = async () => {
|
|
||||||
postRobot.on(
|
|
||||||
"props",
|
|
||||||
{
|
|
||||||
window: window.parent,
|
|
||||||
domain: window.location.origin,
|
|
||||||
},
|
|
||||||
(event) => {
|
|
||||||
// Typescript definition for event is wrong. So read props by casting to <any>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const props = (event as any).data as CellOutputViewerProps;
|
|
||||||
const outputs = (
|
|
||||||
<div
|
|
||||||
data-iframe-height
|
|
||||||
className={`nteract-cell-outputs ${props.hidden ? "hidden" : ""} ${props.expanded ? "expanded" : ""}`}
|
|
||||||
>
|
|
||||||
{props.outputs?.map((output, index) => (
|
|
||||||
<Output output={createImmutableOutput(output)} key={index}>
|
|
||||||
<TransformMedia
|
|
||||||
output_type={"display_data"}
|
|
||||||
id={props.id}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
|
||||||
/>
|
|
||||||
<TransformMedia
|
|
||||||
output_type={"execute_result"}
|
|
||||||
id={props.id}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
|
||||||
/>
|
|
||||||
<KernelOutputError />
|
|
||||||
<StreamText />
|
|
||||||
</Output>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
ReactDOM.render(outputs, document.getElementById("cellOutput"));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Entry point
|
|
||||||
window.addEventListener("load", onInit);
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import { ImmutableDisplayData, ImmutableExecuteResult, JSONObject } from "@nteract/commutable";
|
|
||||||
// import outputs individually to avoid increasing the bundle size
|
|
||||||
import { HTML } from "@nteract/outputs/lib/components/media/html";
|
|
||||||
import { Image } from "@nteract/outputs/lib/components/media/image";
|
|
||||||
import { JavaScript } from "@nteract/outputs/lib/components/media/javascript";
|
|
||||||
import { Json } from "@nteract/outputs/lib/components/media/json";
|
|
||||||
import { LaTeX } from "@nteract/outputs/lib/components/media/latex";
|
|
||||||
import { Plain } from "@nteract/outputs/lib/components/media/plain";
|
|
||||||
import { SVG } from "@nteract/outputs/lib/components/media/svg";
|
|
||||||
import { ContentRef } from "@nteract/types";
|
|
||||||
import React, { Suspense } from "react";
|
|
||||||
|
|
||||||
const EmptyTransform = (): JSX.Element => <></>;
|
|
||||||
|
|
||||||
const displayOrder = [
|
|
||||||
"application/vnd.jupyter.widget-view+json",
|
|
||||||
"application/vnd.vega.v5+json",
|
|
||||||
"application/vnd.vega.v4+json",
|
|
||||||
"application/vnd.vega.v3+json",
|
|
||||||
"application/vnd.vega.v2+json",
|
|
||||||
"application/vnd.vegalite.v4+json",
|
|
||||||
"application/vnd.vegalite.v3+json",
|
|
||||||
"application/vnd.vegalite.v2+json",
|
|
||||||
"application/vnd.vegalite.v1+json",
|
|
||||||
"application/geo+json",
|
|
||||||
"application/vnd.plotly.v1+json",
|
|
||||||
"text/vnd.plotly.v1+html",
|
|
||||||
"application/x-nteract-model-debug+json",
|
|
||||||
"application/vnd.dataresource+json",
|
|
||||||
"application/vdom.v1+json",
|
|
||||||
"application/json",
|
|
||||||
"application/javascript",
|
|
||||||
"text/html",
|
|
||||||
"text/markdown",
|
|
||||||
"text/latex",
|
|
||||||
"image/svg+xml",
|
|
||||||
"image/gif",
|
|
||||||
"image/png",
|
|
||||||
"image/jpeg",
|
|
||||||
"text/plain",
|
|
||||||
];
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const transformsById = new Map<string, React.ComponentType<any>>([
|
|
||||||
["text/vnd.plotly.v1+html", React.lazy(() => import("@nteract/transform-plotly"))],
|
|
||||||
["application/vnd.plotly.v1+json", React.lazy(() => import("@nteract/transform-plotly"))],
|
|
||||||
["application/geo+json", EmptyTransform], // TODO: The geojson transform will likely need some work because of the basemap URL(s)
|
|
||||||
["application/x-nteract-model-debug+json", React.lazy(() => import("@nteract/transform-model-debug"))],
|
|
||||||
["application/vnd.dataresource+json", React.lazy(() => import("@nteract/data-explorer"))],
|
|
||||||
["application/vnd.jupyter.widget-view+json", React.lazy(() => import("./transforms/WidgetDisplay"))],
|
|
||||||
["application/vnd.vegalite.v1+json", React.lazy(() => import("./transforms/VegaLite1"))],
|
|
||||||
["application/vnd.vegalite.v2+json", React.lazy(() => import("./transforms/VegaLite2"))],
|
|
||||||
["application/vnd.vegalite.v3+json", React.lazy(() => import("./transforms/VegaLite3"))],
|
|
||||||
["application/vnd.vegalite.v4+json", React.lazy(() => import("./transforms/VegaLite4"))],
|
|
||||||
["application/vnd.vega.v2+json", React.lazy(() => import("./transforms/Vega2"))],
|
|
||||||
["application/vnd.vega.v3+json", React.lazy(() => import("./transforms/Vega3"))],
|
|
||||||
["application/vnd.vega.v4+json", React.lazy(() => import("./transforms/Vega4"))],
|
|
||||||
["application/vnd.vega.v5+json", React.lazy(() => import("./transforms/Vega5"))],
|
|
||||||
["application/vdom.v1+json", React.lazy(() => import("@nteract/transform-vdom"))],
|
|
||||||
["application/json", Json],
|
|
||||||
["application/javascript", JavaScript],
|
|
||||||
["text/html", HTML],
|
|
||||||
["text/markdown", React.lazy(() => import("@nteract/outputs/lib/components/media/markdown"))], // Markdown increases the bundle size so lazy load it
|
|
||||||
["text/latex", LaTeX],
|
|
||||||
["image/svg+xml", SVG],
|
|
||||||
["image/gif", Image],
|
|
||||||
["image/png", Image],
|
|
||||||
["image/jpeg", Image],
|
|
||||||
["text/plain", Plain],
|
|
||||||
]);
|
|
||||||
|
|
||||||
interface TransformMediaProps {
|
|
||||||
output_type: string;
|
|
||||||
id: string;
|
|
||||||
contentRef: ContentRef;
|
|
||||||
output?: ImmutableDisplayData | ImmutableExecuteResult;
|
|
||||||
onMetadataChange: (metadata: JSONObject, mediaType: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TransformMedia = (props: TransformMediaProps): JSX.Element => {
|
|
||||||
const { Media, mediaType, data, metadata } = getMediaInfo(props);
|
|
||||||
|
|
||||||
// If we had no valid result, return an empty output
|
|
||||||
if (!mediaType || !data) {
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Suspense fallback={<div>Loading...</div>}>
|
|
||||||
<Media
|
|
||||||
onMetadataChange={props.onMetadataChange}
|
|
||||||
data={data}
|
|
||||||
metadata={metadata}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
id={props.id}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMediaInfo = (props: TransformMediaProps) => {
|
|
||||||
const { output, output_type } = props;
|
|
||||||
// This component should only be used with display data and execute result
|
|
||||||
if (!output || !(output_type === "display_data" || output_type === "execute_result")) {
|
|
||||||
console.warn("connected transform media managed to get a non media bundle output");
|
|
||||||
return {
|
|
||||||
Media: EmptyTransform,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the first mediaType in the output data that we support with a handler
|
|
||||||
const mediaType = displayOrder.find(
|
|
||||||
(key) =>
|
|
||||||
Object.prototype.hasOwnProperty.call(output.data, key) &&
|
|
||||||
(Object.prototype.hasOwnProperty.call(transformsById, key) || transformsById.get(key))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mediaType) {
|
|
||||||
const metadata = output.metadata.get(mediaType);
|
|
||||||
const data = output.data[mediaType];
|
|
||||||
|
|
||||||
const Media = transformsById.get(mediaType);
|
|
||||||
return {
|
|
||||||
Media,
|
|
||||||
mediaType,
|
|
||||||
data,
|
|
||||||
metadata,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
Media: EmptyTransform,
|
|
||||||
mediaType,
|
|
||||||
output,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TransformMedia;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Cell Output Viewer</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="cellOutput" id="cellOutput"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega2 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega3 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega4 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega5 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite1 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite2 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite3 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite4 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { WidgetDisplay as default } from "@nteract/jupyter-widgets";
|
|
||||||
@@ -1,9 +1,49 @@
|
|||||||
|
import { HashMap } from "./HashMap";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash map of arrays which allows to:
|
* Hash map of arrays which allows to:
|
||||||
* - push an item by key: add to array and create array if needed
|
* - push an item by key: add to array and create array if needed
|
||||||
* - remove item by key: remove from array and delete array if needed
|
* - remove item by key: remove from array and delete array if needed
|
||||||
*/
|
*/
|
||||||
export class ArrayHashMap<T> extends Map<string, T[]> {
|
|
||||||
|
export class ArrayHashMap<T> {
|
||||||
|
private store: HashMap<T[]>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.store = new HashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public has(key: string): boolean {
|
||||||
|
return this.store.has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): T[] {
|
||||||
|
return this.store.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(): number {
|
||||||
|
return this.store.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.store.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys(): string[] {
|
||||||
|
return this.store.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(key: string): boolean {
|
||||||
|
return this.store.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public forEach(key: string, iteratorFct: (value: T) => void) {
|
||||||
|
const values = this.store.get(key);
|
||||||
|
if (values) {
|
||||||
|
values.forEach((value) => iteratorFct(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item into array.
|
* Insert item into array.
|
||||||
* If no array, create one.
|
* If no array, create one.
|
||||||
@@ -12,8 +52,16 @@ export class ArrayHashMap<T> extends Map<string, T[]> {
|
|||||||
* @param item
|
* @param item
|
||||||
*/
|
*/
|
||||||
public push(key: string, item: T): void {
|
public push(key: string, item: T): void {
|
||||||
const array = this.get(key);
|
let itemsArray: T[] = this.store.get(key);
|
||||||
array ? array.includes(item) || array.push(item) : this.set(key, [item]);
|
if (!itemsArray) {
|
||||||
|
itemsArray = [item];
|
||||||
|
this.store.set(key, itemsArray);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsArray.indexOf(item) === -1) {
|
||||||
|
itemsArray.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,11 +70,18 @@ export class ArrayHashMap<T> extends Map<string, T[]> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param itemToRemove
|
* @param itemToRemove
|
||||||
*/
|
*/
|
||||||
public remove(key: string, itemToRemove: T): void {
|
public remove(key: string, itemToRemove: T) {
|
||||||
const array = this.get(key);
|
if (!this.store.has(key)) {
|
||||||
if (array) {
|
return;
|
||||||
const remaining = array.filter((item) => item !== itemToRemove);
|
}
|
||||||
remaining.length ? this.set(key, remaining) : this.delete(key);
|
|
||||||
|
const itemsArray = this.store.get(key);
|
||||||
|
const index = itemsArray.indexOf(itemToRemove);
|
||||||
|
if (index >= 0) {
|
||||||
|
itemsArray.splice(index, 1);
|
||||||
|
if (itemsArray.length === 0) {
|
||||||
|
this.store.delete(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,10 +75,7 @@ export async function getTokenFromAuthService(verb: string, resourceType: string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _client: Cosmos.CosmosClient;
|
|
||||||
|
|
||||||
export function client(): Cosmos.CosmosClient {
|
export function client(): Cosmos.CosmosClient {
|
||||||
if (_client) return _client;
|
|
||||||
const options: Cosmos.CosmosClientOptions = {
|
const options: Cosmos.CosmosClientOptions = {
|
||||||
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
||||||
key: userContext.masterKey,
|
key: userContext.masterKey,
|
||||||
@@ -92,6 +89,5 @@ export function client(): Cosmos.CosmosClient {
|
|||||||
if (configContext.PROXY_PATH !== undefined) {
|
if (configContext.PROXY_PATH !== undefined) {
|
||||||
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
||||||
}
|
}
|
||||||
_client = new Cosmos.CosmosClient(options);
|
return new Cosmos.CosmosClient(options);
|
||||||
return _client;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
export const getEntityName = (): string => {
|
export const getEntityName = (): string => {
|
||||||
if (userContext.apiType === "Mongo") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
||||||
return "document";
|
return "document";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import { DatePicker, TextField } from "office-ui-fabric-react";
|
|
||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
export interface TableEntityProps {
|
|
||||||
entityValueLabel?: string;
|
|
||||||
entityValuePlaceholder: string;
|
|
||||||
entityValue: string | Date;
|
|
||||||
isEntityTypeDate: boolean;
|
|
||||||
isEntityValueDisable?: boolean;
|
|
||||||
entityTimeValue: string;
|
|
||||||
entityValueType: string;
|
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onSelectDate: (date: Date | null | undefined) => void;
|
|
||||||
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|
||||||
entityValueLabel,
|
|
||||||
entityValuePlaceholder,
|
|
||||||
entityValue,
|
|
||||||
isEntityTypeDate,
|
|
||||||
entityTimeValue,
|
|
||||||
entityValueType,
|
|
||||||
onEntityValueChange,
|
|
||||||
onSelectDate,
|
|
||||||
isEntityValueDisable,
|
|
||||||
onEntityTimeValueChange,
|
|
||||||
}: TableEntityProps): JSX.Element => {
|
|
||||||
if (isEntityTypeDate) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DatePicker
|
|
||||||
className="addEntityDatePicker"
|
|
||||||
placeholder={entityValuePlaceholder}
|
|
||||||
value={entityValue && new Date(entityValue)}
|
|
||||||
ariaLabel={entityValuePlaceholder}
|
|
||||||
onSelectDate={onSelectDate}
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label={entityValueLabel && entityValueLabel}
|
|
||||||
id="entityTimeId"
|
|
||||||
autoFocus
|
|
||||||
type="time"
|
|
||||||
value={entityTimeValue}
|
|
||||||
onChange={onEntityTimeValueChange}
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TextField
|
|
||||||
label={entityValueLabel && entityValueLabel}
|
|
||||||
className="addEntityTextField"
|
|
||||||
id="entityValueId"
|
|
||||||
autoFocus
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
type={entityValueType}
|
|
||||||
placeholder={entityValuePlaceholder}
|
|
||||||
value={typeof entityValue === "string" && entityValue}
|
|
||||||
onChange={onEntityValueChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
70
src/Common/HashMap.test.ts
Normal file
70
src/Common/HashMap.test.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { HashMap } from "./HashMap";
|
||||||
|
|
||||||
|
describe("HashMap", () => {
|
||||||
|
it("should test if key/val exists", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 123);
|
||||||
|
|
||||||
|
expect(map.has("a")).toBe(true);
|
||||||
|
expect(map.has("b")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should get object back", () => {
|
||||||
|
const map = new HashMap<string>();
|
||||||
|
map.set("a", "123");
|
||||||
|
map.set("a", "456");
|
||||||
|
|
||||||
|
expect(map.get("a")).toBe("456");
|
||||||
|
expect(map.get("a")).not.toBe("123");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the right size", () => {
|
||||||
|
const map = new HashMap<string>();
|
||||||
|
map.set("a", "123");
|
||||||
|
map.set("b", "456");
|
||||||
|
|
||||||
|
expect(map.size()).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be iterable", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 10);
|
||||||
|
map.set("c", 100);
|
||||||
|
map.set("d", 1000);
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
map.forEach((key: string, value: number) => {
|
||||||
|
i += value;
|
||||||
|
});
|
||||||
|
expect(i).toBe(1111);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be deleted", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 10);
|
||||||
|
|
||||||
|
expect(map.delete("a")).toBe(true);
|
||||||
|
expect(map.delete("c")).toBe(false);
|
||||||
|
expect(map.has("a")).toBe(false);
|
||||||
|
expect(map.has("b")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should clear", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.clear();
|
||||||
|
expect(map.size()).toBe(0);
|
||||||
|
expect(map.has("a")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return all keys", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 1);
|
||||||
|
expect(map.keys()).toEqual(["a", "b"]);
|
||||||
|
map.clear();
|
||||||
|
expect(map.keys().length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
45
src/Common/HashMap.ts
Normal file
45
src/Common/HashMap.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Simple hashmap implementation that doesn't rely on ES6 Map nor polyfills
|
||||||
|
*/
|
||||||
|
export class HashMap<T> {
|
||||||
|
constructor(private container: { [key: string]: T } = {}) {}
|
||||||
|
|
||||||
|
public has(key: string): boolean {
|
||||||
|
return this.container.hasOwnProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(key: string, value: T): void {
|
||||||
|
this.container[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): T {
|
||||||
|
return this.container[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(): number {
|
||||||
|
return Object.keys(this.container).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(key: string): boolean {
|
||||||
|
if (this.has(key)) {
|
||||||
|
delete this.container[key];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.container = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys(): string[] {
|
||||||
|
return Object.keys(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public forEach(iteratorFct: (key: string, value: T) => void) {
|
||||||
|
for (const k in this.container) {
|
||||||
|
iteratorFct(k, this.container[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,11 @@ import { configContext } from "../ConfigContext";
|
|||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import { Collection } from "../Contracts/ViewModels";
|
import { Collection } from "../Contracts/ViewModels";
|
||||||
|
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
import { userContext } from "../UserContext";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
|
||||||
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
import { MinimalQueryIterator } from "./IteratorUtilities";
|
import { MinimalQueryIterator } from "./IteratorUtilities";
|
||||||
import { sendMessage } from "./MessageHandler";
|
import { sendMessage } from "./MessageHandler";
|
||||||
|
|
||||||
@@ -347,7 +348,10 @@ export function getEndpoint(): string {
|
|||||||
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
||||||
const errorMessage = await response.text();
|
const errorMessage = await response.text();
|
||||||
// Log the error where the user can see it
|
// Log the error where the user can see it
|
||||||
logConsoleError(`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`);
|
NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.Error,
|
||||||
|
`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`
|
||||||
|
);
|
||||||
if (response.status === HttpStatusCodes.Forbidden) {
|
if (response.status === HttpStatusCodes.Forbidden) {
|
||||||
sendMessage({ type: MessageTypes.ForbiddenError, reason: errorMessage });
|
sendMessage({ type: MessageTypes.ForbiddenError, reason: errorMessage });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe("Object cache", () => {
|
|||||||
cache.set("b", 2);
|
cache.set("b", 2);
|
||||||
cache.set("c", 3);
|
cache.set("c", 3);
|
||||||
cache.set("d", 4);
|
cache.set("d", 4);
|
||||||
expect(cache.size).toBe(2);
|
expect(cache.size()).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove first added element to keep size at limit", () => {
|
it("should remove first added element to keep size at limit", () => {
|
||||||
|
|||||||
@@ -1,27 +1,56 @@
|
|||||||
export class ObjectCache<T> extends Map<string, T> {
|
import { HashMap } from "./HashMap";
|
||||||
constructor(private limit: number) {
|
|
||||||
|
export class ObjectCache<T> extends HashMap<T> {
|
||||||
|
private keyQueue: string[]; // Last touched key FIFO to purge cache if too big.
|
||||||
|
private maxNbElements: number;
|
||||||
|
|
||||||
|
public constructor(maxNbElements: number) {
|
||||||
super();
|
super();
|
||||||
|
this.keyQueue = [];
|
||||||
|
this.maxNbElements = maxNbElements;
|
||||||
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): T | undefined {
|
public clear(): void {
|
||||||
return this.touch(key);
|
super.clear();
|
||||||
|
this.keyQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(key: string, value: T): this {
|
public get(key: string): T {
|
||||||
if (this.size === this.limit) {
|
this.markKeyAsTouched(key);
|
||||||
this.delete(this.keys().next().value);
|
return super.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(key: string, value: T): void {
|
||||||
|
super.set(key, value);
|
||||||
|
|
||||||
|
this.markKeyAsTouched(key);
|
||||||
|
|
||||||
|
if (super.size() > this.maxNbElements && key !== this.keyQueue[0]) {
|
||||||
|
this.reduceCacheSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.touch(key, value), this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private touch(key: string, value = super.get(key)) {
|
/**
|
||||||
// Map keeps (re) insertion order according to ES6 spec
|
* Invalidate elements to keep the total number below the limit
|
||||||
if (value) {
|
*/
|
||||||
this.delete(key);
|
private reduceCacheSize(): void {
|
||||||
super.set(key, value);
|
// remove a key
|
||||||
|
const oldKey = this.keyQueue.shift();
|
||||||
|
if (oldKey) {
|
||||||
|
super.delete(oldKey);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
/**
|
||||||
|
* Bubble up this key as new.
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
private markKeyAsTouched(key: string) {
|
||||||
|
const n = this.keyQueue.indexOf(key);
|
||||||
|
if (n > -1) {
|
||||||
|
this.keyQueue.splice(n, 1);
|
||||||
|
}
|
||||||
|
this.keyQueue.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import * as ViewModels from "../Contracts/ViewModels";
|
|||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import * as QueryUtils from "../Utils/QueryUtils";
|
import * as QueryUtils from "../Utils/QueryUtils";
|
||||||
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
||||||
import { createCollection } from "./dataAccess/createCollection";
|
import { createCollection } from "./dataAccess/createCollection";
|
||||||
|
import { handleError } from "./ErrorHandlingUtils";
|
||||||
import { createDocument } from "./dataAccess/createDocument";
|
import { createDocument } from "./dataAccess/createDocument";
|
||||||
import { deleteDocument } from "./dataAccess/deleteDocument";
|
import { deleteDocument } from "./dataAccess/deleteDocument";
|
||||||
import { queryDocuments } from "./dataAccess/queryDocuments";
|
import { queryDocuments } from "./dataAccess/queryDocuments";
|
||||||
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
|
||||||
import { handleError } from "./ErrorHandlingUtils";
|
|
||||||
|
|
||||||
export class QueriesClient {
|
export class QueriesClient {
|
||||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||||
@@ -211,7 +211,7 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fetchQueriesQuery(): string {
|
private fetchQueriesQuery(): string {
|
||||||
if (userContext.apiType === "Mongo") {
|
if (this.container.isPreferredApiMongoDB()) {
|
||||||
return QueriesClient.FetchMongoQuery;
|
return QueriesClient.FetchMongoQuery;
|
||||||
}
|
}
|
||||||
return QueriesClient.FetchQuery;
|
return QueriesClient.FetchQuery;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export class Splitter {
|
|||||||
$(this.leftSide).resizable(splitterOptions);
|
$(this.leftSide).resizable(splitterOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResizeStart: JQueryUI.ResizableEvent = () => {
|
private onResizeStart: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
||||||
if (this.direction === SplitterDirection.Vertical) {
|
if (this.direction === SplitterDirection.Vertical) {
|
||||||
$(".ui-resizable-helper").height("100%");
|
$(".ui-resizable-helper").height("100%");
|
||||||
} else {
|
} else {
|
||||||
@@ -82,7 +82,9 @@ export class Splitter {
|
|||||||
$("iframe").css("pointer-events", "none");
|
$("iframe").css("pointer-events", "none");
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResizeStop: JQueryUI.ResizableEvent = () => $("iframe").css("pointer-events", "auto");
|
private onResizeStop: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
||||||
|
$("iframe").css("pointer-events", "auto");
|
||||||
|
};
|
||||||
|
|
||||||
public collapseLeft() {
|
public collapseLeft() {
|
||||||
this.lastX = $(this.splitter).position().left;
|
this.lastX = $(this.splitter).position().left;
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
import {
|
|
||||||
Dropdown,
|
|
||||||
IDropdownOption,
|
|
||||||
IDropdownStyles,
|
|
||||||
IImageProps,
|
|
||||||
Image,
|
|
||||||
IStackTokens,
|
|
||||||
Stack,
|
|
||||||
TextField,
|
|
||||||
TooltipHost,
|
|
||||||
} from "office-ui-fabric-react";
|
|
||||||
import React, { FunctionComponent } from "react";
|
|
||||||
import DeleteIcon from "../../images/delete.svg";
|
|
||||||
import EditIcon from "../../images/Edit_entity.svg";
|
|
||||||
import { CassandraType, TableType } from "../Explorer/Tables/Constants";
|
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { EntityValue } from "./EntityValue";
|
|
||||||
|
|
||||||
const dropdownStyles: Partial<IDropdownStyles> = { dropdown: { width: 100 } };
|
|
||||||
|
|
||||||
export interface TableEntityProps {
|
|
||||||
entityTypeLabel?: string;
|
|
||||||
entityPropertyLabel?: string;
|
|
||||||
entityValueLabel?: string;
|
|
||||||
isDeleteOptionVisible: boolean;
|
|
||||||
entityProperty: string;
|
|
||||||
entityPropertyPlaceHolder: string;
|
|
||||||
selectedKey: string | number;
|
|
||||||
entityValuePlaceholder: string;
|
|
||||||
entityValue: string | Date;
|
|
||||||
isEntityTypeDate: boolean;
|
|
||||||
options: { key: string; text: string }[];
|
|
||||||
isPropertyTypeDisable: boolean;
|
|
||||||
entityTimeValue: string;
|
|
||||||
isEntityValueDisable?: boolean;
|
|
||||||
onDeleteEntity?: () => void;
|
|
||||||
onEditEntity?: () => void;
|
|
||||||
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onEntityTypeChange: (event: React.FormEvent<HTMLElement>, selectedParam: IDropdownOption) => void;
|
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onSelectDate: (date: Date | null | undefined) => void;
|
|
||||||
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|
||||||
entityTypeLabel,
|
|
||||||
entityPropertyLabel,
|
|
||||||
isDeleteOptionVisible,
|
|
||||||
entityProperty,
|
|
||||||
selectedKey,
|
|
||||||
entityPropertyPlaceHolder,
|
|
||||||
entityValueLabel,
|
|
||||||
entityValuePlaceholder,
|
|
||||||
entityValue,
|
|
||||||
options,
|
|
||||||
isPropertyTypeDisable,
|
|
||||||
isEntityTypeDate,
|
|
||||||
entityTimeValue,
|
|
||||||
isEntityValueDisable,
|
|
||||||
onEditEntity,
|
|
||||||
onDeleteEntity,
|
|
||||||
onEntityPropertyChange,
|
|
||||||
onEntityTypeChange,
|
|
||||||
onEntityValueChange,
|
|
||||||
onSelectDate,
|
|
||||||
onEntityTimeValueChange,
|
|
||||||
}: TableEntityProps): JSX.Element => {
|
|
||||||
const imageProps: IImageProps = {
|
|
||||||
width: 16,
|
|
||||||
height: 30,
|
|
||||||
className: entityPropertyLabel ? "addRemoveIconLabel" : "addRemoveIcon",
|
|
||||||
};
|
|
||||||
|
|
||||||
const sectionStackTokens: IStackTokens = { childrenGap: 12 };
|
|
||||||
|
|
||||||
const getEntityValueType = (): string => {
|
|
||||||
const { Int, Smallint, Tinyint } = CassandraType;
|
|
||||||
const { Double, Int32, Int64 } = TableType;
|
|
||||||
|
|
||||||
if (
|
|
||||||
selectedKey === Double ||
|
|
||||||
selectedKey === Int32 ||
|
|
||||||
selectedKey === Int64 ||
|
|
||||||
selectedKey === Int ||
|
|
||||||
selectedKey === Smallint ||
|
|
||||||
selectedKey === Tinyint
|
|
||||||
) {
|
|
||||||
return "number";
|
|
||||||
}
|
|
||||||
return "string";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Stack horizontal tokens={sectionStackTokens}>
|
|
||||||
<TextField
|
|
||||||
label={entityPropertyLabel && entityPropertyLabel}
|
|
||||||
id="entityPropertyId"
|
|
||||||
autoFocus
|
|
||||||
disabled={isPropertyTypeDisable}
|
|
||||||
placeholder={entityPropertyPlaceHolder}
|
|
||||||
value={entityProperty}
|
|
||||||
onChange={onEntityPropertyChange}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<Dropdown
|
|
||||||
label={entityTypeLabel && entityTypeLabel}
|
|
||||||
selectedKey={selectedKey}
|
|
||||||
onChange={onEntityTypeChange}
|
|
||||||
options={options}
|
|
||||||
disabled={isPropertyTypeDisable}
|
|
||||||
id="entityTypeId"
|
|
||||||
styles={dropdownStyles}
|
|
||||||
/>
|
|
||||||
<EntityValue
|
|
||||||
entityValueLabel={entityValueLabel}
|
|
||||||
entityValueType={getEntityValueType()}
|
|
||||||
isEntityValueDisable={isEntityValueDisable}
|
|
||||||
entityValuePlaceholder={entityValuePlaceholder}
|
|
||||||
entityValue={entityValue}
|
|
||||||
isEntityTypeDate={isEntityTypeDate}
|
|
||||||
entityTimeValue={entityTimeValue}
|
|
||||||
onEntityValueChange={onEntityValueChange}
|
|
||||||
onSelectDate={onSelectDate}
|
|
||||||
onEntityTimeValueChange={onEntityTimeValueChange}
|
|
||||||
/>
|
|
||||||
{!isEntityValueDisable && (
|
|
||||||
<TooltipHost content="Edit property" id="editTooltip">
|
|
||||||
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
|
||||||
</TooltipHost>
|
|
||||||
)}
|
|
||||||
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
|
||||||
<TooltipHost content="Delete property" id="deleteTooltip">
|
|
||||||
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
|
||||||
</TooltipHost>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Image, Stack, TextField } from "office-ui-fabric-react";
|
import { Image, Stack, TextField } from "office-ui-fabric-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 "../../Common/Constants";
|
||||||
import { Tooltip } from "../Tooltip/Tooltip";
|
import { Tooltip } from "../Tooltip";
|
||||||
|
|
||||||
interface UploadProps {
|
interface UploadProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import { JSONObject, OperationResponse } from "@azure/cosmos";
|
|
||||||
import { CollectionBase } from "../../Contracts/ViewModels";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
|
|
||||||
export const bulkCreateDocument = async (
|
|
||||||
collection: CollectionBase,
|
|
||||||
documents: JSONObject[]
|
|
||||||
): Promise<OperationResponse[]> => {
|
|
||||||
const clearMessage = logConsoleProgress(
|
|
||||||
`Executing ${documents.length} bulk operations for container ${collection.id()}`
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client()
|
|
||||||
.database(collection.databaseId)
|
|
||||||
.container(collection.id())
|
|
||||||
.items.bulk(
|
|
||||||
documents.map((doc) => ({ operationType: "Create", resourceBody: doc })),
|
|
||||||
{ continueOnError: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const successCount = response.filter((r) => r.statusCode === 201).length;
|
|
||||||
const throttledCount = response.filter((r) => r.statusCode === 429).length;
|
|
||||||
|
|
||||||
logConsoleInfo(
|
|
||||||
`${
|
|
||||||
documents.length
|
|
||||||
} operations completed for container ${collection.id()}. ${successCount} operations succeeded. ${throttledCount} operations throttled`
|
|
||||||
);
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, "BulkCreateDocument", `Error bulk creating items for container ${collection.id()}`);
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
clearMessage();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { constructRpOptions, createCollection } from "./createCollection";
|
import { createCollection, constructRpOptions } from "./createCollection";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("createCollection", () => {
|
describe("createCollection", () => {
|
||||||
const createCollectionParams: CreateCollectionParams = {
|
const createCollectionParams: CreateCollectionParams = {
|
||||||
@@ -21,7 +22,7 @@ describe("createCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
|
||||||
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { AuthType } from "../../AuthType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import { client } from "../CosmosClient";
|
||||||
import { userContext } from "../../UserContext";
|
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateGremlinGraph,
|
|
||||||
getGremlinGraph,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBCollection,
|
createUpdateMongoDBCollection,
|
||||||
getMongoDBCollection,
|
getMongoDBCollection,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import {
|
||||||
|
createUpdateGremlinGraph,
|
||||||
|
getGremlinGraph,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
|
||||||
import { createDatabase } from "./createDatabase";
|
import { createDatabase } from "./createDatabase";
|
||||||
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const clearMessage = logConsoleProgress(
|
const clearMessage = logConsoleProgress(
|
||||||
@@ -45,7 +46,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
await createDatabase(createDatabaseParams);
|
await createDatabase(createDatabaseParams);
|
||||||
}
|
}
|
||||||
collection = await createCollectionWithARM(params);
|
collection = await createCollectionWithARM(params);
|
||||||
} else if (userContext.apiType === "Mongo") {
|
} else if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
||||||
collection = await createMongoCollectionWithProxy(params);
|
collection = await createMongoCollectionWithProxy(params);
|
||||||
} else {
|
} else {
|
||||||
collection = await createCollectionWithSDK(params);
|
collection = await createCollectionWithSDK(params);
|
||||||
@@ -62,17 +63,17 @@ 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 defaultExperience = userContext.defaultExperience;
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return createSqlContainer(params);
|
return createSqlContainer(params);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return createMongoCollection(params);
|
return createMongoCollection(params);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return createCassandraTable(params);
|
return createCassandraTable(params);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return createGraph(params);
|
return createGraph(params);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
return createTable(params);
|
return createTable(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,36 +1,37 @@
|
|||||||
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseResponse } from "@azure/cosmos";
|
import { DatabaseResponse } from "@azure/cosmos";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { AuthType } from "../../AuthType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import {
|
||||||
import { userContext } from "../../UserContext";
|
CassandraKeyspaceCreateUpdateParameters,
|
||||||
|
GremlinDatabaseCreateUpdateParameters,
|
||||||
|
MongoDBDatabaseCreateUpdateParameters,
|
||||||
|
SqlDatabaseCreateUpdateParameters,
|
||||||
|
CreateUpdateOptions,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraKeyspace,
|
createUpdateCassandraKeyspace,
|
||||||
getCassandraKeyspace,
|
getCassandraKeyspace,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateGremlinDatabase,
|
|
||||||
getGremlinDatabase,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBDatabase,
|
createUpdateMongoDBDatabase,
|
||||||
getMongoDBDatabase,
|
getMongoDBDatabase,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
CassandraKeyspaceCreateUpdateParameters,
|
createUpdateGremlinDatabase,
|
||||||
CreateUpdateOptions,
|
getGremlinDatabase,
|
||||||
GremlinDatabaseCreateUpdateParameters,
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
MongoDBDatabaseCreateUpdateParameters,
|
|
||||||
SqlDatabaseCreateUpdateParameters,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.apiType === "Tables") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||||
throw new Error("Creating database resources is not allowed for tables accounts");
|
throw new Error("Creating database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||||
@@ -48,15 +49,15 @@ 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 defaultExperience = userContext.defaultExperience;
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return createSqlDatabase(params);
|
return createSqlDatabase(params);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return createMongoDatabase(params);
|
return createMongoDatabase(params);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return createCassandraKeyspace(params);
|
return createCassandraKeyspace(params);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return createGremlineDatabase(params);
|
return createGremlineDatabase(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlStoredProcedure,
|
|
||||||
getSqlStoredProcedure,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
SqlStoredProcedureResource,
|
SqlStoredProcedureResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlStoredProcedure,
|
||||||
|
getSqlStoredProcedure,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createStoredProcedure(
|
export async function createStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ export async function createStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createTrigger(
|
export async function createTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -17,7 +18,11 @@ export async function createTrigger(
|
|||||||
): Promise<TriggerDefinition & Resource> {
|
): Promise<TriggerDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlUserDefinedFunction,
|
|
||||||
getSqlUserDefinedFunction,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
SqlUserDefinedFunctionResource,
|
SqlUserDefinedFunctionResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlUserDefinedFunction,
|
||||||
|
getSqlUserDefinedFunction,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createUserDefinedFunction(
|
export async function createUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ export async function createUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteCollection } from "./deleteCollection";
|
import { deleteCollection } from "./deleteCollection";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
|
||||||
describe("deleteCollection", () => {
|
describe("deleteCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +15,7 @@ describe("deleteCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
|
||||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||||
@@ -30,18 +31,18 @@ function deleteCollectionWithARM(databaseId: string, collectionId: string): Prom
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
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: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteDatabase } from "./deleteDatabase";
|
import { deleteDatabase } from "./deleteDatabase";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
|
||||||
describe("deleteDatabase", () => {
|
describe("deleteDatabase", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +15,7 @@ describe("deleteDatabase", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { client } from "../CosmosClient";
|
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
|
||||||
export async function deleteDatabase(databaseId: string): Promise<void> {
|
export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.apiType === "Tables") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||||
throw new Error("Deleting database resources is not allowed for tables accounts");
|
throw new Error("Deleting database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
@@ -33,16 +34,16 @@ function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
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: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteStoredProcedure(
|
export async function deleteStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -12,7 +13,11 @@ export async function deleteStoredProcedure(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlStoredProcedure(
|
await deleteSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlTrigger(
|
await deleteSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlUserDefinedFunction(
|
await deleteSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollection } from "./readCollection";
|
import { readCollection } from "./readCollection";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readCollection", () => {
|
describe("readCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -12,7 +13,7 @@ describe("readCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,12 +36,12 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await getSqlContainerThroughput(
|
rpResponse = await getSqlContainerThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -45,7 +50,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await getMongoDBCollectionThroughput(
|
rpResponse = await getMongoDBCollectionThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -54,7 +59,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await getCassandraTableThroughput(
|
rpResponse = await getCassandraTableThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -63,7 +68,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await getGremlinGraphThroughput(
|
rpResponse = await getGremlinGraphThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -72,7 +77,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollections } from "./readCollections";
|
import { readCollections } from "./readCollections";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readCollections", () => {
|
describe("readCollections", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,7 +14,7 @@ describe("readCollections", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
@@ -13,7 +14,11 @@ import { handleError } from "../ErrorHandlingUtils";
|
|||||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readCollectionsWithARM(databaseId);
|
return await readCollectionsWithARM(databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,22 +37,22 @@ async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Co
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readDatabaseOfferWithARM(params.databaseId);
|
return await readDatabaseOfferWithARM(params.databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,21 +35,21 @@ const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readDatabases } from "./readDatabases";
|
import { readDatabases } from "./readDatabases";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readDatabases", () => {
|
describe("readDatabases", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,7 +14,7 @@ describe("readDatabases", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { AuthType } from "../../AuthType";
|
||||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readDatabases(): Promise<DataModels.Database[]> {
|
export async function readDatabases(): Promise<DataModels.Database[]> {
|
||||||
let databases: DataModels.Database[];
|
let databases: DataModels.Database[];
|
||||||
const clearMessage = logConsoleProgress(`Querying databases`);
|
const clearMessage = logConsoleProgress(`Querying databases`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
databases = await readDatabasesWithARM();
|
databases = await readDatabasesWithARM();
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client().databases.readAll().fetchAll();
|
const sdkResponse = await client().databases.readAll().fetchAll();
|
||||||
@@ -32,19 +37,19 @@ async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readStoredProcedures(
|
export async function readStoredProcedures(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -12,7 +13,11 @@ export async function readStoredProcedures(
|
|||||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlStoredProcedures(
|
const rpResponse = await listSqlStoredProcedures(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { userContext } from "../../UserContext";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readTriggers(
|
export async function readTriggers(
|
||||||
@@ -12,7 +13,11 @@ export async function readTriggers(
|
|||||||
): Promise<(TriggerDefinition & Resource)[]> {
|
): Promise<(TriggerDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlTriggers(
|
const rpResponse = await listSqlTriggers(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readUserDefinedFunctions(
|
export async function readUserDefinedFunctions(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -12,7 +13,11 @@ export async function readUserDefinedFunctions(
|
|||||||
): 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}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlUserDefinedFunctions(
|
const rpResponse = await listSqlUserDefinedFunctions(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ContainerDefinition } from "@azure/cosmos";
|
|||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { Collection } from "../../Contracts/DataModels";
|
import { Collection } from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
@@ -37,7 +38,11 @@ export async function updateCollection(
|
|||||||
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client()
|
const sdkResponse = await client()
|
||||||
@@ -66,18 +71,18 @@ async function updateCollectionWithARM(
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.apiType;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return updateMongoDBCollection(
|
return updateMongoDBCollection(
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
|||||||
@@ -1,53 +1,54 @@
|
|||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
import { HttpHeaders } from "../Constants";
|
||||||
|
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
||||||
import { OfferDefinition } from "@azure/cosmos";
|
import { OfferDefinition } from "@azure/cosmos";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { AuthType } from "../../AuthType";
|
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
import { client } from "../CosmosClient";
|
||||||
import { userContext } from "../../UserContext";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { parseSDKOfferResponse } from "../OfferUtility";
|
||||||
|
import { readCollectionOffer } from "./readCollectionOffer";
|
||||||
|
import { readDatabaseOffer } from "./readDatabaseOffer";
|
||||||
import {
|
import {
|
||||||
|
updateSqlDatabaseThroughput,
|
||||||
|
migrateSqlDatabaseToAutoscale,
|
||||||
|
migrateSqlDatabaseToManualThroughput,
|
||||||
|
migrateSqlContainerToAutoscale,
|
||||||
|
migrateSqlContainerToManualThroughput,
|
||||||
|
updateSqlContainerThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import {
|
||||||
|
updateCassandraKeyspaceThroughput,
|
||||||
migrateCassandraKeyspaceToAutoscale,
|
migrateCassandraKeyspaceToAutoscale,
|
||||||
migrateCassandraKeyspaceToManualThroughput,
|
migrateCassandraKeyspaceToManualThroughput,
|
||||||
migrateCassandraTableToAutoscale,
|
migrateCassandraTableToAutoscale,
|
||||||
migrateCassandraTableToManualThroughput,
|
migrateCassandraTableToManualThroughput,
|
||||||
updateCassandraKeyspaceThroughput,
|
|
||||||
updateCassandraTableThroughput,
|
updateCassandraTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
|
updateMongoDBDatabaseThroughput,
|
||||||
|
migrateMongoDBDatabaseToAutoscale,
|
||||||
|
migrateMongoDBDatabaseToManualThroughput,
|
||||||
|
migrateMongoDBCollectionToAutoscale,
|
||||||
|
migrateMongoDBCollectionToManualThroughput,
|
||||||
|
updateMongoDBCollectionThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import {
|
||||||
|
updateGremlinDatabaseThroughput,
|
||||||
migrateGremlinDatabaseToAutoscale,
|
migrateGremlinDatabaseToAutoscale,
|
||||||
migrateGremlinDatabaseToManualThroughput,
|
migrateGremlinDatabaseToManualThroughput,
|
||||||
migrateGremlinGraphToAutoscale,
|
migrateGremlinGraphToAutoscale,
|
||||||
migrateGremlinGraphToManualThroughput,
|
migrateGremlinGraphToManualThroughput,
|
||||||
updateGremlinDatabaseThroughput,
|
|
||||||
updateGremlinGraphThroughput,
|
updateGremlinGraphThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import {
|
import { userContext } from "../../UserContext";
|
||||||
migrateMongoDBCollectionToAutoscale,
|
|
||||||
migrateMongoDBCollectionToManualThroughput,
|
|
||||||
migrateMongoDBDatabaseToAutoscale,
|
|
||||||
migrateMongoDBDatabaseToManualThroughput,
|
|
||||||
updateMongoDBCollectionThroughput,
|
|
||||||
updateMongoDBDatabaseThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
|
||||||
migrateSqlContainerToAutoscale,
|
|
||||||
migrateSqlContainerToManualThroughput,
|
|
||||||
migrateSqlDatabaseToAutoscale,
|
|
||||||
migrateSqlDatabaseToManualThroughput,
|
|
||||||
updateSqlContainerThroughput,
|
|
||||||
updateSqlDatabaseThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
migrateTableToAutoscale,
|
migrateTableToAutoscale,
|
||||||
migrateTableToManualThroughput,
|
migrateTableToManualThroughput,
|
||||||
updateTableThroughput,
|
updateTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { HttpHeaders } from "../Constants";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { parseSDKOfferResponse } from "../OfferUtility";
|
|
||||||
import { readCollectionOffer } from "./readCollectionOffer";
|
|
||||||
import { readDatabaseOffer } from "./readDatabaseOffer";
|
|
||||||
|
|
||||||
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
let updatedOffer: Offer;
|
let updatedOffer: Offer;
|
||||||
@@ -60,7 +61,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
if (params.collectionId) {
|
if (params.collectionId) {
|
||||||
updatedOffer = await updateCollectionOfferWithARM(params);
|
updatedOffer = await updateCollectionOfferWithARM(params);
|
||||||
} else if (userContext.apiType === "Tables") {
|
} else if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||||
// update table's database offer with SDK since RP doesn't support it
|
// update table's database offer with SDK since RP doesn't support it
|
||||||
updatedOffer = await updateOfferWithSDK(params);
|
updatedOffer = await updateOfferWithSDK(params);
|
||||||
} else {
|
} else {
|
||||||
@@ -81,24 +82,24 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
|
|
||||||
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.apiType) {
|
switch (userContext.defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
await updateSqlContainerOffer(params);
|
await updateSqlContainerOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
await updateMongoCollectionOffer(params);
|
await updateMongoCollectionOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
await updateCassandraTableOffer(params);
|
await updateCassandraTableOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
await updateGremlinGraphOffer(params);
|
await updateGremlinGraphOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
await updateTableOffer(params);
|
await updateTableOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
@@ -115,21 +116,21 @@ const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<
|
|||||||
|
|
||||||
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.apiType) {
|
switch (userContext.defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
await updateSqlDatabaseOffer(params);
|
await updateSqlDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
await updateMongoDatabaseOffer(params);
|
await updateMongoDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
await updateCassandraKeyspaceOffer(params);
|
await updateCassandraKeyspaceOffer(params);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
await updateGremlinDatabaseOffer(params);
|
await updateGremlinDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlStoredProcedure,
|
|
||||||
getSqlStoredProcedure,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
SqlStoredProcedureResource,
|
SqlStoredProcedureResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlStoredProcedure,
|
||||||
|
getSqlStoredProcedure,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function updateStoredProcedure(
|
export async function updateStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ 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") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { TriggerDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function updateTrigger(
|
export async function updateTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -17,7 +18,11 @@ export async function updateTrigger(
|
|||||||
): Promise<TriggerDefinition> {
|
): Promise<TriggerDefinition> {
|
||||||
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlUserDefinedFunction,
|
|
||||||
getSqlUserDefinedFunction,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
SqlUserDefinedFunctionResource,
|
SqlUserDefinedFunctionResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlUserDefinedFunction,
|
||||||
|
getSqlUserDefinedFunction,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function updateUserDefinedFunction(
|
export async function updateUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ export async function updateUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
userContext.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export interface ConfigContext {
|
|||||||
GITHUB_CLIENT_SECRET?: string; // No need to inject secret for prod. Juno already knows it.
|
GITHUB_CLIENT_SECRET?: string; // No need to inject secret for prod. Juno already knows it.
|
||||||
hostedExplorerURL: string;
|
hostedExplorerURL: string;
|
||||||
armAPIVersion?: string;
|
armAPIVersion?: string;
|
||||||
allowedJunoOrigins: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default configuration
|
// Default configuration
|
||||||
@@ -54,13 +53,6 @@ let configContext: Readonly<ConfigContext> = {
|
|||||||
GITHUB_CLIENT_ID: "6cb2f63cf6f7b5cbdeca", // Registered OAuth app: https://github.com/settings/applications/1189306
|
GITHUB_CLIENT_ID: "6cb2f63cf6f7b5cbdeca", // Registered OAuth app: https://github.com/settings/applications/1189306
|
||||||
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
||||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||||
allowedJunoOrigins: [
|
|
||||||
"https://juno-test.documents-dev.windows-int.net",
|
|
||||||
"https://juno-test2.documents-dev.windows-int.net",
|
|
||||||
"https://tools.cosmos.azure.com",
|
|
||||||
"https://tools-staging.cosmos.azure.com",
|
|
||||||
"https://localhost",
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resetConfigContext(): void {
|
export function resetConfigContext(): void {
|
||||||
@@ -94,18 +86,13 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
|||||||
});
|
});
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
try {
|
try {
|
||||||
const { allowedParentFrameOrigins, allowedJunoOrigins, ...externalConfig } = await response.json();
|
const { allowedParentFrameOrigins, ...externalConfig } = await response.json();
|
||||||
Object.assign(configContext, externalConfig);
|
Object.assign(configContext, externalConfig);
|
||||||
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
|
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
|
||||||
updateConfigContext({
|
updateConfigContext({
|
||||||
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins],
|
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (allowedJunoOrigins && allowedJunoOrigins.length > 0) {
|
|
||||||
updateConfigContext({
|
|
||||||
allowedJunoOrigins: [...configContext.allowedJunoOrigins, ...allowedJunoOrigins],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Unable to parse json in config file");
|
console.error("Unable to parse json in config file");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
export enum TabKind {
|
export enum TabKind {
|
||||||
SQLDocuments,
|
SQLDocuments,
|
||||||
MongoDocuments,
|
MongoDocuments,
|
||||||
SchemaAnalyzer,
|
|
||||||
TableEntities,
|
TableEntities,
|
||||||
Graph,
|
Graph,
|
||||||
SQLQuery,
|
SQLQuery,
|
||||||
|
|||||||
@@ -121,10 +121,6 @@ export interface ISchemaRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Collection extends Resource {
|
export interface Collection extends Resource {
|
||||||
// Only in Mongo collections loaded via ARM
|
|
||||||
shardKey?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
defaultTtl?: number;
|
defaultTtl?: number;
|
||||||
indexingPolicy?: IndexingPolicy;
|
indexingPolicy?: IndexingPolicy;
|
||||||
partitionKey?: PartitionKey;
|
partitionKey?: PartitionKey;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
|||||||
import Trigger from "../Explorer/Tree/Trigger";
|
import Trigger from "../Explorer/Tree/Trigger";
|
||||||
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
|
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
|
||||||
import { SelfServeType } from "../SelfServe/SelfServeUtils";
|
import { SelfServeType } from "../SelfServe/SelfServeUtils";
|
||||||
|
import { UploadDetails } from "../workers/upload/definitions";
|
||||||
import * as DataModels from "./DataModels";
|
import * as DataModels from "./DataModels";
|
||||||
import { SubscriptionType } from "./SubscriptionType";
|
import { SubscriptionType } from "./SubscriptionType";
|
||||||
|
|
||||||
@@ -22,14 +23,6 @@ export interface TokenProvider {
|
|||||||
getAuthHeader(): Promise<Headers>;
|
getAuthHeader(): Promise<Headers>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UploadDetailsRecord {
|
|
||||||
fileName: string;
|
|
||||||
numSucceeded: number;
|
|
||||||
numFailed: number;
|
|
||||||
numThrottled: number;
|
|
||||||
errors: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface QueryResultsMetadata {
|
export interface QueryResultsMetadata {
|
||||||
hasMoreResults: boolean;
|
hasMoreResults: boolean;
|
||||||
firstItemIndex: number;
|
firstItemIndex: number;
|
||||||
@@ -141,7 +134,6 @@ export interface Collection extends CollectionBase {
|
|||||||
onTableEntitiesClick(): void;
|
onTableEntitiesClick(): void;
|
||||||
onGraphDocumentsClick(): void;
|
onGraphDocumentsClick(): void;
|
||||||
onMongoDBDocumentsClick(): void;
|
onMongoDBDocumentsClick(): void;
|
||||||
onSchemaAnalyzerClick(): void;
|
|
||||||
openTab(): void;
|
openTab(): void;
|
||||||
|
|
||||||
onSettingsClick: () => Promise<void>;
|
onSettingsClick: () => Promise<void>;
|
||||||
@@ -182,7 +174,7 @@ export interface Collection extends CollectionBase {
|
|||||||
|
|
||||||
onDragOver(source: Collection, event: { originalEvent: DragEvent }): void;
|
onDragOver(source: Collection, event: { originalEvent: DragEvent }): void;
|
||||||
onDrop(source: Collection, event: { originalEvent: DragEvent }): void;
|
onDrop(source: Collection, event: { originalEvent: DragEvent }): void;
|
||||||
uploadFiles(fileList: FileList): Promise<{ data: UploadDetailsRecord[] }>;
|
uploadFiles(fileList: FileList): Promise<UploadDetails>;
|
||||||
|
|
||||||
getLabel(): string;
|
getLabel(): string;
|
||||||
getPendingThroughputSplitNotification(): Promise<DataModels.Notification>;
|
getPendingThroughputSplitNotification(): Promise<DataModels.Notification>;
|
||||||
@@ -277,6 +269,7 @@ export interface TabOptions {
|
|||||||
tabKind: CollectionTabKind;
|
tabKind: CollectionTabKind;
|
||||||
title: string;
|
title: string;
|
||||||
tabPath: string;
|
tabPath: string;
|
||||||
|
isActive: ko.Observable<boolean>;
|
||||||
hashLocation: string;
|
hashLocation: string;
|
||||||
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]) => void;
|
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]) => void;
|
||||||
isTabsContentExpanded?: ko.Observable<boolean>;
|
isTabsContentExpanded?: ko.Observable<boolean>;
|
||||||
@@ -367,7 +360,6 @@ export enum CollectionTabKind {
|
|||||||
Schema = 19,
|
Schema = 19,
|
||||||
CollectionSettingsV2 = 20,
|
CollectionSettingsV2 = 20,
|
||||||
DatabaseSettingsV2 = 21,
|
DatabaseSettingsV2 = 21,
|
||||||
SchemaAnalyzer = 22,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TerminalKind {
|
export enum TerminalKind {
|
||||||
@@ -398,9 +390,6 @@ export interface DataExplorerInputsFrame {
|
|||||||
dataExplorerVersion?: string;
|
dataExplorerVersion?: string;
|
||||||
defaultCollectionThroughput?: CollectionCreationDefaults;
|
defaultCollectionThroughput?: CollectionCreationDefaults;
|
||||||
flights?: readonly string[];
|
flights?: readonly string[];
|
||||||
features?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelfServeFrameInputs {
|
export interface SelfServeFrameInputs {
|
||||||
|
|||||||
8
src/DefaultAccountExperienceType.ts
Normal file
8
src/DefaultAccountExperienceType.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export enum DefaultAccountExperienceType {
|
||||||
|
DocumentDB = "DocumentDB",
|
||||||
|
Graph = "Graph",
|
||||||
|
MongoDB = "MongoDB",
|
||||||
|
Table = "Table",
|
||||||
|
Cassandra = "Cassandra",
|
||||||
|
ApiForMongoDB = "Azure Cosmos DB for MongoDB API",
|
||||||
|
}
|
||||||
7
src/Definitions/worker.d.ts
vendored
Normal file
7
src/Definitions/worker.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
declare module "worker-loader!*" {
|
||||||
|
class WebpackWorker extends Worker {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WebpackWorker;
|
||||||
|
}
|
||||||
@@ -8,6 +8,10 @@ describe("Component Registerer", () => {
|
|||||||
expect(ko.components.isRegistered("input-typeahead")).toBe(true);
|
expect(ko.components.isRegistered("input-typeahead")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should register new-vertex-form component", () => {
|
||||||
|
expect(ko.components.isRegistered("new-vertex-form")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("should register error-display component", () => {
|
it("should register error-display component", () => {
|
||||||
expect(ko.components.isRegistered("error-display")).toBe(true);
|
expect(ko.components.isRegistered("error-display")).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -20,14 +24,75 @@ describe("Component Registerer", () => {
|
|||||||
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should register documents-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("documents-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register stored-procedure-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("stored-procedure-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register trigger-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("trigger-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register user-defined-function-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("user-defined-function-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register settings-tab-v2 component", () => {
|
||||||
|
expect(ko.components.isRegistered("database-settings-tab-v2")).toBe(true);
|
||||||
|
expect(ko.components.isRegistered("collection-settings-tab-v2")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register query-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("query-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register tables-query-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("tables-query-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register graph-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("graph-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register notebookv2-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("notebookv2-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register terminal-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("terminal-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register mongo-shell-tab component", () => {
|
||||||
|
expect(ko.components.isRegistered("mongo-shell-tab")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("should registeradd-collection-pane component", () => {
|
it("should registeradd-collection-pane component", () => {
|
||||||
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
|
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should register delete-collection-confirmation-pane component", () => {
|
||||||
|
expect(ko.components.isRegistered("delete-collection-confirmation-pane")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register graph-new-vertex-pane component", () => {
|
||||||
|
expect(ko.components.isRegistered("graph-new-vertex-pane")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("should register graph-styling-pane component", () => {
|
it("should register graph-styling-pane component", () => {
|
||||||
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should register string-input-pane component", () => {
|
||||||
|
expect(ko.components.isRegistered("string-input-pane")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should register setup-notebooks-pane component", () => {
|
||||||
|
expect(ko.components.isRegistered("setup-notebooks-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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,9 +7,26 @@ import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahea
|
|||||||
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 { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
|
||||||
|
import { NewVertexComponent } from "./Graph/NewVertexComponent/NewVertexComponent";
|
||||||
import * as PaneComponents from "./Panes/PaneComponents";
|
import * as PaneComponents from "./Panes/PaneComponents";
|
||||||
|
import ConflictsTab from "./Tabs/ConflictsTab";
|
||||||
|
import DocumentsTab from "./Tabs/DocumentsTab";
|
||||||
|
import GalleryTab from "./Tabs/GalleryTab";
|
||||||
|
import GraphTab from "./Tabs/GraphTab";
|
||||||
|
import MongoShellTab from "./Tabs/MongoShellTab";
|
||||||
|
import NotebookTabV2 from "./Tabs/NotebookV2Tab";
|
||||||
|
import NotebookViewerTab from "./Tabs/NotebookViewerTab";
|
||||||
|
import QueryTab from "./Tabs/QueryTab";
|
||||||
|
import QueryTablesTab from "./Tabs/QueryTablesTab";
|
||||||
|
import { DatabaseSettingsTabV2, SettingsTabV2 } from "./Tabs/SettingsTabV2";
|
||||||
|
import StoredProcedureTab from "./Tabs/StoredProcedureTab";
|
||||||
|
import TabsManagerTemplate from "./Tabs/TabsManager.html";
|
||||||
|
import TerminalTab from "./Tabs/TerminalTab";
|
||||||
|
import TriggerTab from "./Tabs/TriggerTab";
|
||||||
|
import UserDefinedFunctionTab from "./Tabs/UserDefinedFunctionTab";
|
||||||
|
|
||||||
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
||||||
|
ko.components.register("new-vertex-form", NewVertexComponent);
|
||||||
ko.components.register("error-display", new ErrorDisplayComponent());
|
ko.components.register("error-display", new ErrorDisplayComponent());
|
||||||
ko.components.register("graph-style", GraphStyleComponent);
|
ko.components.register("graph-style", GraphStyleComponent);
|
||||||
ko.components.register("editor", new EditorComponent());
|
ko.components.register("editor", new EditorComponent());
|
||||||
@@ -17,12 +34,40 @@ ko.components.register("json-editor", new JsonEditorComponent());
|
|||||||
ko.components.register("diff-editor", new DiffEditorComponent());
|
ko.components.register("diff-editor", new DiffEditorComponent());
|
||||||
ko.components.register("dynamic-list", DynamicListComponent);
|
ko.components.register("dynamic-list", DynamicListComponent);
|
||||||
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
||||||
|
ko.components.register("tabs-manager", { template: TabsManagerTemplate });
|
||||||
|
|
||||||
|
// Collection Tabs
|
||||||
|
[
|
||||||
|
DocumentsTab,
|
||||||
|
StoredProcedureTab,
|
||||||
|
TriggerTab,
|
||||||
|
UserDefinedFunctionTab,
|
||||||
|
SettingsTabV2,
|
||||||
|
QueryTab,
|
||||||
|
QueryTablesTab,
|
||||||
|
GraphTab,
|
||||||
|
MongoShellTab,
|
||||||
|
ConflictsTab,
|
||||||
|
NotebookTabV2,
|
||||||
|
TerminalTab,
|
||||||
|
GalleryTab,
|
||||||
|
NotebookViewerTab,
|
||||||
|
DatabaseSettingsTabV2,
|
||||||
|
].forEach(({ component: { name, template } }) => ko.components.register(name, { template }));
|
||||||
|
|
||||||
// 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("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
||||||
|
ko.components.register(
|
||||||
|
"delete-collection-confirmation-pane",
|
||||||
|
new PaneComponents.DeleteCollectionConfirmationPaneComponent()
|
||||||
|
);
|
||||||
|
|
||||||
|
ko.components.register("graph-new-vertex-pane", new PaneComponents.GraphNewVertexPaneComponent());
|
||||||
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
||||||
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
||||||
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
||||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
|
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
||||||
|
ko.components.register("setup-notebooks-pane", new PaneComponents.SetupNotebooksPaneComponent());
|
||||||
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import DeleteTriggerIcon from "../../images/DeleteTrigger.svg";
|
|||||||
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
||||||
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
||||||
import Explorer from "./Explorer";
|
import Explorer from "./Explorer";
|
||||||
@@ -29,16 +30,16 @@ export interface DatabaseContextMenuButtonParams {
|
|||||||
* New resource tree (in ReactJS)
|
* New resource tree (in ReactJS)
|
||||||
*/
|
*/
|
||||||
export class ResourceTreeContextMenuButtonFactory {
|
export class ResourceTreeContextMenuButtonFactory {
|
||||||
public static createDatabaseContextMenu(container: Explorer, databaseId: string): TreeNodeMenuItem[] {
|
public static createDatabaseContextMenu(container: Explorer): TreeNodeMenuItem[] {
|
||||||
const items: TreeNodeMenuItem[] = [
|
const items: TreeNodeMenuItem[] = [
|
||||||
{
|
{
|
||||||
iconSrc: AddCollectionIcon,
|
iconSrc: AddCollectionIcon,
|
||||||
onClick: () => container.onNewCollectionClicked(databaseId),
|
onClick: () => container.onNewCollectionClicked(),
|
||||||
label: container.addCollectionText(),
|
label: container.addCollectionText(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (userContext.apiType !== "Tables") {
|
if (userContext.defaultExperience !== DefaultAccountExperienceType.Table) {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: DeleteDatabaseIcon,
|
iconSrc: DeleteDatabaseIcon,
|
||||||
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
||||||
@@ -54,7 +55,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
selectedCollection: ViewModels.Collection
|
selectedCollection: ViewModels.Collection
|
||||||
): TreeNodeMenuItem[] {
|
): TreeNodeMenuItem[] {
|
||||||
const items: TreeNodeMenuItem[] = [];
|
const items: TreeNodeMenuItem[] = [];
|
||||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
onClick: () => selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null),
|
onClick: () => selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null),
|
||||||
@@ -62,7 +63,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType === "Mongo") {
|
if (container.isPreferredApiMongoDB()) {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
||||||
@@ -79,7 +80,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddStoredProcedureIcon,
|
iconSrc: AddStoredProcedureIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@@ -122,7 +123,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
container: Explorer,
|
container: Explorer,
|
||||||
storedProcedure: StoredProcedure
|
storedProcedure: StoredProcedure
|
||||||
): TreeNodeMenuItem[] {
|
): TreeNodeMenuItem[] {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (container.isPreferredApiCassandra()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +137,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static createTriggerContextMenuItems(container: Explorer, trigger: Trigger): TreeNodeMenuItem[] {
|
public static createTriggerContextMenuItems(container: Explorer, trigger: Trigger): TreeNodeMenuItem[] {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (container.isPreferredApiCassandra()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +154,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
container: Explorer,
|
container: Explorer,
|
||||||
userDefinedFunction: UserDefinedFunction
|
userDefinedFunction: UserDefinedFunction
|
||||||
): TreeNodeMenuItem[] {
|
): TreeNodeMenuItem[] {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (container.isPreferredApiCassandra()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { accordionStackTokens } from "../Settings/SettingsRenderUtils";
|
|||||||
export interface CollapsibleSectionProps {
|
export interface CollapsibleSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
isExpandedByDefault: boolean;
|
isExpandedByDefault: boolean;
|
||||||
onExpand?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollapsibleSectionState {
|
export interface CollapsibleSectionState {
|
||||||
@@ -24,12 +23,6 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
this.setState({ isExpanded: !this.state.isExpanded });
|
this.setState({ isExpanded: !this.state.isExpanded });
|
||||||
};
|
};
|
||||||
|
|
||||||
public componentDidUpdate(): void {
|
|
||||||
if (this.state.isExpanded && this.props.onExpand) {
|
|
||||||
this.props.onExpand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { Dialog as FluentDialog, DialogType, DialogFooter, IDialogProps } from "office-ui-fabric-react/lib/Dialog";
|
||||||
|
import { IButtonProps, PrimaryButton, DefaultButton } from "office-ui-fabric-react/lib/Button";
|
||||||
|
import { ITextFieldProps, TextField } from "office-ui-fabric-react/lib/TextField";
|
||||||
|
import { Link } from "office-ui-fabric-react/lib/Link";
|
||||||
import {
|
import {
|
||||||
ChoiceGroup,
|
ChoiceGroup,
|
||||||
FontIcon,
|
FontIcon,
|
||||||
@@ -5,11 +10,6 @@ import {
|
|||||||
IProgressIndicatorProps,
|
IProgressIndicatorProps,
|
||||||
ProgressIndicator,
|
ProgressIndicator,
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import { DefaultButton, IButtonProps, PrimaryButton } from "office-ui-fabric-react/lib/Button";
|
|
||||||
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";
|
|
||||||
|
|
||||||
export interface TextFieldProps extends ITextFieldProps {
|
export interface TextFieldProps extends ITextFieldProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -50,69 +50,61 @@ const DIALOG_TITLE_FONT_SIZE = "17px";
|
|||||||
const DIALOG_TITLE_FONT_WEIGHT = 400;
|
const DIALOG_TITLE_FONT_WEIGHT = 400;
|
||||||
const DIALOG_SUBTEXT_FONT_SIZE = "15px";
|
const DIALOG_SUBTEXT_FONT_SIZE = "15px";
|
||||||
|
|
||||||
export const Dialog: FunctionComponent<DialogProps> = ({
|
export class Dialog extends React.Component<DialogProps> {
|
||||||
title,
|
constructor(props: DialogProps) {
|
||||||
subText,
|
super(props);
|
||||||
isModal,
|
}
|
||||||
visible,
|
|
||||||
choiceGroupProps,
|
public render(): JSX.Element {
|
||||||
textFieldProps,
|
const dialogProps: IDialogProps = {
|
||||||
linkProps,
|
hidden: !this.props.visible,
|
||||||
progressIndicatorProps,
|
dialogContentProps: {
|
||||||
primaryButtonText,
|
type: this.props.type || DialogType.normal,
|
||||||
secondaryButtonText,
|
title: this.props.title,
|
||||||
onPrimaryButtonClick,
|
subText: this.props.subText,
|
||||||
onSecondaryButtonClick,
|
styles: {
|
||||||
primaryButtonDisabled,
|
title: { fontSize: DIALOG_TITLE_FONT_SIZE, fontWeight: DIALOG_TITLE_FONT_WEIGHT },
|
||||||
type,
|
subText: { fontSize: DIALOG_SUBTEXT_FONT_SIZE },
|
||||||
showCloseButton,
|
},
|
||||||
onDismiss,
|
showCloseButton: this.props.showCloseButton || false,
|
||||||
}: DialogProps) => {
|
onDismiss: this.props.onDismiss,
|
||||||
const dialogProps: IDialogProps = {
|
|
||||||
hidden: !visible,
|
|
||||||
dialogContentProps: {
|
|
||||||
type: type || DialogType.normal,
|
|
||||||
title,
|
|
||||||
subText,
|
|
||||||
styles: {
|
|
||||||
title: { fontSize: DIALOG_TITLE_FONT_SIZE, fontWeight: DIALOG_TITLE_FONT_WEIGHT },
|
|
||||||
subText: { fontSize: DIALOG_SUBTEXT_FONT_SIZE },
|
|
||||||
},
|
},
|
||||||
showCloseButton: showCloseButton || false,
|
modalProps: { isBlocking: this.props.isModal, isDarkOverlay: false },
|
||||||
onDismiss,
|
minWidth: DIALOG_MIN_WIDTH,
|
||||||
},
|
maxWidth: DIALOG_MAX_WIDTH,
|
||||||
modalProps: { isBlocking: isModal, isDarkOverlay: false },
|
};
|
||||||
minWidth: DIALOG_MIN_WIDTH,
|
const choiceGroupProps: IChoiceGroupProps = this.props.choiceGroupProps;
|
||||||
maxWidth: DIALOG_MAX_WIDTH,
|
const textFieldProps: ITextFieldProps = this.props.textFieldProps;
|
||||||
};
|
const linkProps: LinkProps = this.props.linkProps;
|
||||||
|
const progressIndicatorProps: IProgressIndicatorProps = this.props.progressIndicatorProps;
|
||||||
|
const primaryButtonProps: IButtonProps = {
|
||||||
|
text: this.props.primaryButtonText,
|
||||||
|
disabled: this.props.primaryButtonDisabled || false,
|
||||||
|
onClick: this.props.onPrimaryButtonClick,
|
||||||
|
};
|
||||||
|
const secondaryButtonProps: IButtonProps =
|
||||||
|
this.props.secondaryButtonText && this.props.onSecondaryButtonClick
|
||||||
|
? {
|
||||||
|
text: this.props.secondaryButtonText,
|
||||||
|
onClick: this.props.onSecondaryButtonClick,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const primaryButtonProps: IButtonProps = {
|
return (
|
||||||
text: primaryButtonText,
|
<FluentDialog {...dialogProps}>
|
||||||
disabled: primaryButtonDisabled || false,
|
{choiceGroupProps && <ChoiceGroup {...choiceGroupProps} />}
|
||||||
onClick: onPrimaryButtonClick,
|
{textFieldProps && <TextField {...textFieldProps} />}
|
||||||
};
|
{linkProps && (
|
||||||
const secondaryButtonProps: IButtonProps =
|
<Link href={linkProps.linkUrl} target="_blank">
|
||||||
secondaryButtonText && onSecondaryButtonClick
|
{linkProps.linkText} <FontIcon iconName="NavigateExternalInline" />
|
||||||
? {
|
</Link>
|
||||||
text: secondaryButtonText,
|
)}
|
||||||
onClick: onSecondaryButtonClick,
|
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
|
||||||
}
|
<DialogFooter>
|
||||||
: undefined;
|
<PrimaryButton {...primaryButtonProps} />
|
||||||
|
{secondaryButtonProps && <DefaultButton {...secondaryButtonProps} />}
|
||||||
return (
|
</DialogFooter>
|
||||||
<FluentDialog {...dialogProps}>
|
</FluentDialog>
|
||||||
{choiceGroupProps && <ChoiceGroup {...choiceGroupProps} />}
|
);
|
||||||
{textFieldProps && <TextField {...textFieldProps} />}
|
}
|
||||||
{linkProps && (
|
}
|
||||||
<Link href={linkProps.linkUrl} target="_blank">
|
|
||||||
{linkProps.linkText} <FontIcon iconName="NavigateExternalInline" />
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
|
|
||||||
<DialogFooter>
|
|
||||||
<PrimaryButton {...primaryButtonProps} />
|
|
||||||
{secondaryButtonProps && <DefaultButton {...secondaryButtonProps} />}
|
|
||||||
</DialogFooter>
|
|
||||||
</FluentDialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { loadMonaco, monaco } from "../../LazyMonaco";
|
|
||||||
import template from "./diff-editor-component.html";
|
import template from "./diff-editor-component.html";
|
||||||
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -92,7 +92,7 @@ export class DiffEditorViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor on diff mode and attach to DOM
|
* Create the monaco editor on diff mode and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected async createDiffEditor(
|
protected createDiffEditor(
|
||||||
originalContent: string,
|
originalContent: string,
|
||||||
modifiedContent: string,
|
modifiedContent: string,
|
||||||
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
||||||
@@ -111,7 +111,7 @@ export class DiffEditorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const language = this.params.editorLanguage || "json";
|
const language = this.params.editorLanguage || "json";
|
||||||
const monaco = await loadMonaco();
|
|
||||||
const originalModel = monaco.editor.createModel(originalContent, language);
|
const originalModel = monaco.editor.createModel(originalContent, language);
|
||||||
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
||||||
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { loadMonaco, monaco } from "../../LazyMonaco";
|
|
||||||
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
||||||
import template from "./editor-component.html";
|
import template from "./editor-component.html";
|
||||||
|
import * as monaco from "monaco-editor";
|
||||||
|
import { SqlCompletionItemProvider, ErrorMarkProvider } from "@azure/cosmos-language-service";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -48,17 +49,15 @@ class EditorViewModel extends JsonEditorViewModel {
|
|||||||
return this.params.contentType;
|
return this.params.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async registerCompletionItemProvider() {
|
protected registerCompletionItemProvider() {
|
||||||
|
let sqlCompletionItemProvider = new SqlCompletionItemProvider();
|
||||||
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
||||||
const { SqlCompletionItemProvider } = await import("@azure/cosmos-language-service");
|
monaco.languages.registerCompletionItemProvider("sql", sqlCompletionItemProvider);
|
||||||
const monaco = await loadMonaco();
|
|
||||||
monaco.languages.registerCompletionItemProvider("sql", new SqlCompletionItemProvider());
|
|
||||||
EditorViewModel.providerRegistered.push("sql");
|
EditorViewModel.providerRegistered.push("sql");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getErrorMarkers(input: string): Promise<monaco.editor.IMarkerData[]> {
|
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
||||||
const { ErrorMarkProvider } = await import("@azure/cosmos-language-service");
|
|
||||||
return ErrorMarkProvider.getErrorMark(input);
|
return ErrorMarkProvider.getErrorMark(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { loadMonaco, monaco } from "../../LazyMonaco";
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
export interface EditorReactProps {
|
export interface EditorReactProps {
|
||||||
language: string;
|
language: string;
|
||||||
@@ -61,7 +61,7 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
private createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
value: this.props.content,
|
value: this.props.content,
|
||||||
language: this.props.language,
|
language: this.props.language,
|
||||||
@@ -74,7 +74,6 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.rootNode.innerHTML = "";
|
this.rootNode.innerHTML = "";
|
||||||
const monaco = await loadMonaco();
|
|
||||||
createCallback(monaco.editor.create(this.rootNode, options));
|
createCallback(monaco.editor.create(this.rootNode, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,21 +128,21 @@ class InputTypeaheadViewModel {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
callback: {
|
callback: {
|
||||||
onClick: (_node: unknown, _a: unknown, item: OnClickItem) => {
|
onClick: (node: any, a: any, item: OnClickItem, event: any) => {
|
||||||
cache.selection = item;
|
cache.selection = item;
|
||||||
|
|
||||||
if (params.selection) {
|
if (params.selection) {
|
||||||
params.selection(item);
|
params.selection(item);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onResult(_node: unknown, query: any) {
|
onResult(node: any, query: any, result: any, resultCount: any, resultCountPerGroup: any) {
|
||||||
cache.inputValue = query;
|
cache.inputValue = query;
|
||||||
if (params.inputValue) {
|
if (params.inputValue) {
|
||||||
params.inputValue(query);
|
params.inputValue(query);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: (_query: string, item: any) => {
|
template: (query: string, item: any) => {
|
||||||
// Don't display id if caption *IS* the id
|
// Don't display id if caption *IS* the id
|
||||||
return item.caption === item.value
|
return item.caption === item.value
|
||||||
? "<span>{{caption}}</span>"
|
? "<span>{{caption}}</span>"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import Q from "q";
|
||||||
|
import * as monaco from "monaco-editor";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { loadMonaco, monaco } from "../../LazyMonaco";
|
|
||||||
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
||||||
import template from "./json-editor-component.html";
|
import template from "./json-editor-component.html";
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected async createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
protected createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
this.registerCompletionItemProvider();
|
this.registerCompletionItemProvider();
|
||||||
this.editorContainer = document.getElementById(this.getEditorId());
|
this.editorContainer = document.getElementById(this.getEditorId());
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
@@ -101,7 +102,6 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.editorContainer.innerHTML = "";
|
this.editorContainer.innerHTML = "";
|
||||||
const monaco = await loadMonaco();
|
|
||||||
createCallback(monaco.editor.create(this.editorContainer, options));
|
createCallback(monaco.editor.create(this.editorContainer, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,16 +109,15 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
protected registerCompletionItemProvider() {}
|
protected registerCompletionItemProvider() {}
|
||||||
|
|
||||||
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
||||||
protected async getErrorMarkers(_: string): Promise<monaco.editor.IMarkerData[]> {
|
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
||||||
return [];
|
return Q.Promise(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getEditorLanguage(): string {
|
protected getEditorLanguage(): string {
|
||||||
return "json";
|
return "json";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
protected configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
||||||
const monaco = await loadMonaco();
|
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
const queryEditorModel = this.editor.getModel();
|
const queryEditorModel = this.editor.getModel();
|
||||||
if (!this.params.isReadOnly && this.params.updatedContent) {
|
if (!this.params.isReadOnly && this.params.updatedContent) {
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { Card } from "@uifabric/react-cards";
|
import { Card } from "@uifabric/react-cards";
|
||||||
import {
|
import {
|
||||||
BaseButton,
|
|
||||||
Button,
|
|
||||||
FontWeights,
|
FontWeights,
|
||||||
Icon,
|
Icon,
|
||||||
IconButton,
|
IconButton,
|
||||||
Image,
|
Image,
|
||||||
ImageFit,
|
ImageFit,
|
||||||
Link,
|
|
||||||
LinkBase,
|
|
||||||
Persona,
|
Persona,
|
||||||
|
Text,
|
||||||
|
Link,
|
||||||
|
BaseButton,
|
||||||
|
Button,
|
||||||
|
LinkBase,
|
||||||
Separator,
|
Separator,
|
||||||
|
TooltipHost,
|
||||||
Spinner,
|
Spinner,
|
||||||
SpinnerSize,
|
SpinnerSize,
|
||||||
Text,
|
|
||||||
TooltipHost,
|
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import React, { FunctionComponent, useState } from "react";
|
import * as React from "react";
|
||||||
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
|
||||||
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
||||||
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
||||||
|
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
||||||
|
|
||||||
export interface GalleryCardComponentProps {
|
export interface GalleryCardComponentProps {
|
||||||
data: IGalleryItem;
|
data: IGalleryItem;
|
||||||
@@ -34,48 +34,166 @@ export interface GalleryCardComponentProps {
|
|||||||
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps> = ({
|
interface GalleryCardComponentState {
|
||||||
data,
|
isDeletingPublishedNotebook: boolean;
|
||||||
isFavorite,
|
}
|
||||||
showDownload,
|
|
||||||
showDelete,
|
|
||||||
onClick,
|
|
||||||
onTagClick,
|
|
||||||
onFavoriteClick,
|
|
||||||
onUnfavoriteClick,
|
|
||||||
onDownloadClick,
|
|
||||||
onDeleteClick,
|
|
||||||
}: GalleryCardComponentProps) => {
|
|
||||||
const CARD_WIDTH = 256;
|
|
||||||
const cardImageHeight = 144;
|
|
||||||
const cardDescriptionMaxChars = 80;
|
|
||||||
const cardItemGapBig = 10;
|
|
||||||
const cardItemGapSmall = 8;
|
|
||||||
const cardDeleteSpinnerHeight = 360;
|
|
||||||
const smallTextLineHeight = 18;
|
|
||||||
|
|
||||||
const [isDeletingPublishedNotebook, setIsDeletingPublishedNotebook] = useState<boolean>(false);
|
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps, GalleryCardComponentState> {
|
||||||
|
public static readonly CARD_WIDTH = 256;
|
||||||
|
private static readonly cardImageHeight = 144;
|
||||||
|
public static readonly cardHeightToWidthRatio =
|
||||||
|
GalleryCardComponent.cardImageHeight / GalleryCardComponent.CARD_WIDTH;
|
||||||
|
private static readonly cardDescriptionMaxChars = 80;
|
||||||
|
private static readonly cardItemGapBig = 10;
|
||||||
|
private static readonly cardItemGapSmall = 8;
|
||||||
|
private static readonly cardDeleteSpinnerHeight = 360;
|
||||||
|
private static readonly smallTextLineHeight = 18;
|
||||||
|
|
||||||
const cardButtonsVisible = isFavorite !== undefined || showDownload || showDelete;
|
constructor(props: GalleryCardComponentProps) {
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
super(props);
|
||||||
year: "numeric",
|
this.state = {
|
||||||
month: "short",
|
isDeletingPublishedNotebook: false,
|
||||||
day: "numeric",
|
};
|
||||||
};
|
}
|
||||||
const dateString = new Date(data.created).toLocaleString("default", options);
|
|
||||||
const cardTitle = FileSystemUtil.stripExtension(data.name, "ipynb");
|
|
||||||
|
|
||||||
const renderTruncatedDescription = (): string => {
|
public render(): JSX.Element {
|
||||||
let truncatedDescription = data.description.substr(0, cardDescriptionMaxChars);
|
const cardButtonsVisible = this.props.isFavorite !== undefined || this.props.showDownload || this.props.showDelete;
|
||||||
if (data.description.length > cardDescriptionMaxChars) {
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
};
|
||||||
|
const dateString = new Date(this.props.data.created).toLocaleString("default", options);
|
||||||
|
const cardTitle = FileSystemUtil.stripExtension(this.props.data.name, "ipynb");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
style={{ background: "white" }}
|
||||||
|
aria-label={cardTitle}
|
||||||
|
data-is-focusable="true"
|
||||||
|
tokens={{ width: GalleryCardComponent.CARD_WIDTH, childrenGap: 0 }}
|
||||||
|
onClick={(event) => this.onClick(event, this.props.onClick)}
|
||||||
|
>
|
||||||
|
{this.state.isDeletingPublishedNotebook && (
|
||||||
|
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
||||||
|
<Spinner
|
||||||
|
size={SpinnerSize.large}
|
||||||
|
label={`Deleting '${cardTitle}'`}
|
||||||
|
styles={{ root: { height: GalleryCardComponent.cardDeleteSpinnerHeight } }}
|
||||||
|
/>
|
||||||
|
</Card.Item>
|
||||||
|
)}
|
||||||
|
{!this.state.isDeletingPublishedNotebook && (
|
||||||
|
<>
|
||||||
|
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
||||||
|
<Persona
|
||||||
|
imageUrl={this.props.data.isSample && CosmosDBLogo}
|
||||||
|
text={this.props.data.author}
|
||||||
|
secondaryText={dateString}
|
||||||
|
/>
|
||||||
|
</Card.Item>
|
||||||
|
|
||||||
|
<Card.Item>
|
||||||
|
<Image
|
||||||
|
src={this.props.data.thumbnailUrl}
|
||||||
|
width={GalleryCardComponent.CARD_WIDTH}
|
||||||
|
height={GalleryCardComponent.cardImageHeight}
|
||||||
|
imageFit={ImageFit.cover}
|
||||||
|
alt={`${cardTitle} cover image`}
|
||||||
|
/>
|
||||||
|
</Card.Item>
|
||||||
|
|
||||||
|
<Card.Section styles={{ root: { padding: GalleryCardComponent.cardItemGapBig } }}>
|
||||||
|
<Text variant="small" nowrap styles={{ root: { height: GalleryCardComponent.smallTextLineHeight } }}>
|
||||||
|
{this.props.data.tags ? (
|
||||||
|
this.props.data.tags.map((tag, index, array) => (
|
||||||
|
<span key={tag}>
|
||||||
|
<Link onClick={(event) => this.onClick(event, () => this.props.onTagClick(tag))}>{tag}</Link>
|
||||||
|
{index === array.length - 1 ? <></> : ", "}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<br />
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
styles={{
|
||||||
|
root: {
|
||||||
|
fontWeight: FontWeights.semibold,
|
||||||
|
paddingTop: GalleryCardComponent.cardItemGapSmall,
|
||||||
|
paddingBottom: GalleryCardComponent.cardItemGapSmall,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
nowrap
|
||||||
|
>
|
||||||
|
{cardTitle}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text variant="small" styles={{ root: { height: GalleryCardComponent.smallTextLineHeight * 2 } }}>
|
||||||
|
{this.renderTruncatedDescription()}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{this.props.data.views !== undefined &&
|
||||||
|
this.generateIconText("RedEye", this.props.data.views.toString())}
|
||||||
|
{this.props.data.downloads !== undefined &&
|
||||||
|
this.generateIconText("Download", this.props.data.downloads.toString())}
|
||||||
|
{this.props.data.favorites !== undefined &&
|
||||||
|
this.generateIconText("Heart", this.props.data.favorites.toString())}
|
||||||
|
</span>
|
||||||
|
</Card.Section>
|
||||||
|
|
||||||
|
{cardButtonsVisible && (
|
||||||
|
<Card.Section
|
||||||
|
styles={{
|
||||||
|
root: {
|
||||||
|
marginLeft: GalleryCardComponent.cardItemGapBig,
|
||||||
|
marginRight: GalleryCardComponent.cardItemGapBig,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{this.props.isFavorite !== undefined &&
|
||||||
|
this.generateIconButtonWithTooltip(
|
||||||
|
this.props.isFavorite ? "HeartFill" : "Heart",
|
||||||
|
this.props.isFavorite ? "Unfavorite" : "Favorite",
|
||||||
|
"left",
|
||||||
|
this.props.isFavorite ? this.props.onUnfavoriteClick : this.props.onFavoriteClick
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.props.showDownload &&
|
||||||
|
this.generateIconButtonWithTooltip("Download", "Download", "left", this.props.onDownloadClick)}
|
||||||
|
|
||||||
|
{this.props.showDelete &&
|
||||||
|
this.generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
||||||
|
this.props.onDeleteClick(
|
||||||
|
() => this.setState({ isDeletingPublishedNotebook: true }),
|
||||||
|
() => this.setState({ isDeletingPublishedNotebook: false })
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Card.Section>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderTruncatedDescription = (): string => {
|
||||||
|
let truncatedDescription = this.props.data.description.substr(0, GalleryCardComponent.cardDescriptionMaxChars);
|
||||||
|
if (this.props.data.description.length > GalleryCardComponent.cardDescriptionMaxChars) {
|
||||||
truncatedDescription = `${truncatedDescription} ...`;
|
truncatedDescription = `${truncatedDescription} ...`;
|
||||||
}
|
}
|
||||||
return truncatedDescription;
|
return truncatedDescription;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateIconText = (iconName: string, text: string): JSX.Element => {
|
private generateIconText = (iconName: string, text: string): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: cardItemGapSmall } }}>
|
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: GalleryCardComponent.cardItemGapSmall } }}>
|
||||||
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -85,7 +203,7 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
|
|||||||
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
||||||
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
||||||
*/
|
*/
|
||||||
const generateIconButtonWithTooltip = (
|
private generateIconButtonWithTooltip = (
|
||||||
iconName: string,
|
iconName: string,
|
||||||
title: string,
|
title: string,
|
||||||
horizontalAlign: "right" | "left",
|
horizontalAlign: "right" | "left",
|
||||||
@@ -102,13 +220,13 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
|
|||||||
iconProps={{ iconName }}
|
iconProps={{ iconName }}
|
||||||
title={title}
|
title={title}
|
||||||
ariaLabel={title}
|
ariaLabel={title}
|
||||||
onClick={(event) => handlerOnClick(event, activate)}
|
onClick={(event) => this.onClick(event, activate)}
|
||||||
/>
|
/>
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerOnClick = (
|
private onClick = (
|
||||||
event:
|
event:
|
||||||
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent>
|
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent>
|
||||||
| React.MouseEvent<
|
| React.MouseEvent<
|
||||||
@@ -121,112 +239,4 @@ export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps>
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
activate();
|
activate();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
style={{ background: "white" }}
|
|
||||||
aria-label={cardTitle}
|
|
||||||
data-is-focusable="true"
|
|
||||||
tokens={{ width: CARD_WIDTH, childrenGap: 0 }}
|
|
||||||
onClick={(event) => handlerOnClick(event, onClick)}
|
|
||||||
>
|
|
||||||
{isDeletingPublishedNotebook && (
|
|
||||||
<Card.Item tokens={{ padding: cardItemGapBig }}>
|
|
||||||
<Spinner
|
|
||||||
size={SpinnerSize.large}
|
|
||||||
label={`Deleting '${cardTitle}'`}
|
|
||||||
styles={{ root: { height: cardDeleteSpinnerHeight } }}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
)}
|
|
||||||
{!isDeletingPublishedNotebook && (
|
|
||||||
<>
|
|
||||||
<Card.Item tokens={{ padding: cardItemGapBig }}>
|
|
||||||
<Persona imageUrl={data.isSample && CosmosDBLogo} text={data.author} secondaryText={dateString} />
|
|
||||||
</Card.Item>
|
|
||||||
|
|
||||||
<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.map((tag, index, array) => (
|
|
||||||
<span key={tag}>
|
|
||||||
<Link onClick={(event) => handlerOnClick(event, () => onTagClick(tag))}>{tag}</Link>
|
|
||||||
{index === array.length - 1 ? <></> : ", "}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<br />
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
fontWeight: FontWeights.semibold,
|
|
||||||
paddingTop: cardItemGapSmall,
|
|
||||||
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.downloads !== undefined && generateIconText("Download", data.downloads.toString())}
|
|
||||||
{data.favorites !== undefined && generateIconText("Heart", data.favorites.toString())}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
|
|
||||||
{cardButtonsVisible && (
|
|
||||||
<Card.Section
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
marginLeft: cardItemGapBig,
|
|
||||||
marginRight: cardItemGapBig,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{isFavorite !== undefined &&
|
|
||||||
generateIconButtonWithTooltip(
|
|
||||||
isFavorite ? "HeartFill" : "Heart",
|
|
||||||
isFavorite ? "Unfavorite" : "Favorite",
|
|
||||||
"left",
|
|
||||||
isFavorite ? onUnfavoriteClick : onFavoriteClick
|
|
||||||
)}
|
|
||||||
|
|
||||||
{showDownload && generateIconButtonWithTooltip("Download", "Download", "left", onDownloadClick)}
|
|
||||||
|
|
||||||
{showDelete &&
|
|
||||||
generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
|
||||||
onDeleteClick(
|
|
||||||
() => setIsDeletingPublishedNotebook(true),
|
|
||||||
() => setIsDeletingPublishedNotebook(false)
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
jest.mock("../../../../Juno/JunoClient");
|
jest.mock("../../../Juno/JunoClient");
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CodeOfConductComponent, CodeOfConductComponentProps } from ".";
|
import { CodeOfConductComponent, CodeOfConductComponentProps } from "./CodeOfConductComponent";
|
||||||
import { HttpStatusCodes } from "../../../../Common/Constants";
|
import { JunoClient } from "../../../Juno/JunoClient";
|
||||||
import { JunoClient } from "../../../../Juno/JunoClient";
|
import { HttpStatusCodes } from "../../../Common/Constants";
|
||||||
|
|
||||||
describe("CodeOfConductComponent", () => {
|
describe("CodeOfConductComponent", () => {
|
||||||
let codeOfConductProps: CodeOfConductComponentProps;
|
let codeOfConductProps: CodeOfConductComponentProps;
|
||||||
123
src/Explorer/Controls/NotebookGallery/CodeOfConductComponent.tsx
Normal file
123
src/Explorer/Controls/NotebookGallery/CodeOfConductComponent.tsx
Normal 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 "office-ui-fabric-react";
|
||||||
|
import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils";
|
||||||
|
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
|
||||||
|
export interface CodeOfConductComponentProps {
|
||||||
|
junoClient: JunoClient;
|
||||||
|
onAcceptCodeOfConduct: (result: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CodeOfConductComponentState {
|
||||||
|
readCodeOfConduct: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CodeOfConductComponent extends React.Component<CodeOfConductComponentProps, CodeOfConductComponentState> {
|
||||||
|
private viewCodeOfConductTraced: boolean;
|
||||||
|
private descriptionPara1: string;
|
||||||
|
private descriptionPara2: string;
|
||||||
|
private descriptionPara3: string;
|
||||||
|
private link1: { label: string; url: string };
|
||||||
|
|
||||||
|
constructor(props: CodeOfConductComponentProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
readCodeOfConduct: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
||||||
|
this.descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
||||||
|
this.descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
||||||
|
this.link1 = { label: "code of conduct.", url: CodeOfConductEndpoints.codeOfConduct };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async acceptCodeOfConduct(): Promise<void> {
|
||||||
|
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.props.junoClient.acceptCodeOfConduct();
|
||||||
|
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
||||||
|
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
||||||
|
}
|
||||||
|
|
||||||
|
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
||||||
|
|
||||||
|
this.props.onAcceptCodeOfConduct(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
traceFailure(
|
||||||
|
Action.NotebooksGalleryAcceptCodeOfConduct,
|
||||||
|
{
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
errorStack: getErrorStack(error),
|
||||||
|
},
|
||||||
|
startKey
|
||||||
|
);
|
||||||
|
|
||||||
|
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onChangeCheckbox = (): void => {
|
||||||
|
this.setState({ readCodeOfConduct: !this.state.readCodeOfConduct });
|
||||||
|
};
|
||||||
|
|
||||||
|
public render(): JSX.Element {
|
||||||
|
if (!this.viewCodeOfConductTraced) {
|
||||||
|
this.viewCodeOfConductTraced = true;
|
||||||
|
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack tokens={{ childrenGap: 20 }}>
|
||||||
|
<Stack.Item>
|
||||||
|
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{this.descriptionPara1}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>{this.descriptionPara2}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>
|
||||||
|
{this.descriptionPara3}
|
||||||
|
<Link href={this.link1.url} target="_blank">
|
||||||
|
{this.link1.label}
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Checkbox
|
||||||
|
styles={{
|
||||||
|
label: {
|
||||||
|
margin: 0,
|
||||||
|
padding: "2 0 2 0",
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label="I have read and accept the code of conduct."
|
||||||
|
onChange={this.onChangeCheckbox}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<PrimaryButton
|
||||||
|
ariaLabel="Continue"
|
||||||
|
title="Continue"
|
||||||
|
onClick={async () => await this.acceptCodeOfConduct()}
|
||||||
|
tabIndex={0}
|
||||||
|
className="genericPaneSubmitBtn"
|
||||||
|
text="Continue"
|
||||||
|
disabled={!this.state.readCodeOfConduct}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import { Checkbox, Link, PrimaryButton, Stack, Text } from "office-ui-fabric-react";
|
|
||||||
import React, { FunctionComponent, useEffect, useState } from "react";
|
|
||||||
import { CodeOfConductEndpoints, HttpStatusCodes } from "../../../../Common/Constants";
|
|
||||||
import { getErrorMessage, getErrorStack, handleError } from "../../../../Common/ErrorHandlingUtils";
|
|
||||||
import { JunoClient } from "../../../../Juno/JunoClient";
|
|
||||||
import { Action } from "../../../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
import { trace, traceFailure, traceStart, traceSuccess } from "../../../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
|
|
||||||
export interface CodeOfConductComponentProps {
|
|
||||||
junoClient: JunoClient;
|
|
||||||
onAcceptCodeOfConduct: (result: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CodeOfConductComponent: FunctionComponent<CodeOfConductComponentProps> = ({
|
|
||||||
junoClient,
|
|
||||||
onAcceptCodeOfConduct,
|
|
||||||
}: CodeOfConductComponentProps) => {
|
|
||||||
const descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
|
||||||
const descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
|
||||||
const descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
|
||||||
const link1: { label: string; url: string } = {
|
|
||||||
label: "code of conduct.",
|
|
||||||
url: CodeOfConductEndpoints.codeOfConduct,
|
|
||||||
};
|
|
||||||
|
|
||||||
const [readCodeOfConduct, setReadCodeOfConduct] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const acceptCodeOfConduct = async (): Promise<void> => {
|
|
||||||
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await junoClient.acceptCodeOfConduct();
|
|
||||||
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
|
||||||
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
|
||||||
}
|
|
||||||
|
|
||||||
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
|
||||||
|
|
||||||
onAcceptCodeOfConduct(response.data);
|
|
||||||
} catch (error) {
|
|
||||||
traceFailure(
|
|
||||||
Action.NotebooksGalleryAcceptCodeOfConduct,
|
|
||||||
{
|
|
||||||
error: getErrorMessage(error),
|
|
||||||
errorStack: getErrorStack(error),
|
|
||||||
},
|
|
||||||
startKey
|
|
||||||
);
|
|
||||||
|
|
||||||
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChangeCheckbox = (): void => {
|
|
||||||
setReadCodeOfConduct(!readCodeOfConduct);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack tokens={{ childrenGap: 20 }}>
|
|
||||||
<Stack.Item>
|
|
||||||
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{descriptionPara1}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>{descriptionPara2}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>
|
|
||||||
{descriptionPara3}
|
|
||||||
<Link href={link1.url} target="_blank">
|
|
||||||
{link1.label}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Checkbox
|
|
||||||
styles={{
|
|
||||||
label: {
|
|
||||||
margin: 0,
|
|
||||||
padding: "2 0 2 0",
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
fontSize: 12,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
label="I have read and accept the code of conduct."
|
|
||||||
onChange={onChangeCheckbox}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<PrimaryButton
|
|
||||||
ariaLabel="Continue"
|
|
||||||
title="Continue"
|
|
||||||
onClick={async () => await acceptCodeOfConduct()}
|
|
||||||
tabIndex={0}
|
|
||||||
className="genericPaneSubmitBtn"
|
|
||||||
text="Continue"
|
|
||||||
disabled={!readCodeOfConduct}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import ko from "knockout";
|
||||||
|
import * as React from "react";
|
||||||
|
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||||
|
import {
|
||||||
|
GalleryAndNotebookViewerComponentProps,
|
||||||
|
GalleryAndNotebookViewerComponent,
|
||||||
|
} from "./GalleryAndNotebookViewerComponent";
|
||||||
|
|
||||||
|
export class GalleryAndNotebookViewerComponentAdapter implements ReactAdapter {
|
||||||
|
private key: string;
|
||||||
|
public parameters: ko.Observable<number>;
|
||||||
|
|
||||||
|
constructor(private props: GalleryAndNotebookViewerComponentProps) {
|
||||||
|
this.reset();
|
||||||
|
this.parameters = ko.observable<number>(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderComponent(): JSX.Element {
|
||||||
|
return <GalleryAndNotebookViewerComponent key={this.key} {...this.props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset(): void {
|
||||||
|
this.key = `GalleryAndNotebookViewerComponent-${Date.now()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public triggerRender(): void {
|
||||||
|
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,20 +21,19 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { HttpStatusCodes } from "../../../Common/Constants";
|
|
||||||
import { handleError } from "../../../Common/ErrorHandlingUtils";
|
|
||||||
import { IGalleryItem, IJunoResponse, IPublicGalleryData, JunoClient } from "../../../Juno/JunoClient";
|
import { IGalleryItem, IJunoResponse, IPublicGalleryData, JunoClient } from "../../../Juno/JunoClient";
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
import { trace } from "../../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import * as GalleryUtils from "../../../Utils/GalleryUtils";
|
import * as GalleryUtils from "../../../Utils/GalleryUtils";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { Dialog, DialogProps } from "../Dialog";
|
import { Dialog, DialogProps } from "../Dialog";
|
||||||
import { GalleryCardComponent, GalleryCardComponentProps } from "./Cards/GalleryCardComponent";
|
import { GalleryCardComponent, GalleryCardComponentProps } from "./Cards/GalleryCardComponent";
|
||||||
import { CodeOfConductComponent } from "./CodeOfConductComponent";
|
|
||||||
import "./GalleryViewerComponent.less";
|
import "./GalleryViewerComponent.less";
|
||||||
|
import { HttpStatusCodes } from "../../../Common/Constants";
|
||||||
|
import Explorer from "../../Explorer";
|
||||||
|
import { CodeOfConductComponent } from "./CodeOfConductComponent";
|
||||||
import { InfoComponent } from "./InfoComponent/InfoComponent";
|
import { InfoComponent } from "./InfoComponent/InfoComponent";
|
||||||
|
import { handleError } from "../../../Common/ErrorHandlingUtils";
|
||||||
|
import { trace } from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
|
||||||
const CARD_WIDTH = 256;
|
|
||||||
export interface GalleryViewerComponentProps {
|
export interface GalleryViewerComponentProps {
|
||||||
container?: Explorer;
|
container?: Explorer;
|
||||||
junoClient: JunoClient;
|
junoClient: JunoClient;
|
||||||
@@ -139,11 +138,11 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
|
|||||||
key: SortBy.MostRecent,
|
key: SortBy.MostRecent,
|
||||||
text: GalleryViewerComponent.mostRecentText,
|
text: GalleryViewerComponent.mostRecentText,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: SortBy.MostFavorited,
|
|
||||||
text: GalleryViewerComponent.mostFavoritedText,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
this.sortingOptions.push({
|
||||||
|
key: SortBy.MostFavorited,
|
||||||
|
text: GalleryViewerComponent.mostFavoritedText,
|
||||||
|
});
|
||||||
|
|
||||||
this.loadTabContent(this.state.selectedTab, this.state.searchText, this.state.sortBy, false);
|
this.loadTabContent(this.state.selectedTab, this.state.searchText, this.state.sortBy, false);
|
||||||
this.loadFavoriteNotebooks(this.state.searchText, this.state.sortBy, false); // Need this to show correct favorite button state
|
this.loadFavoriteNotebooks(this.state.searchText, this.state.sortBy, false); // Need this to show correct favorite button state
|
||||||
@@ -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 / GalleryCardComponent.CARD_WIDTH) || this.columnCount;
|
||||||
this.rowCount = GalleryViewerComponent.rowsPerPage;
|
this.rowCount = GalleryViewerComponent.rowsPerPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,8 +654,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onRenderCell = (data?: IGalleryItem): JSX.Element => {
|
private onRenderCell = (data?: IGalleryItem): JSX.Element => {
|
||||||
const isFavorite =
|
const isFavorite = this.favoriteNotebooks?.find((item) => item.id === data.id) !== undefined;
|
||||||
this.props.container && this.favoriteNotebooks?.find((item) => item.id === data.id) !== undefined;
|
|
||||||
const props: GalleryCardComponentProps = {
|
const props: GalleryCardComponentProps = {
|
||||||
data,
|
data,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
|||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
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 { updateUserContext } from "../../../UserContext";
|
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { CollectionSettingsTabV2 } from "../../Tabs/SettingsTabV2";
|
import { CollectionSettingsTabV2 } from "../../Tabs/SettingsTabV2";
|
||||||
import { SettingsComponent, SettingsComponentProps, SettingsComponentState } from "./SettingsComponent";
|
import { SettingsComponent, SettingsComponentProps, SettingsComponentState } from "./SettingsComponent";
|
||||||
@@ -39,6 +38,7 @@ describe("SettingsComponent", () => {
|
|||||||
tabPath: "",
|
tabPath: "",
|
||||||
node: undefined,
|
node: undefined,
|
||||||
hashLocation: "settings",
|
hashLocation: "settings",
|
||||||
|
isActive: ko.observable(false),
|
||||||
onUpdateTabsButtons: undefined,
|
onUpdateTabsButtons: undefined,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -107,13 +107,7 @@ describe("SettingsComponent", () => {
|
|||||||
expect(settingsComponentInstance.shouldShowKeyspaceSharedThroughputMessage()).toEqual(false);
|
expect(settingsComponentInstance.shouldShowKeyspaceSharedThroughputMessage()).toEqual(false);
|
||||||
|
|
||||||
const newContainer = new Explorer();
|
const newContainer = new Explorer();
|
||||||
updateUserContext({
|
newContainer.isPreferredApiCassandra = ko.computed(() => true);
|
||||||
databaseAccount: {
|
|
||||||
properties: {
|
|
||||||
capabilities: [{ name: "EnableCassandra" }],
|
|
||||||
},
|
|
||||||
} as DataModels.DatabaseAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
const newCollection = { ...collection };
|
const newCollection = { ...collection };
|
||||||
newCollection.container = newContainer;
|
newCollection.container = newContainer;
|
||||||
|
|||||||
@@ -136,13 +136,15 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
this.container = this.collection?.container;
|
this.container = this.collection?.container;
|
||||||
this.offer = this.collection?.offer();
|
this.offer = this.collection?.offer();
|
||||||
this.isAnalyticalStorageEnabled = !!this.collection?.analyticalStorageTtl();
|
this.isAnalyticalStorageEnabled = !!this.collection?.analyticalStorageTtl();
|
||||||
this.shouldShowIndexingPolicyEditor = userContext.apiType !== "Cassandra" && userContext.apiType !== "Mongo";
|
this.shouldShowIndexingPolicyEditor =
|
||||||
|
this.container && !this.container.isPreferredApiCassandra() && !this.container.isPreferredApiMongoDB();
|
||||||
|
|
||||||
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
||||||
|
|
||||||
// Mongo container with system partition key still treat as "Fixed"
|
// Mongo container with system partition key still treat as "Fixed"
|
||||||
this.isFixedContainer =
|
this.isFixedContainer =
|
||||||
userContext.apiType === "Mongo" && (!this.collection?.partitionKey || this.collection?.partitionKey.systemKey);
|
this.container.isPreferredApiMongoDB() &&
|
||||||
|
(!this.collection?.partitionKey || this.collection?.partitionKey.systemKey);
|
||||||
} else {
|
} else {
|
||||||
this.database = this.props.settingsTab.database;
|
this.database = this.props.settingsTab.database;
|
||||||
this.container = this.database?.container;
|
this.container = this.database?.container;
|
||||||
@@ -234,7 +236,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
|
|
||||||
public loadMongoIndexes = async (): Promise<void> => {
|
public loadMongoIndexes = async (): Promise<void> => {
|
||||||
if (
|
if (
|
||||||
userContext.apiType === "Mongo" &&
|
this.container.isPreferredApiMongoDB() &&
|
||||||
this.container.isEnableMongoCapabilityPresent() &&
|
this.container.isEnableMongoCapabilityPresent() &&
|
||||||
this.container.databaseAccount()
|
this.container.databaseAccount()
|
||||||
) {
|
) {
|
||||||
@@ -297,7 +299,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
this.state.wasAutopilotOriginallySet !== this.state.isAutoPilotSelected;
|
this.state.wasAutopilotOriginallySet !== this.state.isAutoPilotSelected;
|
||||||
|
|
||||||
public shouldShowKeyspaceSharedThroughputMessage = (): boolean =>
|
public shouldShowKeyspaceSharedThroughputMessage = (): boolean =>
|
||||||
this.container && userContext.apiType === "Cassandra" && hasDatabaseSharedThroughput(this.collection);
|
this.container && this.container.isPreferredApiCassandra() && hasDatabaseSharedThroughput(this.collection);
|
||||||
|
|
||||||
public hasConflictResolution = (): boolean =>
|
public hasConflictResolution = (): boolean =>
|
||||||
this.container?.databaseAccount &&
|
this.container?.databaseAccount &&
|
||||||
@@ -1000,7 +1002,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
tab: SettingsV2TabTypes.IndexingPolicyTab,
|
tab: SettingsV2TabTypes.IndexingPolicyTab,
|
||||||
content: <IndexingPolicyComponent {...indexingPolicyComponentProps} />,
|
content: <IndexingPolicyComponent {...indexingPolicyComponentProps} />,
|
||||||
});
|
});
|
||||||
} else if (userContext.apiType === "Mongo") {
|
} else if (this.container.isPreferredApiMongoDB()) {
|
||||||
const mongoIndexTabContext = this.getMongoIndexTabContent(mongoIndexingPolicyComponentProps);
|
const mongoIndexTabContext = this.getMongoIndexTabContent(mongoIndexingPolicyComponentProps);
|
||||||
if (mongoIndexTabContext) {
|
if (mongoIndexTabContext) {
|
||||||
tabs.push({
|
tabs.push({
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { MessageBar, MessageBarType, Stack } from "office-ui-fabric-react";
|
|
||||||
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 * as monaco from "monaco-editor";
|
||||||
import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils";
|
|
||||||
import { isDirty, isIndexTransforming } from "../SettingsUtils";
|
import { isDirty, isIndexTransforming } from "../SettingsUtils";
|
||||||
|
import { MessageBar, MessageBarType, Stack } from "office-ui-fabric-react";
|
||||||
|
import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils";
|
||||||
import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent";
|
import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent";
|
||||||
|
|
||||||
export interface IndexingPolicyComponentProps {
|
export interface IndexingPolicyComponentProps {
|
||||||
@@ -84,9 +84,9 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
private async createIndexingPolicyEditor(): Promise<void> {
|
private createIndexingPolicyEditor = (): void => {
|
||||||
const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
|
const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
|
||||||
const monaco = await loadMonaco();
|
|
||||||
this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
|
this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
|
||||||
value: value,
|
value: value,
|
||||||
language: "json",
|
language: "json",
|
||||||
@@ -98,7 +98,7 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
||||||
this.props.logIndexingPolicySuccessMessage();
|
this.props.logIndexingPolicySuccessMessage();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private onEditorContentChange = (): void => {
|
private onEditorContentChange = (): void => {
|
||||||
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { DatabaseAccount } from "../../../../Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "../../../../UserContext";
|
|
||||||
import Explorer from "../../../Explorer";
|
|
||||||
import { ChangeFeedPolicyState, GeospatialConfigType, TtlOff, TtlOn, TtlOnNoDefault, TtlType } from "../SettingsUtils";
|
|
||||||
import { collection, container } from "../TestUtils";
|
|
||||||
import { SubSettingsComponent, SubSettingsComponentProps } from "./SubSettingsComponent";
|
import { SubSettingsComponent, SubSettingsComponentProps } from "./SubSettingsComponent";
|
||||||
|
import { container, collection } from "../TestUtils";
|
||||||
|
import { TtlType, GeospatialConfigType, ChangeFeedPolicyState, TtlOnNoDefault, TtlOn, TtlOff } from "../SettingsUtils";
|
||||||
|
import ko from "knockout";
|
||||||
|
import Explorer from "../../../Explorer";
|
||||||
|
|
||||||
describe("SubSettingsComponent", () => {
|
describe("SubSettingsComponent", () => {
|
||||||
|
container.isPreferredApiDocumentDB = ko.computed(() => true);
|
||||||
|
|
||||||
const baseProps: SubSettingsComponentProps = {
|
const baseProps: SubSettingsComponentProps = {
|
||||||
collection: collection,
|
collection: collection,
|
||||||
container: container,
|
container: container,
|
||||||
@@ -105,13 +106,8 @@ describe("SubSettingsComponent", () => {
|
|||||||
|
|
||||||
it("partitionKey not visible", () => {
|
it("partitionKey not visible", () => {
|
||||||
const newContainer = new Explorer();
|
const newContainer = new Explorer();
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
newContainer.isPreferredApiCassandra = ko.computed(() => true);
|
||||||
properties: {
|
|
||||||
capabilities: [{ name: "EnableCassandra" }],
|
|
||||||
},
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
const props = { ...baseProps, container: newContainer };
|
const props = { ...baseProps, container: newContainer };
|
||||||
const subSettingsComponent = new SubSettingsComponent(props);
|
const subSettingsComponent = new SubSettingsComponent(props);
|
||||||
expect(subSettingsComponent.getPartitionKeyVisible()).toEqual(false);
|
expect(subSettingsComponent.getPartitionKeyVisible()).toEqual(false);
|
||||||
|
|||||||
@@ -1,38 +1,28 @@
|
|||||||
import {
|
|
||||||
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 {
|
||||||
|
GeospatialConfigType,
|
||||||
|
TtlType,
|
||||||
|
ChangeFeedPolicyState,
|
||||||
|
isDirty,
|
||||||
|
IsComponentDirtyResult,
|
||||||
|
TtlOn,
|
||||||
|
TtlOff,
|
||||||
|
TtlOnNoDefault,
|
||||||
|
getSanitizedInputValue,
|
||||||
|
} from "../SettingsUtils";
|
||||||
import Explorer from "../../../Explorer";
|
import Explorer from "../../../Explorer";
|
||||||
import { Int32 } from "../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
import { Int32 } from "../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
||||||
|
import { Label, Text, TextField, Stack, IChoiceGroupOption, ChoiceGroup, MessageBar } from "office-ui-fabric-react";
|
||||||
import {
|
import {
|
||||||
changeFeedPolicyToolTip,
|
|
||||||
getChoiceGroupStyles,
|
|
||||||
getTextFieldStyles,
|
getTextFieldStyles,
|
||||||
messageBarStyles,
|
changeFeedPolicyToolTip,
|
||||||
subComponentStackProps,
|
subComponentStackProps,
|
||||||
titleAndInputStackProps,
|
titleAndInputStackProps,
|
||||||
|
getChoiceGroupStyles,
|
||||||
ttlWarning,
|
ttlWarning,
|
||||||
|
messageBarStyles,
|
||||||
} from "../SettingsRenderUtils";
|
} from "../SettingsRenderUtils";
|
||||||
import {
|
|
||||||
ChangeFeedPolicyState,
|
|
||||||
GeospatialConfigType,
|
|
||||||
getSanitizedInputValue,
|
|
||||||
IsComponentDirtyResult,
|
|
||||||
isDirty,
|
|
||||||
TtlOff,
|
|
||||||
TtlOn,
|
|
||||||
TtlOnNoDefault,
|
|
||||||
TtlType,
|
|
||||||
} from "../SettingsUtils";
|
|
||||||
import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
|
import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
|
||||||
|
|
||||||
export interface SubSettingsComponentProps {
|
export interface SubSettingsComponentProps {
|
||||||
@@ -70,15 +60,17 @@ export interface SubSettingsComponentProps {
|
|||||||
|
|
||||||
export class SubSettingsComponent extends React.Component<SubSettingsComponentProps> {
|
export class SubSettingsComponent extends React.Component<SubSettingsComponentProps> {
|
||||||
private shouldCheckComponentIsDirty = true;
|
private shouldCheckComponentIsDirty = true;
|
||||||
|
private ttlVisible: boolean;
|
||||||
private geospatialVisible: boolean;
|
private geospatialVisible: boolean;
|
||||||
private partitionKeyValue: string;
|
private partitionKeyValue: string;
|
||||||
private partitionKeyName: string;
|
private partitionKeyName: string;
|
||||||
|
|
||||||
constructor(props: SubSettingsComponentProps) {
|
constructor(props: SubSettingsComponentProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.geospatialVisible = userContext.apiType === "SQL";
|
this.ttlVisible = (this.props.container && !this.props.container.isPreferredApiCassandra()) || false;
|
||||||
|
this.geospatialVisible = this.props.container.isPreferredApiDocumentDB();
|
||||||
this.partitionKeyValue = "/" + this.props.collection.partitionKeyProperty;
|
this.partitionKeyValue = "/" + this.props.collection.partitionKeyProperty;
|
||||||
this.partitionKeyName = userContext.apiType === "Mongo" ? "Shard key" : "Partition key";
|
this.partitionKeyName = this.props.container.isPreferredApiMongoDB() ? "Shard key" : "Partition key";
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
@@ -178,51 +170,39 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
): void =>
|
): void =>
|
||||||
this.props.onChangeFeedPolicyChange(ChangeFeedPolicyState[option.key as keyof typeof ChangeFeedPolicyState]);
|
this.props.onChangeFeedPolicyChange(ChangeFeedPolicyState[option.key as keyof typeof ChangeFeedPolicyState]);
|
||||||
|
|
||||||
private getTtlComponent = (): JSX.Element =>
|
private getTtlComponent = (): JSX.Element => (
|
||||||
userContext.apiType === "Mongo" ? (
|
<Stack {...titleAndInputStackProps}>
|
||||||
<MessageBar
|
<ChoiceGroup
|
||||||
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
|
id="timeToLive"
|
||||||
styles={{ text: { fontSize: 14 } }}
|
label="Time to Live"
|
||||||
>
|
selectedKey={this.props.timeToLive}
|
||||||
To enable time-to-live (TTL) for your collection/documents,
|
options={this.ttlChoiceGroupOptions}
|
||||||
<Link href="https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb-time-to-live" target="_blank">
|
onChange={this.onTtlChange}
|
||||||
create a TTL index
|
styles={getChoiceGroupStyles(this.props.timeToLive, this.props.timeToLiveBaseline)}
|
||||||
</Link>
|
/>
|
||||||
.
|
{isDirty(this.props.timeToLive, this.props.timeToLiveBaseline) && this.props.timeToLive === TtlType.On && (
|
||||||
</MessageBar>
|
<MessageBar
|
||||||
) : (
|
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
|
||||||
<Stack {...titleAndInputStackProps}>
|
styles={messageBarStyles}
|
||||||
<ChoiceGroup
|
>
|
||||||
id="timeToLive"
|
{ttlWarning}
|
||||||
label="Time to Live"
|
</MessageBar>
|
||||||
selectedKey={this.props.timeToLive}
|
)}
|
||||||
options={this.ttlChoiceGroupOptions}
|
{this.props.timeToLive === TtlType.On && (
|
||||||
onChange={this.onTtlChange}
|
<TextField
|
||||||
styles={getChoiceGroupStyles(this.props.timeToLive, this.props.timeToLiveBaseline)}
|
id="timeToLiveSeconds"
|
||||||
|
styles={getTextFieldStyles(this.props.timeToLiveSeconds, this.props.timeToLiveSecondsBaseline)}
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
min={1}
|
||||||
|
max={Int32.Max}
|
||||||
|
value={this.props.timeToLiveSeconds?.toString()}
|
||||||
|
onChange={this.onTimeToLiveSecondsChange}
|
||||||
|
suffix="second(s)"
|
||||||
/>
|
/>
|
||||||
{isDirty(this.props.timeToLive, this.props.timeToLiveBaseline) && this.props.timeToLive === TtlType.On && (
|
)}
|
||||||
<MessageBar
|
</Stack>
|
||||||
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
|
);
|
||||||
styles={messageBarStyles}
|
|
||||||
>
|
|
||||||
{ttlWarning}
|
|
||||||
</MessageBar>
|
|
||||||
)}
|
|
||||||
{this.props.timeToLive === TtlType.On && (
|
|
||||||
<TextField
|
|
||||||
id="timeToLiveSeconds"
|
|
||||||
styles={getTextFieldStyles(this.props.timeToLiveSeconds, this.props.timeToLiveSecondsBaseline)}
|
|
||||||
type="number"
|
|
||||||
required
|
|
||||||
min={1}
|
|
||||||
max={Int32.Max}
|
|
||||||
value={this.props.timeToLiveSeconds?.toString()}
|
|
||||||
onChange={this.onTimeToLiveSecondsChange}
|
|
||||||
suffix="second(s)"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
|
|
||||||
private analyticalTtlChoiceGroupOptions: IChoiceGroupOption[] = [
|
private analyticalTtlChoiceGroupOptions: IChoiceGroupOption[] = [
|
||||||
{ key: TtlType.Off, text: "Off", disabled: true },
|
{ key: TtlType.Off, text: "Off", disabled: true },
|
||||||
@@ -320,10 +300,10 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
|
|
||||||
public getPartitionKeyVisible = (): boolean => {
|
public getPartitionKeyVisible = (): boolean => {
|
||||||
if (
|
if (
|
||||||
userContext.apiType === "Cassandra" ||
|
this.props.container.isPreferredApiCassandra() ||
|
||||||
userContext.apiType === "Tables" ||
|
this.props.container.isPreferredApiTable() ||
|
||||||
!this.props.collection.partitionKeyProperty ||
|
!this.props.collection.partitionKeyProperty ||
|
||||||
(userContext.apiType === "Mongo" && this.props.collection.partitionKey.systemKey)
|
(this.props.container.isPreferredApiMongoDB() && this.props.collection.partitionKey.systemKey)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -335,7 +315,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...subComponentStackProps}>
|
<Stack {...subComponentStackProps}>
|
||||||
{userContext.apiType !== "Cassandra" && this.getTtlComponent()}
|
{this.ttlVisible && this.getTtlComponent()}
|
||||||
|
|
||||||
{this.geospatialVisible && this.getGeoSpatialComponent()}
|
{this.geospatialVisible && this.getGeoSpatialComponent()}
|
||||||
|
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
<em>
|
<em>
|
||||||
This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
||||||
</em>
|
</em>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -689,7 +689,7 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
<em>
|
<em>
|
||||||
This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
||||||
</em>
|
</em>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user