Compare commits

..

9 Commits

Author SHA1 Message Date
Steve Faulkner
4be1389705 Upload on failure 2020-12-17 17:01:28 -06:00
Steve Faulkner
65844414dd Test 2020-12-16 20:18:59 -06:00
Steve Faulkner
b9461de695 Test 2020-12-16 20:18:53 -06:00
Steve Faulkner
0473c49cc6 Merge branch 'e2e-test-debugging' of https://github.com/Azure/cosmos-explorer into e2e-test-debugging 2020-12-16 20:18:39 -06:00
Steve Faulkner
53ea8dc528 Test 2020-12-16 20:18:31 -06:00
Steve Faulkner
8b7d43823a Merge branch 'master' into e2e-test-debugging 2020-12-16 20:01:37 -06:00
Steve Faulkner
3ab7e93bab Test 2020-12-16 19:56:40 -06:00
Steve Faulkner
9e2efa01e5 Test 2020-12-16 19:37:55 -06:00
Steve Faulkner
ba5ab37bac Debugging failed tests 2020-12-16 19:22:47 -06:00
592 changed files with 53381 additions and 57940 deletions

View File

@@ -42,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
@@ -87,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
@@ -241,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

View File

@@ -1,39 +1,41 @@
module.exports = {
env: {
browser: true,
es6: true,
es6: true
},
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"],
extends: ["plugin:react/recommended"], // TODO: Add react-hooks
plugins: ["react"],
env: {
jest: true
},
extends: ["plugin:react/recommended"],
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,13 +43,12 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "error",
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
eqeqeq: "error",
"react/display-name": "off",
"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 '{}'"
}
]
}
};

View File

@@ -9,20 +9,6 @@ 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 12.x
uses: actions/setup-node@v1
with:
node-version: 12.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"
@@ -108,7 +94,7 @@ jobs:
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"
@@ -156,7 +142,6 @@ jobs:
run: |
npm ci
npm start &
node utils/cleanupDBs.js
npm run wait-for-server
npm run test:e2e
shell: bash
@@ -166,8 +151,6 @@ jobs:
PORTAL_RUNNER_RESOURCE_GROUP: ${{ secrets.PORTAL_RUNNER_RESOURCE_GROUP }}
PORTAL_RUNNER_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT }}
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT_KEY }}
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT }}
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY }}
NOTEBOOKS_TEST_RUNNER_TENANT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_TENANT_ID }}
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
@@ -184,7 +167,7 @@ jobs:
nuget:
name: Publish Nuget
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
runs-on: ubuntu-latest
env:
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
@@ -208,7 +191,7 @@ jobs:
nugetmpac:
name: Publish Nuget MPAC
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
runs-on: ubuntu-latest
env:
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}

Binary file not shown.

View File

@@ -69,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.
### Architechture
[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFJcbiAgaG9zdGVkKGh0dHBzOi8vY29zbW9zLmF6dXJlLmNvbSlcbiAgcG9ydGFsKFBvcnRhbClcbiAgZW11bGF0b3IoRW11bGF0b3IpXG4gIGFhZFtBQURdXG4gIHJlc291cmNlVG9rZW5bUmVzb3VyY2UgVG9rZW5dXG4gIGNvbm5lY3Rpb25TdHJpbmdbQ29ubmVjdGlvbiBTdHJpbmddXG4gIHBvcnRhbFRva2VuW0VuY3J5cHRlZCBQb3J0YWwgVG9rZW5dXG4gIG1hc3RlcktleVtNYXN0ZXIgS2V5XVxuICBhcm1bQVJNIFJlc291cmNlIFByb3ZpZGVyXVxuICBkYXRhcGxhbmVbRGF0YSBQbGFuZV1cbiAgcHJveHlbUG9ydGFsIEFQSSBQcm94eV1cbiAgc3FsW1NRTF1cbiAgbW9uZ29bTW9uZ29dXG4gIHRhYmxlc1tUYWJsZXNdXG4gIGNhc3NhbmRyYVtDYXNzYW5kcmFdXG4gIGdyYWZbR3JhcGhdXG5cblxuICBlbXVsYXRvciAtLT4gbWFzdGVyS2V5IC0tLS0-IGRhdGFwbGFuZVxuICBwb3J0YWwgLS0-IGFhZFxuICBob3N0ZWQgLS0-IHBvcnRhbFRva2VuICYgcmVzb3VyY2VUb2tlbiAmIGNvbm5lY3Rpb25TdHJpbmcgJiBhYWRcbiAgYWFkIC0tLT4gYXJtXG4gIGFhZCAtLS0-IGRhdGFwbGFuZVxuICBhYWQgLS0tPiBwcm94eVxuICByZXNvdXJjZVRva2VuIC0tLT4gc3FsIC0tPiBkYXRhcGxhbmVcbiAgcG9ydGFsVG9rZW4gLS0tPiBwcm94eVxuICBwcm94eSAtLT4gZGF0YXBsYW5lXG4gIGNvbm5lY3Rpb25TdHJpbmcgLS0-IHNxbCAmIG1vbmdvICYgY2Fzc2FuZHJhICYgZ3JhZiAmIHRhYmxlc1xuICBzcWwgLS0-IGRhdGFwbGFuZVxuICB0YWJsZXMgLS0-IGRhdGFwbGFuZVxuICBtb25nbyAtLT4gcHJveHlcbiAgY2Fzc2FuZHJhIC0tPiBwcm94eVxuICBncmFmIC0tPiBwcm94eVxuXG5cdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)](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).

View File

@@ -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"]
};

View File

@@ -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

View File

@@ -1 +0,0 @@
module.exports = {}

View File

@@ -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"
}

View File

@@ -1,4 +1,3 @@
{
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
"ENABLE_GALLERY_PUBLISH": true
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com"
}

1963
externals/adal.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -6,6 +6,6 @@ module.exports = {
slowMo: 55,
defaultViewport: null,
ignoreHTTPSErrors: true,
args: ["--disable-web-security"],
},
args: ["--disable-web-security"]
}
};

View File

@@ -1,5 +1,5 @@
module.exports = {
preset: "jest-puppeteer",
testMatch: ["<rootDir>/test/**/*.spec.[jt]s?(x)"],
setupFiles: ["dotenv/config"],
setupFiles: ["dotenv/config"]
};

View File

@@ -39,11 +39,11 @@ module.exports = {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 22,
functions: 28,
lines: 33,
statements: 31,
},
branches: 20,
functions: 24,
lines: 30,
statements: 29.0
}
},
// Make calling deprecated APIs throw helpful error messages
@@ -76,7 +76,7 @@ module.exports = {
"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
@@ -164,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,

View File

@@ -3,8 +3,8 @@
/******************************************************************************/
@font-face {
font-family: wf_segoe-ui_normal;
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff");
font-family: wf_segoe-ui_normal;
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;
@@ -151,16 +144,16 @@
/**********************************************************************************/
.flex-display(@display: flex) {
display: ~"-webkit-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
display: ~"-webkit-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
}
.flex-direction(@direction: column) {
-webkit-flex-direction: @direction;
-ms-flex-direction: @direction;
flex-direction: @direction;
-ms-flex-direction: @direction;
flex-direction: @direction;
}
/*************************************************************************************
@@ -168,31 +161,32 @@
**************************************************************************************/
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.selectedRadio,
.selectedRadio:hover,
.selectedRadio:active,
.selectedRadio.dirty,
.tab [type="radio"]:checked ~ label,
.tab [type="radio"]:checked ~ label:hover {
-ms-high-contrast-adjust: none;
-webkit-text-fill-color: HighlightText;
color: HighlightText;
border-color: HighlightText;
background-color: Highlight;
}
.queryMetricsSummaryTuple {
th,
td {
&:nth-child(2) {
width: @IETableDataWidth;
}
&:nth-child(3) {
width: 50%;
}
.selectedRadio,
.selectedRadio:hover,
.selectedRadio:active,
.selectedRadio.dirty,
.tab [type=radio]:checked ~ label,
.tab [type=radio]:checked ~ label:hover {
-ms-high-contrast-adjust: none;
-webkit-text-fill-color: HighlightText;
color: HighlightText;
border-color: HighlightText;
background-color: Highlight;
}
.queryMetricsSummaryTuple {
th, td {
&:nth-child(2) {
width: @IETableDataWidth;
}
&:nth-child(3) {
width: 50%;
}
}
}
}
}
/********************************************************************************************
@@ -200,15 +194,15 @@
*********************************************************************************************/
.hover() {
background-color: @AccentLight;
background-color: @AccentLight;
}
.active() {
background-color: @AccentExtra;
background-color: @AccentExtra;
}
.focus() {
outline: 1px dashed @FocusColor;
outline: 1px dashed @FocusColor;
}
/************************************************************************************************
@@ -218,87 +212,63 @@
@ToggleWidth: 180px;
.toggleSwitch() {
max-width: 100%;
margin-bottom: @SmallSpace;
padding: @SmallSpace;
cursor: pointer;
color: @BaseHigh;
font-weight: 400;
font-size: @mediumFontSize;
font-family: @DataExplorerFont;
max-width: 100%;
margin-bottom: @SmallSpace;
padding: @SmallSpace;
cursor: pointer;
color: @BaseHigh;
font-weight: 400;
font-size: @mediumFontSize;
font-family: @DataExplorerFont;
}
.selectedToggle() {
border-bottom: 2px solid @BaseHigh;
border-bottom: 2px solid @BaseHigh;
}
.unselectedToggle() {
color: @AccentMediumHigh;
color: @AccentMediumHigh;
}
/********************************************************************************************************
Common Data Explorer Icons
*********************************************************************************************************/
.dataExplorerIcons() {
cursor: pointer;
width: @ImgWidth;
height: @ImgHeight;
cursor: pointer;
width: @ImgWidth;
height: @ImgHeight;
}
/*********************************************************************************************************
Info Tooltip
**********************************************************************************************************/
.infoTooltip() {
position: relative;
display: inline-block;
position: relative;
display: inline-block;
}
.tooltipText(@textColor: @BaseLight, @backgroundColor: @BaseHigh) {
visibility: hidden;
background-color: @backgroundColor;
color: @textColor;
position: absolute;
z-index: 1;
left: @MediumSpace;
padding: @MediumSpace;
visibility: hidden;
background-color: @backgroundColor;
color: @textColor;
position: absolute;
z-index: 1;
left: @MediumSpace;
padding: @MediumSpace;
}
.tooltipTextAfter(@color: @BaseDark) {
content: "";
position: absolute;
right: 100%;
border-style: solid;
border-color: transparent @color transparent transparent;
left: 0px;
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
content: "";
position: absolute;
right: 100%;
border-style: solid;
border-color: transparent @color transparent transparent;
left: 0px;
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
}
.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;
visibility: visible;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -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 {

5099
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,14 +6,12 @@
"dependencies": {
"@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "3.9.0",
"@azure/identity": "1.1.0",
"@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "1.2.1",
"@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",
"@jupyterlab/services": "6.0.0-rc.2",
"@jupyterlab/terminal": "3.0.0-rc.2",
"@microsoft/applicationinsights-web": "2.5.9",
"@nteract/commutable": "7.4.2",
"@nteract/commutable": "7.3.2",
"@nteract/connected-components": "6.8.2",
"@nteract/core": "15.1.0",
"@nteract/data-explorer": "8.0.3",
@@ -38,7 +36,6 @@
"@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",
@@ -47,7 +44,7 @@
"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",
"copy-webpack-plugin": "6.0.2",
"crossroads": "0.12.2",
@@ -64,9 +61,6 @@
"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",
"immutable": "4.0.0-rc.12",
"is-ci": "2.0.0",
"jquery": "3.5.1",
@@ -75,7 +69,6 @@
"knockout": "3.5.1",
"mkdirp": "1.0.4",
"monaco-editor": "0.18.1",
"msal": "1.4.4",
"object.entries": "1.1.0",
"office-ui-fabric-react": "7.134.1",
"p-retry": "4.2.0",
@@ -87,17 +80,14 @@
"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",
"styled-components": "4.3.2",
"swr": "0.4.0",
"text-encoding": "0.7.0",
"underscore": "1.9.1",
"url-polyfill": "1.1.7",
@@ -111,7 +101,6 @@
"@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",
@@ -120,7 +109,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",
@@ -128,8 +117,8 @@
"@types/prop-types": "15.5.8",
"@types/puppeteer": "3.0.1",
"@types/q": "1.5.1",
"@types/react": "17.0.0",
"@types/react-dom": "17.0.0",
"@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/sinon": "2.3.3",
@@ -139,6 +128,7 @@
"@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",
@@ -153,9 +143,7 @@
"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",
"expose-loader": "0.7.5",
"fast-glob": "3.2.5",
"file-loader": "2.0.0",
"fs-extra": "7.0.0",
"html-loader": "0.5.5",
@@ -172,7 +160,7 @@
"mini-css-extract-plugin": "0.4.3",
"monaco-editor-webpack-plugin": "1.7.0",
"node-fetch": "2.6.1",
"prettier": "2.2.1",
"prettier": "1.19.1",
"puppeteer": "4.0.0",
"raw-loader": "0.5.1",
"rimraf": "3.0.0",

View File

@@ -2,6 +2,5 @@ export enum AuthType {
AAD = "aad",
EncryptedToken = "encryptedtoken",
MasterKey = "masterkey",
ResourceToken = "resourcetoken",
ConnectionString = "connectionstring",
ResourceToken = "resourcetoken"
}

View File

@@ -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();

View File

@@ -42,7 +42,7 @@ export class Registerer {
// Initial rendering at mount point
ReactDOM.render(adapter.renderComponent(), element);
},
}
} as ko.BindingHandler;
}
}

View File

@@ -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));
}
}

View File

@@ -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";
@@ -119,18 +126,12 @@ export class Features {
public static readonly enableSchema = "enableschema";
public static readonly enableSDKoperations = "enablesdkoperations";
public static readonly showMinRUSurvey = "showminrusurvey";
public static readonly enableDatabaseSettingsTabV1 = "enabledbsettingsv1";
public static readonly selfServeType = "selfservetype";
public static readonly enableKOPanel = "enablekopanel";
}
// 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";
public static readonly GalleryPublish = "gallerypublish";
}
export class AfecFeatures {
@@ -139,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";
}
@@ -150,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
@@ -277,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
];
}
@@ -333,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
}
}
@@ -379,7 +396,7 @@ export class OfferVersions {
export enum ConflictOperationType {
Replace = "replace",
Create = "create",
Delete = "delete",
Delete = "delete"
}
export const EmulatorMasterKey =

View File

@@ -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";

View File

@@ -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());
@@ -77,13 +77,13 @@ export async function getTokenFromAuthService(verb: string, resourceType: string
export function client(): Cosmos.CosmosClient {
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) {

View File

@@ -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);
});

View File

@@ -21,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);
};
@@ -37,7 +37,7 @@ const sendNotificationForError = (errorMessage: string, errorCode: number | stri
}
sendMessage({
type: MessageTypes.ForbiddenError,
reason: errorMessage,
reason: errorMessage
});
}
};
@@ -45,10 +45,10 @@ const sendNotificationForError = (errorMessage: string, errorCode: number | stri
const replaceKnownError = (errorMessage: string): string => {
if (
window.dataExplorer?.subscriptionType() === SubscriptionType.Internal &&
errorMessage?.indexOf("SharedOffer is Disabled for your account") >= 0
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.";
}

View File

@@ -11,8 +11,8 @@ describe("nextPage", () => {
queryMetrics: {},
requestCharge: 1,
headers: {},
activityId: "foo",
}),
activityId: "foo"
})
};
expect(await nextPage(fakeIterator, 10)).toMatchSnapshot();

View File

@@ -14,7 +14,7 @@ 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;
const headers = (response as any).headers || {}; // TODO this is a private key. Remove any
const itemCount = (documents && documents.length) || 0;
@@ -26,7 +26,7 @@ export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex
lastItemIndex: Number(firstItemIndex) + Number(itemCount),
headers,
activityId: response.activityId,
requestCharge: response.requestCharge,
requestCharge: response.requestCharge
};
});
}

View File

@@ -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 => {
@@ -60,6 +60,6 @@ function _generateLogEntry(
level,
message,
area,
code,
code
};
}

View File

@@ -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);

View File

@@ -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 });
@@ -54,7 +54,7 @@ export function sendMessage(data: any): void {
portalChildWindow.parent.postMessage(
{
signature: "pcIframe",
data: data,
data: data
},
portalChildWindow.document.referrer
);

View File

@@ -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);
});
@@ -222,10 +222,10 @@ describe("MongoProxyClient", () => {
resetConfigContext();
delete window.authType;
updateUserContext({
databaseAccount,
databaseAccount
});
updateConfigContext({
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
});
});

View File

@@ -16,7 +16,7 @@ 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() {
@@ -31,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) => {
@@ -42,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
};
});
},
}
};
}
@@ -74,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() || "";
@@ -89,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) {
@@ -102,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);
@@ -137,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();
@@ -151,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();
}
@@ -179,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();
@@ -190,10 +186,10 @@ export function createDocument(
body: JSON.stringify(documentContent),
headers: {
...defaultHeaders,
...authHeaders(),
},
...authHeaders()
}
})
.then((response) => {
.then(response => {
if (response.ok) {
return response.json();
}
@@ -222,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();
@@ -236,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();
}
@@ -263,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();
@@ -276,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;
}
@@ -307,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();
@@ -322,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();
}

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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"
};
};

View File

@@ -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) {

View File

@@ -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

View File

@@ -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);
}

View File

@@ -32,8 +32,8 @@ export default class UrlUtility {
type: type,
objectBody: {
id: id,
self: resourcePath,
},
self: resourcePath
}
};
return result;

View File

@@ -14,15 +14,15 @@ 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
});
});
@@ -40,12 +40,12 @@ describe("createCollection", () => {
return {
database: {
containers: {
create: () => ({}),
},
},
create: () => ({})
}
}
};
},
},
}
}
});
await createCollection(createCollectionParams);
expect(client).toHaveBeenCalled();
@@ -59,7 +59,7 @@ describe("createCollection", () => {
collectionId: "testContainer",
databaseId: "testDatabase",
databaseLevelThroughput: false,
offerThroughput: 400,
offerThroughput: 400
};
expect(constructRpOptions(manualThroughputParams)).toEqual({ throughput: 400 });
@@ -69,12 +69,12 @@ describe("createCollection", () => {
databaseId: "testDatabase",
databaseLevelThroughput: false,
offerThroughput: 400,
autoPilotMaxThroughput: 4000,
autoPilotMaxThroughput: 4000
};
expect(constructRpOptions(autoPilotThroughputParams)).toEqual({
autoscaleSettings: {
maxThroughput: 4000,
},
maxThroughput: 4000
}
});
});
});

View File

@@ -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";
@@ -41,7 +41,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
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 };

View File

@@ -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";
@@ -85,10 +85,10 @@ async function createSqlDatabase(params: DataModels.CreateDatabaseParams): Promi
const rpPayload: SqlDatabaseCreateUpdateParameters = {
properties: {
resource: {
id: params.databaseId,
id: params.databaseId
},
options,
},
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,
id: params.databaseId
},
options,
},
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,
id: params.databaseId
},
options,
},
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,
id: params.databaseId
},
options,
},
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
};
}

View File

@@ -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";
@@ -49,8 +49,8 @@ export async function createStoredProcedure(
const createSprocParams: SqlStoredProcedureCreateUpdateParameters = {
properties: {
resource: storedProcedure as SqlStoredProcedureResource,
options: {},
},
options: {}
}
};
const rpResponse = await createUpdateSqlStoredProcedure(
userContext.subscriptionId,

View File

@@ -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";
@@ -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}`);

View File

@@ -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";
@@ -49,8 +49,8 @@ export async function createUserDefinedFunction(
const createUDFParams: SqlUserDefinedFunctionCreateUpdateParameters = {
properties: {
resource: userDefinedFunction as SqlUserDefinedFunctionResource,
options: {},
},
options: {}
}
};
const rpResponse = await createUpdateSqlUserDefinedFunction(
userContext.subscriptionId,

View File

@@ -13,9 +13,9 @@ describe("deleteCollection", () => {
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "test",
name: "test"
} as DatabaseAccount,
defaultExperience: DefaultAccountExperienceType.DocumentDB,
defaultExperience: DefaultAccountExperienceType.DocumentDB
});
});
@@ -32,11 +32,11 @@ describe("deleteCollection", () => {
return {
container: () => {
return {
delete: (): unknown => undefined,
delete: (): unknown => undefined
};
},
}
};
},
}
});
await deleteCollection("database", "collection");
expect(client).toHaveBeenCalled();

View File

@@ -16,7 +16,10 @@ export async function deleteCollection(databaseId: string, collectionId: string)
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) {

View File

@@ -10,7 +10,7 @@ export const deleteConflict = async (collection: CollectionBase, conflictId: Con
try {
const options = {
partitionKey: getPartitionKeyHeaderForConflict(conflictId),
partitionKey: getPartitionKeyHeaderForConflict(conflictId)
};
await client()

View File

@@ -13,9 +13,9 @@ describe("deleteDatabase", () => {
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "test",
name: "test"
} as DatabaseAccount,
defaultExperience: DefaultAccountExperienceType.DocumentDB,
defaultExperience: DefaultAccountExperienceType.DocumentDB
});
});
@@ -30,9 +30,9 @@ describe("deleteDatabase", () => {
(client as jest.Mock).mockReturnValue({
database: () => {
return {
delete: (): unknown => undefined,
delete: (): unknown => undefined
};
},
}
});
await deleteDatabase("database");
expect(client).toHaveBeenCalled();

View File

@@ -19,7 +19,9 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
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) {

View File

@@ -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}`);

View File

@@ -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}`);

View File

@@ -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}`);

View File

@@ -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(

View File

@@ -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;
}
};

View File

@@ -11,7 +11,10 @@ export async function getIndexTransformationProgress(databaseId: string, collect
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

View File

@@ -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);
};

View File

@@ -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 => {

View File

@@ -10,9 +10,9 @@ describe("readCollection", () => {
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "test",
name: "test"
} as DatabaseAccount,
defaultExperience: DefaultAccountExperienceType.DocumentDB,
defaultExperience: DefaultAccountExperienceType.DocumentDB
});
});
@@ -23,11 +23,11 @@ describe("readCollection", () => {
return {
container: () => {
return {
read: (): unknown => ({}),
read: (): unknown => ({})
};
},
}
};
},
}
});
await readCollection("database", "collection");
expect(client).toHaveBeenCalled();

View File

@@ -7,7 +7,10 @@ export async function readCollection(databaseId: string, collectionId: string):
let collection: DataModels.Collection;
const clearMessage = logConsoleProgress(`Querying container ${collectionId}`);
try {
const response = await client().database(databaseId).container(collectionId).read();
const response = await client()
.database(databaseId)
.container(collectionId)
.read();
collection = response.resource as DataModels.Collection;
} catch (error) {
handleError(error, "ReadCollection", `Error while querying container ${collectionId}`);

View File

@@ -106,7 +106,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
autoscaleMaxThroughput: autoscaleSettings.maxThroughput,
manualThroughput: undefined,
minimumThroughput,
offerReplacePending: resource.offerReplacePending === "true",
offerReplacePending: resource.offerReplacePending === "true"
};
}
@@ -115,7 +115,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
autoscaleMaxThroughput: undefined,
manualThroughput: resource.throughput,
minimumThroughput,
offerReplacePending: resource.offerReplacePending === "true",
offerReplacePending: resource.offerReplacePending === "true"
};
}

View File

@@ -12,9 +12,9 @@ describe("readCollections", () => {
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "test",
name: "test"
} as DatabaseAccount,
defaultExperience: DefaultAccountExperienceType.DocumentDB,
defaultExperience: DefaultAccountExperienceType.DocumentDB
});
});
@@ -32,12 +32,12 @@ describe("readCollections", () => {
containers: {
readAll: () => {
return {
fetchAll: (): unknown => [],
fetchAll: (): unknown => []
};
},
},
}
}
};
},
}
});
await readCollections("database");
expect(client).toHaveBeenCalled();

View File

@@ -23,7 +23,10 @@ export async function readCollections(databaseId: string): Promise<DataModels.Co
return await readCollectionsWithARM(databaseId);
}
const sdkResponse = await client().database(databaseId).containers.readAll().fetchAll();
const sdkResponse = await client()
.database(databaseId)
.containers.readAll()
.fetchAll();
return sdkResponse.resources as DataModels.Collection[];
} catch (error) {
handleError(error, "ReadCollections", `Error while querying containers for database ${databaseId}`);
@@ -60,5 +63,5 @@ async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Co
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
}
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
return rpResponse?.value?.map(collection => collection.properties?.resource as DataModels.Collection);
}

View File

@@ -78,7 +78,7 @@ const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
autoscaleMaxThroughput: autoscaleSettings.maxThroughput,
manualThroughput: undefined,
minimumThroughput,
offerReplacePending: resource.offerReplacePending === "true",
offerReplacePending: resource.offerReplacePending === "true"
};
}
@@ -87,7 +87,7 @@ const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
autoscaleMaxThroughput: undefined,
manualThroughput: resource.throughput,
minimumThroughput,
offerReplacePending: resource.offerReplacePending === "true",
offerReplacePending: resource.offerReplacePending === "true"
};
}

View File

@@ -12,9 +12,9 @@ describe("readDatabases", () => {
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "test",
name: "test"
} as DatabaseAccount,
defaultExperience: DefaultAccountExperienceType.DocumentDB,
defaultExperience: DefaultAccountExperienceType.DocumentDB
});
});
@@ -30,10 +30,10 @@ describe("readDatabases", () => {
databases: {
readAll: () => {
return {
fetchAll: (): unknown => [],
fetchAll: (): unknown => []
};
},
},
}
}
});
await readDatabases();
expect(client).toHaveBeenCalled();

View File

@@ -21,7 +21,9 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
) {
databases = await readDatabasesWithARM();
} else {
const sdkResponse = await client().databases.readAll().fetchAll();
const sdkResponse = await client()
.databases.readAll()
.fetchAll();
databases = sdkResponse.resources as DataModels.Database[];
}
} catch (error) {
@@ -56,5 +58,5 @@ async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
}
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);
return rpResponse?.value?.map(database => database.properties?.resource as DataModels.Database);
}

View File

@@ -8,7 +8,7 @@ import { readOffers } from "./readOffers";
export const readOfferWithSDK = async (offerId: string, resourceId: string): Promise<Offer> => {
if (!offerId) {
const offers = await readOffers();
const offer = offers.find((offer) => offer.resource === resourceId);
const offer = offers.find(offer => offer.resource === resourceId);
if (!offer) {
return undefined;
@@ -18,10 +18,12 @@ export const readOfferWithSDK = async (offerId: string, resourceId: string): Pro
const options: RequestOptions = {
initialHeaders: {
[HttpHeaders.populateCollectionThroughputInfo]: true,
},
[HttpHeaders.populateCollectionThroughputInfo]: true
}
};
const response = await client().offer(offerId).read(options);
const response = await client()
.offer(offerId)
.read(options);
return parseSDKOfferResponse(response);
};

View File

@@ -7,7 +7,9 @@ export const readOffers = async (): Promise<SDKOfferDefinition[]> => {
const clearMessage = logConsoleProgress(`Querying offers`);
try {
const response = await client().offers.readAll().fetchAll();
const response = await client()
.offers.readAll()
.fetchAll();
return response?.resources;
} catch (error) {
// This should be removed when we can correctly identify if an account is serverless when connected using connection string too.

View File

@@ -25,7 +25,7 @@ export async function readStoredProcedures(
databaseId,
collectionId
);
return rpResponse?.value?.map((sproc) => sproc.properties?.resource as StoredProcedureDefinition & Resource);
return rpResponse?.value?.map(sproc => sproc.properties?.resource as StoredProcedureDefinition & Resource);
}
const response = await client()

View File

@@ -25,10 +25,14 @@ export async function readTriggers(
databaseId,
collectionId
);
return rpResponse?.value?.map((trigger) => trigger.properties?.resource as TriggerDefinition & Resource);
return rpResponse?.value?.map(trigger => trigger.properties?.resource as TriggerDefinition & Resource);
}
const response = await client().database(databaseId).container(collectionId).scripts.triggers.readAll().fetchAll();
const response = await client()
.database(databaseId)
.container(collectionId)
.scripts.triggers.readAll()
.fetchAll();
return response?.resources;
} catch (error) {
handleError(error, "ReadTriggers", `Failed to query triggers for container ${collectionId}`);

View File

@@ -25,7 +25,7 @@ export async function readUserDefinedFunctions(
databaseId,
collectionId
);
return rpResponse?.value?.map((udf) => udf.properties?.resource as UserDefinedFunctionDefinition & Resource);
return rpResponse?.value?.map(udf => udf.properties?.resource as UserDefinedFunctionDefinition & Resource);
}
const response = await client()

View File

@@ -8,22 +8,22 @@ import {
MongoDBCollectionCreateUpdateParameters,
MongoDBCollectionResource,
SqlContainerCreateUpdateParameters,
SqlContainerResource,
SqlContainerResource
} from "../../Utils/arm/generatedClients/2020-04-01/types";
import { RequestOptions } from "@azure/cosmos/dist-esm";
import { client } from "../CosmosClient";
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 { handleError } from "../ErrorHandlingUtils";
@@ -130,8 +130,8 @@ export async function updateMongoDBCollectionThroughRP(
const updateParams: MongoDBCollectionCreateUpdateParameters = {
properties: {
resource: newCollection,
options: updateOptions,
},
options: updateOptions
}
};
const updateResponse = await createUpdateMongoDBCollection(

View File

@@ -17,7 +17,7 @@ import {
migrateSqlDatabaseToManualThroughput,
migrateSqlContainerToAutoscale,
migrateSqlContainerToManualThroughput,
updateSqlContainerThroughput,
updateSqlContainerThroughput
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
import {
updateCassandraKeyspaceThroughput,
@@ -25,7 +25,7 @@ import {
migrateCassandraKeyspaceToManualThroughput,
migrateCassandraTableToAutoscale,
migrateCassandraTableToManualThroughput,
updateCassandraTableThroughput,
updateCassandraTableThroughput
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
import {
updateMongoDBDatabaseThroughput,
@@ -33,7 +33,7 @@ import {
migrateMongoDBDatabaseToManualThroughput,
migrateMongoDBCollectionToAutoscale,
migrateMongoDBCollectionToManualThroughput,
updateMongoDBCollectionThroughput,
updateMongoDBCollectionThroughput
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
import {
updateGremlinDatabaseThroughput,
@@ -41,13 +41,13 @@ import {
migrateGremlinDatabaseToManualThroughput,
migrateGremlinGraphToAutoscale,
migrateGremlinGraphToManualThroughput,
updateGremlinGraphThroughput,
updateGremlinGraphThroughput
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
import { userContext } from "../../UserContext";
import {
migrateTableToAutoscale,
migrateTableToManualThroughput,
updateTableThroughput,
updateTableThroughput
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
@@ -110,7 +110,7 @@ const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<
return await readCollectionOffer({
collectionId: params.collectionId,
databaseId: params.databaseId,
offerId: params.currentOffer.id,
offerId: params.currentOffer.id
});
};
@@ -140,7 +140,7 @@ const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Of
return await readDatabaseOffer({
databaseId: params.databaseId,
offerId: params.currentOffer.id,
offerId: params.currentOffer.id
});
};
@@ -358,13 +358,13 @@ const updateGremlinDatabaseOffer = async (params: UpdateOfferParams): Promise<vo
const createUpdateOfferBody = (params: UpdateOfferParams): ThroughputSettingsUpdateParameters => {
const body: ThroughputSettingsUpdateParameters = {
properties: {
resource: {},
},
resource: {}
}
};
if (params.autopilotThroughput) {
body.properties.resource.autoscaleSettings = {
maxThroughput: params.autopilotThroughput,
maxThroughput: params.autopilotThroughput
};
} else {
body.properties.resource.throughput = params.manualThroughput;
@@ -378,7 +378,7 @@ const updateOfferWithSDK = async (params: UpdateOfferParams): Promise<Offer> =>
const newOffer: SDKOfferDefinition = {
content: {
offerThroughput: undefined,
offerIsRUPerMinuteThroughputEnabled: false,
offerIsRUPerMinuteThroughputEnabled: false
},
_etag: undefined,
_ts: undefined,
@@ -388,12 +388,12 @@ const updateOfferWithSDK = async (params: UpdateOfferParams): Promise<Offer> =>
offerResourceId: sdkOfferDefinition.offerResourceId,
offerVersion: sdkOfferDefinition.offerVersion,
offerType: sdkOfferDefinition.offerType,
resource: sdkOfferDefinition.resource,
resource: sdkOfferDefinition.resource
};
if (params.autopilotThroughput) {
newOffer.content.offerAutopilotSettings = {
maxThroughput: params.autopilotThroughput,
maxThroughput: params.autopilotThroughput
};
} else {
newOffer.content.offerThroughput = params.manualThroughput;
@@ -402,12 +402,12 @@ const updateOfferWithSDK = async (params: UpdateOfferParams): Promise<Offer> =>
const options: RequestOptions = {};
if (params.migrateToAutoPilot) {
options.initialHeaders = {
[HttpHeaders.migrateOfferToAutopilot]: "true",
[HttpHeaders.migrateOfferToAutopilot]: "true"
};
delete newOffer.content.offerAutopilotSettings;
} else if (params.migrateToManual) {
options.initialHeaders = {
[HttpHeaders.migrateOfferToManualThroughput]: "true",
[HttpHeaders.migrateOfferToManualThroughput]: "true"
};
newOffer.content.offerAutopilotSettings = { maxThroughput: 0 };
}

View File

@@ -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";
@@ -39,8 +39,8 @@ export async function updateStoredProcedure(
const createSprocParams: SqlStoredProcedureCreateUpdateParameters = {
properties: {
resource: storedProcedure as SqlStoredProcedureResource,
options: {},
},
options: {}
}
};
const rpResponse = await createUpdateSqlStoredProcedure(
userContext.subscriptionId,

View File

@@ -2,7 +2,7 @@ import { AuthType } from "../../AuthType";
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
import {
SqlTriggerCreateUpdateParameters,
SqlTriggerResource,
SqlTriggerResource
} from "../../Utils/arm/generatedClients/2020-04-01/types";
import { TriggerDefinition } from "@azure/cosmos";
import { client } from "../CosmosClient";
@@ -36,8 +36,8 @@ export async function updateTrigger(
const createTriggerParams: SqlTriggerCreateUpdateParameters = {
properties: {
resource: trigger as SqlTriggerResource,
options: {},
},
options: {}
}
};
const rpResponse = await createUpdateSqlTrigger(
userContext.subscriptionId,

View File

@@ -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";
@@ -39,8 +39,8 @@ export async function updateUserDefinedFunction(
const createUDFParams: SqlUserDefinedFunctionCreateUpdateParameters = {
properties: {
resource: userDefinedFunction as SqlUserDefinedFunctionResource,
options: {},
},
options: {}
}
};
const rpResponse = await createUpdateSqlUserDefinedFunction(
userContext.subscriptionId,

View File

@@ -1,10 +1,10 @@
export enum Platform {
Portal = "Portal",
Hosted = "Hosted",
Emulator = "Emulator",
Emulator = "Emulator"
}
export interface ConfigContext {
interface ConfigContext {
platform: Platform;
allowedParentFrameOrigins: string[];
gitSha?: string;
@@ -26,7 +26,6 @@ export interface ConfigContext {
GITHUB_CLIENT_SECRET?: string; // No need to inject secret for prod. Juno already knows it.
hostedExplorerURL: string;
armAPIVersion?: string;
ENABLE_GALLERY_PUBLISH?: boolean;
}
// Default configuration
@@ -38,7 +37,7 @@ let configContext: Readonly<ConfigContext> = {
`^https:\\/\\/[\\.\\w]*portal\\.microsoftazure.de$`,
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`
],
// Webpack injects this at build time
gitSha: process.env.GIT_SHA,
@@ -53,7 +52,7 @@ let configContext: Readonly<ConfigContext> = {
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
GITHUB_CLIENT_ID: "6cb2f63cf6f7b5cbdeca", // Registered OAuth app: https://github.com/settings/applications/1189306
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com"
};
export function resetConfigContext(): void {
@@ -74,24 +73,20 @@ if (process.env.NODE_ENV === "development") {
BACKEND_ENDPOINT: "https://localhost:" + port,
MONGO_BACKEND_ENDPOINT: "https://localhost:" + port,
PROXY_PATH: "/proxy",
EMULATOR_ENDPOINT: "https://localhost:8081",
EMULATOR_ENDPOINT: "https://localhost:8081"
});
}
export async function initializeConfiguration(): Promise<ConfigContext> {
try {
const response = await fetch("./config.json", {
headers: {
"If-None-Match": "", // disable client side cache
},
});
const response = await fetch("./config.json");
if (response.status === 200) {
try {
const { allowedParentFrameOrigins, ...externalConfig } = await response.json();
Object.assign(configContext, externalConfig);
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
updateConfigContext({
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins],
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins]
});
}
} catch (error) {
@@ -109,7 +104,7 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
const platform = params.get("platform");
switch (platform) {
default:
console.error(`Invalid platform query parameter: ${platform}`);
console.log("Invalid platform query parameter given, ignoring");
break;
case Platform.Portal:
case Platform.Hosted:
@@ -118,7 +113,7 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
}
}
} catch (error) {
console.error("No configuration file found using defaults");
console.log("No configuration file found using defaults");
}
return configContext;
}

View File

@@ -7,7 +7,7 @@ export enum TabKind {
TableEntities,
Graph,
SQLQuery,
ScaleSettings,
ScaleSettings
}
/**
@@ -20,7 +20,7 @@ export enum PaneKind {
DeleteDatabase,
GlobalSettings,
AdHocAccess,
SwitchDirectory,
SwitchDirectory
}
/**
@@ -79,5 +79,5 @@ export enum ActionType {
OpenCollectionTab,
OpenPane,
TransmitCachedData,
OpenSampleNotebook,
OpenSampleNotebook
}

View File

@@ -56,7 +56,7 @@ export enum ApiKind {
Table,
Cassandra,
Graph,
MongoDBCompute,
MongoDBCompute
}
export interface GenerateTokenResponse {
@@ -210,9 +210,9 @@ export interface QueryMetrics {
export interface Offer {
id: string;
autoscaleMaxThroughput: number | undefined;
manualThroughput: number | undefined;
minimumThroughput: number | undefined;
autoscaleMaxThroughput: number;
manualThroughput: number;
minimumThroughput: number;
offerDefinition?: SDKOfferDefinition;
offerReplacePending: boolean;
}
@@ -334,7 +334,7 @@ export interface Notification {
export enum ConflictResolutionMode {
Custom = "Custom",
LastWriterWins = "LastWriterWins",
LastWriterWins = "LastWriterWins"
}
/**
@@ -472,7 +472,7 @@ export interface SparkClusterEndpoint {
export enum SparkClusterEndpointKind {
SparkUI = "SparkUI",
HistoryServerUI = "HistoryServerUI",
Livy = "Livy",
Livy = "Livy"
}
export interface RpParameters {
@@ -587,3 +587,11 @@ export interface MemoryUsageInfo {
freeKB: number;
totalKB: number;
}
export interface resourceTokenConnectionStringProperties {
accountEndpoint: string;
collectionId: string;
databaseId: string;
partitionKey?: string;
resourceToken: string;
}

View File

@@ -21,7 +21,7 @@ export enum LogEntryLevel {
/**
* Error level.
*/
Error = 2,
Error = 2
}
/**
* Schema of a log entry.

View File

@@ -33,6 +33,7 @@ export enum MessageTypes {
CreateWorkspace,
CreateSparkPool,
RefreshDatabaseAccount,
InitTestExplorer
}
export { Versions, ActionContracts, Diagnostics };

View File

@@ -3,5 +3,5 @@ export enum SubscriptionType {
EA,
Free,
Internal,
PAYG,
PAYG
}

View File

@@ -3,8 +3,9 @@ import {
Resource,
StoredProcedureDefinition,
TriggerDefinition,
UserDefinedFunctionDefinition,
UserDefinedFunctionDefinition
} from "@azure/cosmos";
import Q from "q";
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
import Explorer from "../Explorer/Explorer";
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
@@ -14,7 +15,6 @@ import DocumentId from "../Explorer/Tree/DocumentId";
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import Trigger from "../Explorer/Tree/Trigger";
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
import { SelfServeType } from "../SelfServe/SelfServeUtils";
import { UploadDetails } from "../workers/upload/definitions";
import * as DataModels from "./DataModels";
import { SubscriptionType } from "./SubscriptionType";
@@ -91,7 +91,6 @@ export interface Database extends TreeNode {
onDeleteDatabaseContextMenuClick(source: Database, event: MouseEvent | KeyboardEvent): void;
onSettingsClick: () => void;
loadOffer(): Promise<void>;
getPendingThroughputSplitNotification(): Promise<DataModels.Notification>;
}
export interface CollectionBase extends TreeNode {
@@ -109,7 +108,7 @@ export interface CollectionBase extends TreeNode {
onDocumentDBDocumentsClick(): void;
onNewQueryClick(source: any, event: MouseEvent, queryText?: string): void;
expandCollection(): void;
expandCollection(): Q.Promise<any>;
collapseCollection(): void;
getDatabase(): Database;
}
@@ -138,6 +137,7 @@ export interface Collection extends CollectionBase {
openTab(): void;
onSettingsClick: () => Promise<void>;
onDeleteCollectionContextMenuClick(source: Collection, event: MouseEvent): void;
onNewGraphClick(): void;
onNewMongoQueryClick(source: any, event: MouseEvent, queryText?: string): void;
@@ -175,10 +175,9 @@ export interface Collection extends CollectionBase {
onDragOver(source: Collection, event: { originalEvent: DragEvent }): void;
onDrop(source: Collection, event: { originalEvent: DragEvent }): void;
uploadFiles(fileList: FileList): Promise<UploadDetails>;
uploadFiles(fileList: FileList): Q.Promise<UploadDetails>;
getLabel(): string;
getPendingThroughputSplitNotification(): Promise<DataModels.Notification>;
}
/**
@@ -196,7 +195,7 @@ export interface PaneOptions {
export enum NeighborType {
SOURCES_ONLY,
TARGETS_ONLY,
BOTH,
BOTH
}
/**
@@ -293,6 +292,10 @@ export interface DocumentsTabOptions extends TabOptions {
resourceTokenPartitionKey?: string;
}
export interface SettingsTabV2Options extends TabOptions {
getPendingNotification: Q.Promise<DataModels.Notification>;
}
export interface ConflictsTabOptions extends TabOptions {
partitionKey: DataModels.PartitionKey;
conflictIds: ko.ObservableArray<ConflictId>;
@@ -322,14 +325,14 @@ export enum DocumentExplorerState {
newDocumentInvalid,
exisitingDocumentNoEdits,
exisitingDocumentDirtyValid,
exisitingDocumentDirtyInvalid,
exisitingDocumentDirtyInvalid
}
export enum IndexingPolicyEditorState {
noCollectionSelected,
noEdits,
dirtyValid,
dirtyInvalid,
dirtyInvalid
}
export enum ScriptEditorState {
@@ -337,7 +340,7 @@ export enum ScriptEditorState {
newValid,
exisitingNoEdits,
exisitingDirtyValid,
exisitingDirtyInvalid,
exisitingDirtyInvalid
}
export enum CollectionTabKind {
@@ -359,14 +362,13 @@ export enum CollectionTabKind {
Gallery = 17,
NotebookViewer = 18,
Schema = 19,
CollectionSettingsV2 = 20,
DatabaseSettingsV2 = 21,
SettingsV2 = 19
}
export enum TerminalKind {
Default = 0,
Mongo = 1,
Cassandra = 2,
Cassandra = 2
}
export interface DataExplorerInputsFrame {
@@ -393,7 +395,6 @@ export interface DataExplorerInputsFrame {
isAuthWithresourceToken?: boolean;
defaultCollectionThroughput?: CollectionCreationDefaults;
flights?: readonly string[];
selfServeType?: SelfServeType;
}
export interface CollectionCreationDefaults {

View File

@@ -6,19 +6,19 @@ describe("The Heatmap Control", () => {
const dataPoints = {
"1": {
"2019-06-19T00:59:10Z": {
"Normalized Throughput": 0.35,
"Normalized Throughput": 0.35
},
"2019-06-19T00:48:10Z": {
"Normalized Throughput": 0.25,
},
},
"Normalized Throughput": 0.25
}
}
};
const chartCaptions = {
chartTitle: "chart title",
yAxisTitle: "YAxisTitle",
tooltipText: "Tooltip text",
timeWindow: 123456789,
timeWindow: 123456789
};
let heatmap: Heatmap;
@@ -75,12 +75,12 @@ describe("The Heatmap Control", () => {
if (dayjs().utcOffset()) {
expect(heatmap.generateMatrixFromMap(dataPoints).xAxisPoints).not.toEqual([
"2019-06-19T00:48:10Z",
"2019-06-19T00:59:10Z",
"2019-06-19T00:59:10Z"
]);
} else {
expect(heatmap.generateMatrixFromMap(dataPoints).xAxisPoints).toEqual([
"2019-06-19T00:48:10Z",
"2019-06-19T00:59:10Z",
"2019-06-19T00:59:10Z"
]);
}
});
@@ -106,9 +106,9 @@ describe("iframe rendering when there is no data", () => {
data: {
chartData: {},
chartSettings: {},
theme: 4,
},
},
theme: 4
}
}
};
const divElement: string = `<div id="${Heatmap.elementId}"></div>`;
@@ -126,9 +126,9 @@ describe("iframe rendering when there is no data", () => {
data: {
chartData: {},
chartSettings: {},
theme: 2,
},
},
theme: 2
}
}
};
const divElement: string = `<div id="${Heatmap.elementId}"></div>`;

View File

@@ -9,7 +9,7 @@ import {
HeatmapData,
LayoutSettings,
PartitionTimeStampToData,
PortalTheme,
PortalTheme
} from "./HeatmapDatatypes";
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
import { sendCachedDataMessage, sendMessage } from "../../Common/MessageHandler";
@@ -43,7 +43,7 @@ export class Heatmap {
return {
family: StyleConstants.DataExplorerFont,
size,
color,
color
};
}
@@ -73,7 +73,7 @@ export class Heatmap {
return 0;
}
}
}),
})
};
// go thru all rows and create 2d matrix for heatmap...
for (let i = 0; i < rows.length; i++) {
@@ -115,7 +115,7 @@ export class Heatmap {
[0.7, "#E46612"],
[0.8, "#E64914"],
[0.9, "#B80016"],
[1.0, "#B80016"],
[1.0, "#B80016"]
],
name: "",
hovertemplate: this._heatmapCaptions.tooltipText,
@@ -123,11 +123,11 @@ export class Heatmap {
thickness: 15,
outlinewidth: 0,
tickcolor: StyleConstants.BaseDark,
tickfont: this._getFontStyles(10, this._defaultFontColor),
tickfont: this._getFontStyles(10, this._defaultFontColor)
},
y: this._chartData.yAxisPoints,
x: this._chartData.xAxisPoints,
},
x: this._chartData.xAxisPoints
}
];
}
@@ -138,7 +138,7 @@ export class Heatmap {
r: 10,
b: 35,
t: 30,
pad: 0,
pad: 0
},
paper_bgcolor: "transparent",
plot_bgcolor: "transparent",
@@ -154,7 +154,7 @@ export class Heatmap {
autotick: true,
fixedrange: true,
ticks: "",
showticklabels: false,
showticklabels: false
},
xaxis: {
fixedrange: true,
@@ -167,13 +167,13 @@ export class Heatmap {
autotick: true,
tickformat: this._heatmapCaptions.timeWindow > 7 ? "%I:%M %p" : "%b %e",
showticklabels: true,
tickfont: this._getFontStyles(10),
tickfont: this._getFontStyles(10)
},
title: {
text: this._heatmapCaptions.chartTitle,
x: 0.01,
font: this._getFontStyles(13, this._defaultFontColor),
},
font: this._getFontStyles(13, this._defaultFontColor)
}
};
}
@@ -181,7 +181,7 @@ export class Heatmap {
return {
/* heatmap can be fully responsive however the min-height needed in that case is greater than the iframe portal height, hence explicit width + height have been set in _getLayoutSettings
responsive: true,*/
displayModeBar: false,
displayModeBar: false
};
}

View File

@@ -8,7 +8,7 @@ export enum PortalTheme {
blue = 1,
azure,
light,
dark,
dark
}
export interface HeatmapData {

View File

@@ -4,5 +4,5 @@ export enum DefaultAccountExperienceType {
MongoDB = "MongoDB",
Table = "Table",
Cassandra = "Cassandra",
ApiForMongoDB = "Azure Cosmos DB for MongoDB API",
ApiForMongoDB = "Azure Cosmos DB for MongoDB API"
}

383
src/Definitions/adal.d.ts vendored Normal file
View File

@@ -0,0 +1,383 @@
// Type definitions for adal-angular 1.0.1.1
// Project: https://github.com/AzureAD/azure-activedirectory-library-for-js#readme
// Definitions by: Daniel Perez Alvarez <https://github.com/unindented>
// Anthony Ciccarello <https://github.com/aciccarello>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
//This is a customized version of adal on top of version 1.0.1 which does not support multi tenant
// Customized version add tenantId to stored tokens so when tenant change, adal will refetch instead of read from sessionStorage
// In module contexts the class constructor function is the exported object
// export = AuthenticationContext;
// This class is defined globally in not in a module context
declare class AuthenticationContext {
instance: string;
config: AuthenticationContext.Options;
callback: AuthenticationContext.TokenCallback;
popUp: boolean;
isAngular: boolean;
/**
* Enum for request type
*/
REQUEST_TYPE: AuthenticationContext.RequestType;
RESPONSE_TYPE: AuthenticationContext.ResponseType;
CONSTANTS: AuthenticationContext.Constants;
constructor(options: AuthenticationContext.Options);
/**
* Initiates the login process by redirecting the user to Azure AD authorization endpoint.
*/
login(): void;
/**
* Returns whether a login is in progress.
*/
loginInProgress(): boolean;
/**
* Gets token for the specified resource from the cache.
* @param resource A URI that identifies the resource for which the token is requested.
* @param tenantId tenant Id.
*/
getCachedToken(resource: string, tenantId: string): string;
/**
* If user object exists, returns it. Else creates a new user object by decoding `id_token` from the cache.
*/
getCachedUser(): AuthenticationContext.UserInfo;
/**
* Adds the passed callback to the array of callbacks for the specified resource.
* @param resource A URI that identifies the resource for which the token is requested.
* @param expectedState A unique identifier (guid).
* @param callback The callback provided by the caller. It will be called with token or error.
*/
registerCallback(
expectedState: string,
resource: string,
callback: AuthenticationContext.TokenCallback,
tenantId: string
): void;
/**
* Acquires token from the cache if it is not expired. Otherwise sends request to AAD to obtain a new token.
* @param resource Resource URI identifying the target resource.
* @param callback The callback provided by the caller. It will be called with token or error.
*/
acquireToken(resource: string, tenantId: string, callback: AuthenticationContext.TokenCallback): void;
/**
* Acquires token (interactive flow using a popup window) by sending request to AAD to obtain a new token.
* @param resource Resource URI identifying the target resource.
* @param extraQueryParameters Query parameters to add to the authentication request.
* @param claims Claims to add to the authentication request.
* @param callback The callback provided by the caller. It will be called with token or error.
*/
acquireTokenPopup(
resource: string,
tenantId: string,
extraQueryParameters: string | null | undefined,
claims: string | null | undefined,
callback: AuthenticationContext.TokenCallback
): void;
/**
* Acquires token (interactive flow using a redirect) by sending request to AAD to obtain a new token. In this case the callback passed in the authentication request constructor will be called.
* @param resource Resource URI identifying the target resource.
* @param extraQueryParameters Query parameters to add to the authentication request.
* @param claims Claims to add to the authentication request.
*/
acquireTokenRedirect(
resource: string,
tenantId: string,
extraQueryParameters?: string | null,
claims?: string | null
): void;
/**
* Redirects the browser to Azure AD authorization endpoint.
* @param urlNavigate URL of the authorization endpoint.
*/
promptUser(urlNavigate: string): void;
/**
* Clears cache items.
*/
clearCache(): void;
/**
* Clears cache items for a given resource.
* @param resource Resource URI identifying the target resource.
*/
clearCacheForResource(resource: string): void;
/**
* Redirects user to logout endpoint. After logout, it will redirect to `postLogoutRedirectUri` if added as a property on the config object.
*/
logOut(): void;
/**
* Calls the passed in callback with the user object or error message related to the user.
* @param callback The callback provided by the caller. It will be called with user or error.
*/
getUser(callback: AuthenticationContext.UserCallback): void;
/**
* Checks if the URL fragment contains access token, id token or error description.
* @param hash Hash passed from redirect page.
*/
isCallback(hash: string): boolean;
/**
* Gets login error.
*/
getLoginError(): string;
/**
* Creates a request info object from the URL fragment and returns it.
*/
getRequestInfo(hash: string): AuthenticationContext.RequestInfo;
/**
* Saves token or error received in the response from AAD in the cache. In case of `id_token`, it also creates the user object.
*/
saveTokenFromHash(requestInfo: AuthenticationContext.RequestInfo): void;
/**
* Gets resource for given endpoint if mapping is provided with config.
* @param endpoint Resource URI identifying the target resource.
*/
getResourceForEndpoint(resource: string): string;
/**
* This method must be called for processing the response received from AAD. It extracts the hash, processes the token or error, saves it in the cache and calls the callbacks with the result.
* @param hash Hash fragment of URL. Defaults to `window.location.hash`.
*/
handleWindowCallback(hash?: string): void;
/**
* Checks the logging Level, constructs the log message and logs it. Users need to implement/override this method to turn on logging.
* @param level Level can be set 0, 1, 2 and 3 which turns on 'error', 'warning', 'info' or 'verbose' level logging respectively.
* @param message Message to log.
* @param error Error to log.
*/
log(level: AuthenticationContext.LoggingLevel, message: string, error: any): void;
/**
* Logs messages when logging level is set to 0.
* @param message Message to log.
* @param error Error to log.
*/
error(message: string, error: any): void;
/**
* Logs messages when logging level is set to 1.
* @param message Message to log.
*/
warn(message: string): void;
/**
* Logs messages when logging level is set to 2.
* @param message Message to log.
*/
info(message: string): void;
/**
* Logs messages when logging level is set to 3.
* @param message Message to log.
*/
verbose(message: string): void;
/**
* Logs Pii messages when Logging Level is set to 0 and window.piiLoggingEnabled is set to true.
* @param message Message to log.
* @param error Error to log.
*/
errorPii(message: string, error: any): void;
/**
* Logs Pii messages when Logging Level is set to 1 and window.piiLoggingEnabled is set to true.
* @param message Message to log.
*/
warnPii(message: string): void;
/**
* Logs messages when Logging Level is set to 2 and window.piiLoggingEnabled is set to true.
* @param message Message to log.
*/
infoPii(message: string): void;
/**
* Logs messages when Logging Level is set to 3 and window.piiLoggingEnabled is set to true.
* @param message Message to log.
*/
verbosePii(message: string): void;
}
declare namespace AuthenticationContext {
function inject(config: Options): AuthenticationContext;
type LoggingLevel = 0 | 1 | 2 | 3;
type RequestType = "LOGIN" | "RENEW_TOKEN" | "UNKNOWN";
type ResponseType = "id_token token" | "token";
interface RequestInfo {
/**
* Object comprising of fields such as id_token/error, session_state, state, e.t.c.
*/
parameters: any;
/**
* Request type.
*/
requestType: RequestType;
/**
* Whether state is valid.
*/
stateMatch: boolean;
/**
* Unique guid used to match the response with the request.
*/
stateResponse: string;
/**
* Whether `requestType` contains `id_token`, `access_token` or error.
*/
valid: boolean;
}
interface UserInfo {
/**
* Username assigned from UPN or email.
*/
userName: string;
/**
* Properties parsed from `id_token`.
*/
profile: any;
}
type TokenCallback = (errorDesc: string | null, token: string | null, error: any) => void;
type UserCallback = (errorDesc: string | null, user: UserInfo | null) => void;
/**
* Configuration options for Authentication Context
*/
interface Options {
/**
* Client ID assigned to your app by Azure Active Directory.
*/
clientId: string;
/**
* Endpoint at which you expect to receive tokens.Defaults to `window.location.href`.
*/
redirectUri?: string;
/**
* Azure Active Directory instance. Defaults to `https://login.microsoftonline.com/`.
*/
instance?: string;
/**
* Your target tenant. Defaults to `common`.
*/
tenant?: string;
/**
* Query parameters to add to the authentication request.
*/
extraQueryParameter?: string;
/**
* Unique identifier used to map the request with the response. Defaults to RFC4122 version 4 guid (128 bits).
*/
correlationId?: string;
/**
* User defined function of handling the navigation to Azure AD authorization endpoint in case of login.
*/
displayCall?: (url: string) => void;
/**
* Set this to true to enable login in a popup winodow instead of a full redirect. Defaults to `false`.
*/
popUp?: boolean;
/**
* Set this to the resource to request on login. Defaults to `clientId`.
*/
loginResource?: string;
/**
* Set this to redirect the user to a custom login page.
*/
localLoginUrl?: string;
/**
* Redirects to start page after login. Defaults to `true`.
*/
navigateToLoginRequestUrl?: boolean;
/**
* Set this to redirect the user to a custom logout page.
*/
logOutUri?: string;
/**
* Redirects the user to postLogoutRedirectUri after logout. Defaults to `redirectUri`.
*/
postLogoutRedirectUri?: string;
/**
* Sets browser storage to either 'localStorage' or sessionStorage'. Defaults to `sessionStorage`.
*/
cacheLocation?: "localStorage" | "sessionStorage";
/**
* Array of keywords or URIs. Adal will attach a token to outgoing requests that have these keywords or URIs.
*/
endpoints?: { [resource: string]: string };
/**
* Array of keywords or URIs. Adal will not attach a token to outgoing requests that have these keywords or URIs.
*/
anonymousEndpoints?: string[];
/**
* If the cached token is about to be expired in the expireOffsetSeconds (in seconds), Adal will renew the token instead of using the cached token. Defaults to 300 seconds.
*/
expireOffsetSeconds?: number;
/**
* The number of milliseconds of inactivity before a token renewal response from AAD should be considered timed out. Defaults to 6 seconds.
*/
loadFrameTimeout?: number;
/**
* Callback to be invoked when a token is acquired.
*/
callback?: TokenCallback;
}
interface LoggingConfig {
level: LoggingLevel;
log: (message: string) => void;
piiLoggingEnabled: boolean;
}
/**
* Enum for storage constants
*/
interface Constants {
ACCESS_TOKEN: "access_token";
EXPIRES_IN: "expires_in";
ID_TOKEN: "id_token";
ERROR_DESCRIPTION: "error_description";
SESSION_STATE: "session_state";
STORAGE: {
TOKEN_KEYS: "adal.token.keys";
ACCESS_TOKEN_KEY: "adal.access.token.key";
EXPIRATION_KEY: "adal.expiration.key";
STATE_LOGIN: "adal.state.login";
STATE_RENEW: "adal.state.renew";
NONCE_IDTOKEN: "adal.nonce.idtoken";
SESSION_STATE: "adal.session.state";
USERNAME: "adal.username";
IDTOKEN: "adal.idtoken";
ERROR: "adal.error";
ERROR_DESCRIPTION: "adal.error.description";
LOGIN_REQUEST: "adal.login.request";
LOGIN_ERROR: "adal.login.error";
RENEW_STATUS: "adal.token.renew.status";
};
RESOURCE_DELIMETER: "|";
LOADFRAME_TIMEOUT: "6000";
TOKEN_RENEW_STATUS_CANCELED: "Canceled";
TOKEN_RENEW_STATUS_COMPLETED: "Completed";
TOKEN_RENEW_STATUS_IN_PROGRESS: "In Progress";
LOGGING_LEVEL: {
ERROR: 0;
WARN: 1;
INFO: 2;
VERBOSE: 3;
};
LEVEL_STRING_MAP: {
0: "ERROR:";
1: "WARNING:";
2: "INFO:";
3: "VERBOSE:";
};
POPUP_WIDTH: 483;
POPUP_HEIGHT: 600;
}
}
// declare global {
// interface Window {
// Logging: AuthenticationContext.LoggingConfig;
// }
// }

View File

@@ -45,8 +45,7 @@ describe("Component Registerer", () => {
});
it("should register settings-tab-v2 component", () => {
expect(ko.components.isRegistered("database-settings-tab-v2")).toBe(true);
expect(ko.components.isRegistered("collection-settings-tab-v2")).toBe(true);
expect(ko.components.isRegistered("settings-tab-v2")).toBe(true);
});
it("should register query-tab component", () => {

View File

@@ -31,7 +31,7 @@ ko.components.register("mongo-documents-tab", new TabComponents.MongoDocumentsTa
ko.components.register("stored-procedure-tab", new TabComponents.StoredProcedureTab());
ko.components.register("trigger-tab", new TabComponents.TriggerTab());
ko.components.register("user-defined-function-tab", new TabComponents.UserDefinedFunctionTab());
ko.components.register("collection-settings-tab-v2", new TabComponents.SettingsTabV2());
ko.components.register("settings-tab-v2", new TabComponents.SettingsTabV2());
ko.components.register("query-tab", new TabComponents.QueryTab());
ko.components.register("tables-query-tab", new TabComponents.QueryTablesTab());
ko.components.register("graph-tab", new TabComponents.GraphTab());
@@ -45,7 +45,6 @@ ko.components.register("notebook-viewer-tab", new TabComponents.NotebookViewerTa
// Database Tabs
ko.components.register("database-settings-tab", new TabComponents.DatabaseSettingsTab());
ko.components.register("database-settings-tab-v2", new TabComponents.SettingsTabV2());
// Panes
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());

View File

@@ -36,8 +36,8 @@ export class ResourceTreeContextMenuButtonFactory {
{
iconSrc: AddCollectionIcon,
onClick: () => container.onNewCollectionClicked(),
label: container.addCollectionText(),
},
label: container.addCollectionText()
}
];
if (userContext.defaultExperience !== DefaultAccountExperienceType.Table) {
@@ -45,7 +45,7 @@ export class ResourceTreeContextMenuButtonFactory {
iconSrc: DeleteDatabaseIcon,
onClick: () => container.deleteDatabaseConfirmationPane.open(),
label: container.deleteDatabaseText(),
styleClass: "deleteDatabaseMenuItem",
styleClass: "deleteDatabaseMenuItem"
});
}
return items;
@@ -60,7 +60,7 @@ export class ResourceTreeContextMenuButtonFactory {
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null),
label: "New SQL Query",
label: "New SQL Query"
});
}
@@ -68,7 +68,7 @@ export class ResourceTreeContextMenuButtonFactory {
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
label: "New Query",
label: "New Query"
});
items.push({
@@ -77,7 +77,7 @@ export class ResourceTreeContextMenuButtonFactory {
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
selectedCollection && selectedCollection.onNewMongoShellClick();
},
label: "New Shell",
label: "New Shell"
});
}
@@ -88,7 +88,7 @@ export class ResourceTreeContextMenuButtonFactory {
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, null);
},
label: "New Stored Procedure",
label: "New Stored Procedure"
});
items.push({
@@ -97,7 +97,7 @@ export class ResourceTreeContextMenuButtonFactory {
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection, null);
},
label: "New UDF",
label: "New UDF"
});
items.push({
@@ -106,15 +106,18 @@ export class ResourceTreeContextMenuButtonFactory {
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, null);
},
label: "New Trigger",
label: "New Trigger"
});
}
items.push({
iconSrc: DeleteCollectionIcon,
onClick: () => container.openDeleteCollectionConfirmationPane(),
onClick: () => {
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
selectedCollection && selectedCollection.onDeleteCollectionContextMenuClick(selectedCollection, null);
},
label: container.deleteCollectionText(),
styleClass: "deleteCollectionMenuItem",
styleClass: "deleteCollectionMenuItem"
});
return items;
@@ -132,8 +135,8 @@ export class ResourceTreeContextMenuButtonFactory {
{
iconSrc: DeleteSprocIcon,
onClick: () => storedProcedure.delete(),
label: "Delete Store Procedure",
},
label: "Delete Store Procedure"
}
];
}
@@ -146,8 +149,8 @@ export class ResourceTreeContextMenuButtonFactory {
{
iconSrc: DeleteTriggerIcon,
onClick: () => trigger.delete(),
label: "Delete Trigger",
},
label: "Delete Trigger"
}
];
}
@@ -163,8 +166,8 @@ export class ResourceTreeContextMenuButtonFactory {
{
iconSrc: DeleteUDFIcon,
onClick: () => userDefinedFunction.delete(),
label: "Delete User Defined Function",
},
label: "Delete User Defined Function"
}
];
}
}

View File

@@ -31,7 +31,7 @@ export class AccessibleElement extends React.Component<AccessibleElementProps> {
...elementProps,
onKeyPress: this.onKeyPress,
onClick: this.props.onActivated,
tabIndex,
tabIndex
});
}
}

View File

@@ -38,7 +38,7 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
super(props);
this.isExpanded = props.isExpanded;
this.state = {
isExpanded: true,
isExpanded: true
};
}
@@ -46,7 +46,7 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
if (this.props.isExpanded !== this.isExpanded) {
this.isExpanded = this.props.isExpanded;
this.setState({
isExpanded: this.props.isExpanded,
isExpanded: this.props.isExpanded
});
}
}

View File

@@ -0,0 +1,159 @@
import React from "react";
import { shallow, mount } from "enzyme";
import { AccountSwitchComponent, AccountSwitchComponentProps } from "./AccountSwitchComponent";
import { AuthType } from "../../../AuthType";
import { DatabaseAccount, Subscription } from "../../../Contracts/DataModels";
import { AccountKind } from "../../../Common/Constants";
const createBlankProps = (): AccountSwitchComponentProps => {
return {
authType: null,
displayText: "",
accounts: [],
selectedAccountName: null,
isLoadingAccounts: false,
onAccountChange: jest.fn(),
subscriptions: [],
selectedSubscriptionId: null,
isLoadingSubscriptions: false,
onSubscriptionChange: jest.fn()
};
};
const createBlankAccount = (): DatabaseAccount => {
return {
id: "",
kind: AccountKind.Default,
name: "",
properties: null,
location: "",
tags: null,
type: ""
};
};
const createBlankSubscription = (): Subscription => {
return {
subscriptionId: "",
displayName: "",
authorizationSource: "",
state: "",
subscriptionPolicies: null,
tenantId: "",
uniqueDisplayName: ""
};
};
const createFullProps = (): AccountSwitchComponentProps => {
const props = createBlankProps();
props.authType = AuthType.AAD;
const account1 = createBlankAccount();
account1.name = "account1";
const account2 = createBlankAccount();
account2.name = "account2";
const account3 = createBlankAccount();
account3.name = "superlongaccountnamestringtest";
props.accounts = [account1, account2, account3];
props.selectedAccountName = "account2";
const sub1 = createBlankSubscription();
sub1.displayName = "sub1";
sub1.subscriptionId = "a6062a74-5d53-4b20-9545-000b95f22297";
const sub2 = createBlankSubscription();
sub2.displayName = "subsubsubsubsubsubsub2";
sub2.subscriptionId = "b20b3e93-0185-4326-8a9c-d44bac276b6b";
props.subscriptions = [sub1, sub2];
props.selectedSubscriptionId = "a6062a74-5d53-4b20-9545-000b95f22297";
return props;
};
describe("test render", () => {
it("renders no auth type -> handle error in code", () => {
const props = createBlankProps();
const wrapper = shallow(<AccountSwitchComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
// Encrypted Token
it("renders auth security token, with selected account name", () => {
const props = createBlankProps();
props.authType = AuthType.EncryptedToken;
props.selectedAccountName = "testaccount";
const wrapper = shallow(<AccountSwitchComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
// AAD
it("renders auth aad, with all information", () => {
const props = createFullProps();
const wrapper = shallow(<AccountSwitchComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders auth aad all dropdown menus", () => {
const props = createFullProps();
const wrapper = mount(<AccountSwitchComponent {...props} />);
expect(wrapper.exists("div.accountSwitchContextualMenu")).toBe(false);
wrapper.find("button.accountSwitchButton").simulate("click");
expect(wrapper.exists("div.accountSwitchContextualMenu")).toBe(true);
expect(wrapper.exists("div.accountSwitchSubscriptionDropdown")).toBe(true);
wrapper.find("DropdownBase.accountSwitchSubscriptionDropdown").simulate("click");
// Click will dismiss the first contextual menu in enzyme. Need to dig deeper to achieve below test
// expect(wrapper.exists("div.accountSwitchSubscriptionDropdownMenu")).toBe(true);
// expect(wrapper.find("button.ms-Dropdown-item").length).toBe(2);
// wrapper.find("div.accountSwitchSubscriptionDropdown").simulate("click");
// expect(wrapper.exists("div.accountSwitchSubscriptionDropdownMenu")).toBe(false);
// expect(wrapper.exists("div.accountSwitchAccountDropdown")).toBe(true);
// wrapper.find("div.accountSwitchAccountDropdown").simulate("click");
// expect(wrapper.exists("div.accountSwitchAccountDropdownMenu")).toBe(true);
// expect(wrapper.find("button.ms-Dropdown-item").length).toBe(3);
// wrapper.find("div.accountSwitchAccountDropdown").simulate("click");
// expect(wrapper.exists("div.accountSwitchAccountDropdownMenu")).toBe(false);
// wrapper.find("button.accountSwitchButton").simulate("click");
// expect(wrapper.exists("div.accountSwitchContextualMenu")).toBe(false);
wrapper.unmount();
});
});
// describe("test function", () => {
// it("switch subscription function", () => {
// const props = createFullProps();
// const wrapper = mount(<AccountSwitchComponent {...props} />);
// wrapper.find("button.accountSwitchButton").simulate("click");
// wrapper.find("div.accountSwitchSubscriptionDropdown").simulate("click");
// wrapper
// .find("button.ms-Dropdown-item")
// .at(1)
// .simulate("click");
// expect(props.onSubscriptionChange).toBeCalled();
// expect(props.onSubscriptionChange).toHaveBeenCalled();
// wrapper.unmount();
// });
// it("switch account", () => {
// const props = createFullProps();
// const wrapper = mount(<AccountSwitchComponent {...props} />);
// wrapper.find("button.accountSwitchButton").simulate("click");
// wrapper.find("div.accountSwitchAccountDropdown").simulate("click");
// wrapper
// .find("button.ms-Dropdown-item")
// .at(0)
// .simulate("click");
// expect(props.onAccountChange).toBeCalled();
// expect(props.onAccountChange).toHaveBeenCalled();
// wrapper.unmount();
// });
// });

View File

@@ -0,0 +1,177 @@
import { AuthType } from "../../../AuthType";
import { StyleConstants } from "../../../Common/Constants";
import { DatabaseAccount, Subscription } from "../../../Contracts/DataModels";
import * as React from "react";
import { DefaultButton, IButtonStyles, IButtonProps } from "office-ui-fabric-react/lib/Button";
import { IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
import { Dropdown, IDropdownOption, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown";
export interface AccountSwitchComponentProps {
authType: AuthType;
selectedAccountName: string;
accounts: DatabaseAccount[];
isLoadingAccounts: boolean;
onAccountChange: (newAccount: DatabaseAccount) => void;
selectedSubscriptionId: string;
subscriptions: Subscription[];
isLoadingSubscriptions: boolean;
onSubscriptionChange: (newSubscription: Subscription) => void;
displayText?: string;
}
export class AccountSwitchComponent extends React.Component<AccountSwitchComponentProps> {
public render(): JSX.Element {
return this.props.authType === AuthType.AAD ? this._renderSwitchDropDown() : this._renderAccountName();
}
private _renderSwitchDropDown(): JSX.Element {
const { displayText, selectedAccountName } = this.props;
const menuProps: IContextualMenuProps = {
directionalHintFixed: true,
className: "accountSwitchContextualMenu",
items: [
{
key: "switchSubscription",
onRender: this._renderSubscriptionDropdown.bind(this)
},
{
key: "switchAccount",
onRender: this._renderAccountDropDown.bind(this)
}
]
};
const buttonStyles: IButtonStyles = {
root: {
fontSize: StyleConstants.DefaultFontSize,
height: 40,
padding: 0,
paddingLeft: 10,
marginRight: 5,
backgroundColor: StyleConstants.BaseDark,
color: StyleConstants.BaseLight
},
rootHovered: {
backgroundColor: StyleConstants.BaseHigh,
color: StyleConstants.BaseLight
},
rootFocused: {
backgroundColor: StyleConstants.BaseHigh,
color: StyleConstants.BaseLight
},
rootPressed: {
backgroundColor: StyleConstants.BaseHigh,
color: StyleConstants.BaseLight
},
rootExpanded: {
backgroundColor: StyleConstants.BaseHigh,
color: StyleConstants.BaseLight
},
textContainer: {
flexGrow: "initial"
}
};
const buttonProps: IButtonProps = {
text: displayText || selectedAccountName,
menuProps: menuProps,
styles: buttonStyles,
className: "accountSwitchButton",
id: "accountSwitchButton"
};
return <DefaultButton {...buttonProps} />;
}
private _renderSubscriptionDropdown(): JSX.Element {
const { subscriptions, selectedSubscriptionId, isLoadingSubscriptions } = this.props;
const options: IDropdownOption[] = subscriptions.map(sub => {
return {
key: sub.subscriptionId,
text: sub.displayName,
data: sub
};
});
const placeHolderText = isLoadingSubscriptions
? "Loading subscriptions"
: !options || !options.length
? "No subscriptions found in current directory"
: "Select subscription from list";
const dropdownProps: IDropdownProps = {
label: "Subscription",
className: "accountSwitchSubscriptionDropdown",
options: options,
onChange: this._onSubscriptionDropdownChange,
defaultSelectedKey: selectedSubscriptionId,
placeholder: placeHolderText,
styles: {
callout: "accountSwitchSubscriptionDropdownMenu"
}
};
return <Dropdown {...dropdownProps} />;
}
private _onSubscriptionDropdownChange = (e: React.FormEvent<HTMLDivElement>, option: IDropdownOption): void => {
if (!option) {
return;
}
this.props.onSubscriptionChange(option.data);
};
private _renderAccountDropDown(): JSX.Element {
const { accounts, selectedAccountName, isLoadingAccounts } = this.props;
const options: IDropdownOption[] = accounts.map(account => {
return {
key: account.name,
text: account.name,
data: account
};
});
// Fabric UI will also try to select the first non-disabled option from dropdown.
// Add a option to prevent pop the message when user click on dropdown on first time.
options.unshift({
key: "select from list",
text: "Select Cosmos DB account from list",
data: undefined
});
const placeHolderText = isLoadingAccounts
? "Loading Cosmos DB accounts"
: !options || !options.length
? "No Cosmos DB accounts found"
: "Select Cosmos DB account from list";
const dropdownProps: IDropdownProps = {
label: "Cosmos DB Account Name",
className: "accountSwitchAccountDropdown",
options: options,
onChange: this._onAccountDropdownChange,
defaultSelectedKey: selectedAccountName,
placeholder: placeHolderText,
styles: {
callout: "accountSwitchAccountDropdownMenu"
}
};
return <Dropdown {...dropdownProps} />;
}
private _onAccountDropdownChange = (e: React.FormEvent<HTMLDivElement>, option: IDropdownOption): void => {
if (!option) {
return;
}
this.props.onAccountChange(option.data);
};
private _renderAccountName(): JSX.Element {
const { displayText, selectedAccountName } = this.props;
return <span className="accountNameHeader">{displayText || selectedAccountName}</span>;
}
}

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