mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-25 11:51:07 +00:00
Compare commits
2 Commits
exclude-ve
...
memory-swr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23599741d7 | ||
|
|
d494278488 |
@@ -4,4 +4,3 @@ PORTAL_RUNNER_PASSWORD=
|
||||
PORTAL_RUNNER_SUBSCRIPTION=
|
||||
PORTAL_RUNNER_RESOURCE_GROUP=
|
||||
PORTAL_RUNNER_DATABASE_ACCOUNT=
|
||||
PORTAL_RUNNER_CONNECTION_STRING=
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -3,8 +3,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- hotfix/**
|
||||
- release/**
|
||||
- hotfix/*
|
||||
- release/*
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
@@ -3,9 +3,7 @@ const isCI = require("is-ci");
|
||||
module.exports = {
|
||||
launch: {
|
||||
headless: isCI,
|
||||
slowMo: 50,
|
||||
defaultViewport: null,
|
||||
ignoreHTTPSErrors: true,
|
||||
args: ["--disable-web-security"]
|
||||
slowMo: isCI ? null : 20,
|
||||
defaultViewport: null
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
@SelectionColor: #3074B0;
|
||||
|
||||
@FocusColor: #605e5c;
|
||||
@FocusColor: #00bcf2;
|
||||
|
||||
/******************************************************************************
|
||||
METRICS
|
||||
|
||||
@@ -1522,10 +1522,6 @@ p {
|
||||
.tooltipVisible();
|
||||
}
|
||||
|
||||
.infoTooltip a {
|
||||
color: @AccentHigh;
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1650,7 +1646,7 @@ p {
|
||||
}
|
||||
|
||||
.contextual-pane .collid {
|
||||
border: 1px solid #605e5c;
|
||||
border: 1px solid #bbbbbb;
|
||||
font-size: 10px;
|
||||
padding: 5px 10px;
|
||||
color: #000;
|
||||
@@ -1743,7 +1739,7 @@ input::-webkit-calendar-picker-indicator {
|
||||
padding-right: 34px;
|
||||
color: @BaseDark;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
overflow-x: hidden;
|
||||
margin: (2 * @MediumSpace) 0px;
|
||||
}
|
||||
|
||||
@@ -2078,7 +2074,7 @@ a:link {
|
||||
.resourceTreeAndTabs {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -2427,6 +2423,22 @@ a:link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
color: #969696;
|
||||
}
|
||||
|
||||
::-moz-placeholder {
|
||||
color: #969696;
|
||||
}
|
||||
|
||||
:-ms-input-placeholder {
|
||||
color: #969696;
|
||||
}
|
||||
|
||||
:-moz-placeholder {
|
||||
color: #969696;
|
||||
}
|
||||
|
||||
::-ms-expand {
|
||||
color: #969696;
|
||||
}
|
||||
@@ -2976,10 +2988,6 @@ settings-pane {
|
||||
.enableAnalyticalStorageRadio:nth-child(n+2) {
|
||||
margin-left: @LargeSpace;
|
||||
}
|
||||
|
||||
.enableAnalyticalStorageRadioLabel {
|
||||
padding: 0px
|
||||
}
|
||||
}
|
||||
|
||||
.addCollectionLabel {
|
||||
@@ -3013,8 +3021,4 @@ settings-pane {
|
||||
|
||||
.warningErrorContent a {
|
||||
color: @AccentMediumHigh
|
||||
}
|
||||
|
||||
.infoBoxContent a {
|
||||
color: @AccentMediumHigh
|
||||
}
|
||||
}
|
||||
246
package-lock.json
generated
246
package-lock.json
generated
@@ -3490,9 +3490,9 @@
|
||||
}
|
||||
},
|
||||
"@fluentui/date-time-utilities": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-7.8.0.tgz",
|
||||
"integrity": "sha512-qzlTp3t+PghebJsLK9JwZr91qBRZ/fOml8TQCIjdtsEn4mH6/ciCwir7Fj8iOEkwwTC0iKsEr1jfsITtJKWSmA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-7.7.0.tgz",
|
||||
"integrity": "sha512-rgtGX5x1AeYUfilfkgP6ag+ZKx41BJcUs16k6iSxXxd/mt00DAPOGY8ODGikKFpjGKcUwjKfYBssyKkVHDucfA==",
|
||||
"requires": {
|
||||
"@uifabric/set-version": "^7.0.22",
|
||||
"tslib": "^1.10.0"
|
||||
@@ -3517,9 +3517,9 @@
|
||||
}
|
||||
},
|
||||
"@fluentui/react-focus": {
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-7.16.0.tgz",
|
||||
"integrity": "sha512-TwB4Av7ID70ejisDIGkCZGKOxlquSazr6W+9Jv1JQAvsBLuj5XOspFJH4/Igjniw1LeO9QmAvFZeh/XRShiObw==",
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-7.15.0.tgz",
|
||||
"integrity": "sha512-xbxB0cbyEoUfQZ19pAqBeWCYJ/4IOu1FG4bhVjDimqSD7qKwJbLlJSDNwmHr05SWprdhmqJe23KOwsHMgyvnrw==",
|
||||
"requires": {
|
||||
"@fluentui/keyboard-key": "^0.2.11",
|
||||
"@uifabric/merge-styles": "^7.18.0",
|
||||
@@ -3685,12 +3685,6 @@
|
||||
"integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==",
|
||||
"dev": true
|
||||
},
|
||||
"@hapi/formula": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-2.0.0.tgz",
|
||||
"integrity": "sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A==",
|
||||
"dev": true
|
||||
},
|
||||
"@hapi/hoek": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz",
|
||||
@@ -3709,12 +3703,6 @@
|
||||
"@hapi/topo": "3.x.x"
|
||||
}
|
||||
},
|
||||
"@hapi/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.0.tgz",
|
||||
"integrity": "sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw==",
|
||||
"dev": true
|
||||
},
|
||||
"@hapi/topo": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz",
|
||||
@@ -7628,16 +7616,6 @@
|
||||
"@types/enzyme": "*"
|
||||
}
|
||||
},
|
||||
"@types/expect-puppeteer": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/expect-puppeteer/-/expect-puppeteer-4.4.3.tgz",
|
||||
"integrity": "sha512-jWZOO9d8ST2vutV5yxZ1OYxxtYD0lOufIgOUlDjyTNBGo8um67shJs2NQDLVDG06wWrabpPPOUQlI8GSvsdKVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/jest": "*",
|
||||
"@types/puppeteer": "*"
|
||||
}
|
||||
},
|
||||
"@types/geojson": {
|
||||
"version": "7946.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||
@@ -7713,33 +7691,6 @@
|
||||
"integrity": "sha512-DC8xTuW/6TYgvEg3HEXS7cu9OijFqprVDXXiOcdOKZCU/5PJNLZU37VVvmZHdtMiGOa8wAA/We+JzbdxFzQTRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jest-environment-puppeteer": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest-environment-puppeteer/-/jest-environment-puppeteer-4.3.2.tgz",
|
||||
"integrity": "sha512-QVR49cGaQMOrWRN7CXlvtPMuVAxa3Z+W3APxhWoSQLG/lvz1y03ECPvS7Y9eK+hgfndK+39400rO6IifDJV9YA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jest/environment": "^24",
|
||||
"@jest/fake-timers": "^24",
|
||||
"@jest/types": "^24",
|
||||
"@types/puppeteer": "*",
|
||||
"jest-mock": "^24"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/environment": {
|
||||
"version": "24.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz",
|
||||
"integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jest/fake-timers": "^24.9.0",
|
||||
"@jest/transform": "^24.9.0",
|
||||
"@jest/types": "^24.9.0",
|
||||
"jest-mock": "^24.9.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
|
||||
@@ -7815,15 +7766,6 @@
|
||||
"integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/puppeteer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-3.0.1.tgz",
|
||||
"integrity": "sha512-t03eNKCvWJXhQ8wkc5C6GYuSqMEdKLOX0GLMGtks25YZr38wKZlKTwGM/BoAPVtdysX7Bb9tdwrDS1+NrW3RRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/pvutils": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pvutils/-/pvutils-0.0.1.tgz",
|
||||
@@ -8447,6 +8389,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@uifabric/react-hooks": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.11.0.tgz",
|
||||
"integrity": "sha512-iU7c+JR+rY5kBTPmrF8F6iJBQw309MX/MvOx6ElhmNceBaa8BqDuqR9+TVfkH+Bxp37bmZnCaQF5w4+QWHZ81g==",
|
||||
"requires": {
|
||||
"@uifabric/set-version": "^7.0.22",
|
||||
"@uifabric/utilities": "^7.31.0",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uifabric/merge-styles": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/merge-styles/-/merge-styles-7.18.0.tgz",
|
||||
"integrity": "sha512-805WIbN7lAJATXKxZjjRbIgN7raRMwWYWeDkJJ52PCPuCesOvbpdr0GkH8rC6GQ7EB0MB7YM2i6Fiye7SFewbw==",
|
||||
"requires": {
|
||||
"@uifabric/set-version": "^7.0.22",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@uifabric/set-version": {
|
||||
"version": "7.0.22",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/set-version/-/set-version-7.0.22.tgz",
|
||||
"integrity": "sha512-IG35UNJNxqI7NC2eYuobGTD+v4W0VHQcC3bYd5Na9EgoC9jVgguS8n6EXUtP/lC1vJEYEyPEZdVwhPxKw4F4Sw==",
|
||||
"requires": {
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@uifabric/utilities": {
|
||||
"version": "7.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/utilities/-/utilities-7.31.0.tgz",
|
||||
"integrity": "sha512-m4Yeyn4gyW7xS8LvOnCesokPModYS2YuE9GQmO++MDZ/vC5RRNlvlyktUZDuxCZ84cNCiXyTQ8nImBaPGnxHVQ==",
|
||||
"requires": {
|
||||
"@uifabric/merge-styles": "^7.18.0",
|
||||
"@uifabric/set-version": "^7.0.22",
|
||||
"prop-types": "^15.7.2",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@uifabric/set-version": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/set-version/-/set-version-7.0.15.tgz",
|
||||
@@ -8947,9 +8929,9 @@
|
||||
}
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
|
||||
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
|
||||
"integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-walk": {
|
||||
@@ -9334,13 +9316,6 @@
|
||||
"integrity": "sha512-yG89F0j9B4B0MKIcFyWWxnpZPLaNTjCj4tkE3fjbAoo0qmpGw0PYYqSbX/4ebnd9Icn8ZgK4K1fvDyEtW1JYtQ==",
|
||||
"requires": {
|
||||
"pvutils": "^1.0.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"pvutils": {
|
||||
"version": "1.0.17",
|
||||
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz",
|
||||
"integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"assert": {
|
||||
@@ -15066,6 +15041,12 @@
|
||||
"pinkie-promise": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"optional": true
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
||||
@@ -15114,6 +15095,7 @@
|
||||
"@types/graceful-fs": "^4.1.2",
|
||||
"anymatch": "^3.0.3",
|
||||
"fb-watchman": "^2.0.0",
|
||||
"fsevents": "^2.1.2",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"jest-serializer": "^25.5.0",
|
||||
"jest-util": "^25.5.0",
|
||||
@@ -17675,19 +17657,6 @@
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"wait-on": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.3.0.tgz",
|
||||
"integrity": "sha512-97dEuUapx4+Y12aknWZn7D25kkjMk16PbWoYzpSdA8bYpVfS6hpl2a2pOWZ3c+Tyt3/i4/pglyZctG3J4V1hWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/joi": "^15.0.3",
|
||||
"core-js": "^2.6.5",
|
||||
"minimist": "^1.2.0",
|
||||
"request": "^2.88.0",
|
||||
"rx": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -22316,16 +22285,6 @@
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@uifabric/react-hooks": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.12.0.tgz",
|
||||
"integrity": "sha512-vPrg7NVtjjZlDS33tDUiyJSov8PNHBBX8w+EN9eatxP0g6dDkvGv8uWd+9Xpxrliuzi7ad7vlmUMOQffYJntMg==",
|
||||
"requires": {
|
||||
"@uifabric/set-version": "^7.0.22",
|
||||
"@uifabric/utilities": "^7.31.0",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@uifabric/set-version": {
|
||||
"version": "7.0.22",
|
||||
"resolved": "https://registry.npmjs.org/@uifabric/set-version/-/set-version-7.0.22.tgz",
|
||||
@@ -23441,6 +23400,11 @@
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"pvutils": {
|
||||
"version": "1.0.17",
|
||||
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz",
|
||||
"integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ=="
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
@@ -23552,9 +23516,9 @@
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.9.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz",
|
||||
"integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==",
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -25791,6 +25755,23 @@
|
||||
"resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.2.3.tgz",
|
||||
"integrity": "sha512-xA0glXYpJ9SYT4JeMp3c0psbqdZsG1c0ywGvdJUPY2FKEgwJV7NgkeYuuQiOxMp+XsK9nCqjm3KDw0LkM1YLXw=="
|
||||
},
|
||||
"swr": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-0.3.2.tgz",
|
||||
"integrity": "sha512-Bs5Bihq1hQ66O5bdKaL47iZ2nlAaBsd8tTLRLkw9stZeuBEfH7zSuQI95S2TpchL0ybsMq3isWwuso2uPvCfHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
@@ -26937,65 +26918,16 @@
|
||||
}
|
||||
},
|
||||
"wait-on": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-4.0.2.tgz",
|
||||
"integrity": "sha512-Qpmgm3Hw/sXm7xK68FBsYy5r+Uid94/QymwnEjn9GTpfiWTUVYm0bccivVwY/BXGYO2r+5Cd8S/DzrRZqHK/9w==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.3.0.tgz",
|
||||
"integrity": "sha512-97dEuUapx4+Y12aknWZn7D25kkjMk16PbWoYzpSdA8bYpVfS6hpl2a2pOWZ3c+Tyt3/i4/pglyZctG3J4V1hWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/joi": "^17.1.1",
|
||||
"lodash": "^4.17.15",
|
||||
"minimist": "^1.2.5",
|
||||
"request": "^2.88.2",
|
||||
"request-promise-native": "^1.0.8",
|
||||
"rxjs": "^6.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hapi/address": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.1.0.tgz",
|
||||
"integrity": "sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"@hapi/hoek": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz",
|
||||
"integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw==",
|
||||
"dev": true
|
||||
},
|
||||
"@hapi/joi": {
|
||||
"version": "17.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-17.1.1.tgz",
|
||||
"integrity": "sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/address": "^4.0.1",
|
||||
"@hapi/formula": "^2.0.0",
|
||||
"@hapi/hoek": "^9.0.0",
|
||||
"@hapi/pinpoint": "^2.0.0",
|
||||
"@hapi/topo": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"@hapi/topo": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz",
|
||||
"integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
|
||||
"integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
}
|
||||
"@hapi/joi": "^15.0.3",
|
||||
"core-js": "^2.6.5",
|
||||
"minimist": "^1.2.0",
|
||||
"request": "^2.88.0",
|
||||
"rx": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"wait-port": {
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"promise-polyfill": "8.1.0",
|
||||
"promise.prototype.finally": "3.1.0",
|
||||
"q": "1.5.1",
|
||||
"react": "16.9.0",
|
||||
"react": "16.13.1",
|
||||
"react-animate-height": "2.0.8",
|
||||
"react-dnd": "9.4.0",
|
||||
"react-dnd-html5-backend": "9.4.0",
|
||||
@@ -102,15 +102,12 @@
|
||||
"@types/d3": "4.13.2",
|
||||
"@types/enzyme": "3.10.3",
|
||||
"@types/enzyme-adapter-react-16": "1.0.5",
|
||||
"@types/expect-puppeteer": "4.4.3",
|
||||
"@types/hasher": "0.0.31",
|
||||
"@types/jest": "23.3.10",
|
||||
"@types/jest-environment-puppeteer": "4.3.2",
|
||||
"@types/memoize-one": "4.1.1",
|
||||
"@types/node": "12.11.1",
|
||||
"@types/promise.prototype.finally": "2.0.3",
|
||||
"@types/prop-types": "15.5.8",
|
||||
"@types/puppeteer": "3.0.1",
|
||||
"@types/q": "1.5.1",
|
||||
"@types/react": "16.8.25",
|
||||
"@types/react-dom": "16.0.7",
|
||||
@@ -163,13 +160,13 @@
|
||||
"rimraf": "3.0.0",
|
||||
"sinon": "3.2.1",
|
||||
"style-loader": "0.23.0",
|
||||
"swr": "0.3.2",
|
||||
"terser-webpack-plugin": "3.0.5",
|
||||
"ts-loader": "6.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"tslint-microsoft-contrib": "6.0.0",
|
||||
"typescript": "4.0.2",
|
||||
"url-loader": "1.1.1",
|
||||
"wait-on": "4.0.2",
|
||||
"webpack": "4.43.0",
|
||||
"webpack-bundle-analyzer": "3.6.1",
|
||||
"webpack-cli": "3.3.10",
|
||||
@@ -188,7 +185,6 @@
|
||||
"test": "rimraf coverage && jest",
|
||||
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles",
|
||||
"watch": "npm run start",
|
||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||
"build:ase": "gulp build:ase",
|
||||
"compile": "tsc",
|
||||
"compile:contracts": "tsc -p ./tsconfig.contracts.json",
|
||||
|
||||
@@ -170,8 +170,89 @@ export enum MongoBackendEndpointType {
|
||||
remote
|
||||
}
|
||||
|
||||
export class MongoBackend {
|
||||
public static localhostEndpoint: string = "/api/mongo/explorer";
|
||||
public static centralUsEndpoint: string = "https://main.documentdb.ext.azure.com/api/mongo/explorer";
|
||||
public static northEuropeEndpoint: string = "https://main.documentdb.ext.azure.com/api/mongo/explorer";
|
||||
public static southEastAsiaEndpoint: string = "https://main.documentdb.ext.azure.com/api/mongo/explorer";
|
||||
|
||||
public static endpointsByRegion: any = {
|
||||
default: MongoBackend.centralUsEndpoint,
|
||||
northeurope: MongoBackend.northEuropeEndpoint,
|
||||
ukwest: MongoBackend.northEuropeEndpoint,
|
||||
uksouth: MongoBackend.northEuropeEndpoint,
|
||||
westeurope: MongoBackend.northEuropeEndpoint,
|
||||
australiaeast: MongoBackend.southEastAsiaEndpoint,
|
||||
australiasoutheast: MongoBackend.southEastAsiaEndpoint,
|
||||
centralindia: MongoBackend.southEastAsiaEndpoint,
|
||||
eastasia: MongoBackend.southEastAsiaEndpoint,
|
||||
japaneast: MongoBackend.southEastAsiaEndpoint,
|
||||
japanwest: MongoBackend.southEastAsiaEndpoint,
|
||||
koreacentral: MongoBackend.southEastAsiaEndpoint,
|
||||
koreasouth: MongoBackend.southEastAsiaEndpoint,
|
||||
southeastasia: MongoBackend.southEastAsiaEndpoint,
|
||||
southindia: MongoBackend.southEastAsiaEndpoint,
|
||||
westindia: MongoBackend.southEastAsiaEndpoint
|
||||
};
|
||||
|
||||
public static endpointsByEnvironment: any = {
|
||||
default: MongoBackendEndpointType.local,
|
||||
localhost: MongoBackendEndpointType.local,
|
||||
prod1: MongoBackendEndpointType.remote,
|
||||
prod2: MongoBackendEndpointType.remote
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: 435619 Add default endpoints per cloud and use regional only when available
|
||||
export class CassandraBackend {
|
||||
public static readonly localhostEndpoint: string = "https://localhost:12901/";
|
||||
public static readonly devEndpoint: string = "https://platformproxycassandradev.azurewebsites.net/";
|
||||
|
||||
public static readonly centralUsEndpoint: string = "https://main.documentdb.ext.azure.com/";
|
||||
public static readonly northEuropeEndpoint: string = "https://main.documentdb.ext.azure.com/";
|
||||
public static readonly southEastAsiaEndpoint: string = "https://main.documentdb.ext.azure.com/";
|
||||
|
||||
public static readonly bf_default: string = "https://main.documentdb.ext.microsoftazure.de/";
|
||||
public static readonly mc_default: string = "https://main.documentdb.ext.azure.cn/";
|
||||
public static readonly ff_default: string = "https://main.documentdb.ext.azure.us/";
|
||||
|
||||
public static readonly endpointsByRegion: any = {
|
||||
default: CassandraBackend.centralUsEndpoint,
|
||||
northeurope: CassandraBackend.northEuropeEndpoint,
|
||||
ukwest: CassandraBackend.northEuropeEndpoint,
|
||||
uksouth: CassandraBackend.northEuropeEndpoint,
|
||||
westeurope: CassandraBackend.northEuropeEndpoint,
|
||||
australiaeast: CassandraBackend.southEastAsiaEndpoint,
|
||||
australiasoutheast: CassandraBackend.southEastAsiaEndpoint,
|
||||
centralindia: CassandraBackend.southEastAsiaEndpoint,
|
||||
eastasia: CassandraBackend.southEastAsiaEndpoint,
|
||||
japaneast: CassandraBackend.southEastAsiaEndpoint,
|
||||
japanwest: CassandraBackend.southEastAsiaEndpoint,
|
||||
koreacentral: CassandraBackend.southEastAsiaEndpoint,
|
||||
koreasouth: CassandraBackend.southEastAsiaEndpoint,
|
||||
southeastasia: CassandraBackend.southEastAsiaEndpoint,
|
||||
southindia: CassandraBackend.southEastAsiaEndpoint,
|
||||
westindia: CassandraBackend.southEastAsiaEndpoint,
|
||||
|
||||
// Black Forest
|
||||
germanycentral: CassandraBackend.bf_default,
|
||||
germanynortheast: CassandraBackend.bf_default,
|
||||
|
||||
// Fairfax
|
||||
usdodeast: CassandraBackend.ff_default,
|
||||
usdodcentral: CassandraBackend.ff_default,
|
||||
usgovarizona: CassandraBackend.ff_default,
|
||||
usgoviowa: CassandraBackend.ff_default,
|
||||
usgovtexas: CassandraBackend.ff_default,
|
||||
usgovvirginia: CassandraBackend.ff_default,
|
||||
|
||||
// Mooncake
|
||||
chinaeast: CassandraBackend.mc_default,
|
||||
chinaeast2: CassandraBackend.mc_default,
|
||||
chinanorth: CassandraBackend.mc_default,
|
||||
chinanorth2: CassandraBackend.mc_default
|
||||
};
|
||||
|
||||
public static readonly createOrDeleteApi: string = "api/cassandra/createordelete";
|
||||
public static readonly guestCreateOrDeleteApi: string = "api/guest/cassandra/createordelete";
|
||||
public static readonly queryApi: string = "api/cassandra";
|
||||
@@ -481,11 +562,3 @@ export class AnalyticalStorageTtl {
|
||||
public static readonly Infinite: number = -1;
|
||||
public static readonly Disabled: number = 0;
|
||||
}
|
||||
|
||||
export class TerminalQueryParams {
|
||||
public static readonly Terminal = "terminal";
|
||||
public static readonly Server = "server";
|
||||
public static readonly Token = "token";
|
||||
public static readonly SubscriptionId = "subscriptionId";
|
||||
public static readonly TerminalEndpoint = "terminalEndpoint";
|
||||
}
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as _ from "underscore";
|
||||
import * as Constants from "./Constants";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as HeadersUtility from "./HeadersUtility";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import Q from "q";
|
||||
import {
|
||||
ConflictDefinition,
|
||||
FeedOptions,
|
||||
ItemDefinition,
|
||||
OfferDefinition,
|
||||
QueryIterator,
|
||||
Resource
|
||||
Resource,
|
||||
TriggerDefinition,
|
||||
OfferDefinition
|
||||
} from "@azure/cosmos";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Q from "q";
|
||||
import { configContext, Platform } from "../ConfigContext";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import ConflictId from "../Explorer/Tree/ConflictId";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import { LocalStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
||||
import { OfferUtils } from "../Utils/OfferUtils";
|
||||
import * as Constants from "./Constants";
|
||||
import { client } from "./CosmosClient";
|
||||
import * as HeadersUtility from "./HeadersUtility";
|
||||
import { LocalStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
||||
import { sendCachedDataMessage } from "./MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { OfferUtils } from "../Utils/OfferUtils";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import { Platform, configContext } from "../ConfigContext";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import ConflictId from "../Explorer/Tree/ConflictId";
|
||||
|
||||
export function getCommonQueryOptions(options: FeedOptions): any {
|
||||
const storedItemPerPageSetting: number = LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage);
|
||||
@@ -53,55 +55,85 @@ export function queryDocuments(
|
||||
return Q(documentsIterator);
|
||||
}
|
||||
|
||||
export function getPartitionKeyHeaderForConflict(conflictId: ConflictId): Object {
|
||||
const partitionKeyDefinition: DataModels.PartitionKey = conflictId.partitionKey;
|
||||
const partitionKeyValue: any = conflictId.partitionKeyValue;
|
||||
|
||||
return getPartitionKeyHeader(partitionKeyDefinition, partitionKeyValue);
|
||||
}
|
||||
|
||||
export function getPartitionKeyHeader(partitionKeyDefinition: DataModels.PartitionKey, partitionKeyValue: any): Object {
|
||||
if (!partitionKeyDefinition) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (partitionKeyValue === undefined) {
|
||||
return [{}];
|
||||
}
|
||||
|
||||
return [partitionKeyValue];
|
||||
}
|
||||
|
||||
export function updateOffer(
|
||||
offer: DataModels.Offer,
|
||||
newOffer: DataModels.Offer,
|
||||
options?: RequestOptions
|
||||
): Q.Promise<DataModels.Offer> {
|
||||
return Q(
|
||||
client()
|
||||
.offer(offer.id)
|
||||
// TODO Remove casting when SDK types are fixed (https://github.com/Azure/azure-sdk-for-js/issues/10660)
|
||||
.replace((newOffer as unknown) as OfferDefinition, options)
|
||||
.then(response => {
|
||||
return Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => response.resource);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function updateDocument(
|
||||
collection: ViewModels.CollectionBase,
|
||||
documentId: DocumentId,
|
||||
newDocument: any
|
||||
): Q.Promise<any> {
|
||||
const partitionKey = documentId.partitionKeyValue;
|
||||
|
||||
export function readStoredProcedures(
|
||||
collection: ViewModels.Collection,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure[]> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.item(documentId.id(), partitionKey)
|
||||
.replace(newDocument)
|
||||
.then(response => response.resource)
|
||||
.scripts.storedProcedures.readAll(options)
|
||||
.fetchAll()
|
||||
.then(response => response.resources as DataModels.StoredProcedure[])
|
||||
);
|
||||
}
|
||||
|
||||
export function readStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.storedProcedure(requestedResource.id)
|
||||
.read(options)
|
||||
.then(response => response.resource as DataModels.StoredProcedure)
|
||||
);
|
||||
}
|
||||
export function readUserDefinedFunctions(
|
||||
collection: ViewModels.Collection,
|
||||
options: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction[]> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.userDefinedFunctions.readAll(options)
|
||||
.fetchAll()
|
||||
.then(response => response.resources as DataModels.UserDefinedFunction[])
|
||||
);
|
||||
}
|
||||
export function readUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.userDefinedFunction(requestedResource.id)
|
||||
.read(options)
|
||||
.then(response => response.resource as DataModels.UserDefinedFunction)
|
||||
);
|
||||
}
|
||||
|
||||
export function readTriggers(collection: ViewModels.Collection, options: any): Q.Promise<DataModels.Trigger[]> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.triggers.readAll(options)
|
||||
.fetchAll()
|
||||
.then(response => response.resources as DataModels.Trigger[])
|
||||
);
|
||||
}
|
||||
|
||||
export function readTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.trigger(requestedResource.id)
|
||||
.read(options)
|
||||
.then(response => response.resource as DataModels.Trigger)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,16 +165,6 @@ export function executeStoredProcedure(
|
||||
);
|
||||
}
|
||||
|
||||
export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Q.Promise<any> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.items.create(newDocument)
|
||||
.then(response => response.resource)
|
||||
);
|
||||
}
|
||||
|
||||
export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
|
||||
const partitionKey = documentId.partitionKeyValue;
|
||||
|
||||
@@ -156,6 +178,155 @@ export function readDocument(collection: ViewModels.CollectionBase, documentId:
|
||||
);
|
||||
}
|
||||
|
||||
export function getPartitionKeyHeaderForConflict(conflictId: ConflictId): Object {
|
||||
const partitionKeyDefinition: DataModels.PartitionKey = conflictId.partitionKey;
|
||||
const partitionKeyValue: any = conflictId.partitionKeyValue;
|
||||
|
||||
return getPartitionKeyHeader(partitionKeyDefinition, partitionKeyValue);
|
||||
}
|
||||
|
||||
export function getPartitionKeyHeader(partitionKeyDefinition: DataModels.PartitionKey, partitionKeyValue: any): Object {
|
||||
if (!partitionKeyDefinition) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (partitionKeyValue === undefined) {
|
||||
return [{}];
|
||||
}
|
||||
|
||||
return [partitionKeyValue];
|
||||
}
|
||||
|
||||
export function updateDocument(
|
||||
collection: ViewModels.CollectionBase,
|
||||
documentId: DocumentId,
|
||||
newDocument: any
|
||||
): Q.Promise<any> {
|
||||
const partitionKey = documentId.partitionKeyValue;
|
||||
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.item(documentId.id(), partitionKey)
|
||||
.replace(newDocument)
|
||||
.then(response => response.resource)
|
||||
);
|
||||
}
|
||||
|
||||
export function updateOffer(
|
||||
offer: DataModels.Offer,
|
||||
newOffer: DataModels.Offer,
|
||||
options?: RequestOptions
|
||||
): Q.Promise<DataModels.Offer> {
|
||||
return Q(
|
||||
client()
|
||||
.offer(offer.id)
|
||||
// TODO Remove casting when SDK types are fixed (https://github.com/Azure/azure-sdk-for-js/issues/10660)
|
||||
.replace((newOffer as unknown) as OfferDefinition, options)
|
||||
.then(response => {
|
||||
return Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => response.resource);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function updateStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: DataModels.StoredProcedure,
|
||||
options: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.storedProcedure(storedProcedure.id)
|
||||
.replace(storedProcedure, options)
|
||||
.then(response => response.resource as DataModels.StoredProcedure)
|
||||
);
|
||||
}
|
||||
|
||||
export function updateUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
userDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.userDefinedFunction(userDefinedFunction.id)
|
||||
.replace(userDefinedFunction, options)
|
||||
.then(response => response.resource as DataModels.StoredProcedure)
|
||||
);
|
||||
}
|
||||
|
||||
export function updateTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
trigger: DataModels.Trigger,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.trigger(trigger.id)
|
||||
.replace(trigger as TriggerDefinition, options)
|
||||
.then(response => response.resource as DataModels.Trigger)
|
||||
);
|
||||
}
|
||||
|
||||
export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Q.Promise<any> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.items.create(newDocument)
|
||||
.then(response => response.resource as DataModels.StoredProcedure)
|
||||
);
|
||||
}
|
||||
|
||||
export function createStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
newStoredProcedure: DataModels.StoredProcedure,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.storedProcedures.create(newStoredProcedure, options)
|
||||
.then(response => response.resource as DataModels.StoredProcedure)
|
||||
);
|
||||
}
|
||||
|
||||
export function createUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
newUserDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.userDefinedFunctions.create(newUserDefinedFunction, options)
|
||||
.then(response => response.resource as DataModels.UserDefinedFunction)
|
||||
);
|
||||
}
|
||||
|
||||
export function createTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
newTrigger: DataModels.Trigger,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.triggers.create(newTrigger as TriggerDefinition, options)
|
||||
.then(response => response.resource as DataModels.Trigger)
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
|
||||
const partitionKey = documentId.partitionKeyValue;
|
||||
|
||||
@@ -184,6 +355,48 @@ export function deleteConflict(
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: DataModels.StoredProcedure,
|
||||
options: any
|
||||
): Q.Promise<any> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.storedProcedure(storedProcedure.id)
|
||||
.delete()
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
userDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options: any
|
||||
): Q.Promise<any> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.userDefinedFunction(userDefinedFunction.id)
|
||||
.delete()
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
trigger: DataModels.Trigger,
|
||||
options: any
|
||||
): Q.Promise<any> {
|
||||
return Q(
|
||||
client()
|
||||
.database(collection.databaseId)
|
||||
.container(collection.id())
|
||||
.scripts.trigger(trigger.id)
|
||||
.delete()
|
||||
);
|
||||
}
|
||||
|
||||
export function readCollectionQuotaInfo(
|
||||
collection: ViewModels.Collection,
|
||||
options: any
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { ConflictDefinition, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Q from "q";
|
||||
import * as Constants from "./Constants";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import Q from "q";
|
||||
import { ConflictDefinition, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as DataAccessUtilityBase from "./DataAccessUtilityBase";
|
||||
import * as Logger from "./Logger";
|
||||
import { MinimalQueryIterator, nextPage } from "./IteratorUtilities";
|
||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import ConflictId from "../Explorer/Tree/ConflictId";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
|
||||
import * as Constants from "./Constants";
|
||||
import { sendNotificationForError } from "./dataAccess/sendNotificationForError";
|
||||
import * as DataAccessUtilityBase from "./DataAccessUtilityBase";
|
||||
import { MinimalQueryIterator, nextPage } from "./IteratorUtilities";
|
||||
import * as Logger from "./Logger";
|
||||
|
||||
// TODO: Log all promise resolutions and errors with verbosity levels
|
||||
export function queryDocuments(
|
||||
@@ -41,6 +42,121 @@ export function getEntityName() {
|
||||
return "item";
|
||||
}
|
||||
|
||||
export function readStoredProcedures(
|
||||
collection: ViewModels.Collection,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.StoredProcedure[]> {
|
||||
var deferred = Q.defer<DataModels.StoredProcedure[]>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Querying stored procedures for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.readStoredProcedures(collection, options)
|
||||
.then(
|
||||
(storedProcedures: DataModels.StoredProcedure[]) => {
|
||||
deferred.resolve(storedProcedures);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to query stored procedures for container ${collection.id()}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadStoredProcedures", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function readStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
return DataAccessUtilityBase.readStoredProcedure(collection, requestedResource, options);
|
||||
}
|
||||
|
||||
export function readUserDefinedFunctions(
|
||||
collection: ViewModels.Collection,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.UserDefinedFunction[]> {
|
||||
var deferred = Q.defer<DataModels.UserDefinedFunction[]>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Querying user defined functions for collection ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.readUserDefinedFunctions(collection, options)
|
||||
.then(
|
||||
(userDefinedFunctions: DataModels.UserDefinedFunction[]) => {
|
||||
deferred.resolve(userDefinedFunctions);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to query user defined functions for container ${collection.id()}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadUDFs", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function readUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
return DataAccessUtilityBase.readUserDefinedFunction(collection, requestedResource, options);
|
||||
}
|
||||
|
||||
export function readTriggers(collection: ViewModels.Collection, options: any): Q.Promise<DataModels.Trigger[]> {
|
||||
var deferred = Q.defer<DataModels.Trigger[]>();
|
||||
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Querying triggers for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.readTriggers(collection, options)
|
||||
.then(
|
||||
(triggers: DataModels.Trigger[]) => {
|
||||
deferred.resolve(triggers);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to query triggers for container ${collection.id()}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadTriggers", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function readTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
requestedResource: DataModels.Resource,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
return DataAccessUtilityBase.readTrigger(collection, requestedResource, options);
|
||||
}
|
||||
|
||||
export function executeStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: StoredProcedure,
|
||||
@@ -49,17 +165,22 @@ export function executeStoredProcedure(
|
||||
): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
|
||||
const clearMessage = logConsoleProgress(`Executing stored procedure ${storedProcedure.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Executing stored procedure ${storedProcedure.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.executeStoredProcedure(collection, storedProcedure, partitionKeyValue, params)
|
||||
.then(
|
||||
(response: any) => {
|
||||
deferred.resolve(response);
|
||||
logConsoleInfo(
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Finished executing stored procedure ${storedProcedure.id()} for container ${storedProcedure.collection.id()}`
|
||||
);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to execute stored procedure ${storedProcedure.id()} for container ${storedProcedure.collection.id()}: ${JSON.stringify(
|
||||
error
|
||||
)}`
|
||||
@@ -70,7 +191,7 @@ export function executeStoredProcedure(
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -84,23 +205,32 @@ export function queryDocumentsPage(
|
||||
): Q.Promise<ViewModels.QueryResults> {
|
||||
var deferred = Q.defer<ViewModels.QueryResults>();
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Querying ${entityName} for container ${resourceName}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Querying ${entityName} for container ${resourceName}`
|
||||
);
|
||||
Q(nextPage(documentsIterator, firstItemIndex))
|
||||
.then(
|
||||
(result: ViewModels.QueryResults) => {
|
||||
const itemCount = (result.documents && result.documents.length) || 0;
|
||||
logConsoleInfo(`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`
|
||||
);
|
||||
deferred.resolve(result);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Failed to query ${entityName} for container ${resourceName}: ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to query ${entityName} for container ${resourceName}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "QueryDocumentsPage", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -109,21 +239,27 @@ export function queryDocumentsPage(
|
||||
export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Reading ${entityName} ${documentId.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Reading ${entityName} ${documentId.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.readDocument(collection, documentId)
|
||||
.then(
|
||||
(document: any) => {
|
||||
deferred.resolve(document);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Failed to read ${entityName} ${documentId.id()}: ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to read ${entityName} ${documentId.id()}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadDocument", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -136,22 +272,31 @@ export function updateDocument(
|
||||
): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Updating ${entityName} ${documentId.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Updating ${entityName} ${documentId.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.updateDocument(collection, documentId, newDocument)
|
||||
.then(
|
||||
(updatedDocument: any) => {
|
||||
logConsoleInfo(`Successfully updated ${entityName} ${documentId.id()}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully updated ${entityName} ${documentId.id()}`
|
||||
);
|
||||
deferred.resolve(updatedDocument);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Failed to update ${entityName} ${documentId.id()}: ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to update ${entityName} ${documentId.id()}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "UpdateDocument", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -163,15 +308,24 @@ export function updateOffer(
|
||||
options: RequestOptions
|
||||
): Q.Promise<DataModels.Offer> {
|
||||
var deferred = Q.defer<any>();
|
||||
const clearMessage = logConsoleProgress(`Updating offer for resource ${offer.resource}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Updating offer for resource ${offer.resource}`
|
||||
);
|
||||
DataAccessUtilityBase.updateOffer(offer, newOffer, options)
|
||||
.then(
|
||||
(replacedOffer: DataModels.Offer) => {
|
||||
logConsoleInfo(`Successfully updated offer for resource ${offer.resource}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully updated offer for resource ${offer.resource}`
|
||||
);
|
||||
deferred.resolve(replacedOffer);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error updating offer for resource ${offer.resource}: ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error updating offer for resource ${offer.resource}: ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(
|
||||
JSON.stringify({
|
||||
oldOffer: offer,
|
||||
@@ -186,7 +340,108 @@ export function updateOffer(
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function updateStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: DataModels.StoredProcedure,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Updating stored procedure ${storedProcedure.id}`
|
||||
);
|
||||
DataAccessUtilityBase.updateStoredProcedure(collection, storedProcedure, options)
|
||||
.then(
|
||||
(updatedStoredProcedure: DataModels.StoredProcedure) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully updated stored procedure ${storedProcedure.id}`
|
||||
);
|
||||
deferred.resolve(updatedStoredProcedure);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while updating stored procedure ${storedProcedure.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "UpdateStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function updateUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
userDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Updating user defined function ${userDefinedFunction.id}`
|
||||
);
|
||||
DataAccessUtilityBase.updateUserDefinedFunction(collection, userDefinedFunction, options)
|
||||
.then(
|
||||
(updatedUserDefinedFunction: DataModels.UserDefinedFunction) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully updated user defined function ${userDefinedFunction.id}`
|
||||
);
|
||||
deferred.resolve(updatedUserDefinedFunction);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while updating user defined function ${userDefinedFunction.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "UpdateUDF", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function updateTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
trigger: DataModels.Trigger
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, `Updating trigger ${trigger.id}`);
|
||||
DataAccessUtilityBase.updateTrigger(collection, trigger)
|
||||
.then(
|
||||
(updatedTrigger: DataModels.Trigger) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, `Updated trigger ${trigger.id}`);
|
||||
deferred.resolve(updatedTrigger);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while updating trigger ${trigger.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "UpdateTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -195,15 +450,22 @@ export function updateOffer(
|
||||
export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Creating new ${entityName} for container ${collection.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Creating new ${entityName} for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.createDocument(collection, newDocument)
|
||||
.then(
|
||||
(savedDocument: any) => {
|
||||
logConsoleInfo(`Successfully created new ${entityName} for container ${collection.id()}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully created new ${entityName} for container ${collection.id()}`
|
||||
);
|
||||
deferred.resolve(savedDocument);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while creating new ${entityName} for container ${collection.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "CreateDocument", error.code);
|
||||
@@ -212,7 +474,115 @@ export function createDocument(collection: ViewModels.CollectionBase, newDocumen
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function createStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
newStoredProcedure: DataModels.StoredProcedure,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Creating stored procedure for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.createStoredProcedure(collection, newStoredProcedure, options)
|
||||
.then(
|
||||
(createdStoredProcedure: DataModels.StoredProcedure) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully created stored procedure for container ${collection.id()}`
|
||||
);
|
||||
deferred.resolve(createdStoredProcedure);
|
||||
},
|
||||
error => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while creating stored procedure for container ${collection.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "CreateStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function createUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
newUserDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options?: any
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Creating user defined function for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.createUserDefinedFunction(collection, newUserDefinedFunction, options)
|
||||
.then(
|
||||
(createdUserDefinedFunction: DataModels.UserDefinedFunction) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully created user defined function for container ${collection.id()}`
|
||||
);
|
||||
deferred.resolve(createdUserDefinedFunction);
|
||||
},
|
||||
error => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while creating user defined function for container ${collection.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "CreateUDF", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function createTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
newTrigger: DataModels.Trigger,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Creating trigger for container ${collection.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.createTrigger(collection, newTrigger, options)
|
||||
.then(
|
||||
(createdTrigger: DataModels.Trigger) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully created trigger for container ${collection.id()}`
|
||||
);
|
||||
deferred.resolve(createdTrigger);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while creating trigger for container ${collection.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "CreateTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -221,22 +591,31 @@ export function createDocument(collection: ViewModels.CollectionBase, newDocumen
|
||||
export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Deleting ${entityName} ${documentId.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Deleting ${entityName} ${documentId.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.deleteDocument(collection, documentId)
|
||||
.then(
|
||||
(response: any) => {
|
||||
logConsoleInfo(`Successfully deleted ${entityName} ${documentId.id()}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully deleted ${entityName} ${documentId.id()}`
|
||||
);
|
||||
deferred.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error while deleting ${entityName} ${documentId.id()}:\n ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while deleting ${entityName} ${documentId.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "DeleteDocument", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -249,22 +628,134 @@ export function deleteConflict(
|
||||
): Q.Promise<any> {
|
||||
var deferred = Q.defer<any>();
|
||||
|
||||
const clearMessage = logConsoleProgress(`Deleting conflict ${conflictId.id()}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Deleting conflict ${conflictId.id()}`
|
||||
);
|
||||
DataAccessUtilityBase.deleteConflict(collection, conflictId, options)
|
||||
.then(
|
||||
(response: any) => {
|
||||
logConsoleInfo(`Successfully deleted conflict ${conflictId.id()}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully deleted conflict ${conflictId.id()}`
|
||||
);
|
||||
deferred.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error while deleting conflict ${conflictId.id()}:\n ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while deleting conflict ${conflictId.id()}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "DeleteConflict", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function deleteStoredProcedure(
|
||||
collection: ViewModels.Collection,
|
||||
storedProcedure: DataModels.StoredProcedure,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.StoredProcedure> {
|
||||
var deferred = Q.defer<any>();
|
||||
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Deleting stored procedure ${storedProcedure.id}`
|
||||
);
|
||||
DataAccessUtilityBase.deleteStoredProcedure(collection, storedProcedure, options)
|
||||
.then(
|
||||
(response: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully deleted stored procedure ${storedProcedure.id}`
|
||||
);
|
||||
deferred.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while deleting stored procedure ${storedProcedure.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "DeleteStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function deleteUserDefinedFunction(
|
||||
collection: ViewModels.Collection,
|
||||
userDefinedFunction: DataModels.UserDefinedFunction,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.UserDefinedFunction> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Deleting user defined function ${userDefinedFunction.id}`
|
||||
);
|
||||
DataAccessUtilityBase.deleteUserDefinedFunction(collection, userDefinedFunction, options)
|
||||
.then(
|
||||
(response: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`Successfully deleted user defined function ${userDefinedFunction.id}`
|
||||
);
|
||||
deferred.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while deleting user defined function ${userDefinedFunction.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "DeleteUDF", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
export function deleteTrigger(
|
||||
collection: ViewModels.Collection,
|
||||
trigger: DataModels.Trigger,
|
||||
options: any = {}
|
||||
): Q.Promise<DataModels.Trigger> {
|
||||
var deferred = Q.defer<any>();
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, `Deleting trigger ${trigger.id}`);
|
||||
DataAccessUtilityBase.deleteTrigger(collection, trigger, options)
|
||||
.then(
|
||||
(response: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, `Successfully deleted trigger ${trigger.id}`);
|
||||
deferred.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while deleting trigger ${trigger.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "DeleteTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -284,21 +775,27 @@ export function readCollectionQuotaInfo(
|
||||
): Q.Promise<DataModels.CollectionQuotaInfo> {
|
||||
var deferred = Q.defer<DataModels.CollectionQuotaInfo>();
|
||||
|
||||
const clearMessage = logConsoleProgress(`Querying quota info for container ${collection.id}`);
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Querying quota info for container ${collection.id}`
|
||||
);
|
||||
DataAccessUtilityBase.readCollectionQuotaInfo(collection, options)
|
||||
.then(
|
||||
(quota: DataModels.CollectionQuotaInfo) => {
|
||||
deferred.resolve(quota);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error while querying quota info for container ${collection.id}:\n ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while querying quota info for container ${collection.id}:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadCollectionQuotaInfo", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -307,21 +804,24 @@ export function readCollectionQuotaInfo(
|
||||
export function readOffers(options: any = {}): Q.Promise<DataModels.Offer[]> {
|
||||
var deferred = Q.defer<DataModels.Offer[]>();
|
||||
|
||||
const clearMessage = logConsoleProgress("Querying offers");
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, "Querying offers");
|
||||
DataAccessUtilityBase.readOffers(options)
|
||||
.then(
|
||||
(offers: DataModels.Offer[]) => {
|
||||
deferred.resolve(offers);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error while querying offers:\n ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while querying offers:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadOffers", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
@@ -333,21 +833,24 @@ export function readOffer(
|
||||
): Q.Promise<DataModels.OfferWithHeaders> {
|
||||
var deferred = Q.defer<DataModels.OfferWithHeaders>();
|
||||
|
||||
const clearMessage = logConsoleProgress("Querying offer");
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, "Querying offer");
|
||||
DataAccessUtilityBase.readOffer(requestedResource, options)
|
||||
.then(
|
||||
(offer: DataModels.OfferWithHeaders) => {
|
||||
deferred.resolve(offer);
|
||||
},
|
||||
(error: any) => {
|
||||
logConsoleError(`Error while querying offer:\n ${JSON.stringify(error)}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while querying offer:\n ${JSON.stringify(error)}`
|
||||
);
|
||||
Logger.logError(JSON.stringify(error), "ReadOffer", error.code);
|
||||
sendNotificationForError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
clearMessage();
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
|
||||
@@ -1,8 +1,49 @@
|
||||
import * as Constants from "../Common/Constants";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { StringUtils } from "../Utils/StringUtils";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
|
||||
export default class EnvironmentUtility {
|
||||
public static getMongoBackendEndpoint(serverId: string, location: string, extensionEndpoint: string = ""): string {
|
||||
const defaultEnvironment: string = "default";
|
||||
const defaultLocation: string = "default";
|
||||
let environment: string = serverId;
|
||||
const endpointType: Constants.MongoBackendEndpointType =
|
||||
Constants.MongoBackend.endpointsByEnvironment[environment] ||
|
||||
Constants.MongoBackend.endpointsByEnvironment[defaultEnvironment];
|
||||
if (endpointType === Constants.MongoBackendEndpointType.local) {
|
||||
return `${extensionEndpoint}${Constants.MongoBackend.localhostEndpoint}`;
|
||||
}
|
||||
|
||||
const normalizedLocation = EnvironmentUtility.normalizeRegionName(location);
|
||||
return (
|
||||
Constants.MongoBackend.endpointsByRegion[normalizedLocation] ||
|
||||
Constants.MongoBackend.endpointsByRegion[defaultLocation]
|
||||
);
|
||||
}
|
||||
|
||||
public static isAadUser(): boolean {
|
||||
return window.authType === AuthType.AAD;
|
||||
}
|
||||
|
||||
public static getCassandraBackendEndpoint(explorer: Explorer): string {
|
||||
const defaultLocation: string = "default";
|
||||
const location: string = EnvironmentUtility.normalizeRegionName(explorer.databaseAccount().location);
|
||||
return (
|
||||
Constants.CassandraBackend.endpointsByRegion[location] ||
|
||||
Constants.CassandraBackend.endpointsByRegion[defaultLocation]
|
||||
);
|
||||
}
|
||||
|
||||
public static normalizeArmEndpointUri(uri: string): string {
|
||||
if (uri && uri.slice(-1) !== "/") {
|
||||
return `${uri}/`;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
private static normalizeRegionName(region: string): string {
|
||||
return region && StringUtils.stripSpacesFromString(region.toLocaleLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Q from "q";
|
||||
import * as MessageHandler from "./MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
|
||||
describe("Message Handler", () => {
|
||||
it("should handle cached message", async () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import Q from "q";
|
||||
import * as _ from "underscore";
|
||||
import * as Constants from "./Constants";
|
||||
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
||||
|
||||
export interface CachedDataPromise<T> {
|
||||
deferred: Q.Deferred<T>;
|
||||
@@ -49,14 +48,12 @@ export function sendCachedDataMessage<TResponseDataModel>(
|
||||
|
||||
export function sendMessage(data: any): void {
|
||||
if (canSendMessage()) {
|
||||
// We try to find data explorer window first, then fallback to current window
|
||||
const portalChildWindow = getDataExplorerWindow(window) || window;
|
||||
portalChildWindow.parent.postMessage(
|
||||
window.parent.postMessage(
|
||||
{
|
||||
signature: "pcIframe",
|
||||
data: data
|
||||
},
|
||||
portalChildWindow.document.referrer
|
||||
window.document.referrer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { AuthType } from "../AuthType";
|
||||
import { resetConfigContext, updateConfigContext } from "../ConfigContext";
|
||||
import { configContext, resetConfigContext, updateConfigContext } from "../ConfigContext";
|
||||
import { DatabaseAccount } from "../Contracts/DataModels";
|
||||
import { Collection } from "../Contracts/ViewModels";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||
import { updateUserContext } from "../UserContext";
|
||||
import { deleteDocument, getEndpoint, queryDocuments, readDocument, updateDocument } from "./MongoProxyClient";
|
||||
jest.mock("../ResourceProvider/ResourceProviderClient.ts");
|
||||
@@ -236,19 +237,19 @@ describe("MongoProxyClient", () => {
|
||||
});
|
||||
|
||||
it("returns a production endpoint", () => {
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount as DatabaseAccount);
|
||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/mongo/explorer");
|
||||
});
|
||||
|
||||
it("returns a development endpoint", () => {
|
||||
updateConfigContext({ MONGO_BACKEND_ENDPOINT: "https://localhost:1234" });
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount as DatabaseAccount);
|
||||
expect(endpoint).toEqual("https://localhost:1234/api/mongo/explorer");
|
||||
});
|
||||
|
||||
it("returns a guest endpoint", () => {
|
||||
window.authType = AuthType.EncryptedToken;
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount as DatabaseAccount);
|
||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
||||
import { userContext } from "../UserContext";
|
||||
import EnvironmentUtility from "./EnvironmentUtility";
|
||||
import { MinimalQueryIterator } from "./IteratorUtilities";
|
||||
import { sendMessage } from "./MessageHandler";
|
||||
|
||||
@@ -77,7 +78,7 @@ export function queryDocuments(
|
||||
collection && collection.partitionKey && !collection.partitionKey.systemKey ? collection.partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint() || "";
|
||||
const endpoint = getEndpoint(databaseAccount) || "";
|
||||
|
||||
const headers = {
|
||||
...defaultHeaders,
|
||||
@@ -138,7 +139,7 @@ export function readDocument(
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount);
|
||||
return window
|
||||
.fetch(`${endpoint}?${queryString.stringify(params)}`, {
|
||||
method: "GET",
|
||||
@@ -178,7 +179,7 @@ export function createDocument(
|
||||
pk: collection && collection.partitionKey && !collection.partitionKey.systemKey ? partitionKeyProperty : ""
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount);
|
||||
|
||||
return window
|
||||
.fetch(`${endpoint}/resourcelist?${queryString.stringify(params)}`, {
|
||||
@@ -220,7 +221,7 @@ export function updateDocument(
|
||||
pk:
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount);
|
||||
|
||||
return window
|
||||
.fetch(`${endpoint}?${queryString.stringify(params)}`, {
|
||||
@@ -259,7 +260,7 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
|
||||
pk:
|
||||
documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperty : ""
|
||||
};
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount);
|
||||
|
||||
return window
|
||||
.fetch(`${endpoint}?${queryString.stringify(params)}`, {
|
||||
@@ -302,7 +303,7 @@ export function createMongoCollectionWithProxy(
|
||||
autoPilotThroughput: params.autoPilotMaxThroughput?.toString()
|
||||
};
|
||||
|
||||
const endpoint = getEndpoint();
|
||||
const endpoint = getEndpoint(databaseAccount);
|
||||
|
||||
return window
|
||||
.fetch(
|
||||
@@ -326,9 +327,12 @@ export function createMongoCollectionWithProxy(
|
||||
});
|
||||
}
|
||||
|
||||
export function getEndpoint(): string {
|
||||
export function getEndpoint(databaseAccount: DataModels.DatabaseAccount): string {
|
||||
const serverId = window.dataExplorer.serverId();
|
||||
const extensionEndpoint = window.dataExplorer.extensionEndpoint();
|
||||
let url = (configContext.MONGO_BACKEND_ENDPOINT || extensionEndpoint) + "/api/mongo/explorer";
|
||||
let url = configContext.MONGO_BACKEND_ENDPOINT
|
||||
? configContext.MONGO_BACKEND_ENDPOINT + "/api/mongo/explorer"
|
||||
: EnvironmentUtility.getMongoBackendEndpoint(serverId, databaseAccount.location, extensionEndpoint);
|
||||
|
||||
if (window.authType === AuthType.EncryptedToken) {
|
||||
url = url.replace("api/mongo", "api/guest/mongo");
|
||||
|
||||
@@ -6,23 +6,26 @@ import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/Contai
|
||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlContainer,
|
||||
getSqlContainer
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraTable,
|
||||
getCassandraTable
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBCollection,
|
||||
getMongoDBCollection
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinGraph,
|
||||
getGremlinGraph
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -9,21 +9,24 @@ import {
|
||||
MongoDBDatabaseCreateUpdateParameters,
|
||||
SqlDatabaseCreateUpdateParameters,
|
||||
CreateUpdateOptions
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlDatabase,
|
||||
getSqlDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraKeyspace,
|
||||
getCassandraKeyspace
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBDatabase,
|
||||
getMongoDBDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinDatabase,
|
||||
getGremlinDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedOffers, refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function createStoredProcedure(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
storedProcedure: StoredProcedureDefinition
|
||||
): Promise<StoredProcedureDefinition & Resource> {
|
||||
let createdStoredProcedure: StoredProcedureDefinition & Resource;
|
||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.storedProcedures.create(storedProcedure);
|
||||
createdStoredProcedure = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while creating stored procedure ${storedProcedure.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "CreateStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return createdStoredProcedure;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function createTrigger(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
trigger: TriggerDefinition
|
||||
): Promise<TriggerDefinition & Resource> {
|
||||
let createdTrigger: TriggerDefinition & Resource;
|
||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.triggers.create(trigger);
|
||||
createdTrigger = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while creating trigger ${trigger.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "CreateTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return createdTrigger;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function createUserDefinedFunction(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
userDefinedFunction: UserDefinedFunctionDefinition
|
||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||
let createdUserDefinedFunction: UserDefinedFunctionDefinition & Resource;
|
||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.userDefinedFunctions.create(userDefinedFunction);
|
||||
createdUserDefinedFunction = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while creating user defined function ${userDefinedFunction.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "CreateUserupdateUserDefinedFunction", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return createdUserDefinedFunction;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { client } from "../CosmosClient";
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function deleteStoredProcedure(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
storedProcedureId: string
|
||||
): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||
try {
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.storedProcedure(storedProcedureId)
|
||||
.delete();
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while deleting stored procedure ${storedProcedureId}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "DeleteStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return undefined;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||
try {
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.trigger(triggerId)
|
||||
.delete();
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while deleting trigger ${triggerId}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "DeleteTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return undefined;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||
try {
|
||||
await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.userDefinedFunction(id)
|
||||
.delete();
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while deleting user defined function ${id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "DeleteUserDefinedFunction", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return undefined;
|
||||
}
|
||||
@@ -2,11 +2,11 @@ import * as DataModels from "../../Contracts/DataModels";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { client } from "../CosmosClient";
|
||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { HttpHeaders } from "../Constants";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import { client } from "../CosmosClient";
|
||||
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { readOffers } from "./readOffers";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
export const readDatabaseOffer = async (
|
||||
params: DataModels.ReadDatabaseOfferParams
|
||||
): Promise<DataModels.OfferWithHeaders> => {
|
||||
let offerId = params.offerId;
|
||||
if (!offerId) {
|
||||
if (
|
||||
window.authType === AuthType.AAD &&
|
||||
!userContext.useSDKOperations &&
|
||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||
) {
|
||||
try {
|
||||
offerId = await getDatabaseOfferIdWithARM(params.databaseId);
|
||||
} catch (error) {
|
||||
if (error.code !== "NotFound") {
|
||||
throw new Error(error);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
offerId = await getDatabaseOfferIdWithSDK(params.databaseResourceId);
|
||||
if (!offerId) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options: RequestOptions = {
|
||||
initialHeaders: {
|
||||
[HttpHeaders.populateCollectionThroughputInfo]: true
|
||||
}
|
||||
};
|
||||
|
||||
const response = await client()
|
||||
.offer(offerId)
|
||||
.read(options);
|
||||
return (
|
||||
response && {
|
||||
...response.resource,
|
||||
headers: response.headers
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const getDatabaseOfferIdWithARM = async (databaseId: string): Promise<string> => {
|
||||
let rpResponse;
|
||||
const subscriptionId = userContext.subscriptionId;
|
||||
const resourceGroup = userContext.resourceGroup;
|
||||
const accountName = userContext.databaseAccount.name;
|
||||
const defaultExperience = userContext.defaultExperience;
|
||||
switch (defaultExperience) {
|
||||
case DefaultAccountExperienceType.DocumentDB:
|
||||
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||
break;
|
||||
case DefaultAccountExperienceType.MongoDB:
|
||||
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||
break;
|
||||
case DefaultAccountExperienceType.Cassandra:
|
||||
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||
break;
|
||||
case DefaultAccountExperienceType.Graph:
|
||||
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||
}
|
||||
|
||||
return rpResponse?.name;
|
||||
};
|
||||
|
||||
const getDatabaseOfferIdWithSDK = async (databaseResourceId: string): Promise<string> => {
|
||||
const offers = await readOffers();
|
||||
const offer = offers.find(offer => offer.resource === databaseResourceId);
|
||||
return offer?.id;
|
||||
};
|
||||
@@ -2,10 +2,10 @@ import * as DataModels from "../../Contracts/DataModels";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { client } from "../CosmosClient";
|
||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Offer } from "../../Contracts/DataModels";
|
||||
import { ClientDefaults } from "../Constants";
|
||||
import { MessageTypes } from "../../Contracts/ExplorerContracts";
|
||||
import { Platform, configContext } from "../../ConfigContext";
|
||||
import { client } from "../CosmosClient";
|
||||
import { sendCachedDataMessage } from "../MessageHandler";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
export const readOffers = async (): Promise<Offer[]> => {
|
||||
try {
|
||||
if (configContext.platform === Platform.Portal) {
|
||||
return sendCachedDataMessage<Offer[]>(MessageTypes.AllOffers, [
|
||||
userContext.databaseAccount.id,
|
||||
ClientDefaults.portalCacheTimeoutMs
|
||||
]);
|
||||
}
|
||||
} catch (error) {
|
||||
// If error getting cached Offers, continue on and read via SDK
|
||||
}
|
||||
|
||||
return client()
|
||||
.offers.readAll()
|
||||
.fetchAll()
|
||||
.then(response => response.resources)
|
||||
.catch(error => {
|
||||
// This should be removed when we can correctly identify if an account is serverless when connected using connection string too.
|
||||
if (error.message.includes("Reading or replacing offers is not supported for serverless accounts")) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function readStoredProcedures(
|
||||
databaseId: string,
|
||||
collectionId: string
|
||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||
let sprocs: (StoredProcedureDefinition & Resource)[];
|
||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.storedProcedures.readAll()
|
||||
.fetchAll();
|
||||
sprocs = response.resources;
|
||||
} catch (error) {
|
||||
logConsoleError(`Failed to query stored procedures for container ${collectionId}: ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "ReadStoredProcedures", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
clearMessage();
|
||||
return sprocs;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function readTriggers(
|
||||
databaseId: string,
|
||||
collectionId: string
|
||||
): Promise<(TriggerDefinition & Resource)[]> {
|
||||
let triggers: (TriggerDefinition & Resource)[];
|
||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.triggers.readAll()
|
||||
.fetchAll();
|
||||
triggers = response.resources;
|
||||
} catch (error) {
|
||||
logConsoleError(`Failed to query triggers for container ${collectionId}: ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "ReadTriggers", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
clearMessage();
|
||||
return triggers;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function readUserDefinedFunctions(
|
||||
databaseId: string,
|
||||
collectionId: string
|
||||
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
||||
let udfs: (UserDefinedFunctionDefinition & Resource)[];
|
||||
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.userDefinedFunctions.readAll()
|
||||
.fetchAll();
|
||||
udfs = response.resources;
|
||||
} catch (error) {
|
||||
logConsoleError(`Failed to query user defined functions for container ${collectionId}: ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "ReadUserDefinedFunctions", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
clearMessage();
|
||||
return udfs;
|
||||
}
|
||||
@@ -6,23 +6,26 @@ import {
|
||||
ExtendedResourceProperties,
|
||||
SqlContainerCreateUpdateParameters,
|
||||
SqlContainerResource
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlContainer,
|
||||
getSqlContainer
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraTable,
|
||||
getCassandraTable
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBCollection,
|
||||
getMongoDBCollection
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinGraph,
|
||||
getGremlinGraph
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function updateStoredProcedure(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
storedProcedure: StoredProcedureDefinition
|
||||
): Promise<StoredProcedureDefinition & Resource> {
|
||||
let updatedStoredProcedure: StoredProcedureDefinition & Resource;
|
||||
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.storedProcedure(storedProcedure.id)
|
||||
.replace(storedProcedure);
|
||||
updatedStoredProcedure = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while updating stored procedure ${storedProcedure.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "UpdateStoredProcedure", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return updatedStoredProcedure;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { TriggerDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function updateTrigger(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
trigger: TriggerDefinition
|
||||
): Promise<TriggerDefinition> {
|
||||
let updatedTrigger: TriggerDefinition;
|
||||
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.trigger(trigger.id)
|
||||
.replace(trigger);
|
||||
updatedTrigger = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while updating trigger ${trigger.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "UpdateTrigger", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return updatedTrigger;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
import { logConsoleError, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { client } from "../CosmosClient";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
export async function updateUserDefinedFunction(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
userDefinedFunction: UserDefinedFunctionDefinition
|
||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||
let updatedUserDefinedFunction: UserDefinedFunctionDefinition & Resource;
|
||||
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
||||
try {
|
||||
const response = await client()
|
||||
.database(databaseId)
|
||||
.container(collectionId)
|
||||
.scripts.userDefinedFunction(userDefinedFunction.id)
|
||||
.replace(userDefinedFunction);
|
||||
updatedUserDefinedFunction = response.resource;
|
||||
} catch (error) {
|
||||
logConsoleError(`Error while updating user defined function ${userDefinedFunction.id}:\n ${JSON.stringify(error)}`);
|
||||
logError(JSON.stringify(error), "UpdateUserupdateUserDefinedFunction", error.code);
|
||||
sendNotificationForError(error);
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
return updatedUserDefinedFunction;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ export enum Platform {
|
||||
|
||||
interface ConfigContext {
|
||||
platform: Platform;
|
||||
allowedParentFrameOrigins: string[];
|
||||
allowedParentFrameOrigins: RegExp;
|
||||
gitSha?: string;
|
||||
proxyPath?: string;
|
||||
AAD_ENDPOINT: string;
|
||||
@@ -30,12 +30,7 @@ interface ConfigContext {
|
||||
// Default configuration
|
||||
let configContext: Readonly<ConfigContext> = {
|
||||
platform: Platform.Portal,
|
||||
allowedParentFrameOrigins: [
|
||||
`^https:\\/\\/cosmos.azure.(com|cn|us)$`,
|
||||
`^https:\\/\\/[\\.\\w]+.portal.azure.(com|cn|us)$`,
|
||||
`^https:\\/\\/[\\.\\w]+.ext.azure.(com|cn|us)$`,
|
||||
`^https:\\/\\/[\\.\\w]+microsoftazure.de$`
|
||||
],
|
||||
allowedParentFrameOrigins: /^https:\/\/portal\.azure\.com$|^https:\/\/portal\.azure\.us$|^https:\/\/portal\.azure\.cn$|^https:\/\/portal\.microsoftazure\.de$|^https:\/\/.+\.portal\.azure\.com$|^https:\/\/.+\.portal\.azure\.us$|^https:\/\/.+\.portal\.azure\.cn$|^https:\/\/.+\.portal\.microsoftazure\.de$|^https:\/\/main\.documentdb\.ext\.azure\.com$|^https:\/\/main\.documentdb\.ext\.microsoftazure\.de$|^https:\/\/main\.documentdb\.ext\.azure\.cn$|^https:\/\/main\.documentdb\.ext\.azure\.us$/,
|
||||
// Webpack injects this at build time
|
||||
gitSha: process.env.GIT_SHA,
|
||||
hostedExplorerURL: "https://cosmos.azure.com/",
|
||||
@@ -78,13 +73,8 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
||||
const response = await fetch("./config.json");
|
||||
if (response.status === 200) {
|
||||
try {
|
||||
const { allowedParentFrameOrigins, ...externalConfig } = await response.json();
|
||||
const externalConfig = await response.json();
|
||||
Object.assign(configContext, externalConfig);
|
||||
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
|
||||
updateConfigContext({
|
||||
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins]
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Unable to parse json in config file");
|
||||
console.error(error);
|
||||
|
||||
@@ -88,6 +88,10 @@ export interface Resource {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ResourceRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Collection extends Resource {
|
||||
defaultTtl?: number;
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
@@ -100,12 +104,39 @@ export interface Collection extends Resource {
|
||||
geospatialConfig?: GeospatialConfig;
|
||||
}
|
||||
|
||||
export interface CreateCollectionWithRpResponse extends Resource {
|
||||
properties: Collection;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface CollectionRequest extends ResourceRequest {
|
||||
defaultTtl?: number;
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
partitionKey?: PartitionKey;
|
||||
uniqueKeyPolicy?: UniqueKeyPolicy;
|
||||
conflictResolutionPolicy?: ConflictResolutionPolicy;
|
||||
}
|
||||
|
||||
export interface Database extends Resource {
|
||||
collections?: Collection[];
|
||||
}
|
||||
|
||||
export interface DocumentId extends Resource {}
|
||||
|
||||
export interface Script extends Resource {
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface StoredProcedure extends Script {}
|
||||
|
||||
export interface UserDefinedFunction extends Script {}
|
||||
|
||||
export interface Trigger extends Script {
|
||||
triggerType: string;
|
||||
triggerOperation: string;
|
||||
}
|
||||
|
||||
export interface ConflictId extends Resource {
|
||||
resourceId?: string;
|
||||
resourceType?: string;
|
||||
@@ -228,6 +259,28 @@ export interface ErrorDataModel {
|
||||
code?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a property bag for telemetry e.g. see ITelemetryError.
|
||||
*/
|
||||
export interface ITelemetryProperties {
|
||||
[propertyName: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a property bag for telemetry e.g. see ITelemetryError.
|
||||
*/
|
||||
export interface ITelemetryEvent {
|
||||
name: string;
|
||||
properties?: ITelemetryProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an error to be logged as telemetry data.
|
||||
*/
|
||||
export interface ITelemetryError extends ITelemetryEvent {
|
||||
error: any;
|
||||
}
|
||||
|
||||
export interface CreateDatabaseAndCollectionRequest {
|
||||
databaseId: string;
|
||||
collectionId: string;
|
||||
@@ -254,6 +307,11 @@ export enum AutopilotTier {
|
||||
Tier4 = 4
|
||||
}
|
||||
|
||||
export interface RpOptions {
|
||||
// tier is sent as string, autoscale as object (AutoPilotCreationSettings)
|
||||
[key: string]: string | AutoPilotCreationSettings;
|
||||
}
|
||||
|
||||
export interface Query {
|
||||
id: string;
|
||||
resourceId: string;
|
||||
@@ -289,10 +347,10 @@ export interface CreateCollectionParams {
|
||||
uniqueKeyPolicy?: UniqueKeyPolicy;
|
||||
}
|
||||
|
||||
export interface ReadDatabaseOfferParams {
|
||||
databaseId: string;
|
||||
databaseResourceId?: string;
|
||||
offerId?: string;
|
||||
export interface SharedThroughputRange {
|
||||
minimumRU: number;
|
||||
maximumRU: number;
|
||||
defaultRU: number;
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
@@ -437,6 +495,25 @@ export interface NotebookConfigurationEndpointInfo {
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface SparkCluster {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
properties: {
|
||||
kind: string;
|
||||
driverSize: string;
|
||||
workerSize: string;
|
||||
workerInstanceCount: number;
|
||||
creationTime: string;
|
||||
status: string;
|
||||
libraries?: SparkClusterLibrary[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface SparkClusterFeedResponse {
|
||||
value: SparkCluster[];
|
||||
}
|
||||
|
||||
export interface SparkClusterConnectionInfo {
|
||||
userName: string;
|
||||
password: string;
|
||||
@@ -478,10 +555,79 @@ export interface MongoParameters extends RpParameters {
|
||||
analyticalStorageTtl?: number;
|
||||
}
|
||||
|
||||
export interface GraphParameters extends RpParameters {
|
||||
pk: string;
|
||||
coll: string;
|
||||
cd: Boolean;
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
}
|
||||
|
||||
export interface CreationRequest {
|
||||
properties: {
|
||||
resource: {
|
||||
id: string;
|
||||
};
|
||||
options: RpOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SqlCollectionParameters extends RpParameters {
|
||||
uniqueKeyPolicy?: UniqueKeyPolicy;
|
||||
pk: string;
|
||||
coll: string;
|
||||
cd: Boolean;
|
||||
analyticalStorageTtl?: number;
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
}
|
||||
|
||||
export interface MongoCreationRequest extends CreationRequest {
|
||||
properties: {
|
||||
resource: {
|
||||
id: string;
|
||||
analyticalStorageTtl?: number;
|
||||
shardKey?: {};
|
||||
};
|
||||
options: RpOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GraphCreationRequest extends CreationRequest {
|
||||
properties: {
|
||||
resource: {
|
||||
id: string;
|
||||
partitionKey: {};
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
};
|
||||
options: RpOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateDatabaseWithRpResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
properties: {
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SparkClusterLibrary {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface SqlCollectionCreationRequest extends CreationRequest {
|
||||
properties: {
|
||||
resource: {
|
||||
uniqueKeyPolicy?: UniqueKeyPolicy;
|
||||
id: string;
|
||||
partitionKey: {};
|
||||
analyticalStorageTtl?: number;
|
||||
indexingPolicy?: IndexingPolicy;
|
||||
};
|
||||
options: RpOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Library extends SparkClusterLibrary {
|
||||
properties: {
|
||||
kind: "Jar";
|
||||
@@ -563,11 +709,6 @@ export interface SparkPool extends ArmResource {
|
||||
properties: SparkPoolProperties;
|
||||
}
|
||||
|
||||
export interface MemoryUsageInfo {
|
||||
freeKB: number;
|
||||
totalKB: number;
|
||||
}
|
||||
|
||||
export interface resourceTokenConnectionStringProperties {
|
||||
accountEndpoint: string;
|
||||
collectionId: string;
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
import {
|
||||
QueryMetrics,
|
||||
Resource,
|
||||
StoredProcedureDefinition,
|
||||
TriggerDefinition,
|
||||
UserDefinedFunctionDefinition
|
||||
} from "@azure/cosmos";
|
||||
import * as DataModels from "./DataModels";
|
||||
import Q from "q";
|
||||
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
|
||||
import ConflictId from "../Explorer/Tree/ConflictId";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { QueryMetrics } from "@azure/cosmos";
|
||||
import { UploadDetails } from "../workers/upload/definitions";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
|
||||
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
|
||||
import Trigger from "../Explorer/Tree/Trigger";
|
||||
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
|
||||
import { UploadDetails } from "../workers/upload/definitions";
|
||||
import * as DataModels from "./DataModels";
|
||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||
import ConflictId from "../Explorer/Tree/ConflictId";
|
||||
|
||||
export interface TokenProvider {
|
||||
getAuthHeader(): Promise<Headers>;
|
||||
@@ -81,15 +75,15 @@ export interface Database extends TreeNode {
|
||||
selectedSubnodeKind: ko.Observable<CollectionTabKind>;
|
||||
|
||||
selectDatabase(): void;
|
||||
expandDatabase(): Promise<void>;
|
||||
expandDatabase(): void;
|
||||
collapseDatabase(): void;
|
||||
|
||||
loadCollections(): Promise<void>;
|
||||
loadCollections(): Q.Promise<void>;
|
||||
findCollectionWithId(collectionRid: string): Collection;
|
||||
openAddCollection(database: Database, event: MouseEvent): void;
|
||||
onDeleteDatabaseContextMenuClick(source: Database, event: MouseEvent | KeyboardEvent): void;
|
||||
readSettings(): void;
|
||||
onSettingsClick: () => void;
|
||||
loadOffer(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface CollectionBase extends TreeNode {
|
||||
@@ -159,13 +153,13 @@ export interface Collection extends CollectionBase {
|
||||
collapseUserDefinedFunctions(): void;
|
||||
collapseTriggers(): void;
|
||||
|
||||
loadUserDefinedFunctions(): Promise<any>;
|
||||
loadStoredProcedures(): Promise<any>;
|
||||
loadTriggers(): Promise<any>;
|
||||
loadUserDefinedFunctions(): Q.Promise<any>;
|
||||
loadStoredProcedures(): Q.Promise<any>;
|
||||
loadTriggers(): Q.Promise<any>;
|
||||
|
||||
createStoredProcedureNode(data: StoredProcedureDefinition & Resource): StoredProcedure;
|
||||
createUserDefinedFunctionNode(data: UserDefinedFunctionDefinition & Resource): UserDefinedFunction;
|
||||
createTriggerNode(data: TriggerDefinition & Resource): Trigger;
|
||||
createStoredProcedureNode(data: DataModels.StoredProcedure): StoredProcedure;
|
||||
createUserDefinedFunctionNode(data: DataModels.UserDefinedFunction): UserDefinedFunction;
|
||||
createTriggerNode(data: DataModels.Trigger): Trigger;
|
||||
findStoredProcedureWithId(sprocRid: string): StoredProcedure;
|
||||
findTriggerWithId(triggerRid: string): Trigger;
|
||||
findUserDefinedFunctionWithId(udfRid: string): UserDefinedFunction;
|
||||
|
||||
@@ -42,8 +42,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
const deleteDatabaseMenuItem = {
|
||||
iconSrc: DeleteDatabaseIcon,
|
||||
onClick: () => container.deleteDatabaseConfirmationPane.open(),
|
||||
label: container.deleteDatabaseText(),
|
||||
styleClass: "deleteDatabaseMenuItem"
|
||||
label: container.deleteDatabaseText()
|
||||
};
|
||||
return [newCollectionMenuItem, deleteDatabaseMenuItem];
|
||||
}
|
||||
@@ -113,8 +112,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onDeleteCollectionContextMenuClick(selectedCollection, null);
|
||||
},
|
||||
label: container.deleteCollectionText(),
|
||||
styleClass: "deleteCollectionMenuItem"
|
||||
label: container.deleteCollectionText()
|
||||
});
|
||||
|
||||
return items;
|
||||
|
||||
@@ -86,7 +86,6 @@ export class DynamicListViewModel extends WaitsForTemplateViewModel {
|
||||
public onRemoveItemKeyPress = (data: any, event: KeyboardEvent, source: any): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.removeItem(data, event);
|
||||
(document.querySelector(".dynamicListItem:last-of-type input") as HTMLElement).focus();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
@@ -95,7 +94,7 @@ export class DynamicListViewModel extends WaitsForTemplateViewModel {
|
||||
|
||||
public addItem(): void {
|
||||
this.listItems.push({ value: ko.observable("") });
|
||||
(document.querySelector(".dynamicListItem:last-of-type input") as HTMLElement).focus();
|
||||
document.getElementById("uniqueKeyItems").focus();
|
||||
}
|
||||
|
||||
public onAddItemKeyPress = (source: any, event: KeyboardEvent): boolean => {
|
||||
|
||||
@@ -66,9 +66,7 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={"firstdivbg headerline"} role="heading" aria-level={2}>
|
||||
{header}
|
||||
</div>
|
||||
<div className={"firstdivbg headerline"}>{header}</div>
|
||||
<div className={"paneMainContent"}>{content}</div>
|
||||
{!this.props.showAuthorizeAccess && (
|
||||
<>
|
||||
|
||||
@@ -8,8 +8,6 @@ import * as Logger from "../../../Common/Logger";
|
||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { StringUtils } from "../../../Utils/StringUtils";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { TerminalQueryParams } from "../../../Common/Constants";
|
||||
|
||||
export interface NotebookTerminalComponentProps {
|
||||
notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo;
|
||||
@@ -34,11 +32,11 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
||||
|
||||
public getTerminalParams(): Map<string, string> {
|
||||
let params: Map<string, string> = new Map<string, string>();
|
||||
params.set(TerminalQueryParams.Terminal, "true");
|
||||
params.set("terminal", "true");
|
||||
|
||||
const terminalEndpoint: string = this.tryGetTerminalEndpoint();
|
||||
if (terminalEndpoint) {
|
||||
params.set(TerminalQueryParams.TerminalEndpoint, terminalEndpoint);
|
||||
params.set("terminalEndpoint", terminalEndpoint);
|
||||
}
|
||||
|
||||
return params;
|
||||
@@ -77,13 +75,11 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
||||
return "";
|
||||
}
|
||||
|
||||
params.set(TerminalQueryParams.Server, serverInfo.notebookServerEndpoint);
|
||||
params.set("server", serverInfo.notebookServerEndpoint);
|
||||
if (serverInfo.authToken && serverInfo.authToken.length > 0) {
|
||||
params.set(TerminalQueryParams.Token, serverInfo.authToken);
|
||||
params.set("token", serverInfo.authToken);
|
||||
}
|
||||
|
||||
params.set(TerminalQueryParams.SubscriptionId, userContext.subscriptionId);
|
||||
|
||||
let result: string = "terminal.html?";
|
||||
for (let key of params.keys()) {
|
||||
result += `${key}=${encodeURIComponent(params.get(key))}&`;
|
||||
|
||||
@@ -30,7 +30,6 @@ export interface NotebookViewerComponentProps {
|
||||
isFavorite?: boolean;
|
||||
backNavigationText: string;
|
||||
hideInputs?: boolean;
|
||||
hidePrompts?: boolean;
|
||||
onBackClick: () => void;
|
||||
onTagClick: (tag: string) => void;
|
||||
}
|
||||
@@ -149,8 +148,7 @@ export class NotebookViewerComponent extends React.Component<
|
||||
{this.state.showProgressBar && <ProgressIndicator />}
|
||||
|
||||
{this.notebookComponentBootstrapper.renderComponent(NotebookReadOnlyRenderer, {
|
||||
hideInputs: this.props.hideInputs,
|
||||
hidePrompts: this.props.hidePrompts
|
||||
hideInputs: this.props.hideInputs
|
||||
})}
|
||||
|
||||
{this.state.dialogProps && <DialogComponent {...this.state.dialogProps} />}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
step: step,
|
||||
'class':'migration collid select-font-size',
|
||||
min: minAutoPilotThroughput,
|
||||
'aria-label': 'Max request units per second',
|
||||
'aria-label': ariaLabel,
|
||||
type: isAutoscaleThroughputInputFieldRequired() ? 'number' : 'hidden',
|
||||
css: {
|
||||
dirty: maxAutoPilotThroughputSet.editableIsDirty
|
||||
|
||||
@@ -159,20 +159,4 @@ describe("TreeNodeComponent", () => {
|
||||
const wrapper = shallow(<TreeNodeComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders loading icon", () => {
|
||||
const node: TreeNode = {
|
||||
label: "label",
|
||||
children: [],
|
||||
isExpanded: true
|
||||
};
|
||||
|
||||
const props = {
|
||||
node,
|
||||
generation: 2,
|
||||
paddingLeft: 9
|
||||
};
|
||||
const wrapper = shallow(<TreeNodeComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,14 +17,12 @@ import {
|
||||
|
||||
import TriangleDownIcon from "../../../../images/Triangle-down.svg";
|
||||
import TriangleRightIcon from "../../../../images/Triangle-right.svg";
|
||||
import LoadingIndicator_3Squares from "../../../../images/LoadingIndicator_3Squares.gif";
|
||||
|
||||
export interface TreeNodeMenuItem {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
iconSrc?: string;
|
||||
isDisabled?: boolean;
|
||||
styleClass?: string;
|
||||
}
|
||||
|
||||
export interface TreeNode {
|
||||
@@ -39,7 +37,6 @@ export interface TreeNode {
|
||||
data?: any; // Piece of data corresponding to this node
|
||||
timestamp?: number;
|
||||
isLeavesParentsSeparate?: boolean; // Display parents together first, then leaves
|
||||
isLoading?: boolean;
|
||||
isSelected?: () => boolean;
|
||||
onClick?: (isExpanded: boolean) => void; // Only if a leaf, other click will expand/collapse
|
||||
onExpanded?: () => void;
|
||||
@@ -186,9 +183,6 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
||||
)}
|
||||
{node.contextMenu && this.renderContextMenuButton(node)}
|
||||
</div>
|
||||
<div className="loadingIconContainer">
|
||||
<img className="loadingIcon" src={LoadingIndicator_3Squares} hidden={!this.props.node.isLoading} />
|
||||
</div>
|
||||
{node.children && (
|
||||
<AnimateHeight duration={TreeNodeComponent.transitionDurationMS} height={this.state.isExpanded ? "auto" : 0}>
|
||||
<div className="nodeChildren" data-test={node.label}>
|
||||
@@ -262,20 +256,13 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
||||
onContextMenu={e => e.target.dispatchEvent(TreeNodeComponent.createClickEvent())}
|
||||
>
|
||||
{props.item.onRenderIcon()}
|
||||
<span
|
||||
className={
|
||||
"treeComponentMenuItemLabel" + (props.item.className ? ` ${props.item.className}Label` : "")
|
||||
}
|
||||
>
|
||||
{props.item.text}
|
||||
</span>
|
||||
<span className="treeComponentMenuItemLabel">{props.item.text}</span>
|
||||
</div>
|
||||
),
|
||||
items: node.contextMenu.map((menuItem: TreeNodeMenuItem) => ({
|
||||
key: menuItem.label,
|
||||
text: menuItem.label,
|
||||
disabled: menuItem.isDisabled,
|
||||
className: menuItem.styleClass,
|
||||
onClick: menuItem.onClick,
|
||||
onRenderIcon: (props: any) => <img src={menuItem.iconSrc} alt="" />
|
||||
}))
|
||||
@@ -295,7 +282,7 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
||||
<img
|
||||
className="expandCollapseIcon"
|
||||
src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon}
|
||||
alt={this.state.isExpanded ? `${node.label} branch is expanded` : `${node.label} branch is collapsed`}
|
||||
alt={this.state.isExpanded ? "Branch is expanded" : "Branch is collapsed"}
|
||||
onKeyPress={(event: React.KeyboardEvent<HTMLDivElement>) => this.onCollapseExpandIconKeyPress(event, node)}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
|
||||
@@ -49,7 +49,7 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
|
||||
tabIndex={-1}
|
||||
>
|
||||
<img
|
||||
alt="label branch is collapsed"
|
||||
alt="Branch is collapsed"
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
@@ -63,15 +63,6 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
|
||||
label
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="loadingIconContainer"
|
||||
>
|
||||
<img
|
||||
className="loadingIcon"
|
||||
hidden={true}
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
animateOpacity={false}
|
||||
animationStateClasses={
|
||||
@@ -149,7 +140,7 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
|
||||
tabIndex={-1}
|
||||
>
|
||||
<img
|
||||
alt="label branch is expanded"
|
||||
alt="Branch is expanded"
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
@@ -188,7 +179,6 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
|
||||
"isBeakVisible": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"className": undefined,
|
||||
"disabled": true,
|
||||
"key": "menuLabel",
|
||||
"onClick": undefined,
|
||||
@@ -211,15 +201,6 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="loadingIconContainer"
|
||||
>
|
||||
<img
|
||||
className="loadingIcon"
|
||||
hidden={true}
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
animateOpacity={false}
|
||||
animationStateClasses={
|
||||
@@ -280,77 +261,6 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`TreeNodeComponent renders loading icon 1`] = `
|
||||
<div
|
||||
className=" main2 nodeItem "
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
>
|
||||
<div
|
||||
className="treeNodeHeader "
|
||||
data-test="label"
|
||||
style={
|
||||
Object {
|
||||
"paddingLeft": 9,
|
||||
}
|
||||
}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<img
|
||||
alt="label branch is expanded"
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
className="nodeLabel"
|
||||
title="label"
|
||||
>
|
||||
label
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="loadingIconContainer"
|
||||
>
|
||||
<img
|
||||
className="loadingIcon"
|
||||
hidden={true}
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
animateOpacity={false}
|
||||
animationStateClasses={
|
||||
Object {
|
||||
"animating": "rah-animating",
|
||||
"animatingDown": "rah-animating--down",
|
||||
"animatingToHeightAuto": "rah-animating--to-height-auto",
|
||||
"animatingToHeightSpecific": "rah-animating--to-height-specific",
|
||||
"animatingToHeightZero": "rah-animating--to-height-zero",
|
||||
"animatingUp": "rah-animating--up",
|
||||
"static": "rah-static",
|
||||
"staticHeightAuto": "rah-static--height-auto",
|
||||
"staticHeightSpecific": "rah-static--height-specific",
|
||||
"staticHeightZero": "rah-static--height-zero",
|
||||
}
|
||||
}
|
||||
applyInlineTransitions={true}
|
||||
delay={0}
|
||||
duration={200}
|
||||
easing="ease"
|
||||
height="auto"
|
||||
style={Object {}}
|
||||
>
|
||||
<div
|
||||
className="nodeChildren"
|
||||
data-test="label"
|
||||
/>
|
||||
</AnimateHeight>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents separated 1`] = `
|
||||
<div
|
||||
className="nodeClassname main12 nodeItem "
|
||||
@@ -368,7 +278,7 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
|
||||
tabIndex={-1}
|
||||
>
|
||||
<img
|
||||
alt="label branch is expanded"
|
||||
alt="Branch is expanded"
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
@@ -421,15 +331,6 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="loadingIconContainer"
|
||||
>
|
||||
<img
|
||||
className="loadingIcon"
|
||||
hidden={true}
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
animateOpacity={false}
|
||||
animationStateClasses={
|
||||
@@ -535,7 +436,7 @@ exports[`TreeNodeComponent renders unsorted children by default 1`] = `
|
||||
tabIndex={-1}
|
||||
>
|
||||
<img
|
||||
alt="label branch is expanded"
|
||||
alt="Branch is expanded"
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
@@ -549,15 +450,6 @@ exports[`TreeNodeComponent renders unsorted children by default 1`] = `
|
||||
label
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="loadingIconContainer"
|
||||
>
|
||||
<img
|
||||
className="loadingIcon"
|
||||
hidden={true}
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
animateOpacity={false}
|
||||
animationStateClasses={
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
&.showingMenu {
|
||||
background-color: #eee;
|
||||
background-color: #EEE;
|
||||
}
|
||||
|
||||
.treeMenuEllipsis {
|
||||
@@ -78,12 +78,3 @@
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.loadingIconContainer {
|
||||
width: 100%;
|
||||
|
||||
.loadingIcon {
|
||||
height: 6px;
|
||||
margin-left: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
||||
import Database from "./Tree/Database";
|
||||
import DeleteCollectionConfirmationPane from "./Panes/DeleteCollectionConfirmationPane";
|
||||
import DeleteDatabaseConfirmationPane from "./Panes/DeleteDatabaseConfirmationPane";
|
||||
import { refreshCachedResources } from "../Common/DocumentClientUtilityBase";
|
||||
import { readOffers, refreshCachedResources } from "../Common/DocumentClientUtilityBase";
|
||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
||||
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
|
||||
@@ -87,7 +87,6 @@ import { ContextualPaneBase } from "./Panes/ContextualPaneBase";
|
||||
import TabsBase from "./Tabs/TabsBase";
|
||||
import { CommandButtonComponentProps } from "./Controls/CommandButton/CommandButtonComponent";
|
||||
import { updateUserContext, userContext } from "../UserContext";
|
||||
import { stringToBlob } from "../Utils/BlobUtils";
|
||||
|
||||
BindingHandlersRegisterer.registerBindingHandlers();
|
||||
// Hold a reference to ComponentRegisterer to prevent transpiler to ignore import
|
||||
@@ -244,7 +243,6 @@ export default class Explorer {
|
||||
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||
public notebookManager?: any; // This is dynamically loaded
|
||||
|
||||
private _panes: ContextualPaneBase[] = [];
|
||||
@@ -375,7 +373,6 @@ export default class Explorer {
|
||||
);
|
||||
}
|
||||
});
|
||||
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
|
||||
this.notificationsClient = options.notificationsClient;
|
||||
this.isEmulator = options.isEmulator;
|
||||
|
||||
@@ -1424,40 +1421,71 @@ export default class Explorer {
|
||||
|
||||
// TODO: Refactor
|
||||
const deferred: Q.Deferred<any> = Q.defer();
|
||||
this._setLoadingStatusText("Fetching databases...");
|
||||
readDatabases().then(
|
||||
(databases: DataModels.Database[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched databases.");
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadDatabases,
|
||||
{
|
||||
databaseAccountName: this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
},
|
||||
startKey
|
||||
);
|
||||
const currentlySelectedNode: ViewModels.TreeNode = this.selectedNode();
|
||||
const deltaDatabases = this.getDeltaDatabases(databases);
|
||||
this.addDatabasesToList(deltaDatabases.toAdd);
|
||||
this.deleteDatabasesFromList(deltaDatabases.toDelete);
|
||||
this.selectedNode(currentlySelectedNode);
|
||||
this._setLoadingStatusText("Fetching containers...");
|
||||
this.refreshAndExpandNewDatabases(deltaDatabases.toAdd)
|
||||
.then(
|
||||
() => {
|
||||
this._setLoadingStatusText("Successfully fetched containers.");
|
||||
deferred.resolve();
|
||||
|
||||
const refreshDatabases = (offers?: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Fetching databases...");
|
||||
readDatabases().then(
|
||||
(databases: DataModels.Database[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched databases.");
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadDatabases,
|
||||
{
|
||||
databaseAccountName: this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
},
|
||||
reason => {
|
||||
this._setLoadingStatusText("Failed to fetch containers.");
|
||||
deferred.reject(reason);
|
||||
}
|
||||
)
|
||||
.finally(() => this.isRefreshingExplorer(false));
|
||||
startKey
|
||||
);
|
||||
const currentlySelectedNode: ViewModels.TreeNode = this.selectedNode();
|
||||
const deltaDatabases = this.getDeltaDatabases(databases, offers);
|
||||
this.addDatabasesToList(deltaDatabases.toAdd);
|
||||
this.deleteDatabasesFromList(deltaDatabases.toDelete);
|
||||
this.selectedNode(currentlySelectedNode);
|
||||
this._setLoadingStatusText("Fetching containers...");
|
||||
this.refreshAndExpandNewDatabases(deltaDatabases.toAdd)
|
||||
.then(
|
||||
() => {
|
||||
this._setLoadingStatusText("Successfully fetched containers.");
|
||||
deferred.resolve();
|
||||
},
|
||||
reason => {
|
||||
this._setLoadingStatusText("Failed to fetch containers.");
|
||||
deferred.reject(reason);
|
||||
}
|
||||
)
|
||||
.finally(() => this.isRefreshingExplorer(false));
|
||||
},
|
||||
error => {
|
||||
this._setLoadingStatusText("Failed to fetch databases.");
|
||||
this.isRefreshingExplorer(false);
|
||||
deferred.reject(error);
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.LoadDatabases,
|
||||
{
|
||||
databaseAccountName: this.databaseAccount().name,
|
||||
defaultExperience: this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||
error: JSON.stringify(error)
|
||||
},
|
||||
startKey
|
||||
);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error while refreshing databases: ${JSON.stringify(error)}`
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const offerPromise: Q.Promise<DataModels.Offer[]> = readOffers({ isServerless: this.isServerlessEnabled() });
|
||||
this._setLoadingStatusText("Fetching offers...");
|
||||
offerPromise.then(
|
||||
(offers: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched offers.");
|
||||
refreshDatabases(offers);
|
||||
},
|
||||
error => {
|
||||
this._setLoadingStatusText("Failed to fetch databases.");
|
||||
this._setLoadingStatusText("Failed to fetch offers.");
|
||||
this.isRefreshingExplorer(false);
|
||||
deferred.reject(error);
|
||||
TelemetryProcessor.traceFailure(
|
||||
@@ -1863,9 +1891,6 @@ export default class Explorer {
|
||||
}
|
||||
|
||||
public findSelectedDatabase(): ViewModels.Database {
|
||||
if (!this.selectedNode()) {
|
||||
return null;
|
||||
}
|
||||
if (this.selectedNode().nodeKind === "Database") {
|
||||
return _.find(this.databases(), (database: ViewModels.Database) => database.rid === this.selectedNode().rid);
|
||||
}
|
||||
@@ -2072,13 +2097,16 @@ export default class Explorer {
|
||||
defaultExperience: this.defaultExperience && this.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
});
|
||||
databasesToLoad.forEach(async (database: ViewModels.Database) => {
|
||||
await database.loadCollections();
|
||||
const isNewDatabase: boolean = _.some(newDatabases, (db: ViewModels.Database) => db.rid === database.rid);
|
||||
if (isNewDatabase) {
|
||||
database.expandDatabase();
|
||||
}
|
||||
this.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.getDatabase().rid === database.rid);
|
||||
databasesToLoad.forEach((database: ViewModels.Database) => {
|
||||
loadCollectionPromises.push(
|
||||
database.loadCollections().finally(() => {
|
||||
const isNewDatabase: boolean = _.some(newDatabases, (db: ViewModels.Database) => db.rid === database.rid);
|
||||
if (isNewDatabase) {
|
||||
database.expandDatabase();
|
||||
}
|
||||
this.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.getDatabase().rid === database.rid);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
Q.all(loadCollectionPromises).done(
|
||||
@@ -2223,7 +2251,8 @@ export default class Explorer {
|
||||
}
|
||||
|
||||
private getDeltaDatabases(
|
||||
updatedDatabaseList: DataModels.Database[]
|
||||
updatedDatabaseList: DataModels.Database[],
|
||||
updatedOffersList: DataModels.Offer[]
|
||||
): { toAdd: ViewModels.Database[]; toDelete: ViewModels.Database[] } {
|
||||
const newDatabases: DataModels.Database[] = _.filter(updatedDatabaseList, (database: DataModels.Database) => {
|
||||
const databaseExists = _.some(
|
||||
@@ -2232,9 +2261,10 @@ export default class Explorer {
|
||||
);
|
||||
return !databaseExists;
|
||||
});
|
||||
const databasesToAdd: ViewModels.Database[] = newDatabases.map(
|
||||
(newDatabase: DataModels.Database) => new Database(this, newDatabase)
|
||||
);
|
||||
const databasesToAdd: ViewModels.Database[] = _.map(newDatabases, (newDatabase: DataModels.Database) => {
|
||||
const databaseOffer: DataModels.Offer = this.getOfferForResource(updatedOffersList, newDatabase._self);
|
||||
return new Database(this, newDatabase, databaseOffer);
|
||||
});
|
||||
|
||||
let databasesToDelete: ViewModels.Database[] = [];
|
||||
ko.utils.arrayForEach(this.databases(), (database: ViewModels.Database) => {
|
||||
@@ -2284,6 +2314,10 @@ export default class Explorer {
|
||||
return null;
|
||||
}
|
||||
|
||||
private getOfferForResource(offers: DataModels.Offer[], resourceId: string): DataModels.Offer {
|
||||
return _.find(offers, (offer: DataModels.Offer) => offer.resource === resourceId);
|
||||
}
|
||||
|
||||
public uploadFile(name: string, content: string, parent: NotebookContentItem): Promise<NotebookContentItem> {
|
||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||
const error = "Attempt to upload notebook, but notebook is not enabled";
|
||||
@@ -2582,11 +2616,9 @@ export default class Explorer {
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
const clearMessage = NotificationConsoleUtils.logConsoleProgress(`Downloading ${notebookFile.path}`);
|
||||
|
||||
return this.notebookManager?.notebookContentClient.readFileContent(notebookFile.path).then(
|
||||
(content: string) => {
|
||||
const blob = stringToBlob(content, "text/plain");
|
||||
const blob = new Blob([content], { type: "octet/stream" });
|
||||
if (navigator.msSaveBlob) {
|
||||
// for IE and Edge
|
||||
navigator.msSaveBlob(blob, notebookFile.name);
|
||||
@@ -2603,16 +2635,12 @@ export default class Explorer {
|
||||
downloadLink.click();
|
||||
downloadLink.remove();
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
},
|
||||
(error: any) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Could not download notebook ${JSON.stringify(error)}`
|
||||
);
|
||||
|
||||
clearMessage();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -3120,15 +3148,4 @@ export default class Explorer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async loadSelectedDatabaseOffer(): Promise<void> {
|
||||
const database = this.findSelectedDatabase();
|
||||
await database?.loadOffer();
|
||||
}
|
||||
|
||||
public async loadDatabaseOffers(): Promise<void> {
|
||||
this.databases()?.forEach(async (database: ViewModels.Database) => {
|
||||
await database.loadOffer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +82,7 @@ export class CommandBarComponentAdapter implements ReactAdapter {
|
||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
|
||||
if (this.isNotebookTabActive()) {
|
||||
uiFabricControlButtons.unshift(
|
||||
CommandBarUtil.createMemoryTracker("memoryTracker", this.container.memoryUsageInfo)
|
||||
);
|
||||
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -391,6 +391,31 @@ export class CommandBarComponentButtonFactory {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private static createScaleAndSettingsButton(container: Explorer): CommandButtonComponentProps {
|
||||
let isShared = false;
|
||||
if (container.isDatabaseNodeSelected()) {
|
||||
isShared = container.findSelectedDatabase().isDatabaseShared();
|
||||
} else if (container.isNodeKindSelected("Collection")) {
|
||||
const database: ViewModels.Database = container.findSelectedCollection().getDatabase();
|
||||
isShared = database && database.isDatabaseShared();
|
||||
}
|
||||
|
||||
const label = isShared ? "Settings" : "Scale & Settings";
|
||||
|
||||
return {
|
||||
iconSrc: ScaleIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && (<any>selectedCollection).onSettingsClick();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewNotebookButton(container: Explorer): CommandButtonComponentProps {
|
||||
const label = "New Notebook";
|
||||
return {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import _ from "underscore";
|
||||
import * as React from "react";
|
||||
import { Observable } from "knockout";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { Dropdown, IDropdownOption, IDropdownStyles } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { IconType } from "office-ui-fabric-react/lib/Icon";
|
||||
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { Dropdown, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import * as React from "react";
|
||||
import _ from "underscore";
|
||||
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
|
||||
/**
|
||||
* Utilities for CommandBar
|
||||
@@ -178,10 +176,10 @@ export class CommandBarUtil {
|
||||
};
|
||||
}
|
||||
|
||||
public static createMemoryTracker(key: string, memoryUsageInfo: Observable<MemoryUsageInfo>): ICommandBarItemProps {
|
||||
public static createMemoryTracker(key: string): ICommandBarItemProps {
|
||||
return {
|
||||
key,
|
||||
onRender: () => <MemoryTrackerComponent memoryUsageInfo={memoryUsageInfo} />
|
||||
onRender: () => <MemoryTrackerComponent />
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,71 @@
|
||||
import * as React from "react";
|
||||
import { Observable, Subscription } from "knockout";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import useSWR from "swr";
|
||||
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator";
|
||||
import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
|
||||
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
||||
import { listConnectionInfo } from "../../../Utils/arm/generatedClients/2020-04-01-notebook/notebookWorkspaces";
|
||||
import { NotebookWorkspaceConnectionInfoResult } from "../../../Utils/arm/generatedClients/2020-04-01-notebook/types";
|
||||
import { userContext } from "../../../UserContext";
|
||||
|
||||
interface MemoryTrackerProps {
|
||||
memoryUsageInfo: Observable<MemoryUsageInfo>;
|
||||
export interface MemoryUsageInfo {
|
||||
total: number;
|
||||
free: number;
|
||||
}
|
||||
|
||||
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
||||
private memoryUsageInfoSubscription: Subscription;
|
||||
const kbInGB = 1048576;
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
||||
if (!memoryUsageInfo) {
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<Spinner size={SpinnerSize.medium} />
|
||||
</Stack>
|
||||
);
|
||||
const fetchMemoryInfo = async (_key: unknown, connectionInfo: NotebookWorkspaceConnectionInfoResult) => {
|
||||
const response = await fetch(`${connectionInfo.notebookServerEndpoint}/api/metrics/memory`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Token ${connectionInfo.authToken}`,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
const memoryUsageInfo = (await response.json()) as MemoryUsageInfo;
|
||||
return {
|
||||
totalKB: memoryUsageInfo.total,
|
||||
freeKB: memoryUsageInfo.free
|
||||
};
|
||||
};
|
||||
|
||||
const totalGB = memoryUsageInfo.totalKB / 1048576;
|
||||
const usedGB = totalGB - memoryUsageInfo.freeKB / 1048576;
|
||||
export const MemoryTrackerComponent: FunctionComponent = () => {
|
||||
const { data: connectionInfo } = useSWR(
|
||||
[
|
||||
"notebooksConnectionInfo",
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
userContext.databaseAccount.name,
|
||||
"default"
|
||||
],
|
||||
(_key, subscriptionId, resourceGroup, accountName, workspace) =>
|
||||
listConnectionInfo(subscriptionId, resourceGroup, accountName, workspace)
|
||||
);
|
||||
const { data } = useSWR(connectionInfo ? ["memoryUsage", connectionInfo] : null, fetchMemoryInfo, {
|
||||
refreshInterval: 2000
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<ProgressIndicator
|
||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||
percentComplete={usedGB / totalGB}
|
||||
/>
|
||||
<Spinner size={SpinnerSize.medium} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
const totalGB = data.totalKB / kbInGB;
|
||||
const usedGB = totalGB - data.freeKB / kbInGB;
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<ProgressIndicator
|
||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||
percentComplete={usedGB / totalGB}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -130,14 +130,11 @@ export class NotificationConsoleComponent extends React.Component<
|
||||
<span className="headerStatusEllipsis">{this.state.headerStatus}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="expandCollapseButton"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={this.state.isExpanded ? "collapse console" : "expand console"}
|
||||
aria-expanded={this.state.isExpanded}
|
||||
>
|
||||
<img src={this.state.isExpanded ? ChevronDownIcon : ChevronUpIcon} alt="" />
|
||||
<div className="expandCollapseButton" role="button" tabIndex={0}>
|
||||
<img
|
||||
src={this.state.isExpanded ? ChevronDownIcon : ChevronUpIcon}
|
||||
alt={this.state.isExpanded ? "collapse console" : "expand console"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AnimateHeight
|
||||
|
||||
@@ -68,14 +68,12 @@ exports[`NotificationConsoleComponent renders the console (expanded) 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-expanded={true}
|
||||
aria-label="collapse console"
|
||||
className="expandCollapseButton"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
alt="collapse console"
|
||||
src=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,89 +2,13 @@
|
||||
* Notebook container related stuff
|
||||
*/
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
|
||||
export class NotebookContainerClient {
|
||||
private reconnectingNotificationId: string;
|
||||
private isResettingWorkspace: boolean;
|
||||
|
||||
constructor(
|
||||
private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>,
|
||||
private onConnectionLost: () => void,
|
||||
private onMemoryUsageInfoUpdate: (update: DataModels.MemoryUsageInfo) => void
|
||||
) {
|
||||
if (notebookServerInfo() && notebookServerInfo().notebookServerEndpoint) {
|
||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||
} else {
|
||||
const subscription = notebookServerInfo.subscribe((newServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => {
|
||||
if (newServerInfo && newServerInfo.notebookServerEndpoint) {
|
||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||
}
|
||||
subscription.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Heartbeat: each ping schedules another ping
|
||||
*/
|
||||
private scheduleHeartbeat(delayMs: number): void {
|
||||
setTimeout(() => {
|
||||
this.getMemoryUsage()
|
||||
.then(memoryUsageInfo => this.onMemoryUsageInfoUpdate(memoryUsageInfo))
|
||||
.finally(() => this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs));
|
||||
}, delayMs);
|
||||
}
|
||||
|
||||
private async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||
if (!this.notebookServerInfo() || !this.notebookServerInfo().notebookServerEndpoint) {
|
||||
const error = "No server endpoint detected";
|
||||
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (this.isResettingWorkspace) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { notebookServerEndpoint, authToken } = this.getNotebookServerConfig();
|
||||
try {
|
||||
const response = await fetch(`${notebookServerEndpoint}/api/metrics/memory`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: authToken,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
if (this.reconnectingNotificationId) {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(this.reconnectingNotificationId);
|
||||
this.reconnectingNotificationId = "";
|
||||
}
|
||||
const memoryUsageInfo = await response.json();
|
||||
if (memoryUsageInfo) {
|
||||
return {
|
||||
totalKB: memoryUsageInfo.total,
|
||||
freeKB: memoryUsageInfo.free
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||
if (!this.reconnectingNotificationId) {
|
||||
this.reconnectingNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
"Connection lost with Notebook server. Attempting to reconnect..."
|
||||
);
|
||||
}
|
||||
this.onConnectionLost();
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
constructor(private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>) {}
|
||||
|
||||
public async resetWorkspace(): Promise<void> {
|
||||
this.isResettingWorkspace = true;
|
||||
|
||||
@@ -194,24 +194,17 @@ export class NotebookContentClient {
|
||||
});
|
||||
}
|
||||
|
||||
public async readFileContent(filePath: string): Promise<string> {
|
||||
const xhr = await this.contentProvider.get(this.getServerConfig(), filePath, { content: 1 }).toPromise();
|
||||
const content = (xhr.response as any).content;
|
||||
if (!content) {
|
||||
throw new Error("No content read");
|
||||
}
|
||||
|
||||
const format = (xhr.response as any).format;
|
||||
switch (format) {
|
||||
case "text":
|
||||
return content;
|
||||
case "base64":
|
||||
return atob(content);
|
||||
case "json":
|
||||
public readFileContent(filePath: string): Promise<string> {
|
||||
return this.contentProvider
|
||||
.get(this.getServerConfig(), filePath, { type: "notebook", format: "text", content: 1 })
|
||||
.toPromise()
|
||||
.then(xhr => {
|
||||
const content = (xhr.response as any).content;
|
||||
if (!content) {
|
||||
throw new Error("No content read");
|
||||
}
|
||||
return stringifyNotebook(content);
|
||||
default:
|
||||
throw new Error(`Unsupported content format ${format}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private deleteNotebookFile(path: string): Promise<string> {
|
||||
|
||||
@@ -16,7 +16,6 @@ import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProv
|
||||
import { GitHubContentProvider } from "../../GitHub/GitHubContentProvider";
|
||||
import { contents } from "rx-jupyter";
|
||||
import { NotebookContainerClient } from "./NotebookContainerClient";
|
||||
import { MemoryUsageInfo } from "../../Contracts/DataModels";
|
||||
import { NotebookContentClient } from "./NotebookContentClient";
|
||||
import { DialogProps } from "../Controls/DialogReactComponent/DialogComponent";
|
||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
||||
@@ -76,11 +75,7 @@ export default class NotebookManager {
|
||||
contents.JupyterContentProvider
|
||||
);
|
||||
|
||||
this.notebookClient = new NotebookContainerClient(
|
||||
this.params.container.notebookServerInfo,
|
||||
() => this.params.container.initNotebooks(this.params.container.databaseAccount()),
|
||||
(update: MemoryUsageInfo) => this.params.container.memoryUsageInfo(update)
|
||||
);
|
||||
this.notebookClient = new NotebookContainerClient(this.params.container.notebookServerInfo);
|
||||
|
||||
this.notebookContentClient = new NotebookContentClient(
|
||||
this.params.container.notebookServerInfo,
|
||||
@@ -113,14 +108,11 @@ export default class NotebookManager {
|
||||
this.params.resourceTree.initializeGitHubRepos(pinnedRepos);
|
||||
this.params.resourceTree.triggerRender();
|
||||
});
|
||||
this.refreshPinnedRepos();
|
||||
this.junoClient.getPinnedRepos(this.gitHubOAuthService.getTokenObservable()()?.scope);
|
||||
}
|
||||
|
||||
public refreshPinnedRepos(): void {
|
||||
const token = this.gitHubOAuthService.getTokenObservable()();
|
||||
if (token) {
|
||||
this.junoClient.getPinnedRepos(token.scope);
|
||||
}
|
||||
this.junoClient.getPinnedRepos(this.gitHubOAuthService.getTokenObservable()()?.scope);
|
||||
}
|
||||
|
||||
public async openPublishNotebookPane(
|
||||
|
||||
@@ -3,7 +3,6 @@ import "./base.css";
|
||||
import "./default.css";
|
||||
|
||||
import { CodeCell, RawCell, Cells, MarkdownCell } from "@nteract/stateful-components";
|
||||
import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt";
|
||||
import { AzureTheme } from "./AzureTheme";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
@@ -16,7 +15,6 @@ import "./NotebookReadOnlyRenderer.less";
|
||||
export interface NotebookRendererProps {
|
||||
contentRef: any;
|
||||
hideInputs?: boolean;
|
||||
hidePrompts?: boolean;
|
||||
}
|
||||
|
||||
interface PassedEditorProps {
|
||||
@@ -40,29 +38,6 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
||||
loadTransform(this.props as any);
|
||||
}
|
||||
|
||||
private renderPrompt(id: string, contentRef: string): JSX.Element {
|
||||
if (this.props.hidePrompts) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Prompt id={id} contentRef={contentRef}>
|
||||
{(props: PassedPromptProps) => {
|
||||
if (props.status === "busy") {
|
||||
return <React.Fragment>{"[*]"}</React.Fragment>;
|
||||
}
|
||||
if (props.status === "queued") {
|
||||
return <React.Fragment>{"[…]"}</React.Fragment>;
|
||||
}
|
||||
if (typeof props.executionCount === "number") {
|
||||
return <React.Fragment>{`[${props.executionCount}]`}</React.Fragment>;
|
||||
}
|
||||
return <React.Fragment>{"[ ]"}</React.Fragment>;
|
||||
}}
|
||||
</Prompt>
|
||||
);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div className="NotebookReadOnlyRender">
|
||||
@@ -71,7 +46,6 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
||||
code: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
|
||||
<CodeCell id={id} contentRef={contentRef}>
|
||||
{{
|
||||
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
|
||||
editor: {
|
||||
codemirror: (props: PassedEditorProps) =>
|
||||
this.props.hideInputs ? <></> : <CodeMirrorEditor {...props} readOnly={"nocursor"} />
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<script type="text/html" id="add-collection-inputs">
|
||||
<!-- Add collection header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span id="containerTitle" role="heading" aria-level="2" data-bind="text: title" ></span>
|
||||
<span id="containerTitle" data-bind="text: title"></span>
|
||||
<div class="closeImg" id="closeBtnAddCollection" role="button" aria-label="Add collection close pane"
|
||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }" tabindex="0">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
@@ -115,10 +115,10 @@
|
||||
|
||||
<!-- Database provisioned throughput - Start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<div class="databaseProvision" aria-label="Provision database throughput"
|
||||
<div class="databaseProvision" aria-label="New database provision support"
|
||||
data-bind="visible: databaseCreateNew">
|
||||
<input tabindex="0" type="checkbox" data-test="addCollectionPane-databaseSharedThroughput"
|
||||
id="addCollection-databaseSharedThroughput" title="Provision database throughput"
|
||||
id="addCollection-databaseSharedThroughput" title="Provision shared throughput"
|
||||
data-bind="checked: databaseCreateNewShared" />
|
||||
<span class="databaseProvisionText" for="databaseSharedThroughput">Provision database throughput</span>
|
||||
<span class="infoTooltip" role="tooltip" tabindex="0">
|
||||
@@ -517,13 +517,13 @@
|
||||
<div>
|
||||
<span class="mandatoryStar">*</span>
|
||||
<span class="addCollectionLabel">Analytical store</span>
|
||||
<span class="infoTooltip" role="tooltip" tabindex="0" data-bind="event: { focus: function(data, event) { transferFocus('tooltip1', 'link1') } }">
|
||||
<span class="infoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information">
|
||||
<span id="tooltip1" class="tooltiptext infoTooltipWidth" data-bind="event: { mouseout: onMouseOut }">
|
||||
<span class="tooltiptext infoTooltipWidth">
|
||||
Enable analytical store capability to perform near real-time analytics on your operational
|
||||
data, without impacting the performance of transactional workloads.
|
||||
Learn more <a id="link1" class="errorLink" href="https://aka.ms/analytical-store-overview"
|
||||
target="_blank" data-bind="event: { focusout: onFocusOut, keydown: onKeyDown.bind($data, 'largePartitionKey') }">here</a>
|
||||
Learn more <a class="errorLink" href="https://aka.ms/analytical-store-overview"
|
||||
target="_blank">here</a>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -537,11 +537,9 @@
|
||||
attr: {
|
||||
'aria-checked': isAnalyticalStorageOn() ? 'true' : 'false'
|
||||
}" />
|
||||
<label for="enableAnalyticalStorageRadioOn" class="enableAnalyticalStorageRadioLabel">
|
||||
<span data-bind="disable: showEnableSynapseLink">
|
||||
On
|
||||
</span>
|
||||
</label>
|
||||
<span for="enableAnalyticalStorageRadioOn" data-bind="disable: showEnableSynapseLink">
|
||||
On
|
||||
</span>
|
||||
|
||||
<input class="enableAnalyticalStorageRadio" id="enableAnalyticalStorageRadioOff"
|
||||
name="analyticalStore" type="radio" role="radio" tabindex="0" data-bind="
|
||||
@@ -551,11 +549,9 @@
|
||||
attr: {
|
||||
'aria-checked': isAnalyticalStorageOn() ? 'false' : 'true'
|
||||
}" />
|
||||
<label for="enableAnalyticalStorageRadioOff" class="enableAnalyticalStorageRadioLabel">
|
||||
<span data-bind="disable: showEnableSynapseLink">
|
||||
Off
|
||||
</span>
|
||||
</label>
|
||||
<span for="enableAnalyticalStorageRadioOff" data-bind="disable: showEnableSynapseLink">
|
||||
Off
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="paragraph italic" data-bind="visible: ttl90DaysEnabled() && isAnalyticalStorageOn()">
|
||||
|
||||
@@ -608,7 +608,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.container.isPreferredApiMongoDB()) {
|
||||
if (this.container.isPreferredApiMongoDB() && this.container.hasStorageAnalyticsAfecFeature()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -666,7 +666,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
||||
const subscriptionType: ViewModels.SubscriptionType =
|
||||
this.container.subscriptionType && this.container.subscriptionType();
|
||||
|
||||
if (subscriptionType === ViewModels.SubscriptionType.EA || this.container.isServerlessEnabled()) {
|
||||
if (subscriptionType === ViewModels.SubscriptionType.EA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
||||
return true;
|
||||
};
|
||||
|
||||
public async open(databaseId?: string) {
|
||||
public open(databaseId?: string) {
|
||||
super.open();
|
||||
// TODO: Figure out if a database level partition split is about to happen once shared throughput read is available
|
||||
this.formWarnings("");
|
||||
@@ -715,40 +715,18 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
||||
dataExplorerArea: Constants.Areas.ContextualPane
|
||||
};
|
||||
|
||||
await this.container.loadDatabaseOffers();
|
||||
this._onDatabasesChange(this.container.databases());
|
||||
this._setFocus();
|
||||
|
||||
TelemetryProcessor.trace(Action.CreateCollection, ActionModifiers.Open, addCollectionPaneOpenMessage);
|
||||
}
|
||||
|
||||
private transferFocus(elementIdToKeepVisible: string, elementIdToFocus: string): void {
|
||||
document.getElementById(elementIdToKeepVisible).style.visibility = "visible";
|
||||
document.getElementById(elementIdToFocus).focus();
|
||||
}
|
||||
|
||||
private onFocusOut(_: any, event: any): void {
|
||||
event.target.parentElement.style.visibility = "";
|
||||
}
|
||||
|
||||
private onMouseOut(_: any, event: any): void {
|
||||
event.target.style.visibility = "";
|
||||
}
|
||||
|
||||
private onKeyDown(previousActiveElementId: string, _: any, event: KeyboardEvent): boolean {
|
||||
if (event.shiftKey && event.keyCode == Constants.KeyCodes.Tab) {
|
||||
document.getElementById(previousActiveElementId).focus();
|
||||
return false;
|
||||
} else {
|
||||
// Execute default action
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDatabasesChange(newDatabaseIds: ViewModels.Database[]) {
|
||||
const cachedDatabaseIdsList = _.map(newDatabaseIds, (database: ViewModels.Database) => {
|
||||
if (database && database.offer && database.offer()) {
|
||||
this._databaseOffers.set(database.id(), database.offer());
|
||||
} else if (database && database.isDatabaseShared && database.isDatabaseShared()) {
|
||||
database.readSettings();
|
||||
}
|
||||
|
||||
return database.id();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<script type="text/html" id="add-database-inputs">
|
||||
<!-- Add database header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span id="databaseTitle" role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span id="databaseTitle" data-bind="text: title"></span>
|
||||
<div class="closeImg" role="button" aria-label="Close pane"
|
||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }" tabindex="0">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
@@ -73,8 +73,8 @@
|
||||
</p>
|
||||
|
||||
<input id="database-id" type="text" aria-required="true" autocomplete="off" pattern="[^/?#\\]*[^/?# \\]"
|
||||
title="May not end with space nor contain characters '\' '/' '#' '?'"
|
||||
size="40" class="collid" data-bind="textInput: databaseId, hasFocus: firstFieldHasFocus, attr: { placeholder: databaseIdPlaceHolder }"
|
||||
title="May not end with space nor contain characters '\' '/' '#' '?'" placeholder="Type a new database id"
|
||||
size="40" class="collid" data-bind="textInput: databaseId, hasFocus: firstFieldHasFocus"
|
||||
aria-label="Database id" autofocus>
|
||||
|
||||
<!-- Database provisioned throughput - Start -->
|
||||
|
||||
@@ -16,7 +16,6 @@ import { PlatformType } from "../../PlatformType";
|
||||
export default class AddDatabasePane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
public databaseIdLabel: ko.Computed<string>;
|
||||
public databaseIdPlaceHolder: ko.Computed<string>;
|
||||
public databaseId: ko.Observable<string>;
|
||||
public databaseIdTooltipText: ko.Computed<string>;
|
||||
public databaseLevelThroughputTooltipText: ko.Computed<string>;
|
||||
@@ -71,11 +70,6 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
||||
this.databaseIdLabel = ko.computed<string>(() =>
|
||||
this.container.isPreferredApiCassandra() ? "Keyspace id" : "Database id"
|
||||
);
|
||||
|
||||
this.databaseIdPlaceHolder = ko.computed<string>(() =>
|
||||
this.container.isPreferredApiCassandra() ? "Type a new keyspace id" : "Type a new database id"
|
||||
);
|
||||
|
||||
this.databaseIdTooltipText = ko.computed<string>(() => {
|
||||
const isCassandraAccount: boolean = this.container.isPreferredApiCassandra();
|
||||
return `A ${isCassandraAccount ? "keyspace" : "database"} is a logical container of one or more ${
|
||||
@@ -337,7 +331,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
||||
const subscriptionType: ViewModels.SubscriptionType =
|
||||
this.container.subscriptionType && this.container.subscriptionType();
|
||||
|
||||
if (subscriptionType === ViewModels.SubscriptionType.EA || this.container.isServerlessEnabled()) {
|
||||
if (subscriptionType === ViewModels.SubscriptionType.EA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="paneContentContainer">
|
||||
<!-- Save Query header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
>
|
||||
<!-- Add Cassandra collection header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -268,6 +268,8 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
||||
const cachedKeyspaceIdsList = _.map(newKeyspaceIds, (keyspace: ViewModels.Database) => {
|
||||
if (keyspace && keyspace.offer && !!keyspace.offer()) {
|
||||
this.keyspaceOffers.set(keyspace.id(), keyspace.offer());
|
||||
} else if (keyspace && keyspace.isDatabaseShared && keyspace.isDatabaseShared()) {
|
||||
keyspace.readSettings();
|
||||
}
|
||||
return keyspace.id();
|
||||
});
|
||||
|
||||
@@ -9,7 +9,6 @@ import Explorer from "../Explorer";
|
||||
|
||||
// TODO: Use specific actions for logging telemetry data
|
||||
export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
|
||||
private initalFocusedElement: HTMLElement | undefined;
|
||||
public id: string;
|
||||
public container: Explorer;
|
||||
public firstFieldHasFocus: ko.Observable<boolean>;
|
||||
@@ -50,11 +49,9 @@ export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
|
||||
this.visible(false);
|
||||
this.isExecuting(false);
|
||||
this.resetData();
|
||||
this.resetFocus();
|
||||
}
|
||||
|
||||
public open() {
|
||||
this.initalFocusedElement = document.activeElement as HTMLElement;
|
||||
this.visible(true);
|
||||
this.firstFieldHasFocus(true);
|
||||
this.resizePane();
|
||||
@@ -126,11 +123,4 @@ export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
|
||||
|
||||
$(paneElement).height(newPaneElementHeight);
|
||||
}
|
||||
|
||||
private resetFocus(): void {
|
||||
if (this.initalFocusedElement) {
|
||||
this.initalFocusedElement.focus();
|
||||
this.initalFocusedElement = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
>
|
||||
<!-- Delete Collection Confirmation header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
@@ -67,7 +67,8 @@
|
||||
name="collectionIdConfirmation"
|
||||
required
|
||||
class="collid"
|
||||
data-bind="value: collectionIdConfirmation, hasFocus: firstFieldHasFocus, attr: { 'aria-label': collectionIdConfirmationText }"
|
||||
data-bind="value: collectionIdConfirmation, hasFocus: firstFieldHasFocus"
|
||||
aria-label="Confirm by typing the collection id"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -134,9 +134,11 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||
expect(telemetryProcessorSpy.called).toBe(true);
|
||||
let deleteFeedback = new DeleteFeedback(SubscriptionId, AccountName, DataModels.ApiKind.SQL, Feedback);
|
||||
expect(
|
||||
telemetryProcessorSpy.calledWith(Action.DeleteCollection, ActionModifiers.Mark, {
|
||||
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
})
|
||||
telemetryProcessorSpy.calledWith(
|
||||
Action.DeleteCollection,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,9 +88,11 @@ export default class DeleteCollectionConfirmationPane extends ContextualPaneBase
|
||||
this.containerDeleteFeedback()
|
||||
);
|
||||
|
||||
TelemetryProcessor.trace(Action.DeleteCollection, ActionModifiers.Mark, {
|
||||
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
});
|
||||
TelemetryProcessor.trace(
|
||||
Action.DeleteCollection,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
);
|
||||
|
||||
this.containerDeleteFeedback("");
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
>
|
||||
<!-- Delete Database Confirmation header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -120,9 +120,11 @@ describe("Delete Database Confirmation Pane", () => {
|
||||
|
||||
return pane.submit().then(() => {
|
||||
let deleteFeedback = new DeleteFeedback(SubscriptionId, AccountName, DataModels.ApiKind.SQL, Feedback);
|
||||
expect(TelemetryProcessor.trace).toHaveBeenCalledWith(Action.DeleteDatabase, ActionModifiers.Mark, {
|
||||
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
});
|
||||
expect(TelemetryProcessor.trace).toHaveBeenCalledWith(
|
||||
Action.DeleteDatabase,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
||||
import { ARMError } from "../../Utils/arm/request";
|
||||
|
||||
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||
public databaseIdConfirmationText: ko.Observable<string>;
|
||||
@@ -97,19 +96,20 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||
this.databaseDeleteFeedback()
|
||||
);
|
||||
|
||||
TelemetryProcessor.trace(Action.DeleteDatabase, ActionModifiers.Mark, {
|
||||
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
});
|
||||
TelemetryProcessor.trace(
|
||||
Action.DeleteDatabase,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
);
|
||||
|
||||
this.databaseDeleteFeedback("");
|
||||
}
|
||||
},
|
||||
(reason: unknown) => {
|
||||
(reason: any) => {
|
||||
this.isExecuting(false);
|
||||
|
||||
const message = reason instanceof ARMError ? reason.message : ErrorParserUtility.parse(reason)[0].message;
|
||||
this.formErrors(message);
|
||||
this.formErrorsDetails(message);
|
||||
const message = ErrorParserUtility.parse(reason);
|
||||
this.formErrors(message[0].message);
|
||||
this.formErrorsDetails(message[0].message);
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.DeleteDatabase,
|
||||
{
|
||||
@@ -130,8 +130,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||
super.resetData();
|
||||
}
|
||||
|
||||
public async open() {
|
||||
await this.container.loadSelectedDatabaseOffer();
|
||||
public open() {
|
||||
this.recordDeleteFeedback(this.shouldRecordFeedback());
|
||||
super.open();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: execute">
|
||||
<!-- Input params header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -70,9 +70,7 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP
|
||||
private renderPanelHeader = (): JSX.Element => {
|
||||
return (
|
||||
<div className="firstdivbg headerline">
|
||||
<span id="databaseTitle" role="heading" aria-level={2}>
|
||||
{this.props.title}
|
||||
</span>
|
||||
<span id="databaseTitle">{this.props.title}</span>
|
||||
<IconButton
|
||||
ariaLabel="Close pane"
|
||||
title="Close pane"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- New Vertex header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2">New Vertex</span>
|
||||
<span>New Vertex</span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Graph Styling header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2">Graph Styling</span>
|
||||
<span>Graph Styling</span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Load Query header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Renew ad-hoc access header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Save Query header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div class="closeImg" role="button" aria-label="Close pane" tabindex="0" data-bind="click: cancel">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Settings Confirmation header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="paneContentContainer">
|
||||
<!-- Setup notebooks header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- String Input header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div class="closeImg" role="button" aria-label="Close pane" tabindex="0" data-bind="click: cancel"></div>
|
||||
</div>
|
||||
<!-- String Input header - End -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="contextual-pane-in">
|
||||
<!-- Switch Directory header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div class="closeImg" role="button" aria-label="Close pane" tabindex="0" data-bind="click: close">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,6 @@ export default class AddTableEntityPane extends TableEntityPane {
|
||||
);
|
||||
this.updateIsActionEnabled();
|
||||
super.open();
|
||||
this.focusValueElement();
|
||||
});
|
||||
} else {
|
||||
this.displayedAttributes(
|
||||
@@ -80,11 +79,7 @@ export default class AddTableEntityPane extends TableEntityPane {
|
||||
);
|
||||
this.updateIsActionEnabled();
|
||||
super.open();
|
||||
this.focusValueElement();
|
||||
}
|
||||
}
|
||||
|
||||
private focusValueElement() {
|
||||
const focusElement = document.getElementById("addTableEntityValue");
|
||||
focusElement && focusElement.focus();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<div
|
||||
id="closeAddEntityPane"
|
||||
class="closeImg"
|
||||
role="button"
|
||||
aria-label="Close pane"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
>
|
||||
<!-- Edit table entity header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Upload File header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div class="closeImg" role="button" aria-label="Close pane" tabindex="0" data-bind="click: cancel">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Upload items header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<span data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
|
||||
@@ -6,6 +6,7 @@ import { AuthType } from "../../AuthType";
|
||||
import { ConsoleDataType } from "../../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as Entities from "./Entities";
|
||||
import EnvironmentUtility from "../../Common/EnvironmentUtility";
|
||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -307,7 +308,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
authType === AuthType.EncryptedToken
|
||||
? Constants.CassandraBackend.guestQueryApi
|
||||
: Constants.CassandraBackend.queryApi;
|
||||
$.ajax(`${collection.container.extensionEndpoint()}${apiEndpoint}`, {
|
||||
$.ajax(`${EnvironmentUtility.getCassandraBackendEndpoint(collection.container)}${apiEndpoint}`, {
|
||||
type: "POST",
|
||||
data: {
|
||||
accountName: collection && collection.container.databaseAccount && collection.container.databaseAccount().name,
|
||||
@@ -558,7 +559,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
authType === AuthType.EncryptedToken
|
||||
? Constants.CassandraBackend.guestKeysApi
|
||||
: Constants.CassandraBackend.keysApi;
|
||||
let endpoint = `${collection.container.extensionEndpoint()}${apiEndpoint}`;
|
||||
let endpoint = `${EnvironmentUtility.getCassandraBackendEndpoint(collection.container)}${apiEndpoint}`;
|
||||
const deferred = Q.defer<CassandraTableKeys>();
|
||||
$.ajax(endpoint, {
|
||||
type: "POST",
|
||||
@@ -613,7 +614,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
authType === AuthType.EncryptedToken
|
||||
? Constants.CassandraBackend.guestSchemaApi
|
||||
: Constants.CassandraBackend.schemaApi;
|
||||
let endpoint = `${collection.container.extensionEndpoint()}${apiEndpoint}`;
|
||||
let endpoint = `${EnvironmentUtility.getCassandraBackendEndpoint(collection.container)}${apiEndpoint}`;
|
||||
const deferred = Q.defer<CassandraTableKey[]>();
|
||||
$.ajax(endpoint, {
|
||||
type: "POST",
|
||||
@@ -667,7 +668,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
authType === AuthType.EncryptedToken
|
||||
? Constants.CassandraBackend.guestCreateOrDeleteApi
|
||||
: Constants.CassandraBackend.createOrDeleteApi;
|
||||
$.ajax(`${explorer.extensionEndpoint()}${apiEndpoint}`, {
|
||||
$.ajax(`${EnvironmentUtility.getCassandraBackendEndpoint(explorer)}${apiEndpoint}`, {
|
||||
type: "POST",
|
||||
data: {
|
||||
accountName: explorer.databaseAccount() && explorer.databaseAccount().name,
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="loadMore">
|
||||
<a role="button" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
<a role="link" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
>Load more</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -598,6 +598,7 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
||||
() => {
|
||||
this.container.isRefreshingExplorer(false);
|
||||
this._setBaseline();
|
||||
this.database.readSettings();
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.UpdateSettings,
|
||||
{
|
||||
@@ -642,9 +643,8 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
||||
};
|
||||
|
||||
public onActivate(): Q.Promise<any> {
|
||||
return super.onActivate().then(async () => {
|
||||
return super.onActivate().then(() => {
|
||||
this.database.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings);
|
||||
await this.database.loadOffer();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="loadMore">
|
||||
<a role="button" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
<a role="link" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
>Load more</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -390,7 +390,7 @@
|
||||
</table>
|
||||
|
||||
<div class="loadMore">
|
||||
<a role="button" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
<a role="link" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
>Load more</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as Constants from "../../Common/Constants";
|
||||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import AuthHeadersUtil from "../../Platform/Hosted/Authorization";
|
||||
import EnvironmentUtility from "../../Common/EnvironmentUtility";
|
||||
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
|
||||
import Q from "q";
|
||||
import TabsBase from "./TabsBase";
|
||||
@@ -108,7 +109,11 @@ export default class MongoShellTab extends TabsBase {
|
||||
) + Constants.MongoDBAccounts.defaultPort.toString();
|
||||
const databaseId = this.collection.databaseId;
|
||||
const collectionId = this.collection.id();
|
||||
const apiEndpoint = this._container.extensionEndpoint();
|
||||
const apiEndpoint = EnvironmentUtility.getMongoBackendEndpoint(
|
||||
this._container.serverId(),
|
||||
userContext.databaseAccount.location,
|
||||
this._container.extensionEndpoint()
|
||||
).replace("/api/mongo/explorer", "");
|
||||
const encryptedAuthToken: string = userContext.accessToken;
|
||||
|
||||
shellIframe.contentWindow.postMessage(
|
||||
@@ -137,7 +142,7 @@ export default class MongoShellTab extends TabsBase {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataToLog = { message: event.data.data.logData };
|
||||
const dataToLog: string = event.data.data.logData;
|
||||
const logType: string = event.data.data.logType;
|
||||
const shellTraceId: string = event.data.data.traceId || "none";
|
||||
|
||||
|
||||
@@ -111,18 +111,17 @@
|
||||
data-bind="visible: isMetricsToggled() && allResultsMetadata().length > 0 && errors().length === 0"
|
||||
>
|
||||
<table class="queryMetricsSummary">
|
||||
<caption>
|
||||
Query Statistics
|
||||
</caption>
|
||||
<thead class="queryMetricsSummaryHead">
|
||||
<tr class="queryMetricsSummaryHeader queryMetricsSummaryTuple">
|
||||
<th title="METRIC" scope="col">METRIC</th>
|
||||
<th title="VALUE" scope="col">VALUE</th>
|
||||
<th title="METRIC">METRIC</th>
|
||||
<th></th>
|
||||
<th title="VALUE">VALUE</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="queryMetricsSummaryBody" data-bind="with: aggregatedQueryMetrics">
|
||||
<tr class="queryMetricsSummaryTuple">
|
||||
<td title="Request Charge">Request Charge</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<span
|
||||
data-bind="text: $parent.requestChargeDisplayText, attr: { title: $parent.requestChargeDisplayText }"
|
||||
@@ -131,6 +130,7 @@
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple">
|
||||
<td title="Showing Results">Showing Results</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<span
|
||||
data-bind="text: $parent.showingDocumentsDisplayText, attr: { title: $parent.showingDocumentsDisplayText }"
|
||||
@@ -138,8 +138,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Retrieved document count">Retrieved document count</span></td>
|
||||
<td>
|
||||
<span title="Retrieved document count">Retrieved document count</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total number of retrieved documents</span>
|
||||
@@ -148,8 +148,8 @@
|
||||
<td><span data-bind="text: retrievedDocumentCount, attr: { title: retrievedDocumentCount }"></span></td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Retrieved document size">Retrieved document size</span></td>
|
||||
<td>
|
||||
<span title="Retrieved document size">Retrieved document size</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total size of retrieved documents in bytes</span>
|
||||
@@ -161,8 +161,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Output document count">Output document count</span></td>
|
||||
<td>
|
||||
<span title="Output document count">Output document count</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Number of output documents</span>
|
||||
@@ -171,8 +171,8 @@
|
||||
<td><span data-bind="text: outputDocumentCount, attr: { title: outputDocumentCount }"></span></td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Output document size">Output document size</span></td>
|
||||
<td>
|
||||
<span title="Output document size">Output document size</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total size of output documents in bytes</span>
|
||||
@@ -184,8 +184,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Index hit document count">Index hit document count</span></td>
|
||||
<td>
|
||||
<span title="Index hit document count">Index hit document count</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total number of documents matched by the filter</span>
|
||||
@@ -194,8 +194,8 @@
|
||||
<td><span data-bind="text: indexHitDocumentCount, attr: { title: indexHitDocumentCount }"></span></td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Index lookup time">Index lookup time</span></td>
|
||||
<td>
|
||||
<span title="Index lookup time">Index lookup time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Time spent in physical index layer</span>
|
||||
@@ -206,8 +206,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Document load time">Document load time</span></td>
|
||||
<td>
|
||||
<span title="Document load time">Document load time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Time spent in loading documents</span>
|
||||
@@ -218,8 +218,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Query engine execution time">Query engine execution time</span></td>
|
||||
<td>
|
||||
<span title="Query engine execution time">Query engine execution time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText queryEngineExeTimeInfo"
|
||||
@@ -236,8 +236,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="System function execution time">System function execution time</span></td>
|
||||
<td>
|
||||
<span title="System function execution time">System function execution time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total time spent executing system (built-in) functions</span>
|
||||
@@ -251,8 +251,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="User defined function execution time">User defined function execution time</span></td>
|
||||
<td>
|
||||
<span title="User defined function execution time">User defined function execution time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Total time spent executing user-defined functions</span>
|
||||
@@ -266,8 +266,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.isQueryMetricsEnabled">
|
||||
<td><span title="Document write time">Document write time</span></td>
|
||||
<td>
|
||||
<span title="Document write time">Document write time</span>
|
||||
<span class="queryMetricInfoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="queryMetricTooltipText">Time spent to write query result set to response buffer</span>
|
||||
@@ -279,6 +279,7 @@
|
||||
</tr>
|
||||
<tr class="queryMetricsSummaryTuple" data-bind="visible: $parent.roundTrips() != null">
|
||||
<td title="Round Trips">Round Trips</td>
|
||||
<td></td>
|
||||
<td><span data-bind="text: $parent.roundTrips, attr: { title: $parent.roundTrips }"></span></td>
|
||||
</tr>
|
||||
<!-- TODO: Report activity id for mongo queries -->
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
margin-left: @MediumSpace;
|
||||
.flex-display();
|
||||
.flex-direction();
|
||||
|
||||
|
||||
|
||||
.togglesWithMetadata {
|
||||
margin-top: @MediumSpace;
|
||||
@@ -102,23 +102,23 @@
|
||||
height: @ToggleHeight;
|
||||
width: @ToggleWidth;
|
||||
margin-left: @MediumSpace;
|
||||
|
||||
|
||||
&:focus {
|
||||
.focus();
|
||||
}
|
||||
|
||||
|
||||
.tab {
|
||||
margin-right: @MediumSpace;
|
||||
}
|
||||
|
||||
|
||||
.toggleSwitch {
|
||||
.toggleSwitch();
|
||||
}
|
||||
|
||||
|
||||
.selectedToggle {
|
||||
.selectedToggle();
|
||||
}
|
||||
|
||||
|
||||
.unselectedToggle {
|
||||
.unselectedToggle();
|
||||
}
|
||||
@@ -136,7 +136,7 @@
|
||||
.queryResultNextEnable {
|
||||
color: @AccentMediumHigh;
|
||||
font-size: @mediumFontSize;
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
height: @ImgHeight;
|
||||
@@ -153,7 +153,7 @@
|
||||
img {
|
||||
height: @ImgHeight;
|
||||
width: @ImgWidth;
|
||||
margin-left: @SmallSpace;
|
||||
margin-left: @SmallSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@
|
||||
cursor: pointer;
|
||||
padding: @SmallSpace;
|
||||
}
|
||||
|
||||
|
||||
.queryMetricsSummaryContainer {
|
||||
.flex-display();
|
||||
.flex-direction();
|
||||
@@ -195,14 +195,10 @@
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
caption {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.queryMetricsSummaryHead {
|
||||
.flex-display();
|
||||
}
|
||||
|
||||
|
||||
.queryMetricsSummaryHeader.queryMetricsSummaryTuple {
|
||||
font-size: 10px;
|
||||
}
|
||||
@@ -211,7 +207,7 @@
|
||||
.flex-display();
|
||||
.flex-direction();
|
||||
}
|
||||
|
||||
|
||||
.queryMetricsSummaryTuple {
|
||||
border-bottom: 1px solid @BaseMedium;
|
||||
height: 32px;
|
||||
@@ -225,14 +221,18 @@
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
flex: 0 0 50%;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
|
||||
.queryMetricInfoTooltip {
|
||||
@@ -264,7 +264,7 @@
|
||||
.tooltipTextAfter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.queryEngineExeTimeInfo {
|
||||
width: @QueryEngineExeInfo;
|
||||
top: -85px;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="error-bar">
|
||||
<div class="error-message" aria-label="Error Message" data-bind="visible: hasQueryError">
|
||||
<span><img class="entity-error-Img" src="/error_red.svg"/></span>
|
||||
<span class="error-text" role="alert" data-bind="text: queryErrorMessage"></span>
|
||||
<span class="error-text" data-bind="text: queryErrorMessage"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tables Query Tab Errors - End-->
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import * as ko from "knockout";
|
||||
import * as monaco from "monaco-editor";
|
||||
import Q from "q";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import * as ko from "knockout";
|
||||
import Q from "q";
|
||||
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
import TabsBase from "./TabsBase";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import * as monaco from "monaco-editor";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
|
||||
export default abstract class ScriptTabBase extends TabsBase implements ViewModels.WaitsForTemplate {
|
||||
public ariaLabel: ko.Observable<string>;
|
||||
@@ -29,8 +30,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
||||
public formIsValid: ko.Computed<boolean>;
|
||||
public formIsDirty: ko.Computed<boolean>;
|
||||
public isNew: ko.Observable<boolean>;
|
||||
// TODO: Remove any. The SDK types for all the script.body are slightly incorrect which makes this REALLY hard to type correct.
|
||||
public resource: ko.Observable<any>;
|
||||
public resource: ko.Observable<DataModels.Script>;
|
||||
public isTemplateReady: ko.Observable<boolean>;
|
||||
protected _partitionKey: DataModels.PartitionKey;
|
||||
|
||||
@@ -194,8 +194,8 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
||||
});
|
||||
}
|
||||
|
||||
public abstract onSaveClick: () => Promise<any>;
|
||||
public abstract onUpdateClick: () => Promise<any>;
|
||||
public abstract onSaveClick: () => Q.Promise<any>;
|
||||
public abstract onUpdateClick: () => Q.Promise<any>;
|
||||
|
||||
public onDiscard = (): Q.Promise<any> => {
|
||||
this.setBaselines();
|
||||
@@ -206,14 +206,14 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
||||
return Q();
|
||||
};
|
||||
|
||||
public onSaveOrUpdateClick(): Promise<any> {
|
||||
public onSaveOrUpdateClick(): Q.Promise<any> {
|
||||
if (this.saveButton.visible()) {
|
||||
return this.onSaveClick();
|
||||
} else if (this.updateButton.visible()) {
|
||||
return this.onUpdateClick();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return Q();
|
||||
}
|
||||
|
||||
protected getTabsButtons(): CommandButtonComponentProps[] {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user