mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-04-24 15:31:50 +01:00
Added Auth
This commit is contained in:
85
package-lock.json
generated
85
package-lock.json
generated
@@ -19,6 +19,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@azure/arm-cosmosdb": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@azure/arm-cosmosdb/-/arm-cosmosdb-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZHQTnBSjJ+TUAlXqfc1M23A0622gSSvYVd5gCqWHwG64e/R4zAySDDXcIi0bGYAUv/0nZzKHYulrgYpU+GnDjw==",
|
||||||
|
"requires": {
|
||||||
|
"@azure/ms-rest-azure-js": "^2.0.1",
|
||||||
|
"@azure/ms-rest-js": "^2.0.4",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@azure/core-auth": {
|
"@azure/core-auth": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.1.3.tgz",
|
||||||
@@ -200,6 +217,71 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@azure/ms-rest-azure-js": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-5e+A710O7gRFISoV4KI/ZyLQbKmjXxQZ1L8Z/sx7jSUQqmswjTnN4yyIZxs5JzfLVkobU0rXxbi5/LVzaI8QXQ==",
|
||||||
|
"requires": {
|
||||||
|
"@azure/ms-rest-js": "^2.0.4",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@azure/ms-rest-js": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-4BXLVImYRt+jcUmEJ5LUWglI8RBNVQndY6IcyvQ4U8O4kIXdmlRz3cJdA/RpXf5rKT38KOoTO2T6Z1f6Z1HDBg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node-fetch": "^2.3.7",
|
||||||
|
"@types/tunnel": "0.0.1",
|
||||||
|
"abort-controller": "^3.0.0",
|
||||||
|
"form-data": "^2.5.0",
|
||||||
|
"node-fetch": "^2.6.0",
|
||||||
|
"tough-cookie": "^3.0.1",
|
||||||
|
"tslib": "^1.10.0",
|
||||||
|
"tunnel": "0.0.6",
|
||||||
|
"uuid": "^3.3.2",
|
||||||
|
"xml2js": "^0.4.19"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"form-data": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.6",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tough-cookie": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
|
||||||
|
"requires": {
|
||||||
|
"ip-regex": "^2.1.0",
|
||||||
|
"psl": "^1.1.28",
|
||||||
|
"punycode": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.10.4",
|
"version": "7.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
||||||
@@ -11731,8 +11813,7 @@
|
|||||||
"ip-regex": {
|
"ip-regex": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
|
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"ipaddr.js": {
|
"ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"description": "Cosmos Explorer",
|
"description": "Cosmos Explorer",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@azure/arm-cosmosdb": "9.1.0",
|
||||||
"@azure/cosmos": "3.9.0",
|
"@azure/cosmos": "3.9.0",
|
||||||
"@azure/cosmos-language-service": "0.0.4",
|
"@azure/cosmos-language-service": "0.0.4",
|
||||||
"@azure/identity": "1.1.0",
|
"@azure/identity": "1.1.0",
|
||||||
@@ -188,7 +189,7 @@
|
|||||||
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
||||||
"copyToConsumers": "node copyToConsumers",
|
"copyToConsumers": "node copyToConsumers",
|
||||||
"test": "rimraf coverage && jest",
|
"test": "rimraf coverage && jest",
|
||||||
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles test/notebooks/uploadRunAndDeleteNotebook.spec.ts",
|
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles",
|
||||||
"watch": "npm run start",
|
"watch": "npm run start",
|
||||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||||
"build:ase": "gulp build:ase",
|
"build:ase": "gulp build:ase",
|
||||||
|
|||||||
@@ -2543,7 +2543,6 @@ export default class Explorer {
|
|||||||
const databaseAccountLocation = databaseAccount && databaseAccount.location.toLowerCase();
|
const databaseAccountLocation = databaseAccount && databaseAccount.location.toLowerCase();
|
||||||
const disallowedLocationsUri = `${configContext.BACKEND_ENDPOINT}/api/disallowedLocations`;
|
const disallowedLocationsUri = `${configContext.BACKEND_ENDPOINT}/api/disallowedLocations`;
|
||||||
const authorizationHeader = getAuthorizationHeader();
|
const authorizationHeader = getAuthorizationHeader();
|
||||||
console.log("auth header:" + JSON.stringify(authorizationHeader));
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(disallowedLocationsUri, {
|
const response = await fetch(disallowedLocationsUri, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|||||||
@@ -1,20 +1,75 @@
|
|||||||
import "./Shared/appInsights";
|
|
||||||
import * as _ from "underscore";
|
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import { MessageTypes } from "./Contracts/ExplorerContracts";
|
import { MessageTypes } from "./Contracts/ExplorerContracts";
|
||||||
|
import * as ViewModels from "./Contracts/ViewModels";
|
||||||
import "../less/hostedexplorer.less";
|
import "../less/hostedexplorer.less";
|
||||||
import "./Explorer/Menus/NavBar/MeControlComponent.less";
|
import "./Explorer/Menus/NavBar/MeControlComponent.less";
|
||||||
import * as ViewModels from "./Contracts/ViewModels";
|
|
||||||
import { ClientSecretCredential } from "@azure/identity";
|
import { ClientSecretCredential } from "@azure/identity";
|
||||||
|
import { CosmosDBManagementClient } from "@azure/arm-cosmosdb";
|
||||||
|
import * as msRest from "@azure/ms-rest-js";
|
||||||
|
import { DatabaseAccountsGetResponse } from "@azure/arm-cosmosdb/esm/models";
|
||||||
|
import { TestExplorerParams } from "./TestExplorerParams";
|
||||||
|
|
||||||
|
class CustomSigner implements msRest.ServiceClientCredentials {
|
||||||
|
private token: string;
|
||||||
|
constructor(token: string) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
async signRequest(webResource: msRest.WebResourceLike): Promise<msRest.WebResourceLike> {
|
||||||
|
webResource.headers.set("authorization", `bearer ${this.token}`);
|
||||||
|
return webResource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TestExplorer {
|
class TestExplorer {
|
||||||
public isButtonVisible: ko.Observable<boolean>;
|
private notebooksTestRunnerApplicationId: string;
|
||||||
|
private notebooksTestRunnerClientId: string;
|
||||||
|
private notebooksTestRunnerClientSecret: string;
|
||||||
|
private notebooksAccountName: string;
|
||||||
|
private notebooksAccountKey: string;
|
||||||
|
private notebooksAccountSubscriptonId: string;
|
||||||
|
private notebooksAccountResourceGroup: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isButtonVisible = ko.observable(true);
|
window.onload = () => {
|
||||||
|
this.initTestExplorer();
|
||||||
|
};
|
||||||
window.addEventListener("message", this.handleMessage.bind(this), false);
|
window.addEventListener("message", this.handleMessage.bind(this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private parseUrlParams = (): void => {
|
||||||
|
window.location.search
|
||||||
|
.substr(1)
|
||||||
|
.split("&")
|
||||||
|
.forEach((item) => {
|
||||||
|
const tmp = item.split("=");
|
||||||
|
const value = decodeURIComponent(tmp[1]);
|
||||||
|
switch (tmp[0]) {
|
||||||
|
case TestExplorerParams.notebooksTestRunnerApplicationId:
|
||||||
|
this.notebooksTestRunnerApplicationId = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksTestRunnerClientId:
|
||||||
|
this.notebooksTestRunnerClientId = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksTestRunnerClientSecret:
|
||||||
|
this.notebooksTestRunnerClientSecret = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksAccountName:
|
||||||
|
this.notebooksAccountName = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksAccountKey:
|
||||||
|
this.notebooksAccountKey = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksAccountSubscriptonId:
|
||||||
|
this.notebooksAccountSubscriptonId = value;
|
||||||
|
break;
|
||||||
|
case TestExplorerParams.notebooksAccountResourceGroup:
|
||||||
|
this.notebooksAccountResourceGroup = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
private handleMessage(event: MessageEvent) {
|
private handleMessage(event: MessageEvent) {
|
||||||
if (event.data.type === MessageTypes.InitTestExplorer || event.data.type === MessageTypes.HideConnectScreen) {
|
if (event.data.type === MessageTypes.InitTestExplorer || event.data.type === MessageTypes.HideConnectScreen) {
|
||||||
this.sendMessageToExplorerFrame(event.data);
|
this.sendMessageToExplorerFrame(event.data);
|
||||||
@@ -22,253 +77,33 @@ class TestExplorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async AADLogin(): Promise<string> {
|
private async AADLogin(): Promise<string> {
|
||||||
const tenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
const credentials = new ClientSecretCredential(
|
||||||
const clientId = "fd8753b0-0707-4e32-84e9-2532af865fb4";
|
this.notebooksTestRunnerApplicationId,
|
||||||
const clientSecret = "xGT82g3sO4AJ.C~G6dii5LP~6-yCit9J-h";
|
this.notebooksTestRunnerClientId,
|
||||||
|
this.notebooksTestRunnerClientSecret
|
||||||
const credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
);
|
||||||
|
|
||||||
const token = await credentials.getToken("https://management.core.windows.net/.default");
|
const token = await credentials.getToken("https://management.core.windows.net/.default");
|
||||||
|
|
||||||
return token.token;
|
return token.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async postMessage(): Promise<void> {
|
private async getDatabaseAccount(token: string): Promise<DatabaseAccountsGetResponse> {
|
||||||
|
const client = new CosmosDBManagementClient(new CustomSigner(token), this.notebooksAccountSubscriptonId);
|
||||||
|
return await client.databaseAccounts.get(this.notebooksAccountResourceGroup, this.notebooksAccountName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initTestExplorer(): Promise<void> {
|
||||||
|
this.parseUrlParams();
|
||||||
const token = await this.AADLogin();
|
const token = await this.AADLogin();
|
||||||
|
const databaseAccount = await this.getDatabaseAccount(token);
|
||||||
|
|
||||||
const content = {
|
const content = {
|
||||||
type: MessageTypes.InitTestExplorer,
|
type: MessageTypes.InitTestExplorer,
|
||||||
inputs: {
|
inputs: {
|
||||||
databaseAccount: {
|
databaseAccount: databaseAccount,
|
||||||
id:
|
subscriptionId: this.notebooksAccountSubscriptonId,
|
||||||
"/subscriptions/18f84a75-22a7-487c-a800-4e1bdad7779a/resourceGroups/srnara-cassandra-test/providers/Microsoft.DocumentDB/databaseAccounts/srnara-notebook",
|
resourceGroup: this.notebooksAccountResourceGroup,
|
||||||
name: "srnara-notebook",
|
|
||||||
location: "East US",
|
|
||||||
type: "Microsoft.DocumentDB/databaseAccounts",
|
|
||||||
kind: "GlobalDocumentDB",
|
|
||||||
tags: { defaultExperience: "Core (SQL)" },
|
|
||||||
systemData: { createdAt: "2019-10-16T20:46:11.4096965Z" },
|
|
||||||
properties: {
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
documentEndpoint: "https://srnara-notebook.documents.azure.com:443/",
|
|
||||||
publicNetworkAccess: "Enabled",
|
|
||||||
enableAutomaticFailover: false,
|
|
||||||
enableMultipleWriteLocations: true,
|
|
||||||
enablePartitionKeyMonitor: false,
|
|
||||||
isVirtualNetworkFilterEnabled: false,
|
|
||||||
virtualNetworkRules: [],
|
|
||||||
EnabledApiTypes: "Sql",
|
|
||||||
disableKeyBasedMetadataWriteAccess: false,
|
|
||||||
enableFreeTier: false,
|
|
||||||
enableAnalyticalStorage: true,
|
|
||||||
instanceId: "41978508-99b1-477d-9205-2d2f1ce7fc1a",
|
|
||||||
createMode: "Default",
|
|
||||||
databaseAccountOfferType: "Standard",
|
|
||||||
consistencyPolicy: { defaultConsistencyLevel: "Session", maxIntervalInSeconds: 5, maxStalenessPrefix: 100 },
|
|
||||||
configurationOverrides: {},
|
|
||||||
writeLocations: [
|
|
||||||
{
|
|
||||||
id: "srnara-notebook-eastus",
|
|
||||||
locationName: "East US",
|
|
||||||
documentEndpoint: "https://srnara-notebook-eastus.documents.azure.com:443/",
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
failoverPriority: 0,
|
|
||||||
isZoneRedundant: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
readLocations: [
|
|
||||||
{
|
|
||||||
id: "srnara-notebook-eastus",
|
|
||||||
locationName: "East US",
|
|
||||||
documentEndpoint: "https://srnara-notebook-eastus.documents.azure.com:443/",
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
failoverPriority: 0,
|
|
||||||
isZoneRedundant: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
locations: [
|
|
||||||
{
|
|
||||||
id: "srnara-notebook-eastus",
|
|
||||||
locationName: "East US",
|
|
||||||
documentEndpoint: "https://srnara-notebook-eastus.documents.azure.com:443/",
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
failoverPriority: 0,
|
|
||||||
isZoneRedundant: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
failoverPolicies: [{ id: "srnara-notebook-eastus", locationName: "East US", failoverPriority: 0 }],
|
|
||||||
cors: [],
|
|
||||||
capabilities: [],
|
|
||||||
ipRules: [],
|
|
||||||
backupPolicy: {
|
|
||||||
type: "Periodic",
|
|
||||||
periodicModeProperties: { backupIntervalInMinutes: 240, backupRetentionIntervalInHours: 8 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscriptionId: "18f84a75-22a7-487c-a800-4e1bdad7779a",
|
|
||||||
resourceGroup: "srnara-cassandra-test",
|
|
||||||
authorizationToken: `Bearer ${token}`,
|
authorizationToken: `Bearer ${token}`,
|
||||||
features: {
|
features: {},
|
||||||
cacheextensionapp: "false",
|
|
||||||
detailednetworktelemetry: "false",
|
|
||||||
logexternaldomainlinks: "true",
|
|
||||||
enableextensionpreviewstamp: "true",
|
|
||||||
gctelemetry: "false",
|
|
||||||
mereactblade: "true",
|
|
||||||
paralleltokens: "false",
|
|
||||||
prefetchbrowsequerymanifest: "false",
|
|
||||||
prefetchtokensinparallel: "true",
|
|
||||||
pretick: "false",
|
|
||||||
reactdatafetch: "false",
|
|
||||||
shellworker: "true",
|
|
||||||
shellworkerassets: "true",
|
|
||||||
shellworkerbrowseprereqs: "true",
|
|
||||||
shellworkersubs: "true",
|
|
||||||
simplebatch: "false",
|
|
||||||
storageperf1: "false",
|
|
||||||
storageperf2: "false",
|
|
||||||
earlymenucontentvm: "false",
|
|
||||||
bladefullrenderx: "false",
|
|
||||||
controlstelemetry: "true",
|
|
||||||
noeffectflight: "true",
|
|
||||||
advisornotificationdays: "30",
|
|
||||||
advisornotificationpercent: "100",
|
|
||||||
allserviceswithoverview: "true",
|
|
||||||
argsharedqueries: "true",
|
|
||||||
argsubscriptions: "true",
|
|
||||||
armviewer: "true",
|
|
||||||
asyncsearch: "true",
|
|
||||||
azureconsole: "true",
|
|
||||||
azurehome: "true",
|
|
||||||
columnchooserreact: "true",
|
|
||||||
contactinfo: "true",
|
|
||||||
custombingsearch: "true",
|
|
||||||
dashboardalphaapi: "true",
|
|
||||||
dashboardautorefresh: "true",
|
|
||||||
dashboardautorefreshinterval: "60",
|
|
||||||
dashboardfeedback: "true",
|
|
||||||
dashboardnewpinexperience: "true",
|
|
||||||
dashboardpreviewapi: "true",
|
|
||||||
dashboardrefresh: "true",
|
|
||||||
devsatsurvey: "true",
|
|
||||||
deploy2020: "true",
|
|
||||||
enableregionmove: "true",
|
|
||||||
enablestartswithmdm: "true",
|
|
||||||
enhancedprint: "true",
|
|
||||||
essentialsjsonview: "true",
|
|
||||||
freelancer: "true",
|
|
||||||
guidedtour: "true",
|
|
||||||
helpcontentwhatsnewenabled: "true",
|
|
||||||
hidefavoritestars: "true",
|
|
||||||
hostingservicesuffix: "mpac",
|
|
||||||
hubsresourceaccessfromconfig: "true",
|
|
||||||
internalonly: "nobanner",
|
|
||||||
iriscore: "true",
|
|
||||||
iriscorealt: "true",
|
|
||||||
iriscoresurfacename: "88000327",
|
|
||||||
irissurfacename: "AzurePortal_Notifications_Preview",
|
|
||||||
landalltohome: "true",
|
|
||||||
loggraphcallwitharmtoken: "true",
|
|
||||||
meazblade: "true",
|
|
||||||
mistendpoint: "https://mist.int.monitor.azure.com",
|
|
||||||
nojqueryeval: "true",
|
|
||||||
nopdlearlymenucontentbundles: "true",
|
|
||||||
npsintervaldays: "90",
|
|
||||||
npspercent: "2.4",
|
|
||||||
npsshowportaluri: "true",
|
|
||||||
policyawarecontrols: "true",
|
|
||||||
prefetchtokens: "true",
|
|
||||||
prewarmingtesting: "true",
|
|
||||||
reactviewendpointindex: "1",
|
|
||||||
reloadafterdays: "5",
|
|
||||||
serverfetchedevents: "true",
|
|
||||||
sessionvalidity: "true",
|
|
||||||
settingsportalinstance: "mpac",
|
|
||||||
shadowargcall: "true",
|
|
||||||
showbugreportlink: "true",
|
|
||||||
showhovercard: "true",
|
|
||||||
sidebarhamburgermode: "true",
|
|
||||||
singlesignout: "true",
|
|
||||||
subscreditcheck: "true",
|
|
||||||
tenants2020: "true",
|
|
||||||
tilegallerycuration: "true",
|
|
||||||
upgradefromtrialbutton: "true",
|
|
||||||
argbrowseviews: "true",
|
|
||||||
argforoldbrowse: "true",
|
|
||||||
argforrgoverview: "true",
|
|
||||||
argtagsfilter: "true",
|
|
||||||
artbrowse: "true",
|
|
||||||
automationtasks: "true",
|
|
||||||
browsecuration: "default",
|
|
||||||
browsedialogcompactpills: "true",
|
|
||||||
browsedialogpills: "true",
|
|
||||||
browsefilterstelemetry: "true",
|
|
||||||
bypasstokencacheforcustomsignin: "true",
|
|
||||||
cloudsimplereservations: "true",
|
|
||||||
contactabilitybycountry: "true",
|
|
||||||
cryptoapihash: "true",
|
|
||||||
dashboardfilters: "true",
|
|
||||||
dashboardfiltersaddbutton: "true",
|
|
||||||
devnps: "true",
|
|
||||||
devnpsintervaldays: "45",
|
|
||||||
devnpspercent: "50.0",
|
|
||||||
enableaeoemails: "false",
|
|
||||||
enablee2emonitoring: "true",
|
|
||||||
enablelocationchange: "true",
|
|
||||||
experimentation: "false",
|
|
||||||
failajaxonnulltoken: "true",
|
|
||||||
fastencode: "true",
|
|
||||||
feedback: "true",
|
|
||||||
feedbackwithsupport: "true",
|
|
||||||
fullscreenblades: "true",
|
|
||||||
hidemodalsonsmallscreens: "true",
|
|
||||||
hidemodalswhendeeplinked: "true",
|
|
||||||
irismessagelimit: "1",
|
|
||||||
isworkbooksavailable: "true",
|
|
||||||
migratetomsal: "true",
|
|
||||||
mspexpert: "true",
|
|
||||||
mspfilter: "true",
|
|
||||||
mspinfo: "true",
|
|
||||||
newresourceapi: "true",
|
|
||||||
newsupportblade: "true",
|
|
||||||
nps: "true",
|
|
||||||
outagebanner: "true",
|
|
||||||
portalpolling: "true",
|
|
||||||
preact: "true",
|
|
||||||
preferredusername: "true",
|
|
||||||
prefetchdrafttoken: "true",
|
|
||||||
prefetchrecents: "true",
|
|
||||||
providers2019: "true",
|
|
||||||
pushtokens: "true",
|
|
||||||
removesubsdropdownlimit: "true",
|
|
||||||
reservationsinbrowse: "true",
|
|
||||||
reservehozscroll: "true",
|
|
||||||
resourcehealth: "true",
|
|
||||||
savedeploymentnotification: "true",
|
|
||||||
seetemplate: "true",
|
|
||||||
serveravatar: "true",
|
|
||||||
showpostcreatefeedbackoption: "true",
|
|
||||||
showservicehealthalerts: "true",
|
|
||||||
showworkflowappkindbrowse: "true",
|
|
||||||
supplementalbatchsize: "20",
|
|
||||||
tenantscoperedirect: "true",
|
|
||||||
tokencaching: "true",
|
|
||||||
usealertsv2blade: "true",
|
|
||||||
usemsallogin: "true",
|
|
||||||
zerosubsexperience: "true",
|
|
||||||
regionsegments: "true",
|
|
||||||
allservicesweave: "false",
|
|
||||||
bundlingkind: "DefaultPartitioner",
|
|
||||||
confighash: "CGZNcAynkOLM",
|
|
||||||
env: "ms",
|
|
||||||
l: "en.en-us",
|
|
||||||
pageversion: "6.659.0.25051.201105-0922",
|
|
||||||
prefetchhome: "false",
|
|
||||||
prewarmie: "false",
|
|
||||||
weaveblade: "true",
|
|
||||||
dataexplorersource: "https://localhost:1234/explorer.html",
|
|
||||||
experimentationflights: "settingsv2;mongoindexeditor"
|
|
||||||
},
|
|
||||||
hasWriteAccess: true,
|
hasWriteAccess: true,
|
||||||
csmEndpoint: "https://management.azure.com",
|
csmEndpoint: "https://management.azure.com",
|
||||||
dnsSuffix: "documents.azure.com",
|
dnsSuffix: "documents.azure.com",
|
||||||
@@ -278,7 +113,7 @@ class TestExplorer {
|
|||||||
quotaId: "Internal_2014-09-01",
|
quotaId: "Internal_2014-09-01",
|
||||||
addCollectionDefaultFlight: "2",
|
addCollectionDefaultFlight: "2",
|
||||||
isTryCosmosDBSubscription: false,
|
isTryCosmosDBSubscription: false,
|
||||||
masterKey: "jB16xFppH34oIsrxhKytgqlGdq4n3UcHAD9J20jNosrOAzDKfAcvM1kfeBM49ccFxjpFW85Du2ISvrjdl7i4fg==",
|
masterKey: this.notebooksAccountKey,
|
||||||
loadDatabaseAccountTimestamp: 1604663109836,
|
loadDatabaseAccountTimestamp: 1604663109836,
|
||||||
dataExplorerVersion: "1.0.1",
|
dataExplorerVersion: "1.0.1",
|
||||||
sharedThroughputMinimum: 400,
|
sharedThroughputMinimum: 400,
|
||||||
@@ -297,10 +132,9 @@ class TestExplorer {
|
|||||||
type: MessageTypes.HideConnectScreen
|
type: MessageTypes.HideConnectScreen
|
||||||
};
|
};
|
||||||
window.postMessage(hideConnectContent, window.location.href);
|
window.postMessage(hideConnectContent, window.location.href);
|
||||||
this.isButtonVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendMessageToExplorerFrame(data: any): void {
|
private sendMessageToExplorerFrame(data: unknown): void {
|
||||||
const explorerFrame = document.getElementById("explorerMenu") as HTMLIFrameElement;
|
const explorerFrame = document.getElementById("explorerMenu") as HTMLIFrameElement;
|
||||||
explorerFrame &&
|
explorerFrame &&
|
||||||
explorerFrame.contentDocument &&
|
explorerFrame.contentDocument &&
|
||||||
|
|||||||
9
src/TestExplorerParams.ts
Normal file
9
src/TestExplorerParams.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export enum TestExplorerParams {
|
||||||
|
notebooksTestRunnerApplicationId = "notebooksTestRunnerApplicationId",
|
||||||
|
notebooksTestRunnerClientId = "notebooksTestRunnerClientId",
|
||||||
|
notebooksTestRunnerClientSecret = "notebooksTestRunnerClientSecret",
|
||||||
|
notebooksAccountName = "notebooksAccountName",
|
||||||
|
notebooksAccountKey = "notebooksAccountKey",
|
||||||
|
notebooksAccountSubscriptonId = "notebooksAccountSubscriptonId",
|
||||||
|
notebooksAccountResourceGroup = "notebooksAccountResourceGroup"
|
||||||
|
}
|
||||||
@@ -9,14 +9,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<switch-directory-pane params="{data: switchDirectoryPane}"></switch-directory-pane>
|
<switch-directory-pane params="{data: switchDirectoryPane}"></switch-directory-pane>
|
||||||
|
|
||||||
<button data-bind="click: postMessage, visible: isButtonVisible">Test login</button>
|
<iframe id="explorerMenu" name="explorer" class="iframe" title="explorer" src="explorer.html?v=1.0.1&platform=Test">
|
||||||
<iframe
|
|
||||||
id="explorerMenu"
|
|
||||||
name="explorer"
|
|
||||||
class="iframe"
|
|
||||||
title="explorer"
|
|
||||||
src="explorer.html?v=1.0.1&platform=Hosted"
|
|
||||||
>
|
|
||||||
</iframe>
|
</iframe>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,18 +1,90 @@
|
|||||||
import { Frame } from "puppeteer";
|
import { ElementHandle, Frame } from "puppeteer";
|
||||||
|
import { TestExplorerParams } from "../../src/TestExplorerParams";
|
||||||
|
|
||||||
|
export const NOTEBOOK_OPERATION_DELAY = 5000;
|
||||||
|
export const RENDER_DELAY = 1000;
|
||||||
|
|
||||||
let testExplorerFrame: Frame;
|
let testExplorerFrame: Frame;
|
||||||
export async function getTestExplorerFrame(): Promise<Frame> {
|
export const getTestExplorerFrame = async (): Promise<Frame> => {
|
||||||
if (testExplorerFrame) {
|
if (testExplorerFrame) {
|
||||||
return testExplorerFrame;
|
return testExplorerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
const prodUrl = "https://localhost:1234/testExplorer.html";
|
const notebooksTestRunnerApplicationId = 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 notebooksAccountName = process.env.NOTEBOOKS_ACCOUNT_NAME;
|
||||||
|
const notebooksAccountKey = process.env.NOTEBOOKS_ACCOUNT_KEY;
|
||||||
|
const notebooksAccountSubscriptonId = process.env.NOTEBOOKS_ACCOUNT_SUBSCRIPTION_ID;
|
||||||
|
const notebooksAccountResourceGroup = process.env.NOTEBOOKS_ACCOUNT_RESOURCE_GROUP;
|
||||||
|
|
||||||
|
const prodUrl = `https://localhost:1234/testExplorer.html?
|
||||||
|
${TestExplorerParams.notebooksTestRunnerApplicationId}=${encodeURI(notebooksTestRunnerApplicationId)}&
|
||||||
|
${TestExplorerParams.notebooksTestRunnerClientId}=${encodeURI(notebooksTestRunnerClientId)}&
|
||||||
|
${TestExplorerParams.notebooksTestRunnerClientSecret}=${encodeURI(notebooksTestRunnerClientSecret)}&
|
||||||
|
${TestExplorerParams.notebooksAccountName}=${encodeURI(notebooksAccountName)}&
|
||||||
|
${TestExplorerParams.notebooksAccountKey}=${encodeURI(notebooksAccountKey)}&
|
||||||
|
${TestExplorerParams.notebooksAccountSubscriptonId}=${encodeURI(notebooksAccountSubscriptonId)}&
|
||||||
|
${TestExplorerParams.notebooksAccountResourceGroup}=${encodeURI(notebooksAccountResourceGroup)}`;
|
||||||
|
|
||||||
await page.goto(prodUrl);
|
await page.goto(prodUrl);
|
||||||
const buttonHandle = await page.waitForSelector("button");
|
|
||||||
buttonHandle.click();
|
|
||||||
|
|
||||||
const handle = await page.waitForSelector("iframe");
|
const handle = await page.waitForSelector("iframe");
|
||||||
testExplorerFrame = await handle.contentFrame();
|
testExplorerFrame = await handle.contentFrame();
|
||||||
await testExplorerFrame.waitForSelector(".galleryHeader");
|
await testExplorerFrame.waitForSelector(".galleryHeader");
|
||||||
return testExplorerFrame;
|
return testExplorerFrame;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const uploadNotebook = async (frame: Frame, uploadNotebookPath: string): Promise<void> => {
|
||||||
|
const notebookResourceTree = await frame.waitForSelector(".notebookResourceTree");
|
||||||
|
|
||||||
|
const treeNodeHeadersBeforeUpload = await notebookResourceTree.$$(".treeNodeHeader");
|
||||||
|
|
||||||
|
const ellipses = await treeNodeHeadersBeforeUpload[2].$("button");
|
||||||
|
await ellipses.click();
|
||||||
|
|
||||||
|
await frame.waitFor(RENDER_DELAY);
|
||||||
|
|
||||||
|
const menuItems = await frame.$$(".ms-ContextualMenu-item");
|
||||||
|
await menuItems[4].click();
|
||||||
|
|
||||||
|
const uploadFileButton = await frame.waitForSelector("#importFileButton");
|
||||||
|
uploadFileButton.click();
|
||||||
|
|
||||||
|
const fileChooser = await page.waitForFileChooser();
|
||||||
|
fileChooser.accept([uploadNotebookPath]);
|
||||||
|
|
||||||
|
const submitButton = await frame.waitForSelector("#uploadFileButton");
|
||||||
|
await submitButton.click();
|
||||||
|
|
||||||
|
await frame.waitFor(NOTEBOOK_OPERATION_DELAY);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNotebookNode = async (frame: Frame, uploadNotebookName: string): Promise<ElementHandle<Element>> => {
|
||||||
|
const notebookResourceTree = await frame.waitForSelector(".notebookResourceTree");
|
||||||
|
let currentNotebookNode: ElementHandle<Element>;
|
||||||
|
|
||||||
|
const treeNodeHeaders = await notebookResourceTree.$$(".treeNodeHeader");
|
||||||
|
for (let i = 1; i < treeNodeHeaders.length; i++) {
|
||||||
|
currentNotebookNode = treeNodeHeaders[i];
|
||||||
|
const nodeLabel = await currentNotebookNode.$eval(".nodeLabel", element => element.textContent);
|
||||||
|
if (nodeLabel === uploadNotebookName) {
|
||||||
|
return currentNotebookNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteNotebook = async (frame: Frame, notebookNodeToDelete: ElementHandle<Element>): Promise<void> => {
|
||||||
|
const ellipses = await notebookNodeToDelete.$(".treeMenuEllipsis");
|
||||||
|
await ellipses.click();
|
||||||
|
|
||||||
|
await frame.waitFor(RENDER_DELAY);
|
||||||
|
|
||||||
|
const menuItems = await frame.$$(".ms-ContextualMenu-item");
|
||||||
|
await menuItems[1].click();
|
||||||
|
|
||||||
|
const deleteAcceptButton = await frame.waitForSelector(".ms-Dialog-action");
|
||||||
|
await deleteAcceptButton.click();
|
||||||
|
await frame.waitFor(NOTEBOOK_OPERATION_DELAY);
|
||||||
|
};
|
||||||
|
|||||||
27
test/notebooks/uploadOpenAndDeleteNotebook.spec.ts
Normal file
27
test/notebooks/uploadOpenAndDeleteNotebook.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import "expect-puppeteer";
|
||||||
|
import { deleteNotebook, getNotebookNode, getTestExplorerFrame, uploadNotebook } from "./notebookTestUtils";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
jest.setTimeout(300000);
|
||||||
|
|
||||||
|
describe("Notebook UI tests", () => {
|
||||||
|
it("Upload, Open and Delete Notebook", async () => {
|
||||||
|
const frame = await getTestExplorerFrame();
|
||||||
|
const uploadNotebookName = "GettingStarted.ipynb";
|
||||||
|
const uploadNotebookPath = path.join(__dirname, "testNotebooks", uploadNotebookName);
|
||||||
|
|
||||||
|
await uploadNotebook(frame, uploadNotebookPath);
|
||||||
|
const uploadedNotebookNode = await getNotebookNode(frame, uploadNotebookName);
|
||||||
|
|
||||||
|
await uploadedNotebookNode.click();
|
||||||
|
await frame.waitForSelector(".tabNavText");
|
||||||
|
const tabTitle = await frame.$eval(".tabNavText", element => element.textContent);
|
||||||
|
expect(tabTitle).toEqual(uploadNotebookName);
|
||||||
|
const closeIcon = await frame.waitForSelector(".close-Icon");
|
||||||
|
await closeIcon.click();
|
||||||
|
|
||||||
|
await deleteNotebook(frame, uploadedNotebookNode);
|
||||||
|
const deletedNotebookNode = await getNotebookNode(frame, uploadNotebookName);
|
||||||
|
expect(deletedNotebookNode).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
import "expect-puppeteer";
|
|
||||||
import { ElementHandle } from "puppeteer";
|
|
||||||
import { getTestExplorerFrame } from "./notebookTestUtils";
|
|
||||||
import * as path from "path"
|
|
||||||
|
|
||||||
jest.setTimeout(300000);
|
|
||||||
const NOTEBOOK_OPERATION_DELAY = 2500;
|
|
||||||
const RENDER_DELAY = 1000;
|
|
||||||
|
|
||||||
describe("sample", () => {
|
|
||||||
it("portal login", async () => {
|
|
||||||
const frame = await getTestExplorerFrame();
|
|
||||||
|
|
||||||
const notebookResourceTree = await frame.waitForSelector(".notebookResourceTree");
|
|
||||||
const uploadNotebookPath = "C:/Users/srnara/Downloads/GettingStarted.ipynb";
|
|
||||||
const uploadNotebookName = path.basename(uploadNotebookPath);
|
|
||||||
|
|
||||||
const treeNodeHeadersBeforeUpload = await notebookResourceTree.$$(".treeNodeHeader");
|
|
||||||
|
|
||||||
let ellipses = await treeNodeHeadersBeforeUpload[2].$("button");
|
|
||||||
await ellipses.click();
|
|
||||||
|
|
||||||
await frame.waitFor(RENDER_DELAY);
|
|
||||||
|
|
||||||
let menuItems = await frame.$$(".ms-ContextualMenu-item");
|
|
||||||
await menuItems[4].click();
|
|
||||||
|
|
||||||
const uploadFileButton = await frame.waitForSelector("#importFileButton");
|
|
||||||
uploadFileButton.click();
|
|
||||||
|
|
||||||
const fileChooser = await page.waitForFileChooser();
|
|
||||||
fileChooser.accept([uploadNotebookPath]);
|
|
||||||
|
|
||||||
const submitButton = await frame.waitForSelector("#uploadFileButton");
|
|
||||||
await submitButton.click();
|
|
||||||
|
|
||||||
await frame.waitFor(NOTEBOOK_OPERATION_DELAY);
|
|
||||||
|
|
||||||
let uploadedNotebookNode: ElementHandle<Element>;
|
|
||||||
const treeNodeHeadersAfterUpload = await notebookResourceTree.$$(".treeNodeHeader");
|
|
||||||
for (var i = 1; i < treeNodeHeadersAfterUpload.length; i++) {
|
|
||||||
uploadedNotebookNode = treeNodeHeadersAfterUpload[i];
|
|
||||||
const nodeLabel = await uploadedNotebookNode.$eval(".nodeLabel", element => element.textContent);
|
|
||||||
if (nodeLabel === uploadNotebookName) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await uploadedNotebookNode.click();
|
|
||||||
await frame.waitForSelector(".tabNavText");
|
|
||||||
const tabTitle = await frame.$eval(".tabNavText", element => element.textContent);
|
|
||||||
expect(tabTitle).toEqual(uploadNotebookName);
|
|
||||||
|
|
||||||
const closeIcon = await frame.waitForSelector(".close-Icon");
|
|
||||||
await closeIcon.click();
|
|
||||||
|
|
||||||
ellipses = await uploadedNotebookNode.$(".treeMenuEllipsis");
|
|
||||||
await ellipses.click();
|
|
||||||
|
|
||||||
await frame.waitFor(RENDER_DELAY);
|
|
||||||
|
|
||||||
menuItems = await frame.$$(".ms-ContextualMenu-item");
|
|
||||||
await menuItems[1].click();
|
|
||||||
|
|
||||||
const deleteAcceptButton = await frame.waitForSelector(".ms-Dialog-action");
|
|
||||||
await deleteAcceptButton.click();
|
|
||||||
await frame.waitFor(NOTEBOOK_OPERATION_DELAY);
|
|
||||||
|
|
||||||
let index: number;
|
|
||||||
let deletedNotebookNode: ElementHandle<Element>;
|
|
||||||
const treeNodeHeadersAfterDelete = await notebookResourceTree.$$(".treeNodeHeader");
|
|
||||||
for (index = 1; index < treeNodeHeadersAfterDelete.length; index++) {
|
|
||||||
deletedNotebookNode = treeNodeHeadersAfterDelete[index];
|
|
||||||
const nodeLabel = await deletedNotebookNode.$eval(".nodeLabel", element => element.textContent);
|
|
||||||
if (nodeLabel === uploadNotebookName) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(index).toEqual(treeNodeHeadersAfterDelete.length);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { Frame } from "puppeteer";
|
import { Frame } from "puppeteer";
|
||||||
|
|
||||||
let testExplorerFrame: Frame;
|
|
||||||
|
|
||||||
export async function login(connectionString: string): Promise<Frame> {
|
export async function login(connectionString: string): Promise<Frame> {
|
||||||
const prodUrl = "https://localhost:1234/hostedExplorer.html";
|
const prodUrl = "https://localhost:1234/hostedExplorer.html";
|
||||||
page.goto(prodUrl);
|
page.goto(prodUrl);
|
||||||
|
|||||||
Reference in New Issue
Block a user