Test Explorer Improvements (#541)

This commit is contained in:
Steve Faulkner
2021-03-14 22:53:16 -05:00
committed by GitHub
parent f86883de6c
commit 254c551999
15 changed files with 427 additions and 506 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { applyExplorerBindings } from "../applyExplorerBindings";
import { AuthType } from "../AuthType";
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 has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
// Pleas tread carefully :)
let explorer: Explorer;
export function useKnockoutExplorer(platform: Platform, explorerParams: ExplorerParams): Explorer {
explorer = explorer || new Explorer(explorerParams);
const [explorer, setExplorer] = useState<Explorer>();
useEffect(() => {
const effect = async () => {
if (platform) {
if (platform === Platform.Hosted) {
await configureHosted();
applyExplorerBindings(explorer);
const explorer = await configureHosted(explorerParams);
setExplorer(explorer);
} else if (platform === Platform.Emulator) {
configureEmulator();
applyExplorerBindings(explorer);
const explorer = configureEmulator(explorerParams);
setExplorer(explorer);
} else if (platform === Platform.Portal) {
configurePortal();
const explorer = await configurePortal(explorerParams);
setExplorer(explorer);
}
}
};
effect();
}, [platform]);
useEffect(() => {
if (explorer) {
applyExplorerBindings(explorer);
}
}, [explorer]);
return explorer;
}
async function configureHosted() {
async function configureHosted(explorerParams: ExplorerParams): Promise<Explorer> {
const win = (window as unknown) as HostedExplorerChildFrame;
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
configureHostedWithEncryptedToken(win.hostedConfig);
return configureHostedWithEncryptedToken(win.hostedConfig, explorerParams);
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
configureHostedWithResourceToken(win.hostedConfig);
return configureHostedWithResourceToken(win.hostedConfig, explorerParams);
} else if (win.hostedConfig.authType === AuthType.ConnectionString) {
configureHostedWithConnectionString(win.hostedConfig);
return configureHostedWithConnectionString(win.hostedConfig, explorerParams);
} 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 accountResourceId = account.id;
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
updateUserContext({
subscriptionId,
resourceGroup,
authType: AuthType.AAD,
authorizationToken: `Bearer ${config.authorizationToken}`,
databaseAccount: config.databaseAccount,
});
const keys = await listKeys(subscriptionId, resourceGroup, account.name);
const explorer = new Explorer(explorerParams);
explorer.configure({
databaseAccount: account,
subscriptionId,
@@ -87,9 +99,10 @@ async function configureHostedWithAAD(config: AAD) {
authorizationToken: `Bearer ${config.authorizationToken}`,
features: extractFeatures(),
});
return explorer;
}
function configureHostedWithConnectionString(config: ConnectionString) {
function configureHostedWithConnectionString(config: ConnectionString, explorerParams: ExplorerParams): Explorer {
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
const databaseAccount = {
id: "",
@@ -106,14 +119,16 @@ function configureHostedWithConnectionString(config: ConnectionString) {
accessToken: encodeURIComponent(config.encryptedToken),
databaseAccount,
});
const explorer = new Explorer(explorerParams);
explorer.configure({
databaseAccount,
masterKey: config.masterKey,
features: extractFeatures(),
});
return explorer;
}
function configureHostedWithResourceToken(config: ResourceToken) {
function configureHostedWithResourceToken(config: ResourceToken, explorerParams: ExplorerParams): Explorer {
const parsedResourceToken = parseResourceTokenConnectionString(config.resourceToken);
const databaseAccount = {
id: "",
@@ -131,6 +146,7 @@ function configureHostedWithResourceToken(config: ResourceToken) {
resourceToken: parsedResourceToken.resourceToken,
endpoint: parsedResourceToken.accountEndpoint,
});
const explorer = new Explorer(explorerParams);
explorer.resourceTokenDatabaseId(parsedResourceToken.databaseId);
explorer.resourceTokenCollectionId(parsedResourceToken.collectionId);
if (parsedResourceToken.partitionKey) {
@@ -142,9 +158,10 @@ function configureHostedWithResourceToken(config: ResourceToken) {
isAuthWithresourceToken: true,
});
explorer.isRefreshingExplorer(false);
return explorer;
}
function configureHostedWithEncryptedToken(config: EncryptedToken) {
function configureHostedWithEncryptedToken(config: EncryptedToken, explorerParams: ExplorerParams): Explorer {
updateUserContext({
authType: AuthType.EncryptedToken,
accessToken: encodeURIComponent(config.encryptedToken),
@@ -152,6 +169,7 @@ function configureHostedWithEncryptedToken(config: EncryptedToken) {
const apiExperience: string = DefaultExperienceUtility.getDefaultExperienceFromApiKind(
config.encryptedTokenMetadata.apiKind
);
const explorer = new Explorer(explorerParams);
explorer.configure({
databaseAccount: {
id: "",
@@ -162,91 +180,98 @@ function configureHostedWithEncryptedToken(config: EncryptedToken) {
},
features: extractFeatures(),
});
return explorer;
}
function configureEmulator() {
function configureEmulator(explorerParams: ExplorerParams): Explorer {
updateUserContext({
databaseAccount: emulatorAccount,
authType: AuthType.MasterKey,
});
const explorer = new Explorer(explorerParams);
explorer.databaseAccount(emulatorAccount);
explorer.isAccountReady(true);
return explorer;
}
function configurePortal() {
async function configurePortal(explorerParams: ExplorerParams): Promise<Explorer> {
updateUserContext({
authType: AuthType.AAD,
});
// In development mode, try to load the iframe message from session storage.
// This allows webpack hot reload to function properly in the portal
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
const initMessage = sessionStorage.getItem("portalDataExplorerInitMessage");
if (initMessage) {
const message = JSON.parse(initMessage);
console.warn(
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
);
console.dir(message);
explorer.configure(message);
applyExplorerBindings(explorer);
return new Promise((resolve) => {
// In development mode, try to load the iframe message from session storage.
// This allows webpack hot reload to function properly in the portal
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
const initMessage = sessionStorage.getItem("portalDataExplorerInitMessage");
if (initMessage) {
const message = JSON.parse(initMessage);
console.warn(
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
);
console.dir(message);
const explorer = new Explorer(explorerParams);
explorer.configure(message);
resolve(explorer);
}
}
}
// In the Portal, configuration of Explorer happens via iframe message
window.addEventListener(
"message",
(event) => {
if (isInvalidParentFrameOrigin(event)) {
return;
}
if (!shouldProcessMessage(event)) {
return;
}
// Check for init message
const message: PortalMessage = event.data?.data;
const inputs = message?.inputs;
const openAction = message?.openAction;
if (inputs) {
if (
configContext.BACKEND_ENDPOINT &&
configContext.platform === Platform.Portal &&
process.env.NODE_ENV === "development"
) {
inputs.extensionEndpoint = configContext.PROXY_PATH;
// In the Portal, configuration of Explorer happens via iframe message
window.addEventListener(
"message",
(event) => {
if (isInvalidParentFrameOrigin(event)) {
return;
}
const authorizationToken = inputs.authorizationToken || "";
const masterKey = inputs.masterKey || "";
const databaseAccount = inputs.databaseAccount;
updateConfigContext({
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
ARM_ENDPOINT: normalizeArmEndpoint(inputs.csmEndpoint || configContext.ARM_ENDPOINT),
});
updateUserContext({
authorizationToken,
masterKey,
databaseAccount,
resourceGroup: inputs.resourceGroup,
subscriptionId: inputs.subscriptionId,
subscriptionType: inputs.subscriptionType,
quotaId: inputs.quotaId,
});
explorer.configure(inputs);
applyExplorerBindings(explorer);
if (openAction) {
handleOpenAction(openAction, explorer.nonSystemDatabases(), explorer);
if (!shouldProcessMessage(event)) {
return;
}
}
},
false
);
sendMessage("ready");
// Check for init message
const message: PortalMessage = event.data?.data;
const inputs = message?.inputs;
const openAction = message?.openAction;
if (inputs) {
if (
configContext.BACKEND_ENDPOINT &&
configContext.platform === Platform.Portal &&
process.env.NODE_ENV === "development"
) {
inputs.extensionEndpoint = configContext.PROXY_PATH;
}
const authorizationToken = inputs.authorizationToken || "";
const masterKey = inputs.masterKey || "";
const databaseAccount = inputs.databaseAccount;
updateConfigContext({
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
ARM_ENDPOINT: normalizeArmEndpoint(inputs.csmEndpoint || configContext.ARM_ENDPOINT),
});
updateUserContext({
authorizationToken,
masterKey,
databaseAccount,
resourceGroup: inputs.resourceGroup,
subscriptionId: inputs.subscriptionId,
subscriptionType: inputs.subscriptionType,
quotaId: inputs.quotaId,
});
const explorer = new Explorer(explorerParams);
explorer.configure(inputs);
resolve(explorer);
if (openAction) {
handleOpenAction(openAction, explorer.nonSystemDatabases(), explorer);
}
}
},
false
);
sendMessage("ready");
});
}
function shouldProcessMessage(event: MessageEvent): boolean {