mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 19:01:28 +00:00
Compare commits
9 Commits
Remove-Exp
...
e2e-test-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4be1389705 | ||
|
|
65844414dd | ||
|
|
b9461de695 | ||
|
|
0473c49cc6 | ||
|
|
53ea8dc528 | ||
|
|
8b7d43823a | ||
|
|
3ab7e93bab | ||
|
|
9e2efa01e5 | ||
|
|
ba5ab37bac |
@@ -4,8 +4,6 @@ PORTAL_RUNNER_SUBSCRIPTION=
|
||||
PORTAL_RUNNER_RESOURCE_GROUP=
|
||||
PORTAL_RUNNER_DATABASE_ACCOUNT=
|
||||
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY=
|
||||
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT=
|
||||
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY=
|
||||
PORTAL_RUNNER_CONNECTION_STRING=
|
||||
NOTEBOOKS_TEST_RUNNER_TENANT_ID=
|
||||
NOTEBOOKS_TEST_RUNNER_CLIENT_ID=
|
||||
|
||||
@@ -11,9 +11,15 @@ src/Common/CosmosClient.test.ts
|
||||
src/Common/CosmosClient.ts
|
||||
src/Common/DataAccessUtilityBase.test.ts
|
||||
src/Common/DataAccessUtilityBase.ts
|
||||
src/Common/DeleteFeedback.ts
|
||||
src/Common/DocumentClientUtilityBase.ts
|
||||
src/Common/EditableUtility.ts
|
||||
src/Common/HashMap.test.ts
|
||||
src/Common/HashMap.ts
|
||||
src/Common/HeadersUtility.test.ts
|
||||
src/Common/HeadersUtility.ts
|
||||
src/Common/IteratorUtilities.test.ts
|
||||
src/Common/IteratorUtilities.ts
|
||||
src/Common/Logger.test.ts
|
||||
src/Common/MessageHandler.test.ts
|
||||
src/Common/MessageHandler.ts
|
||||
@@ -24,6 +30,8 @@ src/Common/ObjectCache.test.ts
|
||||
src/Common/ObjectCache.ts
|
||||
src/Common/QueriesClient.ts
|
||||
src/Common/Splitter.ts
|
||||
src/Common/ThemeUtility.ts
|
||||
src/Common/UrlUtility.ts
|
||||
src/Config.ts
|
||||
src/Contracts/ActionContracts.ts
|
||||
src/Contracts/DataModels.ts
|
||||
@@ -34,6 +42,7 @@ src/Contracts/ViewModels.ts
|
||||
src/Controls/Heatmap/Heatmap.test.ts
|
||||
src/Controls/Heatmap/Heatmap.ts
|
||||
src/Controls/Heatmap/HeatmapDatatypes.ts
|
||||
src/Definitions/adal.d.ts
|
||||
src/Definitions/datatables.d.ts
|
||||
src/Definitions/gif.d.ts
|
||||
src/Definitions/globals.d.ts
|
||||
@@ -45,10 +54,13 @@ src/Definitions/jquery.d.ts
|
||||
src/Definitions/plotly.js-cartesian-dist.d-min.ts
|
||||
src/Definitions/png.d.ts
|
||||
src/Definitions/svg.d.ts
|
||||
src/Definitions/worker.d.ts
|
||||
src/Explorer/ComponentRegisterer.test.ts
|
||||
src/Explorer/ComponentRegisterer.ts
|
||||
src/Explorer/ContextMenuButtonFactory.ts
|
||||
src/Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.ts
|
||||
src/Explorer/Controls/CommandButton/CommandButton.test.ts
|
||||
src/Explorer/Controls/CommandButton/CommandButton.ts
|
||||
src/Explorer/Controls/DiffEditor/DiffEditorComponent.ts
|
||||
src/Explorer/Controls/DynamicList/DynamicList.test.ts
|
||||
src/Explorer/Controls/DynamicList/DynamicListComponent.ts
|
||||
@@ -76,7 +88,7 @@ src/Explorer/DataSamples/ContainerSampleGenerator.test.ts
|
||||
src/Explorer/DataSamples/ContainerSampleGenerator.ts
|
||||
src/Explorer/DataSamples/DataSamplesUtil.test.ts
|
||||
src/Explorer/DataSamples/DataSamplesUtil.ts
|
||||
src/Explorer/Explorer.tsx
|
||||
src/Explorer/Explorer.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts
|
||||
@@ -84,17 +96,22 @@ src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphUtil.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphUtil.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
||||
src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.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.ts
|
||||
src/Explorer/Menus/ContextMenu.ts
|
||||
src/Explorer/MostRecentActivity/MostRecentActivity.ts
|
||||
src/Explorer/Notebook/FileSystemUtil.ts
|
||||
src/Explorer/Notebook/NTeractUtil.ts
|
||||
src/Explorer/Notebook/NotebookClientV2.ts
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookContentProvider.ts
|
||||
src/Explorer/Notebook/NotebookComponent/__mocks__/rx-jupyter.ts
|
||||
@@ -119,21 +136,34 @@ src/Explorer/Panes/AddDatabasePane.ts
|
||||
src/Explorer/Panes/BrowseQueriesPane.ts
|
||||
src/Explorer/Panes/CassandraAddCollectionPane.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.ts
|
||||
src/Explorer/Panes/ExecuteSprocParamsPane.ts
|
||||
src/Explorer/Panes/GraphStylingPane.ts
|
||||
# src/Explorer/Panes/NewVertexPane.ts
|
||||
src/Explorer/Panes/LoadQueryPane.ts
|
||||
src/Explorer/Panes/NewVertexPane.ts
|
||||
src/Explorer/Panes/PaneComponents.ts
|
||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||
src/Explorer/Panes/SaveQueryPane.ts
|
||||
src/Explorer/Panes/SettingsPane.test.ts
|
||||
src/Explorer/Panes/SettingsPane.ts
|
||||
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||
src/Explorer/Panes/StringInputPane.ts
|
||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||
src/Explorer/Panes/Tables/AddTableEntityPane.ts
|
||||
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||
src/Explorer/Panes/Tables/QuerySelectPane.ts
|
||||
src/Explorer/Panes/Tables/TableColumnOptionsPane.ts
|
||||
src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
||||
src/Explorer/SplashScreen/SplashScreen.test.ts
|
||||
src/Explorer/Panes/UploadFilePane.ts
|
||||
src/Explorer/Panes/UploadItemsPane.ts
|
||||
src/Explorer/SplashScreen/SplashScreenComponentAdapter.test.ts
|
||||
src/Explorer/Tables/Constants.ts
|
||||
src/Explorer/Tables/DataTable/CacheBase.ts
|
||||
src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
||||
@@ -141,6 +171,7 @@ src/Explorer/Tables/DataTable/DataTableBuilder.ts
|
||||
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
|
||||
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
|
||||
src/Explorer/Tables/DataTable/DataTableOperations.ts
|
||||
src/Explorer/Tables/DataTable/DataTableUtilities.ts
|
||||
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
||||
src/Explorer/Tables/DataTable/TableCommands.ts
|
||||
src/Explorer/Tables/DataTable/TableEntityCache.ts
|
||||
@@ -149,6 +180,8 @@ src/Explorer/Tables/Entities.ts
|
||||
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
|
||||
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
|
||||
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
||||
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.test.ts
|
||||
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts
|
||||
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
|
||||
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
|
||||
src/Explorer/Tables/QueryBuilder/QueryViewModel.ts
|
||||
@@ -168,6 +201,7 @@ src/Explorer/Tabs/QueryTab.test.ts
|
||||
src/Explorer/Tabs/QueryTab.ts
|
||||
src/Explorer/Tabs/QueryTablesTab.ts
|
||||
src/Explorer/Tabs/ScriptTabBase.ts
|
||||
src/Explorer/Tabs/SparkMasterTab.ts
|
||||
src/Explorer/Tabs/StoredProcedureTab.ts
|
||||
src/Explorer/Tabs/TabComponents.ts
|
||||
src/Explorer/Tabs/TabsBase.ts
|
||||
@@ -208,6 +242,9 @@ src/Platform/Hosted/Authorization.ts
|
||||
src/Platform/Hosted/DataAccessUtility.ts
|
||||
src/Platform/Hosted/ExplorerFactory.ts
|
||||
src/Platform/Hosted/Helpers/ConnectionStringParser.test.ts
|
||||
src/Platform/Hosted/Helpers/ConnectionStringParser.ts
|
||||
src/Platform/Hosted/HostedUtils.test.ts
|
||||
src/Platform/Hosted/HostedUtils.ts
|
||||
src/Platform/Hosted/Main.ts
|
||||
src/Platform/Hosted/Maint.test.ts
|
||||
src/Platform/Hosted/NotificationsClient.ts
|
||||
@@ -231,6 +268,8 @@ src/Shared/ExplorerSettings.ts
|
||||
src/Shared/PriceEstimateCalculator.ts
|
||||
src/Shared/StorageUtility.test.ts
|
||||
src/Shared/StorageUtility.ts
|
||||
src/Shared/StringUtility.test.ts
|
||||
src/Shared/StringUtility.ts
|
||||
src/Shared/appInsights.ts
|
||||
src/SparkClusterManager/ArcadiaResourceManager.ts
|
||||
src/SparkClusterManager/SparkClusterManager.ts
|
||||
@@ -239,11 +278,26 @@ src/Terminal/NotebookAppContracts.d.ts
|
||||
src/Terminal/index.ts
|
||||
src/TokenProviders/PortalTokenProvider.ts
|
||||
src/TokenProviders/TokenProviderFactory.ts
|
||||
src/Utils/AuthorizationUtils.test.ts
|
||||
src/Utils/AuthorizationUtils.ts
|
||||
src/Utils/AutoPilotUtils.test.ts
|
||||
src/Utils/AutoPilotUtils.ts
|
||||
src/Utils/DatabaseAccountUtils.test.ts
|
||||
src/Utils/DatabaseAccountUtils.ts
|
||||
src/Utils/JunoUtils.ts
|
||||
src/Utils/MessageValidation.ts
|
||||
src/Utils/NotebookConfigurationUtils.ts
|
||||
src/Utils/PricingUtils.test.ts
|
||||
src/Utils/QueryUtils.test.ts
|
||||
src/Utils/QueryUtils.ts
|
||||
src/Utils/StringUtils.test.ts
|
||||
src/Utils/StringUtils.ts
|
||||
src/applyExplorerBindings.ts
|
||||
src/global.d.ts
|
||||
src/quickstart.ts
|
||||
src/setupTests.ts
|
||||
src/workers/upload/definitions.ts
|
||||
src/workers/upload/index.ts
|
||||
src/Explorer/Controls/AccessibleElement/AccessibleElement.tsx
|
||||
src/Explorer/Controls/Accordion/AccordionComponent.tsx
|
||||
src/Explorer/Controls/AccountSwitch/AccountSwitchComponent.test.tsx
|
||||
@@ -289,8 +343,18 @@ src/Explorer/Graph/GraphExplorerComponent/QueryContainerComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNeighborsComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
||||
src/Explorer/Menus/CommandBar/CommandBarComponentAdapter.tsx
|
||||
src/Explorer/Menus/CommandBar/CommandBarUtil.test.tsx
|
||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.tsx
|
||||
src/Explorer/Menus/NavBar/ControlBarComponent.tsx
|
||||
src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx
|
||||
src/Explorer/Menus/NavBar/MeControlComponent.test.tsx
|
||||
src/Explorer/Menus/NavBar/MeControlComponent.tsx
|
||||
src/Explorer/Menus/NavBar/MeControlComponentAdapter.tsx
|
||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx
|
||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx
|
||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponentAdapter.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookComponent.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||
@@ -317,7 +381,8 @@ src/Explorer/Notebook/temp/inputs/editor.tsx
|
||||
src/Explorer/Notebook/temp/markdown-cell.tsx
|
||||
src/Explorer/Notebook/temp/source.tsx
|
||||
src/Explorer/Notebook/temp/syntax-highlighter/index.tsx
|
||||
src/Explorer/SplashScreen/SplashScreen.tsx
|
||||
src/Explorer/SplashScreen/SplashScreenComponent.tsx
|
||||
src/Explorer/SplashScreen/SplashScreenComponentApdapter.tsx
|
||||
src/Explorer/Tabs/GalleryTab.tsx
|
||||
src/Explorer/Tabs/NotebookViewerTab.tsx
|
||||
src/Explorer/Tabs/TerminalTab.tsx
|
||||
|
||||
33
.eslintrc.js
33
.eslintrc.js
@@ -1,39 +1,41 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
es6: true
|
||||
},
|
||||
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks"],
|
||||
plugins: ["@typescript-eslint", "no-null", "prefer-arrow"],
|
||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||
globals: {
|
||||
Atomics: "readonly",
|
||||
SharedArrayBuffer: "readonly",
|
||||
SharedArrayBuffer: "readonly"
|
||||
},
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
jsx: true
|
||||
},
|
||||
ecmaVersion: 2018,
|
||||
sourceType: "module",
|
||||
sourceType: "module"
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["**/*.tsx"],
|
||||
env: {
|
||||
jest: true
|
||||
},
|
||||
extends: ["plugin:react/recommended"],
|
||||
plugins: ["react"],
|
||||
plugins: ["react"]
|
||||
},
|
||||
{
|
||||
files: ["**/*.{test,spec}.{ts,tsx}"],
|
||||
env: {
|
||||
jest: true,
|
||||
jest: true
|
||||
},
|
||||
extends: ["plugin:jest/recommended"],
|
||||
plugins: ["jest"],
|
||||
},
|
||||
plugins: ["jest"]
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
"no-console": ["error", { allow: ["error", "warn", "dir"] }],
|
||||
curly: "error",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
@@ -41,15 +43,12 @@ module.exports = {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
||||
eqeqeq: "error",
|
||||
"react/display-name": "off",
|
||||
"react-hooks/rules-of-hooks": "warn", // TODO: error
|
||||
"react-hooks/exhaustive-deps": "warn", // TODO: error
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector: "CallExpression[callee.object.name='JSON'][callee.property.name='stringify'] Identifier[name=/$err/]",
|
||||
message: "Do not use JSON.stringify(error). It will print '{}'",
|
||||
},
|
||||
],
|
||||
},
|
||||
message: "Do not use JSON.stringify(error). It will print '{}'"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1 +0,0 @@
|
||||
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/EDIT_THIS_NUMBER_IN_THE_PR_DESCRIPTION?feature.someFeatureFlagYouMightNeed=true)
|
||||
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@@ -1,9 +0,0 @@
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
133
.github/workflows/ci.yml
vendored
133
.github/workflows/ci.yml
vendored
@@ -9,29 +9,15 @@ on:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
codemetrics:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Log Code Metrics"
|
||||
if: github.ref == 'refs/heads/master'
|
||||
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/codeMetrics.js
|
||||
env:
|
||||
CODE_METRICS_APP_ID: ${{ secrets.CODE_METRICS_APP_ID }}
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Compile TypeScript"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run compile
|
||||
- run: npm run compile:strict
|
||||
@@ -40,10 +26,10 @@ jobs:
|
||||
name: "Check Format"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run format:check
|
||||
lint:
|
||||
@@ -51,10 +37,10 @@ jobs:
|
||||
name: "Lint"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
unittest:
|
||||
@@ -62,21 +48,22 @@ jobs:
|
||||
name: "Unit Tests"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run test
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, format, compile, unittest]
|
||||
name: "Build"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run build:contracts
|
||||
- name: Restore Build Cache
|
||||
@@ -91,32 +78,23 @@ jobs:
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
- name: Upload build to preview blob storage
|
||||
run: az storage blob upload-batch -d '$web' -s 'dist' --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --destination-path "${{github.event.pull_request.head.sha}}" --account-key="${PREVIEW_STORAGE_KEY}"
|
||||
env:
|
||||
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
||||
- name: Upload preview config to blob storage
|
||||
run: az storage blob upload -c '$web' -f ./preview/config.json --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --name "${{github.event.pull_request.head.sha}}/config.json" --account-key="${PREVIEW_STORAGE_KEY}"
|
||||
env:
|
||||
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
||||
endtoendemulator:
|
||||
name: "End To End Emulator Tests"
|
||||
# Temporarily disabled. This test needs to be rewritten in playwright
|
||||
if: false
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- uses: southpolesteve/cosmos-emulator-github-action@v1
|
||||
- name: End to End Tests
|
||||
run: |
|
||||
npm ci
|
||||
npm start &
|
||||
npm run wait-for-server
|
||||
npx jest -c ./jest.config.e2e.js --detectOpenHandles test/sql/container.spec.ts
|
||||
npx jest -c ./jest.config.e2e.js --detectOpenHandles sql
|
||||
shell: bash
|
||||
env:
|
||||
DATA_EXPLORER_ENDPOINT: "https://localhost:1234/explorer.html?platform=Emulator"
|
||||
@@ -127,46 +105,69 @@ jobs:
|
||||
with:
|
||||
name: screenshots
|
||||
path: failed-*
|
||||
endtoend:
|
||||
name: "E2E"
|
||||
accessibility:
|
||||
name: "Accessibility | Hosted"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
||||
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test-file:
|
||||
- ./test/cassandra/container.spec.ts
|
||||
- ./test/sql/container.spec.ts
|
||||
- ./test/mongo/container.spec.ts
|
||||
- ./test/selfServe/selfServeExample.spec.ts
|
||||
- ./test/notebooks/upload.spec.ts
|
||||
- ./test/sql/resourceToken.spec.ts
|
||||
- ./test/tables/container.spec.ts
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- run: npm ci
|
||||
- run: npm start &
|
||||
- run: npm run wait-for-server
|
||||
- name: ${{ matrix['test-file'] }}
|
||||
node-version: 12.x
|
||||
- name: Accessibility Check
|
||||
run: |
|
||||
# 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)
|
||||
# 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 Hosted Tests"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: End to End Hosted Tests
|
||||
run: |
|
||||
npm ci
|
||||
npm start &
|
||||
npm run wait-for-server
|
||||
npm run test:e2e
|
||||
shell: bash
|
||||
env:
|
||||
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 }}
|
||||
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 }}
|
||||
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"
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: screenshots
|
||||
path: screenshots/
|
||||
path: failed-*
|
||||
nuget:
|
||||
name: Publish Nuget
|
||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||
needs: [build]
|
||||
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||
@@ -182,7 +183,7 @@ jobs:
|
||||
- run: cp ./configs/prod.json config.json
|
||||
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
||||
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
||||
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||
- run: nuget push -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||
- uses: actions/upload-artifact@v2
|
||||
name: packages
|
||||
with:
|
||||
@@ -190,7 +191,7 @@ jobs:
|
||||
nugetmpac:
|
||||
name: Publish Nuget MPAC
|
||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||
needs: [build]
|
||||
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||
@@ -207,7 +208,7 @@ jobs:
|
||||
- run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec
|
||||
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
||||
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
||||
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||
- run: nuget push -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||
- uses: actions/upload-artifact@v2
|
||||
name: packages
|
||||
with:
|
||||
|
||||
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
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -15,5 +15,3 @@ Contracts/*
|
||||
.cache/
|
||||
.env
|
||||
failure.png
|
||||
screenshots/*
|
||||
GettingStarted-ignore*.ipynb
|
||||
BIN
.vs/slnx.sqlite
BIN
.vs/slnx.sqlite
Binary file not shown.
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -17,10 +17,5 @@
|
||||
"test/out/**": true,
|
||||
"workers/libs/**": true
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": true
|
||||
}
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
# Coding Guidelines and Recommendations
|
||||
|
||||
Cosmos Explorer has been under constant development for over 5 years. As a result, there are many different patterns and practices in the codebase. This document serves as a guide to how we write code and helps avoid propagating practices which are no longer preferred. Each requirement in this document is labeled and color-coded to show the relative importance. In order from highest to lowest importance:
|
||||
|
||||
✅ DO this. If you feel you need an exception, engage with the project owners _prior_ to implementation.
|
||||
|
||||
⛔️ DO NOT do this. If you feel you need an exception, engage with the project owners _prior_ to implementation.
|
||||
|
||||
☑️ YOU SHOULD strongly consider this but it is not a requirement. If not following this advice, please comment code with why and proactively begin a discussion as part of the PR process.
|
||||
|
||||
⚠️ YOU SHOULD NOT strongly consider not doing this. If not following this advice, please comment code with why and proactively begin a discussion as part of the PR process.
|
||||
|
||||
💭 YOU MAY consider this advice if appropriate to your situation. Other team members may comment on this as part of PR review, but there is no need to be proactive.
|
||||
|
||||
## Development Environment
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Use VSCode and install the following extensions. This setup will catch most linting/formatting/type errors as you develop:
|
||||
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
||||
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
||||
|
||||
💭 YOU MAY
|
||||
|
||||
- Use the [GitHub CLI](https://cli.github.com/). It has helpful workflows for submitting PRs as well as for checking out other team member's PRs.
|
||||
- Use Windows, Linux (including WSL), or OSX. We have team members developing on all three environments.
|
||||
|
||||
✅ DO
|
||||
|
||||
- Maintain cross-platform compatibility when modifying any engineering or build systems
|
||||
|
||||
## Code Formatting
|
||||
|
||||
✅ DO
|
||||
|
||||
- Use [Prettier](https://prettier.io/) to format your code
|
||||
- This will occur automatically if using the recommended editor setup
|
||||
- `npm run format` will also format code
|
||||
|
||||
## Linting
|
||||
|
||||
✅ DO
|
||||
|
||||
- Use [ESLint](https://eslint.org/) to check for code errors.
|
||||
- This will occur automatically if using the recommended editor setup
|
||||
- `npm run lint` will also check for linting errors
|
||||
|
||||
💭 YOU MAY
|
||||
|
||||
- Consider adding new lint rules.
|
||||
- If you find yourself performing "nits" as part of PR review, consider adding a lint rule that will automatically catch the error in the future
|
||||
|
||||
⚠️ YOU SHOULD NOT
|
||||
|
||||
- Disable lint rules
|
||||
- Lint rules exist as guidance and to catch common mistakes
|
||||
- You will find places we disable specific lint rules however it should be exceptional.
|
||||
- If a rule does need to be disabled, prefer disabling a specific line instead of the entire file.
|
||||
|
||||
⛔️ DO NOT
|
||||
|
||||
- Add [TSLint](https://palantir.github.io/tslint/) rules
|
||||
- TSLint has been deprecated and is on track to be removed
|
||||
- Always prefer ESLint rules
|
||||
|
||||
## UI Components
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Write new components using [React](https://reactjs.org/). We are actively migrating Cosmos Explorer off of [Knockout](https://knockoutjs.com/).
|
||||
- Use [Fluent](https://developer.microsoft.com/en-us/fluentui#/) components.
|
||||
- Fluent components are designed to be highly accessible and composable
|
||||
- Using Fluent allows us to build upon the work of the Fluent team and leads to a lower total cost of ownership for UI code
|
||||
|
||||
### React
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Use pure functional components when no state is required
|
||||
|
||||
💭 YOU MAY
|
||||
|
||||
- Use functional (hooks) or class components
|
||||
- The project contains examples of both
|
||||
- Neither is strongly preferred at this time
|
||||
|
||||
⛔️ DO NOT
|
||||
|
||||
- Use inheritance for sharing component behavior.
|
||||
- React documentation covers this topic in detail https://reactjs.org/docs/composition-vs-inheritance.html
|
||||
- Suffix your file or component name with "Component"
|
||||
- Even though the code has examples of it, we are ending the practice.
|
||||
|
||||
## Libraries
|
||||
|
||||
⚠️ YOU SHOULD NOT
|
||||
|
||||
- Add new libraries to package.json.
|
||||
- Adding libraries may bring in code that explodes the bundled size or attempts to run NodeJS code in the browser
|
||||
- Consult with project owners for help with library selection if one is needed
|
||||
|
||||
⛔️ DO NOT
|
||||
|
||||
- Use underscore.js
|
||||
- Much of this library is now native to JS and will be automatically transpiled
|
||||
- Use jQuery
|
||||
- Much of this library is not native to the DOM.
|
||||
- We are planning to remove it
|
||||
|
||||
## Testing
|
||||
|
||||
⛔️ DO NOT
|
||||
|
||||
- Decrease test coverage
|
||||
- Unit/Functional test coverage is checked as part of the CI process
|
||||
|
||||
### Unit Tests
|
||||
|
||||
✅ DO
|
||||
|
||||
- Write unit tests for non-UI and utility code.
|
||||
- Write your tests using [Jest](https://jestjs.io/)
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Abstract non-UI and utility code so it can run either the NodeJS or Browser environment
|
||||
|
||||
### Functional(Component) Tests
|
||||
|
||||
✅ DO
|
||||
|
||||
- Write tests for UI components
|
||||
- Write your tests using [Jest](https://jestjs.io/)
|
||||
- Use either Enzyme or React Testing Library to perform component tests.
|
||||
|
||||
### Mocking
|
||||
|
||||
✅ DO
|
||||
|
||||
- Use Jest's built-in mocking helpers
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Write code that does not require mocking
|
||||
- Build components that do not require mocking extremely large or difficult to mock objects (like Explorer.ts). Pass _only_ what you need.
|
||||
|
||||
⛔️ DO NOT
|
||||
|
||||
- Use sinon.js for mocking
|
||||
- Sinon has been deprecated and planned for removal
|
||||
|
||||
### End to End Tests
|
||||
|
||||
✅ DO
|
||||
|
||||
- Use [Playwright](https://github.com/microsoft/playwright) and [Jest](https://jestjs.io/)
|
||||
- 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.
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Write tests that use accessible attributes to perform actions. Role, Title, Label, etc
|
||||
- More information https://testing-library.com/docs/queries/about#priority
|
||||
|
||||
⚠️ YOU SHOULD NOT
|
||||
|
||||
- Add test specfic `data-*` attributes to dom elements
|
||||
- This is a common current practice, but one we would like to avoid in the future
|
||||
- End to end tests need to use semantic HTML and accesible attributes to be truely end to end
|
||||
- No user or screen reader actually navigates an app using `data-*` attributes
|
||||
- Add arbitrary time delays to wait for page to render or element to be ready.
|
||||
- All the time delays add up and slow down testing.
|
||||
- Prefer using the framework's "wait for..." functionality.
|
||||
|
||||
### Migrating Knockout to React
|
||||
|
||||
✅ DO
|
||||
|
||||
- Consult other team members before beginning migration work. There is a significant amount of flux in patterns we are using and it is important we do not propagate incorrect patterns.
|
||||
- Start by converting HTML to JSX: https://magic.reactjs.net/htmltojsx.htm. Add functionality as a second step.
|
||||
|
||||
☑️ YOU SHOULD
|
||||
|
||||
- Write React components that require no dependency on Knockout or observables to trigger rendering.
|
||||
|
||||
## Browser Support
|
||||
|
||||
✅ DO
|
||||
|
||||
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
||||
- Support IE11
|
||||
- In practice, this should not need to be considered as part of a normal development workflow
|
||||
- Polyfills and transpilation are already provided by our engineering systems.
|
||||
- This requirement will be removed on March 30th, 2021 when Azure drops IE11 support.
|
||||
@@ -13,7 +13,6 @@ For more information see the [Code of Conduct FAQ](https://opensource.microsoft.
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
Resources:
|
||||
@@ -21,3 +20,33 @@ Resources:
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||
|
||||
## Browser support
|
||||
Please make sure to support all modern browsers as well as Internet Explorer 11.
|
||||
For IE support, polyfill is preferred over new usage of lodash or underscore. We already polyfill almost everything by importing babel-polyfill at the top of entry points.
|
||||
|
||||
|
||||
## Coding guidelines, conventions and recommendations
|
||||
### Typescript
|
||||
* Follow this [typescript style guide](https://github.com/excelmicro/typescript) which is based on [airbnb's style guide](https://github.com/airbnb/javascript).
|
||||
* Conventions speficic to this project:
|
||||
- Use double-quotes for string
|
||||
- Don't use `null`, use `undefined`
|
||||
- Pascal case for private static readonly fields
|
||||
- Camel case for classnames in markup
|
||||
* Don't use class unless necessary
|
||||
* Code related to notebooks should be dynamically imported so that it is loaded from a separate bundle only if the account is notebook-enabled. There are already top-level notebook components which are dynamically imported and their dependencies can be statically imported from these files.
|
||||
* Prefer using [Fluent UI controls](https://developer.microsoft.com/en-us/fluentui#/controls/web) over creating your own, in order to maintain consistency and support a11y.
|
||||
|
||||
### React
|
||||
* Prefer using React class components over function components and hooks unless you have a simple component and require no nested functions:
|
||||
* Nested functions may be harder to test independently
|
||||
* Switching from function component to class component later mayb be painful
|
||||
|
||||
## Testing
|
||||
Any PR should not decrease testing coverage.
|
||||
|
||||
## Recommended Tools and VS Code extensions
|
||||
* [Bookmarks](https://github.com/alefragnani/vscode-bookmarks)
|
||||
* [Bracket pair colorizer](https://github.com/CoenraadS/Bracket-Pair-Colorizer-2)
|
||||
* [GitHub Pull Requests and Issues](https://github.com/Microsoft/vscode-pull-request-github)
|
||||
@@ -18,6 +18,7 @@ Run `npm start` to start the development server and automatically rebuild on cha
|
||||
### Hosted Development (https://cosmos.azure.com)
|
||||
|
||||
- Visit: `https://localhost:1234/hostedExplorer.html`
|
||||
- Local sign in via AAD will NOT work. Connection string only in dev mode. Use the Portal if you need AAD auth.
|
||||
- The default webpack dev server configuration will proxy requests to the production portal backend: `https://main.documentdb.ext.azure.com`. This will allow you to use production connection strings on your local machine.
|
||||
|
||||
### Emulator Development
|
||||
@@ -68,10 +69,6 @@ Jest and Puppeteer are used for end to end browser based tests and are contained
|
||||
|
||||
We generally adhere to the release strategy [documented by the Azure SDK Guidelines](https://azure.github.io/azure-sdk/policies_repobranching.html#release-branches). Most releases should happen from the master branch. If master contains commits that cannot be released, you may create a release from a `release/` or `hotfix/` branch. See linked documentation for more details.
|
||||
|
||||
### Architecture
|
||||
|
||||
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcbiAgaG9zdGVkKGh0dHBzOi8vY29zbW9zLmF6dXJlLmNvbSlcbiAgcG9ydGFsKFBvcnRhbClcbiAgZW11bGF0b3IoRW11bGF0b3IpXG4gIGFhZFtBQURdXG4gIHJlc291cmNlVG9rZW5bUmVzb3VyY2UgVG9rZW5dXG4gIGNvbm5lY3Rpb25TdHJpbmdbQ29ubmVjdGlvbiBTdHJpbmddXG4gIHBvcnRhbFRva2VuW0VuY3J5cHRlZCBQb3J0YWwgVG9rZW5dXG4gIG1hc3RlcktleVtNYXN0ZXIgS2V5XVxuICBhcm1bQVJNIFJlc291cmNlIFByb3ZpZGVyXVxuICBkYXRhcGxhbmVbRGF0YSBQbGFuZV1cbiAgcHJveHlbUG9ydGFsIEFQSSBQcm94eV1cbiAgc3FsW1NRTF1cbiAgbW9uZ29bTW9uZ29dXG4gIHRhYmxlc1tUYWJsZXNdXG4gIGNhc3NhbmRyYVtDYXNzYW5kcmFdXG4gIGdyYWZbR3JhcGhdXG5cblxuICBlbXVsYXRvciAtLT4gbWFzdGVyS2V5IC0tLS0-IGRhdGFwbGFuZVxuICBwb3J0YWwgLS0-IGFhZFxuICBob3N0ZWQgLS0-IHBvcnRhbFRva2VuICYgcmVzb3VyY2VUb2tlbiAmIGNvbm5lY3Rpb25TdHJpbmcgJiBhYWRcbiAgYWFkIC0tLT4gYXJtXG4gIGFhZCAtLS0-IGRhdGFwbGFuZVxuICBhYWQgLS0tPiBwcm94eVxuICByZXNvdXJjZVRva2VuIC0tLT4gc3FsIC0tPiBkYXRhcGxhbmVcbiAgcG9ydGFsVG9rZW4gLS0tPiBwcm94eVxuICBwcm94eSAtLT4gZGF0YXBsYW5lXG4gIGNvbm5lY3Rpb25TdHJpbmcgLS0-IHNxbCAmIG1vbmdvICYgY2Fzc2FuZHJhICYgZ3JhZiAmIHRhYmxlc1xuICBzcWwgLS0-IGRhdGFwbGFuZVxuICB0YWJsZXMgLS0-IGRhdGFwbGFuZVxuICBtb25nbyAtLT4gcHJveHlcbiAgY2Fzc2FuZHJhIC0tPiBwcm94eVxuICBncmFmIC0tPiBwcm94eVxuXG5cdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)
|
||||
|
||||
# Contributing
|
||||
|
||||
Please read the [contribution guidelines](./CONTRIBUTING.md).
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-react", "@babel/preset-typescript"],
|
||||
plugins: [["@babel/plugin-proposal-decorators", { legacy: true }]],
|
||||
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-react", "@babel/preset-typescript"]
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Why?
|
||||
|
||||
This adds a mock module for `canvas`. Nteract has a ignored require and undeclared dependency on this module. `cavnas` is a server side node module and is not used in browser side code for nteract.
|
||||
|
||||
Installing it locally (`npm install canvas`) will resolve the problem, but it is a native module so it is flaky depending on the system, node version, processor arch, etc. This module provides a simpler, more robust solution.
|
||||
|
||||
Remove this workaround if [this bug](https://github.com/nteract/any-vega/issues/2) ever gets resolved
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = {}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"name": "canvas",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
1963
externals/adal.js
vendored
Normal file
1963
externals/adal.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
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,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.31449 2.01439L4.00103 5.31963L3.26105 4.57965L7.8407 0L12.4203 4.57965L11.6804 5.31963L8.36691 2.01439V12.8428H7.31449V2.01439ZM13.629 12.8428H14.6814V16H1V12.8428H2.05242V14.9476H13.629V12.8428Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 329 B |
@@ -1,13 +0,0 @@
|
||||
const isCI = require("is-ci");
|
||||
|
||||
module.exports = {
|
||||
exitOnPageError: false,
|
||||
launchOptions: {
|
||||
headless: isCI,
|
||||
slowMo: 10,
|
||||
timeout: 60000,
|
||||
},
|
||||
contextOptions: {
|
||||
ignoreHTTPSErrors: true,
|
||||
},
|
||||
};
|
||||
11
jest-puppeteer.config.js
Normal file
11
jest-puppeteer.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const isCI = require("is-ci");
|
||||
|
||||
module.exports = {
|
||||
launch: {
|
||||
headless: isCI,
|
||||
slowMo: 55,
|
||||
defaultViewport: null,
|
||||
ignoreHTTPSErrors: true,
|
||||
args: ["--disable-web-security"]
|
||||
}
|
||||
};
|
||||
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"]
|
||||
};
|
||||
@@ -21,13 +21,17 @@ module.exports = {
|
||||
collectCoverage: true,
|
||||
|
||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
|
||||
// collectCoverageFrom: [
|
||||
// "src/Common/Headers*"
|
||||
// ],
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: "coverage",
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
coveragePathIgnorePatterns: ["/node_modules/"],
|
||||
// coveragePathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
coverageReporters: ["json", "text", "cobertura"],
|
||||
@@ -35,11 +39,11 @@ module.exports = {
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 25,
|
||||
functions: 25,
|
||||
branches: 20,
|
||||
functions: 24,
|
||||
lines: 30,
|
||||
statements: 30,
|
||||
},
|
||||
statements: 29.0
|
||||
}
|
||||
},
|
||||
|
||||
// Make calling deprecated APIs throw helpful error messages
|
||||
@@ -67,12 +71,12 @@ module.exports = {
|
||||
|
||||
// A map from regular expressions to module names that allow to stub out resources with a single module
|
||||
moduleNameMapper: {
|
||||
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
|
||||
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
|
||||
"^.*[.](svg|png|gif|less)$": "<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
|
||||
"^dnd-core$": "dnd-core/dist/cjs",
|
||||
"^react-dnd$": "react-dnd/dist/cjs",
|
||||
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",
|
||||
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs"
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
@@ -160,11 +164,11 @@ module.exports = {
|
||||
// A map from regular expressions to paths to transformers
|
||||
transform: {
|
||||
"^.+\\.html?$": "html-loader-jest",
|
||||
"^.+\\.[t|j]sx?$": "babel-jest",
|
||||
"^.+\\.[t|j]sx?$": "babel-jest"
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
transformIgnorePatterns: ["/node_modules/", "/externals/"],
|
||||
transformIgnorePatterns: ["/node_modules/", "/externals/"]
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
@@ -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"],
|
||||
};
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
@font-face {
|
||||
font-family: wf_segoe-ui_normal;
|
||||
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff");
|
||||
src: url('../../fonts/segoe-ui/west-european/normal/latest.woff');
|
||||
}
|
||||
|
||||
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||
@@ -20,26 +20,26 @@
|
||||
COLORS
|
||||
/******************************************************************************/
|
||||
|
||||
@AccentMediumHigh: #0058ad;
|
||||
@AccentMedium: #004e87;
|
||||
@AccentHigh: #1ebaed;
|
||||
@AccentExtraHigh: #55b3ff;
|
||||
@AccentLow: #edf6ff;
|
||||
@AccentMediumLow: #ddeefe;
|
||||
@AccentLight: #eef7ff;
|
||||
@AccentExtra: #ddf0ff;
|
||||
@AccentMediumHigh: #0058AD;
|
||||
@AccentMedium: #004E87;
|
||||
@AccentHigh: #1EBAED;
|
||||
@AccentExtraHigh: #55B3FF;
|
||||
@AccentLow: #EDF6FF;
|
||||
@AccentMediumLow: #DDEEFE;
|
||||
@AccentLight: #EEF7FF;
|
||||
@AccentExtra: #DDF0FF;
|
||||
|
||||
@SelectionHigh: #b91f26;
|
||||
@BaseLight: #ffffff;
|
||||
@SelectionHigh: #B91F26;
|
||||
@BaseLight: #FFFFFF;
|
||||
@BaseDark: #000000;
|
||||
@NotificationLow: #fff4ce;
|
||||
@NotificationHigh: #f9e9b0;
|
||||
@Purple1: #8a2da5;
|
||||
@NotificationLow: #FFF4CE;
|
||||
@NotificationHigh: #F9E9B0;
|
||||
@Purple1: #8A2DA5;
|
||||
@Dirty: #9b4f96;
|
||||
|
||||
@BaseLow: #f2f2f2;
|
||||
@BaseMediumLow: #e6e6e6;
|
||||
@BaseMedium: #cccccc;
|
||||
@BaseLow: #F2F2F2;
|
||||
@BaseMediumLow: #E6E6E6;
|
||||
@BaseMedium: #CCCCCC;
|
||||
@BaseMediumHigh: #767676;
|
||||
@BaseHigh: #393939;
|
||||
|
||||
@@ -53,17 +53,10 @@
|
||||
|
||||
@ErrorColor: @SelectionHigh;
|
||||
|
||||
@SelectionColor: #3074b0;
|
||||
@SelectionColor: #3074B0;
|
||||
|
||||
@FocusColor: #605e5c;
|
||||
|
||||
@GalleryBackgroundColor: #fdfdfd;
|
||||
|
||||
//Icons
|
||||
@InfoIconColor: #0072c6;
|
||||
@WarningIconColor: #db7500;
|
||||
@ErrorIconColor: #b91f26;
|
||||
|
||||
/******************************************************************************
|
||||
METRICS
|
||||
/******************************************************************************/
|
||||
@@ -87,7 +80,7 @@
|
||||
@ImgWidth: 14px;
|
||||
@ImgHeight: 14px;
|
||||
|
||||
@toggleFontWeight: 700;
|
||||
@toggleFontWeight:700;
|
||||
|
||||
//Resource Tree
|
||||
@TreeLineHeight: 17px;
|
||||
@@ -172,8 +165,8 @@
|
||||
.selectedRadio:hover,
|
||||
.selectedRadio:active,
|
||||
.selectedRadio.dirty,
|
||||
.tab [type="radio"]:checked ~ label,
|
||||
.tab [type="radio"]:checked ~ label:hover {
|
||||
.tab [type=radio]:checked ~ label,
|
||||
.tab [type=radio]:checked ~ label:hover {
|
||||
-ms-high-contrast-adjust: none;
|
||||
-webkit-text-fill-color: HighlightText;
|
||||
color: HighlightText;
|
||||
@@ -182,8 +175,9 @@
|
||||
}
|
||||
|
||||
.queryMetricsSummaryTuple {
|
||||
th,
|
||||
td {
|
||||
|
||||
th, td {
|
||||
|
||||
&:nth-child(2) {
|
||||
width: @IETableDataWidth;
|
||||
}
|
||||
@@ -278,27 +272,3 @@
|
||||
.tooltipVisible() {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.inputTooltip() {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.inputTooltipText(@textColor: @BaseLight, @backgroundColor: @BaseHigh) {
|
||||
background-color: @backgroundColor;
|
||||
color: @textColor;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
padding: @MediumSpace;
|
||||
}
|
||||
|
||||
.inputTooltipTextAfter(@color: @BaseDark) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
border-style: solid;
|
||||
border-color: transparent @color transparent transparent;
|
||||
left: 10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: @InfoPointerColor transparent;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ body {
|
||||
height: 100%;
|
||||
|
||||
:focus {
|
||||
.focus();
|
||||
.focus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ body {
|
||||
border-radius: 3px;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
content:"";
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 13px;
|
||||
@@ -53,13 +53,13 @@ body {
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
content:"";
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
right: 14px;
|
||||
border-width: 0 9px 9px;
|
||||
border-style: solid;
|
||||
border-color: #fff rgba(0, 0, 0, 0);
|
||||
border-color: #FFF rgba(0, 0, 0, 0);
|
||||
display: block;
|
||||
width: 0;
|
||||
}
|
||||
@@ -88,6 +88,7 @@ body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
|
||||
.urlContainer {
|
||||
margin-left: @DefaultSpace;
|
||||
|
||||
@@ -154,7 +155,7 @@ body {
|
||||
}
|
||||
|
||||
.urlTokenTooltiptext {
|
||||
bottom: 28px;
|
||||
bottom:28px;
|
||||
width: 250px;
|
||||
.tooltipText();
|
||||
|
||||
@@ -178,8 +179,7 @@ body {
|
||||
.active();
|
||||
}
|
||||
|
||||
&:focus .urlTokenCopyTooltiptext,
|
||||
&:focus .urlTokenCopyTooltiptext {
|
||||
&:focus .urlTokenCopyTooltiptext, &:focus .urlTokenCopyTooltiptext {
|
||||
.tooltipVisible();
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ body {
|
||||
|
||||
.shareLink {
|
||||
width: 300px;
|
||||
background-color: #ffffff;
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid @BaseMedium;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -423,7 +423,7 @@ body {
|
||||
|
||||
.ui-dialog.ui-corner-all.ui-widget.ui-widget-content.ui-front.no-close.ui-dialog-buttons {
|
||||
border: 1px solid @BaseMedium;
|
||||
box-shadow: 0 0 @DefaultSpace @BoxShadow;
|
||||
box-shadow:0 0 @DefaultSpace @BoxShadow;
|
||||
padding: 0px;
|
||||
|
||||
.ui-widget-header.ui-helper-clearfix.ui-dialog-titlebar.connectTitlebar {
|
||||
@@ -718,12 +718,11 @@ execute-sproc-params-pane {
|
||||
}
|
||||
}
|
||||
|
||||
.stored-procedure-tab {
|
||||
stored-procedure-tab {
|
||||
@ToggleHeight: 30px;
|
||||
@ToggleWidth: 180px;
|
||||
|
||||
.results-container,
|
||||
.errors-container {
|
||||
.results-container, .errors-container {
|
||||
padding: @MediumSpace 0px 0px @MediumSpace;
|
||||
height: 100%;
|
||||
.flex-display();
|
||||
@@ -830,8 +829,8 @@ notification-console {
|
||||
}
|
||||
|
||||
.flexContainer {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
width:100%;
|
||||
.flex-display();
|
||||
.flex-direction();
|
||||
}
|
||||
@@ -863,8 +862,8 @@ notification-console {
|
||||
|
||||
.topSelected:hover {
|
||||
border-left: 4px solid @AccentMediumHigh;
|
||||
background: #666666 !important;
|
||||
cursor: default !important;
|
||||
background: #666666!important;
|
||||
cursor: default!important;
|
||||
}
|
||||
|
||||
#Quickstart:hover span.activemenu,
|
||||
@@ -935,19 +934,19 @@ menuQuickStart {
|
||||
.content {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
transition: all 0.4s ease-in-out;
|
||||
-ms-transition: all 0.4s ease-in-out;
|
||||
-webkit-transition: all 0.4s ease-in-out;
|
||||
-moz-transition: all 0.4s ease-in-out;
|
||||
transition: all .4s ease-in-out;
|
||||
-ms-transition: all .4s ease-in-out;
|
||||
-webkit-transition: all .4s ease-in-out;
|
||||
-moz-transition: all .4s ease-in-out;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.mini {
|
||||
width: 0%;
|
||||
float: left;
|
||||
transition: all 0.4s ease-in-out;
|
||||
-webkit-transition: all 0.4s ease-in-out;
|
||||
-moz-transition: all 0.4s ease-in-out;
|
||||
transition: all .4s ease-in-out;
|
||||
-webkit-transition: all .4s ease-in-out;
|
||||
-moz-transition: all .4s ease-in-out;
|
||||
height: 100vh;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -1097,13 +1096,13 @@ menuQuickStart {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#tbodycontent > tr > td {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
#tbodycontent>tr>td {
|
||||
border-bottom: 1px solid #CCCCCC;
|
||||
border-top: none;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#tbodycontent > tr:last-child > td {
|
||||
#tbodycontent>tr:last-child>td {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
@@ -1139,8 +1138,8 @@ menuQuickStart {
|
||||
}
|
||||
|
||||
.loadErrorIcon {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
width:128px;
|
||||
height:128px;
|
||||
}
|
||||
|
||||
.loadErrorDetailsLink {
|
||||
@@ -1152,7 +1151,7 @@ menuQuickStart {
|
||||
padding-top: 28px;
|
||||
padding-left: @MediumSpace;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
width:100%;
|
||||
overflow: hidden;
|
||||
.flex-display();
|
||||
|
||||
@@ -1164,7 +1163,7 @@ menuQuickStart {
|
||||
diff-editor {
|
||||
padding-top: 28px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
width:100%;
|
||||
overflow: hidden;
|
||||
.flex-display();
|
||||
|
||||
@@ -1206,7 +1205,7 @@ menuQuickStart {
|
||||
|
||||
.gridRowSelected:hover {
|
||||
cursor: default;
|
||||
.hover();
|
||||
.hover()
|
||||
}
|
||||
|
||||
.gridRowHighlighted {
|
||||
@@ -1214,7 +1213,7 @@ menuQuickStart {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.table-hover > tbody > tr:hover {
|
||||
.table-hover>tbody>tr:hover {
|
||||
.hover();
|
||||
}
|
||||
|
||||
@@ -1241,7 +1240,7 @@ menuQuickStart {
|
||||
border-top: 1px solid #eee;
|
||||
margin-left: -17px;
|
||||
width: 100%;
|
||||
color: 1px solid #53575b;
|
||||
color: 1px solid #53575B;
|
||||
}
|
||||
|
||||
.partitioning-btn {
|
||||
@@ -1309,7 +1308,7 @@ menuQuickStart {
|
||||
|
||||
.collid-white {
|
||||
width: 100%;
|
||||
border: solid 1px #ddd;
|
||||
border: solid 1px #DDD;
|
||||
}
|
||||
|
||||
.plusimg-but {
|
||||
@@ -1439,7 +1438,7 @@ p {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.createNewDatabaseOrUseExistingRadio:nth-child(n + 2) {
|
||||
.createNewDatabaseOrUseExistingRadio:nth-child(n+2) {
|
||||
margin-left: @LargeSpace;
|
||||
}
|
||||
|
||||
@@ -1523,21 +1522,6 @@ p {
|
||||
.tooltipVisible();
|
||||
}
|
||||
|
||||
.inputTooltip {
|
||||
.inputTooltip();
|
||||
}
|
||||
|
||||
.inputTooltip .inputTooltipText {
|
||||
top: -68px;
|
||||
.inputTooltipText();
|
||||
}
|
||||
|
||||
.inputTooltip .inputTooltipText::after {
|
||||
border-width: @MediumSpace @MediumSpace 0 @MediumSpace;
|
||||
top: 55px;
|
||||
.inputTooltipTextAfter();
|
||||
}
|
||||
|
||||
.infoTooltip a {
|
||||
color: @AccentHigh;
|
||||
}
|
||||
@@ -1647,6 +1631,7 @@ p {
|
||||
margin-left: -32px;
|
||||
}
|
||||
|
||||
|
||||
/* Variant of paddingspan3 without the margins */
|
||||
|
||||
.contextual-pane .paddingspan3b {
|
||||
@@ -1659,7 +1644,7 @@ p {
|
||||
}
|
||||
|
||||
.contextual-pane hr {
|
||||
border: 1px solid #53575b;
|
||||
border: 1px solid #53575B;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
@@ -1709,7 +1694,6 @@ input::-webkit-calendar-picker-indicator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.contextual-pane .paneErrorDetailsContainer {
|
||||
@@ -1834,11 +1818,11 @@ label {
|
||||
|
||||
.datalist-arrow:focus:after,
|
||||
.datalist-arrow:active:after {
|
||||
background: #1ebbee;
|
||||
background: #1EBBEE;
|
||||
}
|
||||
|
||||
input::-webkit-calendar-picker-indicator::after {
|
||||
content: "\276F";
|
||||
content: '\276F';
|
||||
right: 0;
|
||||
top: -8%;
|
||||
display: block;
|
||||
@@ -1852,7 +1836,7 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
}
|
||||
|
||||
.datalist-arrow:after:hover {
|
||||
content: "\276F";
|
||||
content: '\276F';
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
top: 6%;
|
||||
@@ -1864,7 +1848,7 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
background-color: #1ebbee;
|
||||
background-color: #1EBBEE;
|
||||
}
|
||||
|
||||
.Introline3 {
|
||||
@@ -1918,26 +1902,26 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.qslevel > li > a {
|
||||
.qslevel>li>a {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.qslevel > li.active {
|
||||
.qslevel>li.active {
|
||||
border-bottom: 4px solid #767676;
|
||||
}
|
||||
|
||||
.nav-tabs-margin {
|
||||
padding-top: 8px;
|
||||
background-color: #f2f2f2;
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
|
||||
.navTabHeight {
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
.qslevel > li.active > a,
|
||||
.qslevel > li > a:focus,
|
||||
.nav.nav-tabs.qslevel > li > a:hover {
|
||||
.qslevel>li.active>a,
|
||||
.qslevel>li>a:focus,
|
||||
.nav.nav-tabs.qslevel>li>a:hover {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background-color: transparent !important;
|
||||
@@ -1957,16 +1941,16 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.numberheading > p {
|
||||
.numberheading>p {
|
||||
padding-top: 10px;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.numberheading > ul {
|
||||
.numberheading>ul {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.numberheading > ul > li > a {
|
||||
.numberheading>ul>li>a {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
@@ -1974,7 +1958,7 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.step1 > input {
|
||||
.step1>input {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -1994,7 +1978,7 @@ input::-webkit-calendar-picker-indicator::after {
|
||||
.atags {
|
||||
color: @AccentMediumHigh;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.qsmenuicons {
|
||||
@@ -2057,7 +2041,7 @@ a:link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav > li > a:focus {
|
||||
.nav>li>a:focus {
|
||||
background-color: white;
|
||||
outline: none;
|
||||
}
|
||||
@@ -2099,7 +2083,7 @@ a:link {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
overflow-y: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -2234,10 +2218,10 @@ a:link {
|
||||
.documentsGridHeaderContainer {
|
||||
padding-left: 5px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
border-bottom: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.documentsGridHeaderContainer > table {
|
||||
.documentsGridHeaderContainer>table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: unset;
|
||||
@@ -2250,7 +2234,7 @@ a:link {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #fff !important;
|
||||
border-bottom: 1px solid #cccccc !important;
|
||||
border-bottom: 1px solid #CCCCCC !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2291,14 +2275,14 @@ a:link {
|
||||
overflow-x: hidden;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
width: 100%;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.tabdocuments > .tabdocumentsGridElement {
|
||||
.tabdocuments>.tabdocumentsGridElement {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.tabdocuments > .evenlySpacedHeader {
|
||||
.tabdocuments>.evenlySpacedHeader {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
@@ -2332,7 +2316,7 @@ td a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.loadMore > a:focus {
|
||||
.loadMore>a:focus {
|
||||
outline: 1px dotted;
|
||||
}
|
||||
|
||||
@@ -2362,7 +2346,7 @@ td a:hover {
|
||||
}
|
||||
|
||||
.table-fixed tbody td,
|
||||
.table-fixed thead > tr > th {
|
||||
.table-fixed thead>tr>th {
|
||||
float: left;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
@@ -2399,52 +2383,52 @@ a:link {
|
||||
color: #393939;
|
||||
}
|
||||
|
||||
.tab [type="radio"] {
|
||||
.tab [type=radio] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabcontent {
|
||||
clear: both;
|
||||
clear:both;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: @MediumSpace 0px;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:checked ~ label {
|
||||
.tab [type=radio]:checked~label {
|
||||
border: 1px solid #0072c6;
|
||||
background-color: @AccentMediumHigh;
|
||||
color: white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:checked ~ label:hover {
|
||||
.tab [type=radio]:checked~label:hover {
|
||||
border: 1px solid @AccentMediumHigh;
|
||||
background-color: @AccentMediumHigh;
|
||||
color: white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:checked ~ label:active {
|
||||
.tab [type=radio]:checked~label:active {
|
||||
border: 1px solid #0072c6;
|
||||
background-color: #0072c6;
|
||||
color: white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:checked ~ label ~ .tabcontent {
|
||||
.tab [type=radio]:checked~label~.tabcontent {
|
||||
z-index: 1;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:not(:checked) ~ label:hover {
|
||||
.tab [type=radio]:not(:checked)~label:hover {
|
||||
border: 1px solid #969696;
|
||||
background-color: #969696;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab [type="radio"]:not(:checked) ~ label ~ .tabcontent {
|
||||
.tab [type=radio]:not(:checked)~label~.tabcontent {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -2453,10 +2437,10 @@ a:link {
|
||||
}
|
||||
|
||||
.atagdetails {
|
||||
padding-left: 55px !important;
|
||||
padding-left: 55px!important;
|
||||
}
|
||||
|
||||
.contextual-pane-in .form-errors + img {
|
||||
.contextual-pane-in .form-errors+img {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 92px;
|
||||
@@ -2548,8 +2532,8 @@ a:link {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.queryButton {
|
||||
margin-left: @LargeSpace;
|
||||
.queryButton{
|
||||
margin-left:@LargeSpace;
|
||||
}
|
||||
|
||||
.hrline1 {
|
||||
@@ -2647,9 +2631,9 @@ a:link {
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > .tabNavContentContainer,
|
||||
.nav-tabs > li.active > .tabNavContentContainer:focus,
|
||||
.nav-tabs > li.active > .tabNavContentContainer:hover {
|
||||
.nav-tabs>li.active>.tabNavContentContainer,
|
||||
.nav-tabs>li.active>.tabNavContentContainer:focus,
|
||||
.nav-tabs>li.active>.tabNavContentContainer:hover {
|
||||
color: #555;
|
||||
cursor: default;
|
||||
background-color: @BaseLight;
|
||||
@@ -2661,7 +2645,7 @@ a:link {
|
||||
width: @ActiveTabWidth;
|
||||
}
|
||||
|
||||
.nav-tabs > li.active:focus > .tabNavContentContainer {
|
||||
.nav-tabs>li.active:focus>.tabNavContentContainer {
|
||||
.focus();
|
||||
}
|
||||
|
||||
@@ -2748,7 +2732,7 @@ a:link {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
flex-grow: 1;
|
||||
flex-grow: 1
|
||||
}
|
||||
|
||||
.tabIconSection {
|
||||
@@ -2815,7 +2799,7 @@ a:link {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nav-tabs > li > a:active {
|
||||
.nav-tabs>li>a:active {
|
||||
background-color: #e0e0e0;
|
||||
width: 100%;
|
||||
border: 1px solid @AccentMediumHigh;
|
||||
@@ -2838,17 +2822,17 @@ a:link {
|
||||
}
|
||||
|
||||
.tabCommandDisabled {
|
||||
color: #cccccc;
|
||||
color: #CCCCCC;
|
||||
cursor: default;
|
||||
background-color: #ffffff;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.tabCommandDisabled:active {
|
||||
border: 1px solid #ffffff;
|
||||
border: 1px solid #FFFFFF;
|
||||
}
|
||||
|
||||
.tabCommandDisabled:hover {
|
||||
background-color: #ffffff;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
#explorerNotificationConsole {
|
||||
@@ -2873,7 +2857,7 @@ a:link {
|
||||
}
|
||||
|
||||
.uniqueTooltiptext {
|
||||
bottom: 28px;
|
||||
bottom:28px;
|
||||
.tooltipText();
|
||||
}
|
||||
|
||||
@@ -2956,13 +2940,13 @@ settings-pane {
|
||||
}
|
||||
|
||||
.linkDarkBackground {
|
||||
color: @AccentExtraHigh;
|
||||
color: @AccentExtraHigh
|
||||
}
|
||||
|
||||
.linkDarkBackground:hover,
|
||||
.linkDarkBackground:active,
|
||||
.linkDarkBackground:focus {
|
||||
color: @AccentHigh;
|
||||
color: @AccentHigh
|
||||
}
|
||||
|
||||
.library-add-button {
|
||||
@@ -2978,11 +2962,11 @@ settings-pane {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
#deletecollectionconfirmationpane .paneMainContent > div:not(:first-child) {
|
||||
#deletecollectionconfirmationpane .paneMainContent > div:not(:first-child){
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#deletedatabaseconfirmationpane .paneMainContent > div:not(:first-child) {
|
||||
#deletedatabaseconfirmationpane .paneMainContent > div:not(:first-child){
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
@@ -2994,12 +2978,12 @@ settings-pane {
|
||||
margin-top: @SmallSpace;
|
||||
}
|
||||
|
||||
.enableAnalyticalStorageRadio:nth-child(n + 2) {
|
||||
.enableAnalyticalStorageRadio:nth-child(n+2) {
|
||||
margin-left: @LargeSpace;
|
||||
}
|
||||
|
||||
.enableAnalyticalStorageRadioLabel {
|
||||
padding: 0px;
|
||||
padding: 0px
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3008,19 +2992,19 @@ settings-pane {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.button.enabled {
|
||||
background: #fff;
|
||||
.button.enabled{
|
||||
background: #FFF;
|
||||
border-radius: 2px;
|
||||
color: #323130;
|
||||
padding: 3px 20px;
|
||||
border: 1px solid #8a8886;
|
||||
border: 1px solid #8A8886;
|
||||
}
|
||||
|
||||
.button.disabled {
|
||||
background: #f3f2f1;
|
||||
border: 0px solid #8a8886;
|
||||
.button.disabled{
|
||||
background: #F3F2F1;
|
||||
border: 0px solid #8A8886;
|
||||
border-radius: 2px;
|
||||
color: #a19f9d;
|
||||
color: #A19F9D;
|
||||
padding: 3px 20px;
|
||||
}
|
||||
|
||||
@@ -3033,55 +3017,13 @@ settings-pane {
|
||||
}
|
||||
|
||||
.warningErrorContent a {
|
||||
color: @AccentMediumHigh;
|
||||
color: @AccentMediumHigh
|
||||
}
|
||||
|
||||
.infoBoxContent a {
|
||||
color: @AccentMediumHigh;
|
||||
color: @AccentMediumHigh
|
||||
}
|
||||
|
||||
.collapsibleSection :hover {
|
||||
.collapsibleSection :hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.messageBarInfoIcon {
|
||||
color: @InfoIconColor;
|
||||
}
|
||||
|
||||
.messageBarWarningIcon {
|
||||
color: @WarningIconColor;
|
||||
}
|
||||
|
||||
.freeTierInfoBanner {
|
||||
background-color: @BaseLow;
|
||||
display: inline-flex;
|
||||
padding: @DefaultSpace;
|
||||
width: 100%;
|
||||
|
||||
.freeTierInfoIcon img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.freeTierInfoMessage {
|
||||
margin: auto 0;
|
||||
padding-left: @MediumSpace;
|
||||
}
|
||||
}
|
||||
|
||||
.freeTierInlineWarning {
|
||||
display: inline-flex;
|
||||
padding: 8px 8px 8px 0;
|
||||
width: 100%;
|
||||
|
||||
.freeTierWarningIcon img {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.freeTierWarningMessage {
|
||||
margin: auto 0;
|
||||
padding-left: @SmallSpace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
@NavMediumSpace: 10px;
|
||||
@NavLargeSpace: 15px;
|
||||
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
top: -200px;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||
padding: 0px;
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
@import "./Common/Constants";
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
float: left;
|
||||
transition: all .0s ease-in-out;
|
||||
-ms-transition: all 0s ease-in-out;
|
||||
-webkit-transition: all 0s ease-in-out;
|
||||
-moz-transition: all .0s ease-in-out;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
border-left: 0px solid white;
|
||||
}
|
||||
|
||||
.resourceTree {
|
||||
height: 100%;
|
||||
flex: 0 0 auto;
|
||||
.main {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.resourceTreeScroll {
|
||||
|
||||
12160
package-lock.json
generated
12160
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
92
package.json
92
package.json
@@ -5,16 +5,13 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "3.10.5",
|
||||
"@azure/cosmos": "3.9.0",
|
||||
"@azure/identity": "1.1.0",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "1.2.1",
|
||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||
"@babel/plugin-proposal-class-properties": "7.12.1",
|
||||
"@babel/plugin-proposal-decorators": "7.12.12",
|
||||
"@jupyterlab/services": "6.0.2",
|
||||
"@jupyterlab/terminal": "3.0.3",
|
||||
"@microsoft/applicationinsights-web": "2.6.1",
|
||||
"@nteract/commutable": "7.4.2",
|
||||
"@jupyterlab/services": "6.0.0-rc.2",
|
||||
"@jupyterlab/terminal": "3.0.0-rc.2",
|
||||
"@microsoft/applicationinsights-web": "2.5.9",
|
||||
"@nteract/commutable": "7.3.2",
|
||||
"@nteract/connected-components": "6.8.2",
|
||||
"@nteract/core": "15.1.0",
|
||||
"@nteract/data-explorer": "8.0.3",
|
||||
@@ -25,7 +22,7 @@
|
||||
"@nteract/iron-icons": "1.0.0",
|
||||
"@nteract/jupyter-widgets": "2.0.0",
|
||||
"@nteract/logos": "1.0.0",
|
||||
"@nteract/markdown": "4.6.0",
|
||||
"@nteract/markdown": "4.4.0",
|
||||
"@nteract/monaco-editor": "3.2.2",
|
||||
"@nteract/octicons": "2.0.0",
|
||||
"@nteract/outputs": "3.0.9",
|
||||
@@ -39,16 +36,16 @@
|
||||
"@nteract/transform-vega": "7.0.6",
|
||||
"@octokit/rest": "17.9.2",
|
||||
"@phosphor/widgets": "1.9.3",
|
||||
"@testing-library/jest-dom": "5.11.9",
|
||||
"@types/mkdirp": "1.0.1",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@uifabric/react-cards": "0.109.110",
|
||||
"@uifabric/styling": "7.13.7",
|
||||
"abort-controller": "3.0.0",
|
||||
"applicationinsights": "1.8.0",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"bootstrap": "3.4.1",
|
||||
"canvas": "file:./canvas",
|
||||
"canvas": "2.6.1",
|
||||
"clean-webpack-plugin": "0.1.19",
|
||||
"clipboard-copy": "4.0.1",
|
||||
"copy-webpack-plugin": "6.0.2",
|
||||
"crossroads": "0.12.2",
|
||||
"css-element-queries": "1.1.1",
|
||||
@@ -58,14 +55,12 @@
|
||||
"date-fns": "1.29.0",
|
||||
"dayjs": "1.8.19",
|
||||
"dotenv": "8.2.0",
|
||||
"es6-object-assign": "1.1.0",
|
||||
"es6-symbol": "3.1.3",
|
||||
"eslint-plugin-jest": "23.13.2",
|
||||
"eslint-plugin-react": "7.20.0",
|
||||
"hasher": "1.2.0",
|
||||
"html2canvas": "1.0.0-rc.5",
|
||||
"i18next": "19.8.4",
|
||||
"i18next-browser-languagedetector": "6.0.1",
|
||||
"i18next-http-backend": "1.0.23",
|
||||
"iframe-resizer-react": "1.1.0",
|
||||
"immutable": "4.0.0-rc.12",
|
||||
"is-ci": "2.0.0",
|
||||
"jquery": "3.5.1",
|
||||
@@ -74,62 +69,67 @@
|
||||
"knockout": "3.5.1",
|
||||
"mkdirp": "1.0.4",
|
||||
"monaco-editor": "0.18.1",
|
||||
"ms": "2.1.3",
|
||||
"msal": "1.4.4",
|
||||
"office-ui-fabric-react": "7.164.2",
|
||||
"object.entries": "1.1.0",
|
||||
"office-ui-fabric-react": "7.134.1",
|
||||
"p-retry": "4.2.0",
|
||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||
"post-robot": "10.0.42",
|
||||
"promise-polyfill": "8.1.0",
|
||||
"promise.prototype.finally": "3.1.0",
|
||||
"q": "1.5.1",
|
||||
"react": "16.13.1",
|
||||
"react-animate-height": "2.0.8",
|
||||
"react-dnd": "9.4.0",
|
||||
"react-dnd-html5-backend": "9.4.0",
|
||||
"react-dom": "16.13.1",
|
||||
"react-dom": "16.9.0",
|
||||
"react-hotkeys": "2.0.0",
|
||||
"react-i18next": "11.8.5",
|
||||
"react-notification-system": "0.2.17",
|
||||
"react-redux": "7.1.3",
|
||||
"redux": "4.0.4",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rx-jupyter": "5.5.12",
|
||||
"rxjs": "6.6.3",
|
||||
"sanitize-html": "2.3.3",
|
||||
"styled-components": "4.3.2",
|
||||
"swr": "0.4.0",
|
||||
"terser-webpack-plugin": "3.1.0",
|
||||
"text-encoding": "0.7.0",
|
||||
"underscore": "1.9.1",
|
||||
"utility-types": "3.10.0"
|
||||
"url-polyfill": "1.1.7",
|
||||
"utility-types": "3.10.0",
|
||||
"webcrypto-liner": "1.1.4",
|
||||
"webfontloader": "1.6.28",
|
||||
"whatwg-fetch": "3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
"@babel/preset-env": "7.9.0",
|
||||
"@babel/preset-react": "7.9.4",
|
||||
"@babel/preset-typescript": "7.9.0",
|
||||
"@testing-library/react": "11.2.3",
|
||||
"@types/applicationinsights-js": "1.0.7",
|
||||
"@types/codemirror": "0.0.56",
|
||||
"@types/crossroads": "0.0.30",
|
||||
"@types/d3": "5.9.2",
|
||||
"@types/enzyme": "3.10.7",
|
||||
"@types/enzyme-adapter-react-16": "1.0.6",
|
||||
"@types/expect-puppeteer": "4.4.3",
|
||||
"@types/hasher": "0.0.31",
|
||||
"@types/jest": "26.0.20",
|
||||
"@types/jest": "23.3.10",
|
||||
"@types/jest-environment-puppeteer": "4.3.2",
|
||||
"@types/memoize-one": "4.1.1",
|
||||
"@types/node": "12.11.1",
|
||||
"@types/post-robot": "10.0.1",
|
||||
"@types/promise.prototype.finally": "2.0.3",
|
||||
"@types/prop-types": "15.5.8",
|
||||
"@types/puppeteer": "3.0.1",
|
||||
"@types/q": "1.5.1",
|
||||
"@types/react": "17.0.3",
|
||||
"@types/react-dom": "17.0.3",
|
||||
"@types/react": "16.9.56",
|
||||
"@types/react-dom": "16.0.7",
|
||||
"@types/react-notification-system": "0.2.39",
|
||||
"@types/react-redux": "7.1.7",
|
||||
"@types/sanitize-html": "1.27.2",
|
||||
"@types/sinon": "2.3.3",
|
||||
"@types/styled-components": "5.1.1",
|
||||
"@types/text-encoding": "0.0.33",
|
||||
"@types/underscore": "1.7.36",
|
||||
"@types/webfontloader": "1.6.29",
|
||||
"@typescript-eslint/eslint-plugin": "4.0.1",
|
||||
"@typescript-eslint/parser": "4.0.1",
|
||||
"adal-angular": "1.0.15",
|
||||
"axe-puppeteer": "1.1.0",
|
||||
"babel-jest": "24.9.0",
|
||||
"babel-loader": "8.1.0",
|
||||
"buffer": "5.1.0",
|
||||
@@ -143,19 +143,16 @@
|
||||
"eslint-cli": "1.1.1",
|
||||
"eslint-plugin-no-null": "1.0.2",
|
||||
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"expect-playwright": "0.3.3",
|
||||
"expose-loader": "0.7.5",
|
||||
"fast-glob": "3.2.5",
|
||||
"file-loader": "2.0.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"html-inline-css-webpack-plugin": "1.11.0",
|
||||
"html-loader": "0.5.5",
|
||||
"html-loader-jest": "0.2.1",
|
||||
"html-webpack-plugin": "4.5.2",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"inline-css": "2.2.5",
|
||||
"jest": "25.5.4",
|
||||
"jest-canvas-mock": "2.1.0",
|
||||
"jest-playwright-preset": "1.5.1",
|
||||
"jest-puppeteer": "4.4.0",
|
||||
"jest-trx-results-processor": "0.0.7",
|
||||
"less": "3.8.1",
|
||||
"less-loader": "4.1.0",
|
||||
@@ -163,23 +160,24 @@
|
||||
"mini-css-extract-plugin": "0.4.3",
|
||||
"monaco-editor-webpack-plugin": "1.7.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"playwright": "1.10.0",
|
||||
"prettier": "2.2.1",
|
||||
"prettier": "1.19.1",
|
||||
"puppeteer": "4.0.0",
|
||||
"raw-loader": "0.5.1",
|
||||
"react-dev-utils": "11.0.4",
|
||||
"rimraf": "3.0.0",
|
||||
"sinon": "3.2.1",
|
||||
"style-loader": "0.23.0",
|
||||
"terser-webpack-plugin": "3.0.5",
|
||||
"ts-loader": "6.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"tslint-microsoft-contrib": "6.0.0",
|
||||
"typescript": "4.2.4",
|
||||
"typescript": "4.0.2",
|
||||
"url-loader": "1.1.1",
|
||||
"wait-on": "4.0.2",
|
||||
"webpack": "4.43.0",
|
||||
"webpack-bundle-analyzer": "3.6.1",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-dev-server": "3.11.0"
|
||||
"webpack-dev-server": "3.11.0",
|
||||
"worker-loader": "2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node --max-old-space-size=10196 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
||||
@@ -202,8 +200,8 @@
|
||||
"format:check": "prettier --check \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
||||
"lint": "tslint --project tsconfig.json && eslint \"**/*.{ts,tsx}\"",
|
||||
"build:contracts": "npm run compile:contracts",
|
||||
"strict:find": "node ./strict-null-checks/find.js",
|
||||
"strict:add": "node ./strict-null-checks/auto-add.js",
|
||||
"strictEligibleFiles": "node ./strict-migration-tools/index.js",
|
||||
"autoAddStrictEligibleFiles": "node ./strict-migration-tools/autoAdd.js",
|
||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
||||
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
||||
},
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
[defaults]
|
||||
group = stfaul
|
||||
sku = P1v2
|
||||
appserviceplan = stfaul_asp_Linux_centralus_0
|
||||
location = centralus
|
||||
web = cosmos-explorer-preview
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Cosmos Explorer Preview
|
||||
|
||||
Cosmos Explorer Preview makes it possible to try a working version of any commit on master or in a PR. No need to run the app locally or deploy to staging.
|
||||
|
||||
Initial support is for Hosted (Connection string only) or the Azure Portal. Examples:
|
||||
|
||||
Connection string URLs: https://cosmos-explorer-preview.azurewebsites.net/commit/COMMIT_SHA/hostedExplorer.html
|
||||
Portal URLs: https://ms.portal.azure.com/?dataExplorerSource=https://cosmos-explorer-preview.azurewebsites.net/commit/COMMIT_SHA/explorer.html#home
|
||||
|
||||
In both cases replace `COMMIT_SHA` with the commit you want to view. It must have already completed its build on GitHub Actions.
|
||||
|
||||
### Architechture
|
||||
|
||||
- This folder contains a NodeJS app deployed to Azure App Service that powers preview URLs:
|
||||
- Paths starting with `/commit/` are proxied to an Azure Storage account containing build artifacts
|
||||
- Paths starting with `/proxy/` are proxied dynamically to Cosmos account endpoints. Required otherwise CORS would need to be configured for every account accessed.
|
||||
- Paths starting with `/api/` are proxied to Portal APIs that do not support CORS.
|
||||
- On GitHub Actions build completion:
|
||||
- All files in dist are uploaded to an Azure Storage account namespaced by the SHA of the commit
|
||||
- `/preview/config.json` is uploaded to the same folder with preview specific configuration
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PROXY_PATH": "/proxy"
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
const express = require("express");
|
||||
const { createProxyMiddleware } = require("http-proxy-middleware");
|
||||
const port = process.env.PORT || 3000;
|
||||
const fetch = require("node-fetch");
|
||||
|
||||
const api = createProxyMiddleware("/api", {
|
||||
target: "https://main.documentdb.ext.azure.com",
|
||||
changeOrigin: true,
|
||||
logLevel: "debug",
|
||||
bypass: (req, res) => {
|
||||
if (req.method === "OPTIONS") {
|
||||
res.statusCode = 200;
|
||||
res.send();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const proxy = createProxyMiddleware("/proxy", {
|
||||
target: "https://main.documentdb.ext.azure.com",
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
logLevel: "debug",
|
||||
pathRewrite: { "^/proxy": "" },
|
||||
router: (req) => {
|
||||
let newTarget = req.headers["x-ms-proxy-target"];
|
||||
return newTarget;
|
||||
},
|
||||
});
|
||||
|
||||
const commit = createProxyMiddleware("/commit", {
|
||||
target: "https://cosmosexplorerpreview.blob.core.windows.net",
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
logLevel: "debug",
|
||||
pathRewrite: { "^/commit": "$web/" },
|
||||
});
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(api);
|
||||
app.use(proxy);
|
||||
app.use(commit);
|
||||
app.get("/pull/:pr(\\d+)", (req, res) => {
|
||||
const pr = req.params.pr;
|
||||
const [, query] = req.originalUrl.split("?");
|
||||
const search = new URLSearchParams(query);
|
||||
|
||||
fetch("https://api.github.com/repos/Azure/cosmos-explorer/pulls/" + pr)
|
||||
.then((response) => response.json())
|
||||
.then(({ head: { ref, sha } }) => {
|
||||
const prUrl = new URL("https://github.com/Azure/cosmos-explorer/pull/" + pr);
|
||||
prUrl.hash = ref;
|
||||
search.set("feature.pr", prUrl.href);
|
||||
|
||||
const explorer = new URL("https://cosmos-explorer-preview.azurewebsites.net/commit/" + sha + "/explorer.html");
|
||||
explorer.search = search.toString();
|
||||
|
||||
const portal = new URL("https://ms.portal.azure.com/");
|
||||
portal.searchParams.set("dataExplorerSource", explorer.href);
|
||||
|
||||
return res.redirect(portal.href);
|
||||
})
|
||||
.catch(() => res.sendStatus(500));
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port: ${port}`);
|
||||
});
|
||||
1146
preview/package-lock.json
generated
1146
preview/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "cosmos-explorer-preview",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"deploy": "az webapp up -n cosmos-explorer-preview --subscription cosmosdb-portalteam-generaldemo -g stfaul",
|
||||
"start": "node index.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Microsoft Corporation",
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"http-proxy-middleware": "^1.1.0",
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
"offerThroughput": 400,
|
||||
"databaseLevelThroughput": false,
|
||||
"collectionId": "Persons",
|
||||
"createNewDatabase": true,
|
||||
"partitionKey": { "kind": "Hash", "paths": ["/name"] },
|
||||
"data": [
|
||||
"g.addV('person').property(id, '1').property('name', 'Eva').property('age', 44)",
|
||||
|
||||
@@ -2,6 +2,5 @@ export enum AuthType {
|
||||
AAD = "aad",
|
||||
EncryptedToken = "encryptedtoken",
|
||||
MasterKey = "masterkey",
|
||||
ResourceToken = "resourcetoken",
|
||||
ConnectionString = "connectionstring",
|
||||
ResourceToken = "resourcetoken"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as ko from "knockout";
|
||||
import * as ReactBindingHandler from "./ReactBindingHandler";
|
||||
import "../Explorer/Tables/DataTable/DataTableBindingManager";
|
||||
|
||||
export class BindingHandlersRegisterer {
|
||||
public static registerBindingHandlers() {
|
||||
@@ -14,7 +13,7 @@ export class BindingHandlersRegisterer {
|
||||
) {
|
||||
const value = ko.unwrap(wrappedValueAccessor());
|
||||
bindingContext?.$data.isTemplateReady(value);
|
||||
},
|
||||
}
|
||||
} as ko.BindingHandler;
|
||||
|
||||
ReactBindingHandler.Registerer.register();
|
||||
|
||||
@@ -42,7 +42,7 @@ export class Registerer {
|
||||
|
||||
// Initial rendering at mount point
|
||||
ReactDOM.render(adapter.renderComponent(), element);
|
||||
},
|
||||
}
|
||||
} as ko.BindingHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
@@ -40,7 +40,7 @@ export class ArrayHashMap<T> {
|
||||
public forEach(key: string, iteratorFct: (value: T) => void) {
|
||||
const values = this.store.get(key);
|
||||
if (values) {
|
||||
values.forEach((value) => iteratorFct(value));
|
||||
values.forEach(value => iteratorFct(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import { HashMap } from "./HashMap";
|
||||
|
||||
export class AuthorizationEndpoints {
|
||||
public static arm: string = "https://management.core.windows.net/";
|
||||
public static common: string = "https://login.windows.net/";
|
||||
}
|
||||
|
||||
export class CodeOfConductEndpoints {
|
||||
public static privacyStatement: string = "https://aka.ms/ms-privacy-policy";
|
||||
public static codeOfConduct: string = "https://aka.ms/cosmos-code-of-conduct";
|
||||
@@ -7,7 +14,7 @@ export class CodeOfConductEndpoints {
|
||||
export class EndpointsRegex {
|
||||
public static readonly cassandra = [
|
||||
"AccountEndpoint=(.*).cassandra.cosmosdb.azure.com",
|
||||
"HostName=(.*).cassandra.cosmos.azure.com",
|
||||
"HostName=(.*).cassandra.cosmos.azure.com"
|
||||
];
|
||||
public static readonly mongo = "mongodb://.*:(.*)@(.*).documents.azure.com";
|
||||
public static readonly mongoCompute = "mongodb://.*:(.*)@(.*).mongo.cosmos.azure.com";
|
||||
@@ -98,12 +105,33 @@ export class CapabilityNames {
|
||||
public static readonly EnableServerless: string = "EnableServerless";
|
||||
}
|
||||
|
||||
export class Features {
|
||||
public static readonly cosmosdb = "cosmosdb";
|
||||
public static readonly enableChangeFeedPolicy = "enablechangefeedpolicy";
|
||||
public static readonly executeSproc = "dataexplorerexecutesproc";
|
||||
public static readonly hostedDataExplorer = "hosteddataexplorerenabled";
|
||||
public static readonly enableTtl = "enablettl";
|
||||
public static readonly enableNotebooks = "enablenotebooks";
|
||||
public static readonly enableGalleryPublish = "enablegallerypublish";
|
||||
public static readonly enableLinkInjection = "enablelinkinjection";
|
||||
public static readonly enableSpark = "enablespark";
|
||||
public static readonly livyEndpoint = "livyendpoint";
|
||||
public static readonly notebookServerUrl = "notebookserverurl";
|
||||
public static readonly notebookServerToken = "notebookservertoken";
|
||||
public static readonly notebookBasePath = "notebookbasepath";
|
||||
public static readonly canExceedMaximumValue = "canexceedmaximumvalue";
|
||||
public static readonly enableFixedCollectionWithSharedThroughput = "enablefixedcollectionwithsharedthroughput";
|
||||
public static readonly ttl90Days = "ttl90days";
|
||||
public static readonly enableRightPanelV2 = "enablerightpanelv2";
|
||||
public static readonly enableSchema = "enableschema";
|
||||
public static readonly enableSDKoperations = "enablesdkoperations";
|
||||
public static readonly showMinRUSurvey = "showminrusurvey";
|
||||
}
|
||||
|
||||
// flight names returned from the portal are always lowercase
|
||||
export class Flights {
|
||||
public static readonly SettingsV2 = "settingsv2";
|
||||
public static readonly MongoIndexEditor = "mongoindexeditor";
|
||||
public static readonly MongoIndexing = "mongoindexing";
|
||||
public static readonly AutoscaleTest = "autoscaletest";
|
||||
}
|
||||
|
||||
export class AfecFeatures {
|
||||
@@ -112,6 +140,19 @@ export class AfecFeatures {
|
||||
public static readonly StorageAnalytics = "storageanalytics-public-preview";
|
||||
}
|
||||
|
||||
export class Spark {
|
||||
public static readonly MaxWorkerCount = 10;
|
||||
public static readonly SKUs: HashMap<string> = new HashMap({
|
||||
"Cosmos.Spark.D1s": "D1s / 1 core / 4GB RAM",
|
||||
"Cosmos.Spark.D2s": "D2s / 2 cores / 8GB RAM",
|
||||
"Cosmos.Spark.D4s": "D4s / 4 cores / 16GB RAM",
|
||||
"Cosmos.Spark.D8s": "D8s / 8 cores / 32GB RAM",
|
||||
"Cosmos.Spark.D16s": "D16s / 16 cores / 64GB RAM",
|
||||
"Cosmos.Spark.D32s": "D32s / 32 cores / 128GB RAM",
|
||||
"Cosmos.Spark.D64s": "D64s / 64 cores / 256GB RAM"
|
||||
});
|
||||
}
|
||||
|
||||
export class TagNames {
|
||||
public static defaultExperience: string = "defaultExperience";
|
||||
}
|
||||
@@ -123,7 +164,7 @@ export class MongoDBAccounts {
|
||||
|
||||
export enum MongoBackendEndpointType {
|
||||
local,
|
||||
remote,
|
||||
remote
|
||||
}
|
||||
|
||||
// TODO: 435619 Add default endpoints per cloud and use regional only when available
|
||||
@@ -250,7 +291,7 @@ export class HttpStatusCodes {
|
||||
HttpStatusCodes.InternalServerError, // TODO: Handle all 500s on Portal backend and remove from retries list
|
||||
HttpStatusCodes.BadGateway,
|
||||
HttpStatusCodes.ServiceUnavailable,
|
||||
HttpStatusCodes.GatewayTimeout,
|
||||
HttpStatusCodes.GatewayTimeout
|
||||
];
|
||||
}
|
||||
|
||||
@@ -306,7 +347,10 @@ export class HashRoutePrefixes {
|
||||
public static docsWithIds(databaseId: string, collectionId: string, docId: string) {
|
||||
const transformedDatabasePrefix: string = this.docs.replace("{db_id}", databaseId);
|
||||
|
||||
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("{doc_id}", docId).replace("/", ""); // strip the first slash since hasher adds it
|
||||
return transformedDatabasePrefix
|
||||
.replace("{coll_id}", collectionId)
|
||||
.replace("{doc_id}", docId)
|
||||
.replace("/", ""); // strip the first slash since hasher adds it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +396,7 @@ export class OfferVersions {
|
||||
export enum ConflictOperationType {
|
||||
Replace = "replace",
|
||||
Create = "create",
|
||||
Delete = "delete",
|
||||
Delete = "delete"
|
||||
}
|
||||
|
||||
export const EmulatorMasterKey =
|
||||
|
||||
@@ -10,17 +10,17 @@ describe("tokenProvider", () => {
|
||||
resourceId: "",
|
||||
resourceType: "dbs" as ResourceType,
|
||||
headers: {},
|
||||
getAuthorizationTokenUsingMasterKey: () => "",
|
||||
getAuthorizationTokenUsingMasterKey: () => ""
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
json: () => "{}",
|
||||
headers: new Map(),
|
||||
headers: new Map()
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe("tokenProvider", () => {
|
||||
|
||||
it("does not call the auth service if a master key is set", async () => {
|
||||
updateUserContext({
|
||||
masterKey: "foo",
|
||||
masterKey: "foo"
|
||||
});
|
||||
await tokenProvider(options);
|
||||
expect((window.fetch as any).mock.calls.length).toBe(0);
|
||||
@@ -50,7 +50,7 @@ describe("getTokenFromAuthService", () => {
|
||||
window.fetch = jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
json: () => "{}",
|
||||
headers: new Map(),
|
||||
headers: new Map()
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -61,7 +61,7 @@ describe("getTokenFromAuthService", () => {
|
||||
|
||||
it("builds the correct URL in production", () => {
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
getTokenFromAuthService("GET", "dbs", "foo");
|
||||
expect(window.fetch).toHaveBeenCalledWith(
|
||||
@@ -72,7 +72,7 @@ describe("getTokenFromAuthService", () => {
|
||||
|
||||
it("builds the correct URL in dev", () => {
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://localhost:1234",
|
||||
BACKEND_ENDPOINT: "https://localhost:1234"
|
||||
});
|
||||
getTokenFromAuthService("GET", "dbs", "foo");
|
||||
expect(window.fetch).toHaveBeenCalledWith(
|
||||
@@ -96,15 +96,15 @@ describe("endpoint", () => {
|
||||
documentEndpoint: "bar",
|
||||
gremlinEndpoint: "foo",
|
||||
tableEndpoint: "foo",
|
||||
cassandraEndpoint: "foo",
|
||||
},
|
||||
},
|
||||
cassandraEndpoint: "foo"
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(endpoint()).toEqual("bar");
|
||||
});
|
||||
it("uses _endpoint if set", () => {
|
||||
updateUserContext({
|
||||
endpoint: "baz",
|
||||
endpoint: "baz"
|
||||
});
|
||||
expect(endpoint()).toEqual("baz");
|
||||
});
|
||||
@@ -121,7 +121,7 @@ describe("requestPlugin", () => {
|
||||
updateConfigContext({
|
||||
platform: Platform.Hosted,
|
||||
BACKEND_ENDPOINT: "https://localhost:1234",
|
||||
PROXY_PATH: "/proxy",
|
||||
PROXY_PATH: "/proxy"
|
||||
});
|
||||
const headers = {};
|
||||
const endpoint = "https://docs.azure.com";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as Cosmos from "@azure/cosmos";
|
||||
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
||||
import { configContext, Platform } from "../ConfigContext";
|
||||
import { userContext } from "../UserContext";
|
||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
||||
import { userContext } from "../UserContext";
|
||||
|
||||
const _global = typeof self === "undefined" ? window : self;
|
||||
|
||||
@@ -32,7 +32,7 @@ export const tokenProvider = async (requestInfo: RequestInfo) => {
|
||||
};
|
||||
|
||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
||||
requestContext.endpoint = new URL(configContext.PROXY_PATH, window.location.href).href;
|
||||
requestContext.endpoint = configContext.PROXY_PATH;
|
||||
requestContext.headers["x-ms-proxy-target"] = endpoint();
|
||||
return next(requestContext);
|
||||
};
|
||||
@@ -58,13 +58,13 @@ export async function getTokenFromAuthService(verb: string, resourceType: string
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-ms-encrypted-auth-token": userContext.accessToken,
|
||||
"x-ms-encrypted-auth-token": userContext.accessToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
verb,
|
||||
resourceType,
|
||||
resourceId,
|
||||
}),
|
||||
resourceId
|
||||
})
|
||||
});
|
||||
//TODO I am not sure why we have to parse the JSON again here. fetch should do it for us when we call .json()
|
||||
const result = JSON.parse(await response.json());
|
||||
@@ -75,23 +75,19 @@ export async function getTokenFromAuthService(verb: string, resourceType: string
|
||||
}
|
||||
}
|
||||
|
||||
let _client: Cosmos.CosmosClient;
|
||||
|
||||
export function client(): Cosmos.CosmosClient {
|
||||
if (_client) return _client;
|
||||
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() || " ", // CosmosClient gets upset if we pass a falsy value here
|
||||
key: userContext.masterKey,
|
||||
tokenProvider,
|
||||
connectionPolicy: {
|
||||
enableEndpointDiscovery: false,
|
||||
enableEndpointDiscovery: false
|
||||
},
|
||||
userAgentSuffix: "Azure Portal",
|
||||
userAgentSuffix: "Azure Portal"
|
||||
};
|
||||
|
||||
if (configContext.PROXY_PATH !== undefined) {
|
||||
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
||||
}
|
||||
_client = new Cosmos.CosmosClient(options);
|
||||
return _client;
|
||||
return new Cosmos.CosmosClient(options);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export default class EditableUtility {
|
||||
return false;
|
||||
});
|
||||
|
||||
observable.subscribe((edit) => {
|
||||
observable.subscribe(edit => {
|
||||
var edits = observable.edits && observable.edits();
|
||||
if (!edits) {
|
||||
return;
|
||||
@@ -83,9 +83,9 @@ export default class EditableUtility {
|
||||
});
|
||||
|
||||
observable.editableIsValid = ko.observable<boolean>(true);
|
||||
observable.subscribe((value) => {
|
||||
observable.subscribe(value => {
|
||||
const validations: ((value: T) => boolean)[] = (observable.validations && observable.validations()) || [];
|
||||
const isValid = validations.every((validate) => validate(value));
|
||||
const isValid = validations.every(validate => validate(value));
|
||||
observable.editableIsValid(isValid);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,61 +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;
|
||||
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,
|
||||
onEntityTimeValueChange,
|
||||
}: TableEntityProps): JSX.Element => {
|
||||
if (isEntityTypeDate) {
|
||||
return (
|
||||
<>
|
||||
<DatePicker
|
||||
className="addEntityDatePicker"
|
||||
placeholder={entityValuePlaceholder}
|
||||
value={entityValue && new Date(entityValue)}
|
||||
ariaLabel={entityValuePlaceholder}
|
||||
onSelectDate={onSelectDate}
|
||||
/>
|
||||
<TextField
|
||||
label={entityValueLabel && entityValueLabel}
|
||||
id="entityTimeId"
|
||||
autoFocus
|
||||
type="time"
|
||||
value={entityTimeValue}
|
||||
onChange={onEntityTimeValueChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TextField
|
||||
label={entityValueLabel && entityValueLabel}
|
||||
className="addEntityTextField"
|
||||
id="entityValueId"
|
||||
autoFocus
|
||||
type={entityValueType}
|
||||
placeholder={entityValuePlaceholder}
|
||||
value={typeof entityValue === "string" && entityValue}
|
||||
onChange={onEntityValueChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,8 @@
|
||||
import { ARMError } from "../Utils/arm/request";
|
||||
import { HttpStatusCodes } from "./Constants";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { SubscriptionType } from "../Contracts/SubscriptionType";
|
||||
import { userContext } from "../UserContext";
|
||||
import { ARMError } from "../Utils/arm/request";
|
||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||
import { HttpStatusCodes } from "./Constants";
|
||||
import { logError } from "./Logger";
|
||||
import { sendMessage } from "./MessageHandler";
|
||||
|
||||
@@ -22,7 +21,7 @@ export const handleError = (error: string | ARMError | Error, area: string, cons
|
||||
sendNotificationForError(errorMessage, errorCode);
|
||||
};
|
||||
|
||||
export const getErrorMessage = (error: string | Error = ""): string => {
|
||||
export const getErrorMessage = (error: string | Error): string => {
|
||||
const errorMessage = typeof error === "string" ? error : error.message;
|
||||
return replaceKnownError(errorMessage);
|
||||
};
|
||||
@@ -38,18 +37,18 @@ const sendNotificationForError = (errorMessage: string, errorCode: number | stri
|
||||
}
|
||||
sendMessage({
|
||||
type: MessageTypes.ForbiddenError,
|
||||
reason: errorMessage,
|
||||
reason: errorMessage
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const replaceKnownError = (errorMessage: string): string => {
|
||||
if (
|
||||
userContext.subscriptionType === SubscriptionType.Internal &&
|
||||
errorMessage?.indexOf("SharedOffer is Disabled for your account") >= 0
|
||||
window.dataExplorer?.subscriptionType() === SubscriptionType.Internal &&
|
||||
errorMessage.indexOf("SharedOffer is Disabled for your account") >= 0
|
||||
) {
|
||||
return "Database throughput is not supported for internal subscriptions.";
|
||||
} else if (errorMessage?.indexOf("Partition key paths must contain only valid") >= 0) {
|
||||
} else if (errorMessage.indexOf("Partition key paths must contain only valid") >= 0) {
|
||||
return "Partition key paths must contain only valid characters and not contain a trailing slash or wildcard character.";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
import * as Constants from "./Constants";
|
||||
|
||||
import { LocalStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
||||
|
||||
// x-ms-resource-quota: databases = 100; collections = 5000; users = 500000; permissions = 2000000;
|
||||
export function getQuota(responseHeaders: any): any {
|
||||
return responseHeaders && responseHeaders[Constants.HttpHeaders.resourceQuota]
|
||||
? parseStringIntoObject(responseHeaders[Constants.HttpHeaders.resourceQuota])
|
||||
: null;
|
||||
}
|
||||
|
||||
export function shouldEnableCrossPartitionKey(): boolean {
|
||||
return LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true";
|
||||
}
|
||||
|
||||
function parseStringIntoObject(resourceString: string) {
|
||||
var entityObject: any = {};
|
||||
|
||||
if (resourceString) {
|
||||
var entitiesArray: string[] = resourceString.split(";");
|
||||
for (var i: any = 0; i < entitiesArray.length; i++) {
|
||||
var entity: string[] = entitiesArray[i].split("=");
|
||||
entityObject[entity[0]] = entity[1];
|
||||
}
|
||||
}
|
||||
|
||||
return entityObject;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ describe("nextPage", () => {
|
||||
queryMetrics: {},
|
||||
requestCharge: 1,
|
||||
headers: {},
|
||||
activityId: "foo",
|
||||
}),
|
||||
activityId: "foo"
|
||||
})
|
||||
};
|
||||
|
||||
expect(await nextPage(fakeIterator, 10)).toMatchSnapshot();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { QueryResults } from "../Contracts/ViewModels";
|
||||
|
||||
interface QueryResponse {
|
||||
// [Todo] remove any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
resources: any[];
|
||||
hasMoreResults: boolean;
|
||||
activityId: string;
|
||||
@@ -16,9 +14,8 @@ export interface MinimalQueryIterator {
|
||||
// Pick<QueryIterator<any>, "fetchNext">;
|
||||
|
||||
export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex: number): Promise<QueryResults> {
|
||||
return documentsIterator.fetchNext().then((response) => {
|
||||
return documentsIterator.fetchNext().then(response => {
|
||||
const documents = response.resources;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const headers = (response as any).headers || {}; // TODO this is a private key. Remove any
|
||||
const itemCount = (documents && documents.length) || 0;
|
||||
return {
|
||||
@@ -29,7 +26,7 @@ export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex
|
||||
lastItemIndex: Number(firstItemIndex) + Number(itemCount),
|
||||
headers,
|
||||
activityId: response.activityId,
|
||||
requestCharge: response.requestCharge,
|
||||
requestCharge: response.requestCharge
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SeverityLevel } from "@microsoft/applicationinsights-web";
|
||||
import { Diagnostics, MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { trackTrace } from "../Shared/appInsights";
|
||||
import { sendMessage } from "./MessageHandler";
|
||||
import { Diagnostics, MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { appInsights } from "../Shared/appInsights";
|
||||
import { SeverityLevel } from "@microsoft/applicationinsights-web";
|
||||
|
||||
// TODO: Move to a separate Diagnostics folder
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -29,7 +29,7 @@ export function logError(errorMessage: string, area: string, code?: number | str
|
||||
function _logEntry(entry: Diagnostics.LogEntry): void {
|
||||
sendMessage({
|
||||
type: MessageTypes.LogInfo,
|
||||
data: JSON.stringify(entry),
|
||||
data: JSON.stringify(entry)
|
||||
});
|
||||
|
||||
const severityLevel = ((level: Diagnostics.LogEntryLevel): SeverityLevel => {
|
||||
@@ -46,7 +46,7 @@ function _logEntry(entry: Diagnostics.LogEntry): void {
|
||||
return SeverityLevel.Information;
|
||||
}
|
||||
})(entry.level);
|
||||
trackTrace({ message: entry.message, severityLevel }, { area: entry.area });
|
||||
appInsights.trackTrace({ message: entry.message, severityLevel }, { area: entry.area });
|
||||
}
|
||||
|
||||
function _generateLogEntry(
|
||||
@@ -60,6 +60,6 @@ function _generateLogEntry(
|
||||
level,
|
||||
message,
|
||||
area,
|
||||
code,
|
||||
code
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ describe("Message Handler", () => {
|
||||
let mockPromise = {
|
||||
id: "123",
|
||||
startTime: new Date(),
|
||||
deferred: Q.defer<any>(),
|
||||
deferred: Q.defer<any>()
|
||||
};
|
||||
let mockMessage = { message: { id: "123", data: "{}" } };
|
||||
MessageHandler.RequestMap[mockPromise.id] = mockPromise;
|
||||
@@ -18,7 +18,7 @@ describe("Message Handler", () => {
|
||||
let message = {
|
||||
id: "123",
|
||||
startTime: new Date(),
|
||||
deferred: Q.defer<any>(),
|
||||
deferred: Q.defer<any>()
|
||||
};
|
||||
|
||||
MessageHandler.handleCachedDataMessage(message);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import Q from "q";
|
||||
import * as _ from "underscore";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
||||
import * as Constants from "./Constants";
|
||||
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
||||
|
||||
export interface CachedDataPromise<T> {
|
||||
deferred: Q.Deferred<T>;
|
||||
@@ -35,7 +35,7 @@ export function sendCachedDataMessage<TResponseDataModel>(
|
||||
let cachedDataPromise: CachedDataPromise<TResponseDataModel> = {
|
||||
deferred: Q.defer<TResponseDataModel>(),
|
||||
startTime: new Date(),
|
||||
id: _.uniqueId(),
|
||||
id: _.uniqueId()
|
||||
};
|
||||
RequestMap[cachedDataPromise.id] = cachedDataPromise;
|
||||
sendMessage({ type: messageType, params: params, id: cachedDataPromise.id });
|
||||
@@ -48,18 +48,17 @@ export function sendCachedDataMessage<TResponseDataModel>(
|
||||
}
|
||||
|
||||
export function sendMessage(data: any): void {
|
||||
_sendMessage({
|
||||
if (canSendMessage()) {
|
||||
// We try to find data explorer window first, then fallback to current window
|
||||
const portalChildWindow = getDataExplorerWindow(window) || window;
|
||||
portalChildWindow.parent.postMessage(
|
||||
{
|
||||
signature: "pcIframe",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function sendReadyMessage(): void {
|
||||
_sendMessage({
|
||||
signature: "pcIframe",
|
||||
kind: "ready",
|
||||
data: "ready",
|
||||
});
|
||||
data: data
|
||||
},
|
||||
portalChildWindow.document.referrer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function canSendMessage(): boolean {
|
||||
@@ -75,17 +74,3 @@ export function runGarbageCollector() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const _sendMessage = (message: any): void => {
|
||||
if (canSendMessage()) {
|
||||
// Portal window can receive messages from only child windows
|
||||
const portalChildWindow = getDataExplorerWindow(window) || window;
|
||||
if (portalChildWindow === window) {
|
||||
// Current window is a child of portal, send message to portal window
|
||||
portalChildWindow.parent.postMessage(message, portalChildWindow.document.referrer || "*");
|
||||
} else {
|
||||
// Current window is not a child of portal, send message to the child window instead (which is data explorer)
|
||||
portalChildWindow.postMessage(message, portalChildWindow.location.origin || "*");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ const fetchMock = () => {
|
||||
ok: true,
|
||||
text: () => "{}",
|
||||
json: () => "{}",
|
||||
headers: new Map(),
|
||||
headers: new Map()
|
||||
});
|
||||
};
|
||||
|
||||
@@ -27,8 +27,8 @@ const collection = {
|
||||
partitionKey: {
|
||||
paths: ["/pk"],
|
||||
kind: "Hash",
|
||||
version: 1,
|
||||
},
|
||||
version: 1
|
||||
}
|
||||
} as Collection;
|
||||
|
||||
const documentId = ({
|
||||
@@ -38,8 +38,8 @@ const documentId = ({
|
||||
partitionKey: {
|
||||
paths: ["/pk"],
|
||||
kind: "Hash",
|
||||
version: 1,
|
||||
},
|
||||
version: 1
|
||||
}
|
||||
} as unknown) as DocumentId;
|
||||
|
||||
const databaseAccount = {
|
||||
@@ -52,8 +52,8 @@ const databaseAccount = {
|
||||
documentEndpoint: "bar",
|
||||
gremlinEndpoint: "foo",
|
||||
tableEndpoint: "foo",
|
||||
cassandraEndpoint: "foo",
|
||||
},
|
||||
cassandraEndpoint: "foo"
|
||||
}
|
||||
} as DatabaseAccount;
|
||||
|
||||
describe("MongoProxyClient", () => {
|
||||
@@ -61,10 +61,10 @@ describe("MongoProxyClient", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(fetchMock);
|
||||
});
|
||||
@@ -93,10 +93,10 @@ describe("MongoProxyClient", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(fetchMock);
|
||||
});
|
||||
@@ -125,10 +125,10 @@ describe("MongoProxyClient", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(fetchMock);
|
||||
});
|
||||
@@ -157,10 +157,10 @@ describe("MongoProxyClient", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(fetchMock);
|
||||
});
|
||||
@@ -189,10 +189,10 @@ describe("MongoProxyClient", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
window.fetch = jest.fn().mockImplementation(fetchMock);
|
||||
});
|
||||
@@ -220,11 +220,12 @@ describe("MongoProxyClient", () => {
|
||||
describe("getEndpoint", () => {
|
||||
beforeEach(() => {
|
||||
resetConfigContext();
|
||||
delete window.authType;
|
||||
updateUserContext({
|
||||
databaseAccount,
|
||||
databaseAccount
|
||||
});
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
|
||||
});
|
||||
});
|
||||
|
||||
@@ -240,9 +241,7 @@ describe("MongoProxyClient", () => {
|
||||
});
|
||||
|
||||
it("returns a guest endpoint", () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.EncryptedToken,
|
||||
});
|
||||
window.authType = AuthType.EncryptedToken;
|
||||
const endpoint = getEndpoint();
|
||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||
});
|
||||
|
||||
@@ -5,21 +5,22 @@ import { configContext } from "../ConfigContext";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { Collection } from "../Contracts/ViewModels";
|
||||
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import { userContext } from "../UserContext";
|
||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
||||
import { userContext } from "../UserContext";
|
||||
import { MinimalQueryIterator } from "./IteratorUtilities";
|
||||
import { sendMessage } from "./MessageHandler";
|
||||
|
||||
const defaultHeaders = {
|
||||
[HttpHeaders.apiType]: ApiType.MongoDB.toString(),
|
||||
[CosmosSDKConstants.HttpHeaders.MaxEntityCount]: "100",
|
||||
[CosmosSDKConstants.HttpHeaders.Version]: "2017-11-15",
|
||||
[CosmosSDKConstants.HttpHeaders.Version]: "2017-11-15"
|
||||
};
|
||||
|
||||
function authHeaders() {
|
||||
if (userContext.authType === AuthType.EncryptedToken) {
|
||||
if (window.authType === AuthType.EncryptedToken) {
|
||||
return { [HttpHeaders.guestAccessToken]: userContext.accessToken };
|
||||
} else {
|
||||
return { [HttpHeaders.authorization]: userContext.authorizationToken };
|
||||
@@ -30,7 +31,7 @@ export function queryIterator(databaseId: string, collection: Collection, query:
|
||||
let continuationToken: string;
|
||||
return {
|
||||
fetchNext: () => {
|
||||
return queryDocuments(databaseId, collection, false, query).then((response) => {
|
||||
return queryDocuments(databaseId, collection, false, query).then(response => {
|
||||
continuationToken = response.continuationToken;
|
||||
const headers: { [key: string]: string | number } = {};
|
||||
response.headers.forEach((value, key) => {
|
||||
@@ -41,10 +42,10 @@ export function queryIterator(databaseId: string, collection: Collection, query:
|
||||
headers,
|
||||
requestCharge: Number(headers[CosmosSDKConstants.HttpHeaders.RequestCharge]),
|
||||
activityId: String(headers[CosmosSDKConstants.HttpHeaders.ActivityId]),
|
||||
hasMoreResults: !!continuationToken,
|
||||
hasMoreResults: !!continuationToken
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,9 +74,7 @@ export function queryDocuments(
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
pk:
|
||||
collection && collection.partitionKey && !collection.partitionKey.systemKey
|
||||
? collection.partitionKeyProperty
|
||||
: "",
|
||||
collection && collection.partitionKey && !collection.partitionKey.systemKey ? collection.partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint() || "";
|
||||
@@ -88,7 +87,7 @@ export function queryDocuments(
|
||||
[CosmosSDKConstants.HttpHeaders.EnableScanInQuery]: "true",
|
||||
[CosmosSDKConstants.HttpHeaders.EnableCrossPartitionQuery]: "true",
|
||||
[CosmosSDKConstants.HttpHeaders.ParallelizeCrossPartitionQuery]: "true",
|
||||
[HttpHeaders.contentType]: "application/query+json",
|
||||
[HttpHeaders.contentType]: "application/query+json"
|
||||
};
|
||||
|
||||
if (continuationToken) {
|
||||
@@ -101,14 +100,14 @@ export function queryDocuments(
|
||||
.fetch(`${endpoint}${path}?${queryString.stringify(params)}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ query }),
|
||||
headers,
|
||||
headers
|
||||
})
|
||||
.then(async (response) => {
|
||||
.then(async response => {
|
||||
if (response.ok) {
|
||||
return {
|
||||
continuationToken: response.headers.get(CosmosSDKConstants.HttpHeaders.Continuation),
|
||||
documents: (await response.json()).Documents as DataModels.DocumentId[],
|
||||
headers: response.headers,
|
||||
headers: response.headers
|
||||
};
|
||||
}
|
||||
errorHandling(response, "querying documents", params);
|
||||
@@ -136,9 +135,7 @@ export function readDocument(
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
pk:
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey
|
||||
? documentId.partitionKeyProperty
|
||||
: "",
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
@@ -150,10 +147,10 @@ export function readDocument(
|
||||
...authHeaders(),
|
||||
[CosmosSDKConstants.HttpHeaders.PartitionKey]: encodeURIComponent(
|
||||
JSON.stringify(documentId.partitionKeyHeader())
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
@@ -178,7 +175,7 @@ export function createDocument(
|
||||
sid: userContext.subscriptionId,
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
pk: collection && collection.partitionKey && !collection.partitionKey.systemKey ? partitionKeyProperty : "",
|
||||
pk: collection && collection.partitionKey && !collection.partitionKey.systemKey ? partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
@@ -189,10 +186,10 @@ export function createDocument(
|
||||
body: JSON.stringify(documentContent),
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
...authHeaders(),
|
||||
},
|
||||
...authHeaders()
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
@@ -221,9 +218,7 @@ export function updateDocument(
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
pk:
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey
|
||||
? documentId.partitionKeyProperty
|
||||
: "",
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
const endpoint = getEndpoint();
|
||||
|
||||
@@ -235,10 +230,10 @@ export function updateDocument(
|
||||
...defaultHeaders,
|
||||
...authHeaders(),
|
||||
[HttpHeaders.contentType]: "application/json",
|
||||
[CosmosSDKConstants.HttpHeaders.PartitionKey]: JSON.stringify(documentId.partitionKeyHeader()),
|
||||
},
|
||||
[CosmosSDKConstants.HttpHeaders.PartitionKey]: JSON.stringify(documentId.partitionKeyHeader())
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
@@ -262,9 +257,7 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
pk:
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey
|
||||
? documentId.partitionKeyProperty
|
||||
: "",
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
const endpoint = getEndpoint();
|
||||
|
||||
@@ -275,10 +268,10 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
|
||||
...defaultHeaders,
|
||||
...authHeaders(),
|
||||
[HttpHeaders.contentType]: "application/json",
|
||||
[CosmosSDKConstants.HttpHeaders.PartitionKey]: JSON.stringify(documentId.partitionKeyHeader()),
|
||||
},
|
||||
[CosmosSDKConstants.HttpHeaders.PartitionKey]: JSON.stringify(documentId.partitionKeyHeader())
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -306,7 +299,7 @@ export function createMongoCollectionWithProxy(
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
isAutoPilot: !!params.autoPilotMaxThroughput,
|
||||
autoPilotThroughput: params.autoPilotMaxThroughput?.toString(),
|
||||
autoPilotThroughput: params.autoPilotMaxThroughput?.toString()
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
@@ -321,11 +314,11 @@ export function createMongoCollectionWithProxy(
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
...authHeaders(),
|
||||
[HttpHeaders.contentType]: "application/json",
|
||||
},
|
||||
[HttpHeaders.contentType]: "application/json"
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
@@ -336,7 +329,7 @@ export function createMongoCollectionWithProxy(
|
||||
export function getEndpoint(): string {
|
||||
let url = (configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT) + "/api/mongo/explorer";
|
||||
|
||||
if (userContext.authType === AuthType.EncryptedToken) {
|
||||
if (window.authType === AuthType.EncryptedToken) {
|
||||
url = url.replace("api/mongo", "api/guest/mongo");
|
||||
}
|
||||
return url;
|
||||
@@ -347,7 +340,10 @@ export function getEndpoint(): string {
|
||||
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
||||
const errorMessage = await response.text();
|
||||
// Log the error where the user can see it
|
||||
logConsoleError(`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`
|
||||
);
|
||||
if (response.status === HttpStatusCodes.Forbidden) {
|
||||
sendMessage({ type: MessageTypes.ForbiddenError, reason: errorMessage });
|
||||
return;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
export default class MongoUtility {
|
||||
public static tojson = function (x: any, indent: string, nolint: boolean) {
|
||||
public static tojson = function(x: any, indent: string, nolint: boolean) {
|
||||
if (x === null || x === undefined) {
|
||||
return String(x);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ export default class MongoUtility {
|
||||
}
|
||||
};
|
||||
|
||||
private static tojsonObject = function (x: any, indent: string, nolint: boolean) {
|
||||
private static tojsonObject = function(x: any, indent: string, nolint: boolean) {
|
||||
var lineEnding = nolint ? " " : "\n";
|
||||
var tabSpace = nolint ? "" : "\t";
|
||||
indent = indent || "";
|
||||
@@ -114,7 +114,7 @@ export default class MongoUtility {
|
||||
}
|
||||
}
|
||||
// Add proper line endings, indents, and commas to each line
|
||||
s += $.map(pairs, function (pair) {
|
||||
s += $.map(pairs, function(pair) {
|
||||
return lineEnding + indent + pair;
|
||||
}).join(",");
|
||||
s += lineEnding;
|
||||
@@ -124,7 +124,7 @@ export default class MongoUtility {
|
||||
return s + indent + "}";
|
||||
};
|
||||
|
||||
private static tojsonArray = function (a: any, indent: string, nolint: boolean) {
|
||||
private static tojsonArray = function(a: any, indent: string, nolint: boolean) {
|
||||
if (a.length === 0) {
|
||||
return "[ ]";
|
||||
}
|
||||
@@ -151,7 +151,7 @@ export default class MongoUtility {
|
||||
return s;
|
||||
};
|
||||
|
||||
private static hasDefinedProperty = function (obj: any, prop: string): boolean {
|
||||
private static hasDefinedProperty = function(obj: any, prop: string): boolean {
|
||||
if (Object.getPrototypeOf === undefined || Object.getPrototypeOf(obj) === null) {
|
||||
return false;
|
||||
} else if (obj.hasOwnProperty(prop)) {
|
||||
|
||||
@@ -9,14 +9,14 @@ describe("parseSDKOfferResponse", () => {
|
||||
offerThroughput: 500,
|
||||
collectionThroughputInfo: {
|
||||
minimumRUForCollection: 400,
|
||||
numPhysicalPartitions: 1,
|
||||
numPhysicalPartitions: 1
|
||||
}
|
||||
},
|
||||
},
|
||||
id: "test",
|
||||
id: "test"
|
||||
} as SDKOfferDefinition;
|
||||
|
||||
const mockResponse = {
|
||||
resource: mockOfferDefinition,
|
||||
resource: mockOfferDefinition
|
||||
} as OfferResponse;
|
||||
|
||||
const expectedResult: Offer = {
|
||||
@@ -25,7 +25,7 @@ describe("parseSDKOfferResponse", () => {
|
||||
minimumThroughput: 400,
|
||||
id: "test",
|
||||
offerDefinition: mockOfferDefinition,
|
||||
offerReplacePending: false,
|
||||
offerReplacePending: false
|
||||
};
|
||||
|
||||
expect(OfferUtility.parseSDKOfferResponse(mockResponse)).toEqual(expectedResult);
|
||||
@@ -37,17 +37,17 @@ describe("parseSDKOfferResponse", () => {
|
||||
offerThroughput: 400,
|
||||
collectionThroughputInfo: {
|
||||
minimumRUForCollection: 400,
|
||||
numPhysicalPartitions: 1,
|
||||
numPhysicalPartitions: 1
|
||||
},
|
||||
offerAutopilotSettings: {
|
||||
maxThroughput: 5000,
|
||||
maxThroughput: 5000
|
||||
}
|
||||
},
|
||||
},
|
||||
id: "test",
|
||||
id: "test"
|
||||
} as SDKOfferDefinition;
|
||||
|
||||
const mockResponse = {
|
||||
resource: mockOfferDefinition,
|
||||
resource: mockOfferDefinition
|
||||
} as OfferResponse;
|
||||
|
||||
const expectedResult: Offer = {
|
||||
@@ -56,7 +56,7 @@ describe("parseSDKOfferResponse", () => {
|
||||
minimumThroughput: 400,
|
||||
id: "test",
|
||||
offerDefinition: mockOfferDefinition,
|
||||
offerReplacePending: false,
|
||||
offerReplacePending: false
|
||||
};
|
||||
|
||||
expect(OfferUtility.parseSDKOfferResponse(mockResponse)).toEqual(expectedResult);
|
||||
|
||||
@@ -2,11 +2,8 @@ import { Offer, SDKOfferDefinition } from "../Contracts/DataModels";
|
||||
import { OfferResponse } from "@azure/cosmos";
|
||||
import { HttpHeaders } from "./Constants";
|
||||
|
||||
export const parseSDKOfferResponse = (offerResponse: OfferResponse): Offer | undefined => {
|
||||
const offerDefinition: SDKOfferDefinition | undefined = offerResponse?.resource;
|
||||
if (!offerDefinition) {
|
||||
return undefined;
|
||||
}
|
||||
export const parseSDKOfferResponse = (offerResponse: OfferResponse): Offer => {
|
||||
const offerDefinition: SDKOfferDefinition = offerResponse?.resource;
|
||||
const offerContent = offerDefinition.content;
|
||||
if (!offerContent) {
|
||||
return undefined;
|
||||
@@ -15,14 +12,14 @@ export const parseSDKOfferResponse = (offerResponse: OfferResponse): Offer | und
|
||||
const minimumThroughput = offerContent.collectionThroughputInfo?.minimumRUForCollection;
|
||||
const autopilotSettings = offerContent.offerAutopilotSettings;
|
||||
|
||||
if (autopilotSettings && autopilotSettings.maxThroughput && minimumThroughput) {
|
||||
if (autopilotSettings) {
|
||||
return {
|
||||
id: offerDefinition.id,
|
||||
autoscaleMaxThroughput: autopilotSettings.maxThroughput,
|
||||
manualThroughput: undefined,
|
||||
minimumThroughput,
|
||||
offerDefinition,
|
||||
offerReplacePending: offerResponse.headers?.[HttpHeaders.offerReplacePending] === "true",
|
||||
offerReplacePending: offerResponse.headers?.[HttpHeaders.offerReplacePending] === "true"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,6 +29,6 @@ export const parseSDKOfferResponse = (offerResponse: OfferResponse): Offer | und
|
||||
manualThroughput: offerContent.offerThroughput,
|
||||
minimumThroughput,
|
||||
offerDefinition,
|
||||
offerReplacePending: offerResponse.headers?.[HttpHeaders.offerReplacePending] === "true",
|
||||
offerReplacePending: offerResponse.headers?.[HttpHeaders.offerReplacePending] === "true"
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ export const fetchPortalNotifications = async (): Promise<DataModels.Notificatio
|
||||
const headers = { [authorizationHeader.header]: authorizationHeader.token };
|
||||
|
||||
const response = await window.fetch(url, {
|
||||
headers,
|
||||
headers
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import Explorer from "../Explorer/Explorer";
|
||||
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||
import * as QueryUtils from "../Utils/QueryUtils";
|
||||
import { QueryUtils } from "../Utils/QueryUtils";
|
||||
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
||||
import { userContext } from "../UserContext";
|
||||
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
||||
@@ -20,7 +20,7 @@ export class QueriesClient {
|
||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||
paths: [`/${SavedQueries.PartitionKeyProperty}`],
|
||||
kind: BackendDefaults.partitionKeyKind,
|
||||
version: BackendDefaults.partitionKeyVersion,
|
||||
version: BackendDefaults.partitionKeyVersion
|
||||
};
|
||||
private static readonly FetchQuery: string = "SELECT * FROM c";
|
||||
private static readonly FetchMongoQuery: string = "{}";
|
||||
@@ -40,7 +40,7 @@ export class QueriesClient {
|
||||
databaseId: SavedQueries.DatabaseName,
|
||||
partitionKey: QueriesClient.PartitionKey,
|
||||
offerThroughput: SavedQueries.OfferThroughput,
|
||||
databaseLevelThroughput: false,
|
||||
databaseLevelThroughput: false
|
||||
})
|
||||
.then(
|
||||
(collection: DataModels.Collection) => {
|
||||
@@ -120,7 +120,7 @@ export class QueriesClient {
|
||||
resourceId: resourceId,
|
||||
queryName: queryName,
|
||||
query: query,
|
||||
id: id,
|
||||
id: id
|
||||
};
|
||||
try {
|
||||
this.validateQuery(parsedQuery);
|
||||
@@ -161,7 +161,7 @@ export class QueriesClient {
|
||||
const documentId = new DocumentId(
|
||||
{
|
||||
partitionKey: QueriesClient.PartitionKey,
|
||||
partitionKeyProperty: "id",
|
||||
partitionKeyProperty: "id"
|
||||
} as DocumentsTab,
|
||||
query,
|
||||
query.queryName
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SplitterMetrics } from "./Constants";
|
||||
|
||||
export enum SplitterDirection {
|
||||
Horizontal = "horizontal",
|
||||
Vertical = "vertical",
|
||||
Vertical = "vertical"
|
||||
}
|
||||
|
||||
export interface SplitterBounds {
|
||||
@@ -23,10 +23,10 @@ export class Splitter {
|
||||
public splitterId: string;
|
||||
public leftSideId: string;
|
||||
|
||||
public splitter!: HTMLElement;
|
||||
public leftSide!: HTMLElement;
|
||||
public lastX!: number;
|
||||
public lastWidth!: number;
|
||||
public splitter: HTMLElement;
|
||||
public leftSide: HTMLElement;
|
||||
public lastX: number;
|
||||
public lastWidth: number;
|
||||
|
||||
private isCollapsed: ko.Observable<boolean>;
|
||||
private bounds: SplitterBounds;
|
||||
@@ -42,16 +42,15 @@ export class Splitter {
|
||||
}
|
||||
|
||||
public initialize() {
|
||||
if (document.getElementById(this.splitterId) !== null && document.getElementById(this.leftSideId) != null) {
|
||||
this.splitter = <HTMLElement>document.getElementById(this.splitterId);
|
||||
this.leftSide = <HTMLElement>document.getElementById(this.leftSideId);
|
||||
}
|
||||
this.splitter = document.getElementById(this.splitterId);
|
||||
this.leftSide = document.getElementById(this.leftSideId);
|
||||
|
||||
const isVerticalSplitter: boolean = this.direction === SplitterDirection.Vertical;
|
||||
const splitterOptions: JQueryUI.ResizableOptions = {
|
||||
animate: true,
|
||||
animateDuration: "fast",
|
||||
start: this.onResizeStart,
|
||||
stop: this.onResizeStop,
|
||||
stop: this.onResizeStop
|
||||
};
|
||||
|
||||
if (isVerticalSplitter) {
|
||||
@@ -91,7 +90,9 @@ export class Splitter {
|
||||
this.lastWidth = $(this.leftSide).width();
|
||||
$(this.splitter).css("left", SplitterMetrics.CollapsedPositionLeft);
|
||||
$(this.leftSide).css("width", "");
|
||||
$(this.leftSide).resizable("option", "disabled", true).removeClass("ui-resizable-disabled"); // remove class so splitter is visible
|
||||
$(this.leftSide)
|
||||
.resizable("option", "disabled", true)
|
||||
.removeClass("ui-resizable-disabled"); // remove class so splitter is visible
|
||||
$(this.splitter).removeClass("ui-resizable-e");
|
||||
this.isCollapsed(true);
|
||||
}
|
||||
|
||||
@@ -1,136 +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;
|
||||
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,
|
||||
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()}
|
||||
entityValuePlaceholder={entityValuePlaceholder}
|
||||
entityValue={entityValue}
|
||||
isEntityTypeDate={isEntityTypeDate}
|
||||
entityTimeValue={entityTimeValue}
|
||||
onEntityValueChange={onEntityValueChange}
|
||||
onSelectDate={onSelectDate}
|
||||
onEntityTimeValueChange={onEntityTimeValueChange}
|
||||
/>
|
||||
<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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -2,7 +2,8 @@
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
export function getMonacoTheme(theme: string): string {
|
||||
export default class ThemeUtility {
|
||||
public static getMonacoTheme(theme: string): string {
|
||||
switch (theme) {
|
||||
case "default":
|
||||
case "hc-white":
|
||||
@@ -14,4 +15,5 @@ export function getMonacoTheme(theme: string): string {
|
||||
default:
|
||||
return "vs";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { useId } from "@uifabric/react-hooks";
|
||||
import { ITooltipHostStyles, TooltipHost } from "office-ui-fabric-react/lib/Tooltip";
|
||||
import * as React from "react";
|
||||
import InfoBubble from "../../../images/info-bubble.svg";
|
||||
|
||||
const calloutProps = { gapSpace: 0 };
|
||||
const hostStyles: Partial<ITooltipHostStyles> = { root: { display: "inline-block" } };
|
||||
|
||||
export interface TooltipProps {
|
||||
children: string;
|
||||
}
|
||||
export const Tooltip: React.FunctionComponent = ({ children }: TooltipProps) => {
|
||||
const tooltipId = useId("tooltip");
|
||||
|
||||
return children ? (
|
||||
<span>
|
||||
<TooltipHost content={children} id={tooltipId} calloutProps={calloutProps} styles={hostStyles}>
|
||||
<img className="infoImg" src={InfoBubble} alt="More information" />
|
||||
</TooltipHost>
|
||||
</span>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
import { Image, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
|
||||
import FolderIcon from "../../../images/folder_16x16.svg";
|
||||
import * as Constants from "../Constants";
|
||||
import { Tooltip } from "../Tooltip/Tooltip";
|
||||
|
||||
interface UploadProps {
|
||||
label: string;
|
||||
accept?: string;
|
||||
tooltip?: string;
|
||||
multiple?: boolean;
|
||||
tabIndex?: number;
|
||||
onUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
export const Upload: FunctionComponent<UploadProps> = ({
|
||||
label,
|
||||
accept,
|
||||
tooltip,
|
||||
multiple,
|
||||
tabIndex,
|
||||
...props
|
||||
}: UploadProps) => {
|
||||
const [selectedFilesTitle, setSelectedFilesTitle] = useState<string[]>([]);
|
||||
|
||||
const fileRef = useRef<HTMLInputElement>();
|
||||
|
||||
const onImportLinkKeyPress = (event: KeyboardEvent<HTMLAnchorElement>): void => {
|
||||
if (event.keyCode === Constants.KeyCodes.Enter || event.keyCode === Constants.KeyCodes.Space) {
|
||||
onImportLinkClick();
|
||||
}
|
||||
};
|
||||
|
||||
const onImportLinkClick = (): void => {
|
||||
fileRef?.current?.click();
|
||||
};
|
||||
|
||||
const onUpload = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
const { files } = event.target;
|
||||
|
||||
const newFileList = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
newFileList.push(files.item(i).name);
|
||||
}
|
||||
if (newFileList) {
|
||||
setSelectedFilesTitle(newFileList);
|
||||
props.onUpload(event);
|
||||
}
|
||||
};
|
||||
const title = label + " to upload";
|
||||
return (
|
||||
<div>
|
||||
<span className="renewUploadItemsHeader">{label}</span>
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
<Stack horizontal>
|
||||
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
|
||||
<input
|
||||
type="file"
|
||||
id="importFileInput"
|
||||
style={{ display: "none" }}
|
||||
ref={fileRef}
|
||||
accept={accept}
|
||||
tabIndex={tabIndex}
|
||||
multiple={multiple}
|
||||
title="Upload Icon"
|
||||
onChange={onUpload}
|
||||
role="button"
|
||||
/>
|
||||
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
|
||||
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
|
||||
</a>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,12 +1,5 @@
|
||||
interface Result {
|
||||
type?: string;
|
||||
objectBody?: {
|
||||
id: string;
|
||||
self: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function parseDocumentsPath(resourcePath: string): Result {
|
||||
export default class UrlUtility {
|
||||
public static parseDocumentsPath(resourcePath: string): any {
|
||||
if (typeof resourcePath !== "string") {
|
||||
return {};
|
||||
}
|
||||
@@ -23,9 +16,9 @@ export function parseDocumentsPath(resourcePath: string): Result {
|
||||
resourcePath = "/" + resourcePath;
|
||||
}
|
||||
|
||||
let id: string;
|
||||
let type: string;
|
||||
const pathParts = resourcePath.split("/");
|
||||
var id: string;
|
||||
var type: string;
|
||||
var pathParts = resourcePath.split("/");
|
||||
|
||||
if (pathParts.length % 2 === 0) {
|
||||
id = pathParts[pathParts.length - 2];
|
||||
@@ -35,27 +28,28 @@ export function parseDocumentsPath(resourcePath: string): Result {
|
||||
type = pathParts[pathParts.length - 2];
|
||||
}
|
||||
|
||||
const result = {
|
||||
var result = {
|
||||
type: type,
|
||||
objectBody: {
|
||||
id: id,
|
||||
self: resourcePath,
|
||||
},
|
||||
self: resourcePath
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function createUri(baseUri: string, relativeUri: string): string {
|
||||
public static createUri(baseUri: string, relativeUri: string): string {
|
||||
if (!baseUri) {
|
||||
throw new Error("baseUri is null or empty");
|
||||
}
|
||||
|
||||
const slashAtEndOfUriRegex = /\/$/,
|
||||
var slashAtEndOfUriRegex = /\/$/,
|
||||
slashAtStartOfUriRegEx = /^\//;
|
||||
|
||||
const normalizedBaseUri = baseUri.replace(slashAtEndOfUriRegex, "") + "/",
|
||||
var normalizedBaseUri = baseUri.replace(slashAtEndOfUriRegex, "") + "/",
|
||||
normalizedRelativeUri = (relativeUri && relativeUri.replace(slashAtStartOfUriRegEx, "")) || "";
|
||||
|
||||
return normalizedBaseUri + normalizedRelativeUri;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`requestPlugin Emulator builds a url for emulator proxy via webpack 1`] = `
|
||||
Object {
|
||||
"endpoint": "http://localhost/proxy",
|
||||
"endpoint": "/proxy",
|
||||
"headers": Object {
|
||||
"x-ms-proxy-target": "http://localhost",
|
||||
},
|
||||
@@ -12,7 +12,7 @@ Object {
|
||||
|
||||
exports[`requestPlugin Hosted builds a proxy URL in development 1`] = `
|
||||
Object {
|
||||
"endpoint": "http://localhost/proxy",
|
||||
"endpoint": "/proxy",
|
||||
"headers": Object {
|
||||
"x-ms-proxy-target": "baz",
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -14,42 +14,38 @@ describe("createCollection", () => {
|
||||
collectionId: "testContainer",
|
||||
databaseId: "testDatabase",
|
||||
databaseLevelThroughput: true,
|
||||
offerThroughput: 400,
|
||||
offerThroughput: 400
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
name: "test",
|
||||
name: "test"
|
||||
} as DatabaseAccount,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB
|
||||
});
|
||||
});
|
||||
|
||||
it("should call ARM if logged in with AAD", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.AAD,
|
||||
});
|
||||
window.authType = AuthType.AAD;
|
||||
await createCollection(createCollectionParams);
|
||||
expect(armRequest).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.MasterKey,
|
||||
});
|
||||
window.authType = AuthType.MasterKey;
|
||||
(client as jest.Mock).mockReturnValue({
|
||||
databases: {
|
||||
createIfNotExists: () => {
|
||||
return {
|
||||
database: {
|
||||
containers: {
|
||||
create: () => ({}),
|
||||
},
|
||||
},
|
||||
create: () => ({})
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
await createCollection(createCollectionParams);
|
||||
expect(client).toHaveBeenCalled();
|
||||
@@ -63,7 +59,7 @@ describe("createCollection", () => {
|
||||
collectionId: "testContainer",
|
||||
databaseId: "testDatabase",
|
||||
databaseLevelThroughput: false,
|
||||
offerThroughput: 400,
|
||||
offerThroughput: 400
|
||||
};
|
||||
expect(constructRpOptions(manualThroughputParams)).toEqual({ throughput: 400 });
|
||||
|
||||
@@ -73,12 +69,12 @@ describe("createCollection", () => {
|
||||
databaseId: "testDatabase",
|
||||
databaseLevelThroughput: false,
|
||||
offerThroughput: 400,
|
||||
autoPilotMaxThroughput: 4000,
|
||||
autoPilotMaxThroughput: 4000
|
||||
};
|
||||
expect(constructRpOptions(autoPilotThroughputParams)).toEqual({
|
||||
autoscaleSettings: {
|
||||
maxThroughput: 4000,
|
||||
},
|
||||
maxThroughput: 4000
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,15 +11,15 @@ import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraTable,
|
||||
getCassandraTable,
|
||||
getCassandraTable
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBCollection,
|
||||
getMongoDBCollection,
|
||||
getMongoDBCollection
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinGraph,
|
||||
getGremlinGraph,
|
||||
getGremlinGraph
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -35,13 +35,13 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
||||
);
|
||||
try {
|
||||
let collection: DataModels.Collection;
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (params.createNewDatabase) {
|
||||
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
||||
autoPilotMaxThroughput: params.autoPilotMaxThroughput,
|
||||
databaseId: params.databaseId,
|
||||
databaseLevelThroughput: params.databaseLevelThroughput,
|
||||
offerThroughput: params.offerThroughput,
|
||||
offerThroughput: params.offerThroughput
|
||||
};
|
||||
await createDatabase(createDatabaseParams);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ const createSqlContainer = async (params: DataModels.CreateCollectionParams): Pr
|
||||
|
||||
const options: ARMTypes.CreateUpdateOptions = constructRpOptions(params);
|
||||
const resource: ARMTypes.SqlContainerResource = {
|
||||
id: params.collectionId,
|
||||
id: params.collectionId
|
||||
};
|
||||
if (params.analyticalStorageTtl) {
|
||||
resource.analyticalStorageTtl = params.analyticalStorageTtl;
|
||||
@@ -118,8 +118,8 @@ const createSqlContainer = async (params: DataModels.CreateCollectionParams): Pr
|
||||
const rpPayload: ARMTypes.SqlDatabaseCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource,
|
||||
options,
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
|
||||
const createResponse = await createUpdateSqlContainer(
|
||||
@@ -154,7 +154,7 @@ const createMongoCollection = async (params: DataModels.CreateCollectionParams):
|
||||
|
||||
const options: ARMTypes.CreateUpdateOptions = constructRpOptions(params);
|
||||
const resource: ARMTypes.MongoDBCollectionResource = {
|
||||
id: params.collectionId,
|
||||
id: params.collectionId
|
||||
};
|
||||
if (params.analyticalStorageTtl) {
|
||||
resource.analyticalStorageTtl = params.analyticalStorageTtl;
|
||||
@@ -170,8 +170,8 @@ const createMongoCollection = async (params: DataModels.CreateCollectionParams):
|
||||
const rpPayload: ARMTypes.MongoDBCollectionCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource,
|
||||
options,
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
|
||||
const createResponse = await createUpdateMongoDBCollection(
|
||||
@@ -185,7 +185,7 @@ const createMongoCollection = async (params: DataModels.CreateCollectionParams):
|
||||
|
||||
if (params.createMongoWildcardIndex) {
|
||||
TelemetryProcessor.trace(Action.CreateMongoCollectionWithWildcardIndex, ActionModifiers.Mark, {
|
||||
message: "Mongo Collection created with wildcard index on all fields.",
|
||||
message: "Mongo Collection created with wildcard index on all fields."
|
||||
});
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ const createCassandraTable = async (params: DataModels.CreateCollectionParams):
|
||||
|
||||
const options: ARMTypes.CreateUpdateOptions = constructRpOptions(params);
|
||||
const resource: ARMTypes.CassandraTableResource = {
|
||||
id: params.collectionId,
|
||||
id: params.collectionId
|
||||
};
|
||||
if (params.analyticalStorageTtl) {
|
||||
resource.analyticalStorageTtl = params.analyticalStorageTtl;
|
||||
@@ -221,8 +221,8 @@ const createCassandraTable = async (params: DataModels.CreateCollectionParams):
|
||||
const rpPayload: ARMTypes.CassandraTableCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource,
|
||||
options,
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
|
||||
const createResponse = await createUpdateCassandraTable(
|
||||
@@ -256,7 +256,7 @@ const createGraph = async (params: DataModels.CreateCollectionParams): Promise<D
|
||||
|
||||
const options: ARMTypes.CreateUpdateOptions = constructRpOptions(params);
|
||||
const resource: ARMTypes.GremlinGraphResource = {
|
||||
id: params.collectionId,
|
||||
id: params.collectionId
|
||||
};
|
||||
|
||||
if (params.indexingPolicy) {
|
||||
@@ -272,8 +272,8 @@ const createGraph = async (params: DataModels.CreateCollectionParams): Promise<D
|
||||
const rpPayload: ARMTypes.GremlinGraphCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource,
|
||||
options,
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
|
||||
const createResponse = await createUpdateGremlinGraph(
|
||||
@@ -306,14 +306,14 @@ const createTable = async (params: DataModels.CreateCollectionParams): Promise<D
|
||||
|
||||
const options: ARMTypes.CreateUpdateOptions = constructRpOptions(params);
|
||||
const resource: ARMTypes.TableResource = {
|
||||
id: params.collectionId,
|
||||
id: params.collectionId
|
||||
};
|
||||
|
||||
const rpPayload: ARMTypes.TableCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource,
|
||||
options,
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
|
||||
const createResponse = await createUpdateTable(
|
||||
@@ -334,13 +334,13 @@ export const constructRpOptions = (params: DataModels.CreateDatabaseParams): ARM
|
||||
if (params.autoPilotMaxThroughput) {
|
||||
return {
|
||||
autoscaleSettings: {
|
||||
maxThroughput: params.autoPilotMaxThroughput,
|
||||
},
|
||||
maxThroughput: params.autoPilotMaxThroughput
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
throughput: params.offerThroughput,
|
||||
throughput: params.offerThroughput
|
||||
};
|
||||
};
|
||||
|
||||
@@ -350,7 +350,7 @@ const createCollectionWithSDK = async (params: DataModels.CreateCollectionParams
|
||||
partitionKey: params.partitionKey || undefined,
|
||||
indexingPolicy: params.indexingPolicy || undefined,
|
||||
uniqueKeyPolicy: params.uniqueKeyPolicy || undefined,
|
||||
analyticalStorageTtl: params.analyticalStorageTtl,
|
||||
analyticalStorageTtl: params.analyticalStorageTtl
|
||||
} as ContainerRequest; // TODO: remove cast when https://github.com/Azure/azure-cosmos-js/issues/423 is fixed
|
||||
const collectionOptions: RequestOptions = {};
|
||||
const createDatabaseBody: DatabaseRequest = { id: params.databaseId };
|
||||
|
||||
@@ -8,21 +8,21 @@ import {
|
||||
GremlinDatabaseCreateUpdateParameters,
|
||||
MongoDBDatabaseCreateUpdateParameters,
|
||||
SqlDatabaseCreateUpdateParameters,
|
||||
CreateUpdateOptions,
|
||||
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 {
|
||||
createUpdateCassandraKeyspace,
|
||||
getCassandraKeyspace,
|
||||
getCassandraKeyspace
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBDatabase,
|
||||
getMongoDBDatabase,
|
||||
getMongoDBDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinDatabase,
|
||||
getGremlinDatabase,
|
||||
getGremlinDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { handleError } from "../ErrorHandlingUtils";
|
||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -34,7 +34,7 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
|
||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||
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 (window.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||
? createDatabaseWithARM(params)
|
||||
: createDatabaseWithSDK(params));
|
||||
|
||||
@@ -85,10 +85,10 @@ async function createSqlDatabase(params: DataModels.CreateDatabaseParams): Promi
|
||||
const rpPayload: SqlDatabaseCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: {
|
||||
id: params.databaseId,
|
||||
},
|
||||
options,
|
||||
id: params.databaseId
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
const createResponse = await createUpdateSqlDatabase(
|
||||
userContext.subscriptionId,
|
||||
@@ -121,10 +121,10 @@ async function createMongoDatabase(params: DataModels.CreateDatabaseParams): Pro
|
||||
const rpPayload: MongoDBDatabaseCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: {
|
||||
id: params.databaseId,
|
||||
},
|
||||
options,
|
||||
id: params.databaseId
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
const createResponse = await createUpdateMongoDBDatabase(
|
||||
userContext.subscriptionId,
|
||||
@@ -157,10 +157,10 @@ async function createCassandraKeyspace(params: DataModels.CreateDatabaseParams):
|
||||
const rpPayload: CassandraKeyspaceCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: {
|
||||
id: params.databaseId,
|
||||
},
|
||||
options,
|
||||
id: params.databaseId
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
const createResponse = await createUpdateCassandraKeyspace(
|
||||
userContext.subscriptionId,
|
||||
@@ -193,10 +193,10 @@ async function createGremlineDatabase(params: DataModels.CreateDatabaseParams):
|
||||
const rpPayload: GremlinDatabaseCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: {
|
||||
id: params.databaseId,
|
||||
},
|
||||
options,
|
||||
id: params.databaseId
|
||||
},
|
||||
options
|
||||
}
|
||||
};
|
||||
const createResponse = await createUpdateGremlinDatabase(
|
||||
userContext.subscriptionId,
|
||||
@@ -231,12 +231,12 @@ function constructRpOptions(params: DataModels.CreateDatabaseParams): CreateUpda
|
||||
if (params.autoPilotMaxThroughput) {
|
||||
return {
|
||||
autoscaleSettings: {
|
||||
maxThroughput: params.autoPilotMaxThroughput,
|
||||
},
|
||||
maxThroughput: params.autoPilotMaxThroughput
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
throughput: params.offerThroughput,
|
||||
throughput: params.offerThroughput
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType
|
||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||
import {
|
||||
SqlStoredProcedureCreateUpdateParameters,
|
||||
SqlStoredProcedureResource,
|
||||
SqlStoredProcedureResource
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import {
|
||||
createUpdateSqlStoredProcedure,
|
||||
getSqlStoredProcedure,
|
||||
getSqlStoredProcedure
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { handleError } from "../ErrorHandlingUtils";
|
||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -22,7 +22,7 @@ export async function createStoredProcedure(
|
||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -49,8 +49,8 @@ export async function createStoredProcedure(
|
||||
const createSprocParams: SqlStoredProcedureCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: storedProcedure as SqlStoredProcedureResource,
|
||||
options: {},
|
||||
},
|
||||
options: {}
|
||||
}
|
||||
};
|
||||
const rpResponse = await createUpdateSqlStoredProcedure(
|
||||
userContext.subscriptionId,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType
|
||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||
import {
|
||||
SqlTriggerCreateUpdateParameters,
|
||||
SqlTriggerResource,
|
||||
SqlTriggerResource
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
@@ -19,7 +19,7 @@ export async function createTrigger(
|
||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -44,8 +44,8 @@ export async function createTrigger(
|
||||
const createTriggerParams: SqlTriggerCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: trigger as SqlTriggerResource,
|
||||
options: {},
|
||||
},
|
||||
options: {}
|
||||
}
|
||||
};
|
||||
const rpResponse = await createUpdateSqlTrigger(
|
||||
userContext.subscriptionId,
|
||||
@@ -59,7 +59,10 @@ export async function createTrigger(
|
||||
return rpResponse && (rpResponse.properties?.resource as TriggerDefinition & Resource);
|
||||
}
|
||||
|
||||
const response = await client().database(databaseId).container(collectionId).scripts.triggers.create(trigger);
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.triggers.create(trigger);
|
||||
return response.resource;
|
||||
} catch (error) {
|
||||
handleError(error, "CreateTrigger", `Error while creating trigger ${trigger.id}`);
|
||||
|
||||
@@ -3,12 +3,12 @@ import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType
|
||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
import {
|
||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||
SqlUserDefinedFunctionResource,
|
||||
SqlUserDefinedFunctionResource
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import {
|
||||
createUpdateSqlUserDefinedFunction,
|
||||
getSqlUserDefinedFunction,
|
||||
getSqlUserDefinedFunction
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { handleError } from "../ErrorHandlingUtils";
|
||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -22,7 +22,7 @@ export async function createUserDefinedFunction(
|
||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -49,8 +49,8 @@ export async function createUserDefinedFunction(
|
||||
const createUDFParams: SqlUserDefinedFunctionCreateUpdateParameters = {
|
||||
properties: {
|
||||
resource: userDefinedFunction as SqlUserDefinedFunctionResource,
|
||||
options: {},
|
||||
},
|
||||
options: {}
|
||||
}
|
||||
};
|
||||
const rpResponse = await createUpdateSqlUserDefinedFunction(
|
||||
userContext.subscriptionId,
|
||||
|
||||
@@ -13,34 +13,30 @@ describe("deleteCollection", () => {
|
||||
beforeAll(() => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
name: "test",
|
||||
name: "test"
|
||||
} as DatabaseAccount,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB
|
||||
});
|
||||
});
|
||||
|
||||
it("should call ARM if logged in with AAD", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.AAD,
|
||||
});
|
||||
window.authType = AuthType.AAD;
|
||||
await deleteCollection("database", "collection");
|
||||
expect(armRequest).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.MasterKey,
|
||||
});
|
||||
window.authType = AuthType.MasterKey;
|
||||
(client as jest.Mock).mockReturnValue({
|
||||
database: () => {
|
||||
return {
|
||||
container: () => {
|
||||
return {
|
||||
delete: (): unknown => undefined,
|
||||
delete: (): unknown => undefined
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
await deleteCollection("database", "collection");
|
||||
expect(client).toHaveBeenCalled();
|
||||
|
||||
@@ -13,10 +13,13 @@ import { client } from "../CosmosClient";
|
||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||
try {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
await deleteCollectionWithARM(databaseId, collectionId);
|
||||
} else {
|
||||
await client().database(databaseId).container(collectionId).delete();
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.delete();
|
||||
}
|
||||
logConsoleInfo(`Successfully deleted container ${collectionId}`);
|
||||
} catch (error) {
|
||||
|
||||
@@ -10,7 +10,7 @@ export const deleteConflict = async (collection: CollectionBase, conflictId: Con
|
||||
|
||||
try {
|
||||
const options = {
|
||||
partitionKey: getPartitionKeyHeaderForConflict(conflictId),
|
||||
partitionKey: getPartitionKeyHeaderForConflict(conflictId)
|
||||
};
|
||||
|
||||
await client()
|
||||
|
||||
@@ -13,30 +13,26 @@ describe("deleteDatabase", () => {
|
||||
beforeAll(() => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
name: "test",
|
||||
name: "test"
|
||||
} as DatabaseAccount,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||
defaultExperience: DefaultAccountExperienceType.DocumentDB
|
||||
});
|
||||
});
|
||||
|
||||
it("should call ARM if logged in with AAD", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.AAD,
|
||||
});
|
||||
window.authType = AuthType.AAD;
|
||||
await deleteDatabase("database");
|
||||
expect(armRequest).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||
updateUserContext({
|
||||
authType: AuthType.MasterKey,
|
||||
});
|
||||
window.authType = AuthType.MasterKey;
|
||||
(client as jest.Mock).mockReturnValue({
|
||||
database: () => {
|
||||
return {
|
||||
delete: (): unknown => undefined,
|
||||
delete: (): unknown => undefined
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
await deleteDatabase("database");
|
||||
expect(client).toHaveBeenCalled();
|
||||
|
||||
@@ -16,10 +16,12 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||
throw new Error("Deleting database resources is not allowed for tables accounts");
|
||||
}
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
await deleteDatabaseWithARM(databaseId);
|
||||
} else {
|
||||
await client().database(databaseId).delete();
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.delete();
|
||||
}
|
||||
logConsoleInfo(`Successfully deleted database ${databaseId}`);
|
||||
} catch (error) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export async function deleteStoredProcedure(
|
||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -27,7 +27,11 @@ export async function deleteStoredProcedure(
|
||||
storedProcedureId
|
||||
);
|
||||
} else {
|
||||
await client().database(databaseId).container(collectionId).scripts.storedProcedure(storedProcedureId).delete();
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.storedProcedure(storedProcedureId)
|
||||
.delete();
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, "DeleteStoredProcedure", `Error while deleting stored procedure ${storedProcedureId}`);
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function deleteTrigger(databaseId: string, collectionId: string, tr
|
||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -23,7 +23,11 @@ export async function deleteTrigger(databaseId: string, collectionId: string, tr
|
||||
triggerId
|
||||
);
|
||||
} else {
|
||||
await client().database(databaseId).container(collectionId).scripts.trigger(triggerId).delete();
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.trigger(triggerId)
|
||||
.delete();
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, "DeleteTrigger", `Error while deleting trigger ${triggerId}`);
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function deleteUserDefinedFunction(databaseId: string, collectionId
|
||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||
) {
|
||||
@@ -23,7 +23,11 @@ export async function deleteUserDefinedFunction(databaseId: string, collectionId
|
||||
id
|
||||
);
|
||||
} else {
|
||||
await client().database(databaseId).container(collectionId).scripts.userDefinedFunction(id).delete();
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.userDefinedFunction(id)
|
||||
.delete();
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, "DeleteUserDefinedFunction", `Error while deleting user defined function ${id}`);
|
||||
|
||||
@@ -33,7 +33,7 @@ export const executeStoredProcedure = async (
|
||||
);
|
||||
return {
|
||||
result: response.resource,
|
||||
scriptLogs: response.headers[HttpHeaders.scriptLogResults] as string,
|
||||
scriptLogs: response.headers[HttpHeaders.scriptLogResults] as string
|
||||
};
|
||||
} catch (error) {
|
||||
handleError(
|
||||
|
||||
@@ -41,7 +41,7 @@ interface MetricsResponse {
|
||||
}
|
||||
|
||||
export const getCollectionUsageSizeInKB = async (databaseName: string, containerName: string): Promise<number> => {
|
||||
if (userContext.authType !== AuthType.AAD) {
|
||||
if (window.authType !== AuthType.AAD) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ export const getCollectionUsageSizeInKB = async (databaseName: string, container
|
||||
apiVersion: "2018-01-01",
|
||||
queryParams: {
|
||||
filter,
|
||||
metricNames,
|
||||
},
|
||||
metricNames
|
||||
}
|
||||
});
|
||||
|
||||
if (metricsResponse?.value?.length !== 2) {
|
||||
@@ -76,7 +76,7 @@ export const getCollectionUsageSizeInKB = async (databaseName: string, container
|
||||
return dataUsageSizeInKb + indexUsageSizeInKb;
|
||||
} catch (error) {
|
||||
handleError(error, "getCollectionUsageSize");
|
||||
return undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,16 +3,18 @@ import { handleError } from "../ErrorHandlingUtils";
|
||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import * as Constants from "../Constants";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
export async function getIndexTransformationProgress(databaseId: string, collectionId: string): Promise<number> {
|
||||
if (userContext.authType !== AuthType.AAD) {
|
||||
if (window.authType !== AuthType.AAD) {
|
||||
return undefined;
|
||||
}
|
||||
let indexTransformationPercentage: number;
|
||||
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
|
||||
try {
|
||||
const response = await client().database(databaseId).container(collectionId).read({ populateQuotaInfo: true });
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.read({ populateQuotaInfo: true });
|
||||
|
||||
indexTransformationPercentage = parseInt(
|
||||
response.headers[Constants.HttpHeaders.collectionIndexTransformationProgress] as string
|
||||
|
||||
@@ -7,5 +7,8 @@ export const queryConflicts = (
|
||||
query: string,
|
||||
options: FeedOptions
|
||||
): QueryIterator<ConflictDefinition & Resource> => {
|
||||
return client().database(databaseId).container(containerId).conflicts.query(query, options);
|
||||
return client()
|
||||
.database(databaseId)
|
||||
.container(containerId)
|
||||
.conflicts.query(query, options);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,10 @@ export const queryDocuments = (
|
||||
options: FeedOptions
|
||||
): QueryIterator<ItemDefinition & Resource> => {
|
||||
options = getCommonQueryOptions(options);
|
||||
return client().database(databaseId).container(containerId).items.query(query, options);
|
||||
return client()
|
||||
.database(databaseId)
|
||||
.container(containerId)
|
||||
.items.query(query, options);
|
||||
};
|
||||
|
||||
export const getCommonQueryOptions = (options: FeedOptions): FeedOptions => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user