mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 06:56:38 +00:00
Test Explorer Improvements (#541)
This commit is contained in:
parent
f86883de6c
commit
254c551999
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -15,10 +15,10 @@ jobs:
|
|||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: node utils/codeMetrics.js
|
- run: node utils/codeMetrics.js
|
||||||
env:
|
env:
|
||||||
@ -28,10 +28,10 @@ jobs:
|
|||||||
name: "Compile TypeScript"
|
name: "Compile TypeScript"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run compile
|
- run: npm run compile
|
||||||
- run: npm run compile:strict
|
- run: npm run compile:strict
|
||||||
@ -40,10 +40,10 @@ jobs:
|
|||||||
name: "Check Format"
|
name: "Check Format"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run format:check
|
- run: npm run format:check
|
||||||
lint:
|
lint:
|
||||||
@ -51,10 +51,10 @@ jobs:
|
|||||||
name: "Lint"
|
name: "Lint"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
unittest:
|
unittest:
|
||||||
@ -62,10 +62,10 @@ jobs:
|
|||||||
name: "Unit Tests"
|
name: "Unit Tests"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run test
|
- run: npm run test
|
||||||
build:
|
build:
|
||||||
@ -74,10 +74,10 @@ jobs:
|
|||||||
name: "Build"
|
name: "Build"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build:contracts
|
- run: npm run build:contracts
|
||||||
- name: Restore Build Cache
|
- name: Restore Build Cache
|
||||||
@ -98,10 +98,10 @@ jobs:
|
|||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- uses: southpolesteve/cosmos-emulator-github-action@v1
|
- uses: southpolesteve/cosmos-emulator-github-action@v1
|
||||||
- name: End to End Tests
|
- name: End to End Tests
|
||||||
run: |
|
run: |
|
||||||
@ -125,10 +125,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 12.x
|
- name: Use Node.js 14.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12.x
|
node-version: 14.x
|
||||||
- name: Accessibility Check
|
- name: Accessibility Check
|
||||||
run: |
|
run: |
|
||||||
# Ubuntu gets mad when webpack runs too many files watchers
|
# Ubuntu gets mad when webpack runs too many files watchers
|
||||||
@ -163,6 +163,7 @@ jobs:
|
|||||||
TABLES_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_TABLE }}
|
TABLES_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_TABLE }}
|
||||||
DATA_EXPLORER_ENDPOINT: "https://localhost:1234/hostedExplorer.html"
|
DATA_EXPLORER_ENDPOINT: "https://localhost:1234/hostedExplorer.html"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
test-file:
|
test-file:
|
||||||
- ./test/cassandra/container.spec.ts
|
- ./test/cassandra/container.spec.ts
|
||||||
|
110
package-lock.json
generated
110
package-lock.json
generated
@ -949,14 +949,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-class-properties": {
|
"node_modules/@babel/plugin-syntax-class-properties": {
|
||||||
"version": "7.12.1",
|
"version": "7.12.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
|
||||||
"integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==",
|
"integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.10.4"
|
"@babel/helper-plugin-utils": "^7.12.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/plugin-syntax-class-properties/node_modules/@babel/helper-plugin-utils": {
|
||||||
|
"version": "7.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz",
|
||||||
|
"integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@babel/plugin-syntax-decorators": {
|
"node_modules/@babel/plugin-syntax-decorators": {
|
||||||
"version": "7.12.1",
|
"version": "7.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.1.tgz",
|
||||||
@ -1951,9 +1957,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@istanbuljs/schema": {
|
"node_modules/@istanbuljs/schema": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||||
"integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
|
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@ -2127,9 +2133,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jest/globals/node_modules/@types/yargs": {
|
"node_modules/@jest/globals/node_modules/@types/yargs": {
|
||||||
"version": "15.0.12",
|
"version": "15.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||||
"integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==",
|
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -4908,9 +4914,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
"integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==",
|
"integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@ -15439,9 +15445,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest/node_modules/@types/yargs": {
|
"node_modules/jest/node_modules/@types/yargs": {
|
||||||
"version": "15.0.12",
|
"version": "15.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||||
"integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==",
|
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -15756,9 +15762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest/node_modules/fsevents": {
|
"node_modules/jest/node_modules/fsevents": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
"integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==",
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@ -16751,9 +16757,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest/node_modules/string-width": {
|
"node_modules/jest/node_modules/string-width": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
@ -22760,11 +22766,6 @@
|
|||||||
"safer-buffer": "^2.0.2",
|
"safer-buffer": "^2.0.2",
|
||||||
"tweetnacl": "~0.14.0"
|
"tweetnacl": "~0.14.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
|
||||||
"sshpk-conv": "bin/sshpk-conv",
|
|
||||||
"sshpk-sign": "bin/sshpk-sign",
|
|
||||||
"sshpk-verify": "bin/sshpk-verify"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -25098,8 +25099,7 @@
|
|||||||
"node_modules/webcrypto-liner/node_modules/core-js": {
|
"node_modules/webcrypto-liner/node_modules/core-js": {
|
||||||
"version": "3.8.3",
|
"version": "3.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
|
||||||
"integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==",
|
"integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q=="
|
||||||
"hasInstallScript": true
|
|
||||||
},
|
},
|
||||||
"node_modules/webfontloader": {
|
"node_modules/webfontloader": {
|
||||||
"version": "1.6.28",
|
"version": "1.6.28",
|
||||||
@ -27019,12 +27019,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-syntax-class-properties": {
|
"@babel/plugin-syntax-class-properties": {
|
||||||
"version": "7.12.1",
|
"version": "7.12.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
|
||||||
"integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==",
|
"integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-plugin-utils": "^7.10.4"
|
"@babel/helper-plugin-utils": "^7.12.13"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-plugin-utils": {
|
||||||
|
"version": "7.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz",
|
||||||
|
"integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-syntax-decorators": {
|
"@babel/plugin-syntax-decorators": {
|
||||||
@ -27993,9 +28001,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@istanbuljs/schema": {
|
"@istanbuljs/schema": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||||
"integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
|
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jest/console": {
|
"@jest/console": {
|
||||||
@ -28135,9 +28143,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "15.0.12",
|
"version": "15.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||||
"integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==",
|
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -30752,9 +30760,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/graceful-fs": {
|
"@types/graceful-fs": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
"integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==",
|
"integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@ -39218,9 +39226,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "15.0.12",
|
"version": "15.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||||
"integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==",
|
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -39473,9 +39481,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
"integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==",
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@ -40261,9 +40269,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as Cosmos from "@azure/cosmos";
|
import * as Cosmos from "@azure/cosmos";
|
||||||
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
||||||
import { configContext, Platform } from "../ConfigContext";
|
import { configContext, Platform } from "../ConfigContext";
|
||||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
import { userContext } from "../UserContext";
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||||
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
||||||
import { userContext } from "../UserContext";
|
import { getErrorMessage } from "./ErrorHandlingUtils";
|
||||||
|
|
||||||
const _global = typeof self === "undefined" ? window : self;
|
const _global = typeof self === "undefined" ? window : self;
|
||||||
|
|
||||||
|
@ -775,14 +775,8 @@ export default class Explorer {
|
|||||||
$(document.body).click(() => $(".commandDropdownContainer").hide());
|
$(document.body).click(() => $(".commandDropdownContainer").hide());
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO move this to API customization class
|
switch (userContext.apiType) {
|
||||||
this.defaultExperience.subscribe((defaultExperience) => {
|
case "SQL":
|
||||||
const defaultExperienceNormalizedString = (
|
|
||||||
defaultExperience || Constants.DefaultAccountExperience.Default
|
|
||||||
).toLowerCase();
|
|
||||||
|
|
||||||
switch (defaultExperienceNormalizedString) {
|
|
||||||
case Constants.DefaultAccountExperience.DocumentDB.toLowerCase():
|
|
||||||
this.addCollectionText("New Container");
|
this.addCollectionText("New Container");
|
||||||
this.addDatabaseText("New Database");
|
this.addDatabaseText("New Database");
|
||||||
this.collectionTitle("SQL API");
|
this.collectionTitle("SQL API");
|
||||||
@ -798,8 +792,7 @@ export default class Explorer {
|
|||||||
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the container id");
|
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the container id");
|
||||||
this.refreshTreeTitle("Refresh containers");
|
this.refreshTreeTitle("Refresh containers");
|
||||||
break;
|
break;
|
||||||
case Constants.DefaultAccountExperience.MongoDB.toLowerCase():
|
case "Mongo":
|
||||||
case Constants.DefaultAccountExperience.ApiForMongoDB.toLowerCase():
|
|
||||||
this.addCollectionText("New Collection");
|
this.addCollectionText("New Collection");
|
||||||
this.addDatabaseText("New Database");
|
this.addDatabaseText("New Database");
|
||||||
this.collectionTitle("Collections");
|
this.collectionTitle("Collections");
|
||||||
@ -813,7 +806,7 @@ export default class Explorer {
|
|||||||
);
|
);
|
||||||
this.refreshTreeTitle("Refresh collections");
|
this.refreshTreeTitle("Refresh collections");
|
||||||
break;
|
break;
|
||||||
case Constants.DefaultAccountExperience.Graph.toLowerCase():
|
case "Gremlin":
|
||||||
this.addCollectionText("New Graph");
|
this.addCollectionText("New Graph");
|
||||||
this.addDatabaseText("New Database");
|
this.addDatabaseText("New Database");
|
||||||
this.deleteCollectionText("Delete Graph");
|
this.deleteCollectionText("Delete Graph");
|
||||||
@ -827,7 +820,7 @@ export default class Explorer {
|
|||||||
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the graph id");
|
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the graph id");
|
||||||
this.refreshTreeTitle("Refresh graphs");
|
this.refreshTreeTitle("Refresh graphs");
|
||||||
break;
|
break;
|
||||||
case Constants.DefaultAccountExperience.Table.toLowerCase():
|
case "Tables":
|
||||||
this.addCollectionText("New Table");
|
this.addCollectionText("New Table");
|
||||||
this.addDatabaseText("New Database");
|
this.addDatabaseText("New Database");
|
||||||
this.deleteCollectionText("Delete Table");
|
this.deleteCollectionText("Delete Table");
|
||||||
@ -844,7 +837,7 @@ export default class Explorer {
|
|||||||
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the table id");
|
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the table id");
|
||||||
this.tableDataClient = new TablesAPIDataClient();
|
this.tableDataClient = new TablesAPIDataClient();
|
||||||
break;
|
break;
|
||||||
case Constants.DefaultAccountExperience.Cassandra.toLowerCase():
|
case "Cassandra":
|
||||||
this.addCollectionText("New Table");
|
this.addCollectionText("New Table");
|
||||||
this.addDatabaseText("New Keyspace");
|
this.addDatabaseText("New Keyspace");
|
||||||
this.deleteCollectionText("Delete Table");
|
this.deleteCollectionText("Delete Table");
|
||||||
@ -864,7 +857,6 @@ export default class Explorer {
|
|||||||
this.tableDataClient = new CassandraAPIDataClient();
|
this.tableDataClient = new CassandraAPIDataClient();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
|
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
|
||||||
|
|
||||||
|
149
src/Main.tsx
149
src/Main.tsx
@ -1,74 +1,70 @@
|
|||||||
// CSS Dependencies
|
// CSS Dependencies
|
||||||
|
import "abort-controller/polyfill";
|
||||||
|
import "babel-polyfill";
|
||||||
import "bootstrap/dist/css/bootstrap.css";
|
import "bootstrap/dist/css/bootstrap.css";
|
||||||
import "../less/documentDB.less";
|
import "es6-object-assign/auto";
|
||||||
import "../less/tree.less";
|
import "es6-symbol/implement";
|
||||||
import "../less/forms.less";
|
import "object.entries/auto";
|
||||||
import "../less/menus.less";
|
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
|
||||||
import "../less/infobox.less";
|
import "promise-polyfill/src/polyfill";
|
||||||
import "../less/messagebox.less";
|
import "promise.prototype.finally/auto";
|
||||||
import "./Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.less";
|
import React, { useState } from "react";
|
||||||
import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
|
import ReactDOM from "react-dom";
|
||||||
import "./Explorer/Menus/CommandBar/CommandBarComponent.less";
|
import "url-polyfill/url-polyfill.min";
|
||||||
import "./Explorer/Menus/CommandBar/MemoryTrackerComponent.less";
|
import "webcrypto-liner/build/webcrypto-liner.shim.min";
|
||||||
import "./Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.less";
|
import "whatwg-fetch";
|
||||||
import "./Explorer/Controls/DynamicList/DynamicListComponent.less";
|
|
||||||
import "./Explorer/Controls/JsonEditor/JsonEditorComponent.less";
|
|
||||||
import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less";
|
|
||||||
import "./Explorer/Panes/PanelComponent.less";
|
|
||||||
import "../less/TableStyles/queryBuilder.less";
|
|
||||||
import "../externals/jquery.dataTables.min.css";
|
|
||||||
import "../less/TableStyles/fulldatatables.less";
|
|
||||||
import "../less/TableStyles/EntityEditor.less";
|
|
||||||
import "../less/TableStyles/CustomizeColumns.less";
|
|
||||||
import "../less/resourceTree.less";
|
|
||||||
import "../externals/jquery.typeahead.min.css";
|
|
||||||
import "../externals/jquery-ui.min.css";
|
import "../externals/jquery-ui.min.css";
|
||||||
|
import "../externals/jquery-ui.min.js";
|
||||||
import "../externals/jquery-ui.structure.min.css";
|
import "../externals/jquery-ui.structure.min.css";
|
||||||
import "../externals/jquery-ui.theme.min.css";
|
import "../externals/jquery-ui.theme.min.css";
|
||||||
import "./Explorer/Graph/NewVertexComponent/newVertexComponent.less";
|
import "../externals/jquery.dataTables.min.css";
|
||||||
import "./Explorer/Panes/GraphNewVertexPane.less";
|
import "../externals/jquery.typeahead.min.css";
|
||||||
import "./Explorer/Tabs/QueryTab.less";
|
import "../externals/jquery.typeahead.min.js";
|
||||||
import "./Explorer/Controls/TreeComponent/treeComponent.less";
|
|
||||||
import "./Explorer/Controls/Accordion/AccordionComponent.less";
|
|
||||||
import "./Explorer/SplashScreen/SplashScreen.less";
|
|
||||||
import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less";
|
|
||||||
|
|
||||||
// Image Dependencies
|
// Image Dependencies
|
||||||
import "../images/CosmosDB_rgb_ui_lighttheme.ico";
|
import "../images/CosmosDB_rgb_ui_lighttheme.ico";
|
||||||
import "../images/favicon.ico";
|
import "../images/favicon.ico";
|
||||||
|
|
||||||
import "./Shared/appInsights";
|
|
||||||
import "babel-polyfill";
|
|
||||||
import "es6-symbol/implement";
|
|
||||||
import "webcrypto-liner/build/webcrypto-liner.shim.min";
|
|
||||||
import "./Libs/jquery";
|
|
||||||
import "bootstrap/dist/js/npm";
|
|
||||||
import "../externals/jquery.typeahead.min.js";
|
|
||||||
import "../externals/jquery-ui.min.js";
|
|
||||||
import "promise-polyfill/src/polyfill";
|
|
||||||
import "abort-controller/polyfill";
|
|
||||||
import "whatwg-fetch";
|
|
||||||
import "es6-object-assign/auto";
|
|
||||||
import "promise.prototype.finally/auto";
|
|
||||||
import "object.entries/auto";
|
|
||||||
import "./Libs/is-integer-polyfill";
|
|
||||||
import "url-polyfill/url-polyfill.min";
|
|
||||||
|
|
||||||
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
|
|
||||||
import { ExplorerParams } from "./Explorer/Explorer";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
import hdeConnectImage from "../images/HdeConnectCosmosDB.svg";
|
import hdeConnectImage from "../images/HdeConnectCosmosDB.svg";
|
||||||
import refreshImg from "../images/refresh-cosmos.svg";
|
|
||||||
import arrowLeftImg from "../images/imgarrowlefticon.svg";
|
import arrowLeftImg from "../images/imgarrowlefticon.svg";
|
||||||
import { KOCommentEnd, KOCommentIfStart } from "./koComment";
|
import refreshImg from "../images/refresh-cosmos.svg";
|
||||||
|
import "../less/documentDB.less";
|
||||||
|
import "../less/forms.less";
|
||||||
|
import "../less/infobox.less";
|
||||||
|
import "../less/menus.less";
|
||||||
|
import "../less/messagebox.less";
|
||||||
|
import "../less/resourceTree.less";
|
||||||
|
import "../less/TableStyles/CustomizeColumns.less";
|
||||||
|
import "../less/TableStyles/EntityEditor.less";
|
||||||
|
import "../less/TableStyles/fulldatatables.less";
|
||||||
|
import "../less/TableStyles/queryBuilder.less";
|
||||||
|
import "../less/tree.less";
|
||||||
|
import "./Explorer/Controls/Accordion/AccordionComponent.less";
|
||||||
|
import "./Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.less";
|
||||||
|
import { Dialog, DialogProps } from "./Explorer/Controls/Dialog";
|
||||||
|
import "./Explorer/Controls/DynamicList/DynamicListComponent.less";
|
||||||
|
import "./Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.less";
|
||||||
|
import "./Explorer/Controls/JsonEditor/JsonEditorComponent.less";
|
||||||
|
import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less";
|
||||||
|
import "./Explorer/Controls/TreeComponent/treeComponent.less";
|
||||||
|
import { ExplorerParams } from "./Explorer/Explorer";
|
||||||
|
import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less";
|
||||||
|
import "./Explorer/Graph/NewVertexComponent/newVertexComponent.less";
|
||||||
|
import "./Explorer/Menus/CommandBar/CommandBarComponent.less";
|
||||||
|
import "./Explorer/Menus/CommandBar/MemoryTrackerComponent.less";
|
||||||
|
import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
|
||||||
|
import { NotificationConsoleComponent } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
|
import "./Explorer/Panes/GraphNewVertexPane.less";
|
||||||
|
import "./Explorer/Panes/PanelComponent.less";
|
||||||
|
import { PanelContainerComponent } from "./Explorer/Panes/PanelContainerComponent";
|
||||||
|
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
|
||||||
|
import "./Explorer/SplashScreen/SplashScreen.less";
|
||||||
|
import "./Explorer/Tabs/QueryTab.less";
|
||||||
import { useConfig } from "./hooks/useConfig";
|
import { useConfig } from "./hooks/useConfig";
|
||||||
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
|
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
|
||||||
import { useSidePanel } from "./hooks/useSidePanel";
|
import { useSidePanel } from "./hooks/useSidePanel";
|
||||||
import { NotificationConsoleComponent } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
import { KOCommentEnd, KOCommentIfStart } from "./koComment";
|
||||||
import { PanelContainerComponent } from "./Explorer/Panes/PanelContainerComponent";
|
import "./Libs/is-integer-polyfill";
|
||||||
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
|
import "./Libs/jquery";
|
||||||
import { Dialog, DialogProps } from "./Explorer/Controls/Dialog";
|
import "./Shared/appInsights";
|
||||||
|
|
||||||
initializeIcons();
|
initializeIcons();
|
||||||
|
|
||||||
@ -103,6 +99,10 @@ const App: React.FunctionComponent = () => {
|
|||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const explorer = useKnockoutExplorer(config?.platform, explorerParams);
|
const explorer = useKnockoutExplorer(config?.platform, explorerParams);
|
||||||
|
|
||||||
|
if (!explorer) {
|
||||||
|
return <LoadingExplorer />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flexContainer">
|
<div className="flexContainer">
|
||||||
<div id="divExplorer" className="flexContainer hideOverflows" style={{ display: "none" }}>
|
<div id="divExplorer" className="flexContainer hideOverflows" style={{ display: "none" }}>
|
||||||
@ -236,21 +236,6 @@ const App: React.FunctionComponent = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Global loader - Start */}
|
|
||||||
<div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer">
|
|
||||||
<div className="splashLoaderContentContainer">
|
|
||||||
<p className="connectExplorerContent">
|
|
||||||
<img src={hdeConnectImage} alt="Azure Cosmos DB" />
|
|
||||||
</p>
|
|
||||||
<p className="splashLoaderTitle" id="explorerLoadingStatusTitle">
|
|
||||||
Welcome to Azure Cosmos DB
|
|
||||||
</p>
|
|
||||||
<p className="splashLoaderText" id="explorerLoadingStatusText" role="alert">
|
|
||||||
Connecting...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Global loader - End */}
|
|
||||||
<PanelContainerComponent
|
<PanelContainerComponent
|
||||||
isOpen={isPanelOpen}
|
isOpen={isPanelOpen}
|
||||||
panelContent={panelContent}
|
panelContent={panelContent}
|
||||||
@ -294,3 +279,21 @@ const App: React.FunctionComponent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.body);
|
ReactDOM.render(<App />, document.body);
|
||||||
|
|
||||||
|
function LoadingExplorer(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="splashLoaderContainer">
|
||||||
|
<div className="splashLoaderContentContainer">
|
||||||
|
<p className="connectExplorerContent">
|
||||||
|
<img src={hdeConnectImage} alt="Azure Cosmos DB" />
|
||||||
|
</p>
|
||||||
|
<p className="splashLoaderTitle" id="explorerLoadingStatusTitle">
|
||||||
|
Welcome to Azure Cosmos DB
|
||||||
|
</p>
|
||||||
|
<p className="splashLoaderText" id="explorerLoadingStatusText" role="alert">
|
||||||
|
Connecting...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { applyExplorerBindings } from "../applyExplorerBindings";
|
import { applyExplorerBindings } from "../applyExplorerBindings";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { AccountKind, DefaultAccountExperience } from "../Common/Constants";
|
import { AccountKind, DefaultAccountExperience } from "../Common/Constants";
|
||||||
@ -32,53 +32,65 @@ import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
|
|||||||
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
||||||
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
|
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
|
||||||
// Pleas tread carefully :)
|
// Pleas tread carefully :)
|
||||||
let explorer: Explorer;
|
|
||||||
|
|
||||||
export function useKnockoutExplorer(platform: Platform, explorerParams: ExplorerParams): Explorer {
|
export function useKnockoutExplorer(platform: Platform, explorerParams: ExplorerParams): Explorer {
|
||||||
explorer = explorer || new Explorer(explorerParams);
|
const [explorer, setExplorer] = useState<Explorer>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const effect = async () => {
|
const effect = async () => {
|
||||||
if (platform) {
|
if (platform) {
|
||||||
if (platform === Platform.Hosted) {
|
if (platform === Platform.Hosted) {
|
||||||
await configureHosted();
|
const explorer = await configureHosted(explorerParams);
|
||||||
applyExplorerBindings(explorer);
|
setExplorer(explorer);
|
||||||
} else if (platform === Platform.Emulator) {
|
} else if (platform === Platform.Emulator) {
|
||||||
configureEmulator();
|
const explorer = configureEmulator(explorerParams);
|
||||||
applyExplorerBindings(explorer);
|
setExplorer(explorer);
|
||||||
} else if (platform === Platform.Portal) {
|
} else if (platform === Platform.Portal) {
|
||||||
configurePortal();
|
const explorer = await configurePortal(explorerParams);
|
||||||
|
setExplorer(explorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
effect();
|
effect();
|
||||||
}, [platform]);
|
}, [platform]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (explorer) {
|
||||||
|
applyExplorerBindings(explorer);
|
||||||
|
}
|
||||||
|
}, [explorer]);
|
||||||
|
|
||||||
return explorer;
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function configureHosted() {
|
async function configureHosted(explorerParams: ExplorerParams): Promise<Explorer> {
|
||||||
const win = (window as unknown) as HostedExplorerChildFrame;
|
const win = (window as unknown) as HostedExplorerChildFrame;
|
||||||
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
|
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
|
||||||
configureHostedWithEncryptedToken(win.hostedConfig);
|
return configureHostedWithEncryptedToken(win.hostedConfig, explorerParams);
|
||||||
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
|
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
|
||||||
configureHostedWithResourceToken(win.hostedConfig);
|
return configureHostedWithResourceToken(win.hostedConfig, explorerParams);
|
||||||
} else if (win.hostedConfig.authType === AuthType.ConnectionString) {
|
} else if (win.hostedConfig.authType === AuthType.ConnectionString) {
|
||||||
configureHostedWithConnectionString(win.hostedConfig);
|
return configureHostedWithConnectionString(win.hostedConfig, explorerParams);
|
||||||
} else if (win.hostedConfig.authType === AuthType.AAD) {
|
} else if (win.hostedConfig.authType === AuthType.AAD) {
|
||||||
await configureHostedWithAAD(win.hostedConfig);
|
return configureHostedWithAAD(win.hostedConfig, explorerParams);
|
||||||
}
|
}
|
||||||
|
throw new Error(`Unknown hosted config: ${win.hostedConfig}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function configureHostedWithAAD(config: AAD) {
|
async function configureHostedWithAAD(config: AAD, explorerParams: ExplorerParams): Promise<Explorer> {
|
||||||
const account = config.databaseAccount;
|
const account = config.databaseAccount;
|
||||||
const accountResourceId = account.id;
|
const accountResourceId = account.id;
|
||||||
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
|
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
|
||||||
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
|
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
|
subscriptionId,
|
||||||
|
resourceGroup,
|
||||||
authType: AuthType.AAD,
|
authType: AuthType.AAD,
|
||||||
authorizationToken: `Bearer ${config.authorizationToken}`,
|
authorizationToken: `Bearer ${config.authorizationToken}`,
|
||||||
databaseAccount: config.databaseAccount,
|
databaseAccount: config.databaseAccount,
|
||||||
});
|
});
|
||||||
const keys = await listKeys(subscriptionId, resourceGroup, account.name);
|
const keys = await listKeys(subscriptionId, resourceGroup, account.name);
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure({
|
explorer.configure({
|
||||||
databaseAccount: account,
|
databaseAccount: account,
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
@ -87,9 +99,10 @@ async function configureHostedWithAAD(config: AAD) {
|
|||||||
authorizationToken: `Bearer ${config.authorizationToken}`,
|
authorizationToken: `Bearer ${config.authorizationToken}`,
|
||||||
features: extractFeatures(),
|
features: extractFeatures(),
|
||||||
});
|
});
|
||||||
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureHostedWithConnectionString(config: ConnectionString) {
|
function configureHostedWithConnectionString(config: ConnectionString, explorerParams: ExplorerParams): Explorer {
|
||||||
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
||||||
const databaseAccount = {
|
const databaseAccount = {
|
||||||
id: "",
|
id: "",
|
||||||
@ -106,14 +119,16 @@ function configureHostedWithConnectionString(config: ConnectionString) {
|
|||||||
accessToken: encodeURIComponent(config.encryptedToken),
|
accessToken: encodeURIComponent(config.encryptedToken),
|
||||||
databaseAccount,
|
databaseAccount,
|
||||||
});
|
});
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure({
|
explorer.configure({
|
||||||
databaseAccount,
|
databaseAccount,
|
||||||
masterKey: config.masterKey,
|
masterKey: config.masterKey,
|
||||||
features: extractFeatures(),
|
features: extractFeatures(),
|
||||||
});
|
});
|
||||||
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureHostedWithResourceToken(config: ResourceToken) {
|
function configureHostedWithResourceToken(config: ResourceToken, explorerParams: ExplorerParams): Explorer {
|
||||||
const parsedResourceToken = parseResourceTokenConnectionString(config.resourceToken);
|
const parsedResourceToken = parseResourceTokenConnectionString(config.resourceToken);
|
||||||
const databaseAccount = {
|
const databaseAccount = {
|
||||||
id: "",
|
id: "",
|
||||||
@ -131,6 +146,7 @@ function configureHostedWithResourceToken(config: ResourceToken) {
|
|||||||
resourceToken: parsedResourceToken.resourceToken,
|
resourceToken: parsedResourceToken.resourceToken,
|
||||||
endpoint: parsedResourceToken.accountEndpoint,
|
endpoint: parsedResourceToken.accountEndpoint,
|
||||||
});
|
});
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.resourceTokenDatabaseId(parsedResourceToken.databaseId);
|
explorer.resourceTokenDatabaseId(parsedResourceToken.databaseId);
|
||||||
explorer.resourceTokenCollectionId(parsedResourceToken.collectionId);
|
explorer.resourceTokenCollectionId(parsedResourceToken.collectionId);
|
||||||
if (parsedResourceToken.partitionKey) {
|
if (parsedResourceToken.partitionKey) {
|
||||||
@ -142,9 +158,10 @@ function configureHostedWithResourceToken(config: ResourceToken) {
|
|||||||
isAuthWithresourceToken: true,
|
isAuthWithresourceToken: true,
|
||||||
});
|
});
|
||||||
explorer.isRefreshingExplorer(false);
|
explorer.isRefreshingExplorer(false);
|
||||||
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureHostedWithEncryptedToken(config: EncryptedToken) {
|
function configureHostedWithEncryptedToken(config: EncryptedToken, explorerParams: ExplorerParams): Explorer {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.EncryptedToken,
|
authType: AuthType.EncryptedToken,
|
||||||
accessToken: encodeURIComponent(config.encryptedToken),
|
accessToken: encodeURIComponent(config.encryptedToken),
|
||||||
@ -152,6 +169,7 @@ function configureHostedWithEncryptedToken(config: EncryptedToken) {
|
|||||||
const apiExperience: string = DefaultExperienceUtility.getDefaultExperienceFromApiKind(
|
const apiExperience: string = DefaultExperienceUtility.getDefaultExperienceFromApiKind(
|
||||||
config.encryptedTokenMetadata.apiKind
|
config.encryptedTokenMetadata.apiKind
|
||||||
);
|
);
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure({
|
explorer.configure({
|
||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
id: "",
|
id: "",
|
||||||
@ -162,21 +180,25 @@ function configureHostedWithEncryptedToken(config: EncryptedToken) {
|
|||||||
},
|
},
|
||||||
features: extractFeatures(),
|
features: extractFeatures(),
|
||||||
});
|
});
|
||||||
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureEmulator() {
|
function configureEmulator(explorerParams: ExplorerParams): Explorer {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
databaseAccount: emulatorAccount,
|
databaseAccount: emulatorAccount,
|
||||||
authType: AuthType.MasterKey,
|
authType: AuthType.MasterKey,
|
||||||
});
|
});
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.databaseAccount(emulatorAccount);
|
explorer.databaseAccount(emulatorAccount);
|
||||||
explorer.isAccountReady(true);
|
explorer.isAccountReady(true);
|
||||||
|
return explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configurePortal() {
|
async function configurePortal(explorerParams: ExplorerParams): Promise<Explorer> {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.AAD,
|
authType: AuthType.AAD,
|
||||||
});
|
});
|
||||||
|
return new Promise((resolve) => {
|
||||||
// In development mode, try to load the iframe message from session storage.
|
// In development mode, try to load the iframe message from session storage.
|
||||||
// This allows webpack hot reload to function properly in the portal
|
// This allows webpack hot reload to function properly in the portal
|
||||||
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
|
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
|
||||||
@ -187,8 +209,9 @@ function configurePortal() {
|
|||||||
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
|
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
|
||||||
);
|
);
|
||||||
console.dir(message);
|
console.dir(message);
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure(message);
|
explorer.configure(message);
|
||||||
applyExplorerBindings(explorer);
|
resolve(explorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,8 +259,9 @@ function configurePortal() {
|
|||||||
quotaId: inputs.quotaId,
|
quotaId: inputs.quotaId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure(inputs);
|
explorer.configure(inputs);
|
||||||
applyExplorerBindings(explorer);
|
resolve(explorer);
|
||||||
if (openAction) {
|
if (openAction) {
|
||||||
handleOpenAction(openAction, explorer.nonSystemDatabases(), explorer);
|
handleOpenAction(openAction, explorer.nonSystemDatabases(), explorer);
|
||||||
}
|
}
|
||||||
@ -247,6 +271,7 @@ function configurePortal() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
sendMessage("ready");
|
sendMessage("ready");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldProcessMessage(event: MessageEvent): boolean {
|
function shouldProcessMessage(event: MessageEvent): boolean {
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import "expect-puppeteer";
|
import "expect-puppeteer";
|
||||||
import { getTestExplorerFrame } from "../testExplorer/TestExplorerUtils";
|
import { createDatabase, generateUniqueName, onClickSaveButton } from "../utils/shared";
|
||||||
import { createDatabase, onClickSaveButton } from "../utils/shared";
|
|
||||||
import { generateUniqueName } from "../utils/shared";
|
|
||||||
import { ApiKind } from "../../src/Contracts/DataModels";
|
|
||||||
|
|
||||||
const LOADING_STATE_DELAY = 5000;
|
const LOADING_STATE_DELAY = 5000;
|
||||||
jest.setTimeout(300000);
|
jest.setTimeout(300000);
|
||||||
@ -12,7 +9,9 @@ describe("MongoDB Index policy tests", () => {
|
|||||||
try {
|
try {
|
||||||
const singleFieldId = generateUniqueName("key");
|
const singleFieldId = generateUniqueName("key");
|
||||||
const wildCardId = generateUniqueName("key") + "$**";
|
const wildCardId = generateUniqueName("key") + "$**";
|
||||||
const frame = await getTestExplorerFrame(ApiKind.MongoDB);
|
await page.goto("https://localhost:1234/testExplorer.html?accountName=portal-mongo-runner");
|
||||||
|
const handle = await page.waitForSelector("iframe");
|
||||||
|
const frame = await handle.contentFrame();
|
||||||
const dropDown = "Index Type ";
|
const dropDown = "Index Type ";
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
@ -20,24 +19,18 @@ describe("MongoDB Index policy tests", () => {
|
|||||||
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
||||||
await frame.waitFor(LOADING_STATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
||||||
const dbId = await createDatabase(frame);
|
const { databaseId, collectionId } = await createDatabase(frame);
|
||||||
await frame.waitFor(25000);
|
await frame.waitFor(25000);
|
||||||
// click on database
|
// click on database
|
||||||
await frame.waitForSelector(`div[data-test="${dbId}"]`);
|
await frame.waitForSelector(`div[data-test="${databaseId}"]`);
|
||||||
await frame.waitFor(LOADING_STATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
await frame.click(`div[data-test="${dbId}"]`);
|
await frame.click(`div[data-test="${databaseId}"]`);
|
||||||
await frame.waitFor(LOADING_STATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
|
|
||||||
// click on scale & setting
|
// click on scale & setting
|
||||||
const containers = await frame.$$(
|
await frame.waitFor(`div[data-test="${collectionId}"]`), { visible: true };
|
||||||
`div[class="nodeChildren"] > div[class="collectionHeader main2 nodeItem "]> div[class="treeNodeHeader "]`
|
|
||||||
);
|
|
||||||
const selectedContainer = (await frame.evaluate((element) => element.innerText, containers[0]))
|
|
||||||
.replace(/[\u{0080}-\u{FFFF}]/gu, "")
|
|
||||||
.trim();
|
|
||||||
await frame.waitFor(`div[data-test="${selectedContainer}"]`), { visible: true };
|
|
||||||
await frame.waitFor(LOADING_STATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
await frame.click(`div[data-test="${selectedContainer}"]`);
|
await frame.click(`div[data-test="${collectionId}"]`);
|
||||||
|
|
||||||
await frame.waitFor(`div[data-test="Scale & Settings"]`), { visible: true };
|
await frame.waitFor(`div[data-test="Scale & Settings"]`), { visible: true };
|
||||||
await frame.waitFor(LOADING_STATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import { uploadNotebookIfNotExist } from "./notebookTestUtils";
|
import { uploadNotebookIfNotExist } from "./notebookTestUtils";
|
||||||
import { ElementHandle, Frame } from "puppeteer";
|
|
||||||
import { getTestExplorerFrame } from "../testExplorer/TestExplorerUtils";
|
|
||||||
|
|
||||||
jest.setTimeout(300000);
|
jest.setTimeout(300000);
|
||||||
|
|
||||||
const notebookName = "GettingStarted.ipynb";
|
const notebookName = "GettingStarted.ipynb";
|
||||||
let frame: Frame;
|
|
||||||
let uploadedNotebookNode: ElementHandle<Element>;
|
|
||||||
|
|
||||||
describe("Notebook UI tests", () => {
|
describe("Notebook UI tests", () => {
|
||||||
it("Upload, Open and Delete Notebook", async () => {
|
it("Upload, Open and Delete Notebook", async () => {
|
||||||
try {
|
try {
|
||||||
frame = await getTestExplorerFrame();
|
await page.goto("https://localhost:1234/testExplorer.html");
|
||||||
|
const handle = await page.waitForSelector("iframe");
|
||||||
|
const frame = await handle.contentFrame();
|
||||||
await frame.waitForSelector(".galleryHeader");
|
await frame.waitForSelector(".galleryHeader");
|
||||||
uploadedNotebookNode = await uploadNotebookIfNotExist(frame, notebookName);
|
const uploadedNotebookNode = await uploadNotebookIfNotExist(frame, notebookName);
|
||||||
await uploadedNotebookNode.click();
|
await uploadedNotebookNode.click();
|
||||||
await frame.waitForSelector(".tabNavText");
|
await frame.waitForSelector(".tabNavText");
|
||||||
const tabTitle = await frame.$eval(".tabNavText", (element) => element.textContent);
|
const tabTitle = await frame.$eval(".tabNavText", (element) => element.textContent);
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
import { Frame } from "puppeteer";
|
|
||||||
import { TestExplorerParams } from "../testExplorer/TestExplorerParams";
|
|
||||||
import { getTestExplorerFrame } from "../testExplorer/TestExplorerUtils";
|
|
||||||
import { SelfServeType } from "../../src/SelfServe/SelfServeUtils";
|
|
||||||
import { ApiKind } from "../../src/Contracts/DataModels";
|
|
||||||
|
|
||||||
jest.setTimeout(300000);
|
jest.setTimeout(300000);
|
||||||
|
|
||||||
let frame: Frame;
|
|
||||||
describe("Self Serve", () => {
|
describe("Self Serve", () => {
|
||||||
it("Launch Self Serve Example", async () => {
|
it("Launch Self Serve Example", async () => {
|
||||||
try {
|
try {
|
||||||
frame = await getTestExplorerFrame(
|
await page.goto("https://localhost:1234/testExplorer.html?iframeSrc=selfServe.html");
|
||||||
ApiKind.SQL,
|
const handle = await page.waitForSelector("iframe");
|
||||||
new Map<string, string>([[TestExplorerParams.selfServeType, SelfServeType.example]])
|
const frame = await handle.contentFrame();
|
||||||
);
|
|
||||||
|
|
||||||
// wait for refresh RP call to end
|
// wait for refresh RP call to end
|
||||||
await frame.waitFor(10000);
|
await frame.waitFor(10000);
|
||||||
|
@ -1,82 +1,50 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
|
import { ClientSecretCredential } from "@azure/identity";
|
||||||
import "../../less/hostedexplorer.less";
|
import "../../less/hostedexplorer.less";
|
||||||
import { TestExplorerParams } from "./TestExplorerParams";
|
import { DataExplorerInputsFrame } from "../../src/Contracts/ViewModels";
|
||||||
import { CosmosDBManagementClient } from "@azure/arm-cosmosdb";
|
import { updateUserContext } from "../../src/UserContext";
|
||||||
import * as msRest from "@azure/ms-rest-js";
|
import { get, listKeys } from "../../src/Utils/arm/generatedClients/2020-04-01/databaseAccounts";
|
||||||
import * as ViewModels from "../../src/Contracts/ViewModels";
|
|
||||||
import { Capability, DatabaseAccount } from "../../src/Contracts/DataModels";
|
|
||||||
|
|
||||||
class CustomSigner implements msRest.ServiceClientCredentials {
|
const resourceGroup = process.env.RESOURCE_GROUP || "";
|
||||||
private token: string;
|
const subscriptionId = process.env.SUBSCRIPTION_ID || "";
|
||||||
constructor(token: string) {
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
this.token = token;
|
const accountName = urlSearchParams.get("accountName") || "portal-sql-runner";
|
||||||
|
const selfServeType = urlSearchParams.get("selfServeType") || "example";
|
||||||
|
const iframeSrc = urlSearchParams.get("iframeSrc") || "explorer.html?platform=Portal&disablePortalInitCache";
|
||||||
|
|
||||||
|
if (!process.env.AZURE_CLIENT_SECRET) {
|
||||||
|
throw new Error(
|
||||||
|
"process.env.AZURE_CLIENT_SECRET was not set! Set it in your .env file and restart webpack dev server"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async signRequest(webResource: msRest.WebResourceLike): Promise<msRest.WebResourceLike> {
|
// Azure SDK clients accept the credential as a parameter
|
||||||
webResource.headers.set("authorization", `bearer ${this.token}`);
|
const credentials = new ClientSecretCredential(
|
||||||
return webResource;
|
process.env.AZURE_TENANT_ID,
|
||||||
|
process.env.AZURE_CLIENT_ID,
|
||||||
|
process.env.AZURE_CLIENT_SECRET,
|
||||||
|
{
|
||||||
|
authorityHost: "https://localhost:1234",
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const getDatabaseAccount = async (
|
|
||||||
token: string,
|
|
||||||
notebooksAccountSubscriptonId: string,
|
|
||||||
notebooksAccountResourceGroup: string,
|
|
||||||
notebooksAccountName: string
|
|
||||||
): Promise<DatabaseAccount> => {
|
|
||||||
const client = new CosmosDBManagementClient(new CustomSigner(token), notebooksAccountSubscriptonId);
|
|
||||||
const databaseAccountGetResponse = await client.databaseAccounts.get(
|
|
||||||
notebooksAccountResourceGroup,
|
|
||||||
notebooksAccountName
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const databaseAccount: DatabaseAccount = {
|
console.log("Resource Group:", resourceGroup);
|
||||||
id: databaseAccountGetResponse.id,
|
console.log("Subcription: ", subscriptionId);
|
||||||
name: databaseAccountGetResponse.name,
|
console.log("Account Name: ", accountName);
|
||||||
location: databaseAccountGetResponse.location,
|
|
||||||
type: databaseAccountGetResponse.type,
|
|
||||||
kind: databaseAccountGetResponse.kind,
|
|
||||||
tags: databaseAccountGetResponse.tags,
|
|
||||||
properties: {
|
|
||||||
documentEndpoint: databaseAccountGetResponse.documentEndpoint,
|
|
||||||
tableEndpoint: undefined,
|
|
||||||
gremlinEndpoint: undefined,
|
|
||||||
cassandraEndpoint: undefined,
|
|
||||||
capabilities: databaseAccountGetResponse.capabilities.map((capability) => {
|
|
||||||
return { name: capability.name } as Capability;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return databaseAccount;
|
|
||||||
};
|
|
||||||
|
|
||||||
const initTestExplorer = async (): Promise<void> => {
|
const initTestExplorer = async (): Promise<void> => {
|
||||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
const { token } = await credentials.getToken("https://management.core.windows.net/.default");
|
||||||
const portalRunnerDatabaseAccount = decodeURIComponent(
|
updateUserContext({
|
||||||
urlSearchParams.get(TestExplorerParams.portalRunnerDatabaseAccount)
|
authorizationToken: `bearer ${token}`,
|
||||||
);
|
});
|
||||||
const portalRunnerDatabaseAccountKey = decodeURIComponent(
|
const databaseAccount = await get(subscriptionId, resourceGroup, accountName);
|
||||||
urlSearchParams.get(TestExplorerParams.portalRunnerDatabaseAccountKey)
|
const keys = await listKeys(subscriptionId, resourceGroup, accountName);
|
||||||
);
|
|
||||||
const portalRunnerSubscripton = decodeURIComponent(urlSearchParams.get(TestExplorerParams.portalRunnerSubscripton));
|
|
||||||
const portalRunnerResourceGroup = decodeURIComponent(
|
|
||||||
urlSearchParams.get(TestExplorerParams.portalRunnerResourceGroup)
|
|
||||||
);
|
|
||||||
const selfServeType = urlSearchParams.get(TestExplorerParams.selfServeType);
|
|
||||||
|
|
||||||
const token = decodeURIComponent(urlSearchParams.get(TestExplorerParams.token));
|
|
||||||
const databaseAccount = await getDatabaseAccount(
|
|
||||||
token,
|
|
||||||
portalRunnerSubscripton,
|
|
||||||
portalRunnerResourceGroup,
|
|
||||||
portalRunnerDatabaseAccount
|
|
||||||
);
|
|
||||||
|
|
||||||
const initTestExplorerContent = {
|
const initTestExplorerContent = {
|
||||||
inputs: {
|
inputs: {
|
||||||
databaseAccount: databaseAccount,
|
databaseAccount: databaseAccount,
|
||||||
subscriptionId: portalRunnerSubscripton,
|
subscriptionId,
|
||||||
resourceGroup: portalRunnerResourceGroup,
|
resourceGroup,
|
||||||
authorizationToken: `Bearer ${token}`,
|
authorizationToken: `Bearer ${token}`,
|
||||||
features: {},
|
features: {},
|
||||||
hasWriteAccess: true,
|
hasWriteAccess: true,
|
||||||
@ -88,7 +56,7 @@ const initTestExplorer = async (): Promise<void> => {
|
|||||||
quotaId: "Internal_2014-09-01",
|
quotaId: "Internal_2014-09-01",
|
||||||
addCollectionDefaultFlight: "2",
|
addCollectionDefaultFlight: "2",
|
||||||
isTryCosmosDBSubscription: false,
|
isTryCosmosDBSubscription: false,
|
||||||
masterKey: portalRunnerDatabaseAccountKey,
|
masterKey: keys.primaryMasterKey,
|
||||||
loadDatabaseAccountTimestamp: 1604663109836,
|
loadDatabaseAccountTimestamp: 1604663109836,
|
||||||
dataExplorerVersion: "1.0.1",
|
dataExplorerVersion: "1.0.1",
|
||||||
sharedThroughputMinimum: 400,
|
sharedThroughputMinimum: 400,
|
||||||
@ -101,7 +69,7 @@ const initTestExplorer = async (): Promise<void> => {
|
|||||||
// add UI test only when feature is not dependent on flights anymore
|
// add UI test only when feature is not dependent on flights anymore
|
||||||
flights: [],
|
flights: [],
|
||||||
selfServeType,
|
selfServeType,
|
||||||
} as ViewModels.DataExplorerInputsFrame,
|
} as DataExplorerInputsFrame,
|
||||||
};
|
};
|
||||||
|
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
@ -127,16 +95,8 @@ const initTestExplorer = async (): Promise<void> => {
|
|||||||
iframe.name = "explorer";
|
iframe.name = "explorer";
|
||||||
iframe.classList.add("iframe");
|
iframe.classList.add("iframe");
|
||||||
iframe.title = "explorer";
|
iframe.title = "explorer";
|
||||||
iframe.src = getIframeSrc(selfServeType);
|
iframe.src = iframeSrc;
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIframeSrc = (selfServeType: string): string => {
|
|
||||||
let iframeSrc = "explorer.html?platform=Portal&disablePortalInitCache";
|
|
||||||
if (selfServeType) {
|
|
||||||
iframeSrc = `selfServe.html?selfServeType=${selfServeType}`;
|
|
||||||
}
|
|
||||||
return iframeSrc;
|
|
||||||
};
|
|
||||||
|
|
||||||
initTestExplorer();
|
initTestExplorer();
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
export enum TestExplorerParams {
|
|
||||||
portalRunnerDatabaseAccount = "portalRunnerDatabaseAccount",
|
|
||||||
portalRunnerDatabaseAccountKey = "portalRunnerDatabaseAccountKey",
|
|
||||||
portalRunnerSubscripton = "portalRunnerSubscripton",
|
|
||||||
portalRunnerResourceGroup = "portalRunnerResourceGroup",
|
|
||||||
selfServeType = "selfServeType",
|
|
||||||
token = "token",
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { Frame } from "puppeteer";
|
|
||||||
import { TestExplorerParams } from "./TestExplorerParams";
|
|
||||||
import { ClientSecretCredential } from "@azure/identity";
|
|
||||||
import { ApiKind } from "../../src/Contracts/DataModels";
|
|
||||||
|
|
||||||
let testExplorerFrame: Frame;
|
|
||||||
export const getTestExplorerFrame = async (apiKind?: ApiKind, params?: Map<string, string>): Promise<Frame> => {
|
|
||||||
if (testExplorerFrame) {
|
|
||||||
return testExplorerFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
let portalRunnerDatabaseAccount: string;
|
|
||||||
let portalRunnerDatabaseAccountKey: string;
|
|
||||||
|
|
||||||
switch (apiKind) {
|
|
||||||
case ApiKind.MongoDB:
|
|
||||||
portalRunnerDatabaseAccount = process.env.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT;
|
|
||||||
portalRunnerDatabaseAccountKey = process.env.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
portalRunnerDatabaseAccount = process.env.PORTAL_RUNNER_DATABASE_ACCOUNT;
|
|
||||||
portalRunnerDatabaseAccountKey = process.env.PORTAL_RUNNER_DATABASE_ACCOUNT_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
const notebooksTestRunnerTenantId = process.env.NOTEBOOKS_TEST_RUNNER_TENANT_ID;
|
|
||||||
const notebooksTestRunnerClientId = process.env.NOTEBOOKS_TEST_RUNNER_CLIENT_ID;
|
|
||||||
const notebooksTestRunnerClientSecret = process.env.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET;
|
|
||||||
const portalRunnerSubscripton = process.env.PORTAL_RUNNER_SUBSCRIPTION;
|
|
||||||
const portalRunnerResourceGroup = process.env.PORTAL_RUNNER_RESOURCE_GROUP;
|
|
||||||
|
|
||||||
const credentials = new ClientSecretCredential(
|
|
||||||
notebooksTestRunnerTenantId,
|
|
||||||
notebooksTestRunnerClientId,
|
|
||||||
notebooksTestRunnerClientSecret
|
|
||||||
);
|
|
||||||
|
|
||||||
const { token } = await credentials.getToken("https://management.core.windows.net/.default");
|
|
||||||
|
|
||||||
const testExplorerUrl = new URL("testExplorer.html", "https://localhost:1234");
|
|
||||||
testExplorerUrl.searchParams.append(
|
|
||||||
TestExplorerParams.portalRunnerDatabaseAccount,
|
|
||||||
encodeURI(portalRunnerDatabaseAccount)
|
|
||||||
);
|
|
||||||
testExplorerUrl.searchParams.append(
|
|
||||||
TestExplorerParams.portalRunnerDatabaseAccountKey,
|
|
||||||
encodeURI(portalRunnerDatabaseAccountKey)
|
|
||||||
);
|
|
||||||
testExplorerUrl.searchParams.append(TestExplorerParams.portalRunnerSubscripton, encodeURI(portalRunnerSubscripton));
|
|
||||||
testExplorerUrl.searchParams.append(
|
|
||||||
TestExplorerParams.portalRunnerResourceGroup,
|
|
||||||
encodeURI(portalRunnerResourceGroup)
|
|
||||||
);
|
|
||||||
testExplorerUrl.searchParams.append(TestExplorerParams.token, encodeURI(token));
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
for (const key of params.keys()) {
|
|
||||||
testExplorerUrl.searchParams.append(key, encodeURI(params.get(key)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.goto(testExplorerUrl.toString());
|
|
||||||
const handle = await page.waitForSelector("iframe");
|
|
||||||
return await handle.contentFrame();
|
|
||||||
};
|
|
@ -30,8 +30,8 @@ export function generateDatabaseName(baseName = "db", length = 1): string {
|
|||||||
return `${baseName}${crypto.randomBytes(length).toString("hex")}-${Date.now()}`;
|
return `${baseName}${crypto.randomBytes(length).toString("hex")}-${Date.now()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createDatabase(frame: Frame): Promise<string> {
|
export async function createDatabase(frame: Frame): Promise<{ databaseId: string; collectionId: string }> {
|
||||||
const dbId = generateDatabaseName();
|
const databaseId = generateDatabaseName();
|
||||||
const collectionId = generateUniqueName("col");
|
const collectionId = generateUniqueName("col");
|
||||||
const shardKey = "partitionKey";
|
const shardKey = "partitionKey";
|
||||||
// create new collection
|
// create new collection
|
||||||
@ -50,7 +50,7 @@ export async function createDatabase(frame: Frame): Promise<string> {
|
|||||||
await frame.waitFor('input[data-test="addCollection-newDatabaseId"]');
|
await frame.waitFor('input[data-test="addCollection-newDatabaseId"]');
|
||||||
const dbInput = await frame.$('input[data-test="addCollection-newDatabaseId"]');
|
const dbInput = await frame.$('input[data-test="addCollection-newDatabaseId"]');
|
||||||
await dbInput.press("Backspace");
|
await dbInput.press("Backspace");
|
||||||
await dbInput.type(dbId);
|
await dbInput.type(databaseId);
|
||||||
|
|
||||||
// type collection id
|
// type collection id
|
||||||
await frame.waitFor('input[data-test="addCollection-collectionId"]');
|
await frame.waitFor('input[data-test="addCollection-collectionId"]');
|
||||||
@ -67,7 +67,7 @@ export async function createDatabase(frame: Frame): Promise<string> {
|
|||||||
// click submit
|
// click submit
|
||||||
await frame.waitFor("#submitBtnAddCollection");
|
await frame.waitFor("#submitBtnAddCollection");
|
||||||
await frame.click("#submitBtnAddCollection");
|
await frame.click("#submitBtnAddCollection");
|
||||||
return dbId;
|
return { databaseId, collectionId };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function onClickSaveButton(frame: Frame): Promise<void> {
|
export async function onClickSaveButton(frame: Frame): Promise<void> {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
const msRestNodeAuth = require("@azure/ms-rest-nodeauth");
|
const msRestNodeAuth = require("@azure/ms-rest-nodeauth");
|
||||||
const { CosmosDBManagementClient } = require("@azure/arm-cosmosdb");
|
const { CosmosDBManagementClient } = require("@azure/arm-cosmosdb");
|
||||||
const ms = require("ms");
|
const ms = require("ms");
|
||||||
const { time } = require("console");
|
|
||||||
|
|
||||||
const clientId = process.env["NOTEBOOKS_TEST_RUNNER_CLIENT_ID"];
|
const clientId = process.env["NOTEBOOKS_TEST_RUNNER_CLIENT_ID"];
|
||||||
const secret = process.env["NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET"];
|
const secret = process.env["NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET"];
|
||||||
@ -9,7 +8,7 @@ const tenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
|||||||
const subscriptionId = "69e02f2d-f059-4409-9eac-97e8a276ae2c";
|
const subscriptionId = "69e02f2d-f059-4409-9eac-97e8a276ae2c";
|
||||||
const resourceGroupName = "runners";
|
const resourceGroupName = "runners";
|
||||||
|
|
||||||
const sixtyMinutesAgo = new Date(Date.now() - 1000 * 60 * 60).getTime();
|
const thirtyMinutesAgo = new Date(Date.now() - 1000 * 60 * 30).getTime();
|
||||||
|
|
||||||
function friendlyTime(date) {
|
function friendlyTime(date) {
|
||||||
try {
|
try {
|
||||||
@ -29,7 +28,7 @@ async function main() {
|
|||||||
const mongoDatabases = await client.mongoDBResources.listMongoDBDatabases(resourceGroupName, account.name);
|
const mongoDatabases = await client.mongoDBResources.listMongoDBDatabases(resourceGroupName, account.name);
|
||||||
for (const database of mongoDatabases) {
|
for (const database of mongoDatabases) {
|
||||||
const timestamp = Number(database.name.split("-")[1]);
|
const timestamp = Number(database.name.split("-")[1]);
|
||||||
if (timestamp && timestamp < sixtyMinutesAgo) {
|
if (timestamp && timestamp < thirtyMinutesAgo) {
|
||||||
await client.mongoDBResources.deleteMongoDBDatabase(resourceGroupName, account.name, database.name);
|
await client.mongoDBResources.deleteMongoDBDatabase(resourceGroupName, account.name, database.name);
|
||||||
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
|
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
|
||||||
} else {
|
} else {
|
||||||
@ -40,7 +39,7 @@ async function main() {
|
|||||||
const sqlDatabases = await client.sqlResources.listSqlDatabases(resourceGroupName, account.name);
|
const sqlDatabases = await client.sqlResources.listSqlDatabases(resourceGroupName, account.name);
|
||||||
for (const database of sqlDatabases) {
|
for (const database of sqlDatabases) {
|
||||||
const timestamp = Number(database.name.split("-")[1]);
|
const timestamp = Number(database.name.split("-")[1]);
|
||||||
if (timestamp && timestamp < sixtyMinutesAgo) {
|
if (timestamp && timestamp < thirtyMinutesAgo) {
|
||||||
await client.sqlResources.deleteSqlDatabase(resourceGroupName, account.name, database.name);
|
await client.sqlResources.deleteSqlDatabase(resourceGroupName, account.name, database.name);
|
||||||
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
|
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
require("dotenv/config");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
|
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
@ -14,6 +15,16 @@ const isCI = require("is-ci");
|
|||||||
|
|
||||||
const gitSha = childProcess.execSync("git rev-parse HEAD").toString("utf8");
|
const gitSha = childProcess.execSync("git rev-parse HEAD").toString("utf8");
|
||||||
|
|
||||||
|
const AZURE_CLIENT_ID = "fd8753b0-0707-4e32-84e9-2532af865fb4";
|
||||||
|
const AZURE_TENANT_ID = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
||||||
|
const SUBSCRIPTION_ID = "69e02f2d-f059-4409-9eac-97e8a276ae2c";
|
||||||
|
const RESOURCE_GROUP = "runners";
|
||||||
|
const AZURE_CLIENT_SECRET = process.env.AZURE_CLIENT_SECRET || process.env.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET; // TODO Remove. Exists for backwards compat with old .env files. Prefer AZURE_CLIENT_SECRET
|
||||||
|
|
||||||
|
if (!AZURE_CLIENT_SECRET) {
|
||||||
|
console.warn("AZURE_CLIENT_SECRET is not set. testExplorer.html will not work.");
|
||||||
|
}
|
||||||
|
|
||||||
const cssRule = {
|
const cssRule = {
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: [MiniCssExtractPlugin.loader, "css-loader"],
|
use: [MiniCssExtractPlugin.loader, "css-loader"],
|
||||||
@ -102,6 +113,11 @@ module.exports = function (env = {}, argv = {}) {
|
|||||||
|
|
||||||
if (mode === "development") {
|
if (mode === "development") {
|
||||||
envVars.NODE_ENV = "development";
|
envVars.NODE_ENV = "development";
|
||||||
|
envVars.AZURE_CLIENT_ID = AZURE_CLIENT_ID;
|
||||||
|
envVars.AZURE_TENANT_ID = AZURE_TENANT_ID;
|
||||||
|
envVars.AZURE_CLIENT_SECRET = AZURE_CLIENT_SECRET;
|
||||||
|
envVars.SUBSCRIPTION_ID = SUBSCRIPTION_ID;
|
||||||
|
envVars.RESOURCE_GROUP = RESOURCE_GROUP;
|
||||||
typescriptRule.use[0].options.compilerOptions = { target: "ES2018" };
|
typescriptRule.use[0].options.compilerOptions = { target: "ES2018" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +298,12 @@ module.exports = function (env = {}, argv = {}) {
|
|||||||
secure: false,
|
secure: false,
|
||||||
logLevel: "debug",
|
logLevel: "debug",
|
||||||
},
|
},
|
||||||
|
[`/${AZURE_TENANT_ID}`]: {
|
||||||
|
target: "https://login.microsoftonline.com/",
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
logLevel: "debug",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
stats: "minimal",
|
stats: "minimal",
|
||||||
|
Loading…
Reference in New Issue
Block a user