mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-22 10:21:37 +00:00
WIP, checkpoint
This commit is contained in:
@@ -3,15 +3,25 @@ import { useBoolean } from "@uifabric/react-hooks";
|
||||
import { HttpHeaders } from "../../../Common/Constants";
|
||||
import { GenerateTokenResponse } from "../../../Contracts/DataModels";
|
||||
import { configContext } from "../../../ConfigContext";
|
||||
import { AuthType } from "../../../AuthType";
|
||||
import { isResourceTokenConnectionString } from "../Helpers/ResourceTokenUtils";
|
||||
|
||||
interface Props {
|
||||
connectionString: string;
|
||||
login: () => void;
|
||||
setEncryptedToken: (token: string) => void;
|
||||
setConnectionString: (connectionString: string) => void;
|
||||
setAuthType: (authType: AuthType) => void;
|
||||
}
|
||||
|
||||
export const ConnectExplorer: React.FunctionComponent<Props> = ({ setEncryptedToken, login }: Props) => {
|
||||
const [connectionString, setConnectionString] = React.useState<string>("");
|
||||
const [isConnectionStringVisible, { setTrue: showConnectionString }] = useBoolean(false);
|
||||
export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
||||
setEncryptedToken,
|
||||
login,
|
||||
setAuthType,
|
||||
connectionString,
|
||||
setConnectionString
|
||||
}: Props) => {
|
||||
const [isFormVisible, { setTrue: showForm }] = useBoolean(false);
|
||||
|
||||
return (
|
||||
<div id="connectExplorer" className="connectExplorerContainer" style={{ display: "flex" }}>
|
||||
@@ -21,11 +31,17 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({ setEncryptedTo
|
||||
<img src="images/HdeConnectCosmosDB.svg" alt="Azure Cosmos DB" />
|
||||
</p>
|
||||
<p className="welcomeText">Welcome to Azure Cosmos DB</p>
|
||||
{isConnectionStringVisible ? (
|
||||
{isFormVisible ? (
|
||||
<form
|
||||
id="connectWithConnectionString"
|
||||
onSubmit={async event => {
|
||||
event.preventDefault();
|
||||
|
||||
if (isResourceTokenConnectionString(connectionString)) {
|
||||
setAuthType(AuthType.ResourceToken);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = new Headers();
|
||||
headers.append(HttpHeaders.connectionString, connectionString);
|
||||
const url = configContext.BACKEND_ENDPOINT + "/api/guest/tokens/generateToken";
|
||||
@@ -37,6 +53,7 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({ setEncryptedTo
|
||||
const result: GenerateTokenResponse = JSON.parse(await response.json());
|
||||
console.log(result.readWrite || result.read);
|
||||
setEncryptedToken(decodeURIComponent(result.readWrite || result.read));
|
||||
setAuthType(AuthType.ConnectionString);
|
||||
}}
|
||||
>
|
||||
<p className="connectExplorerContent connectStringText">Connect to your account with connection string</p>
|
||||
@@ -66,7 +83,7 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({ setEncryptedTo
|
||||
) : (
|
||||
<div id="connectWithAad">
|
||||
<input className="filterbtnstyle" type="button" value="Sign In" onClick={login} />
|
||||
<p className="switchConnectTypeText" onClick={showConnectionString}>
|
||||
<p className="switchConnectTypeText" onClick={showForm}>
|
||||
Connect to your account with connection string
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Main from "./Main";
|
||||
import { isResourceTokenConnectionString, parseResourceTokenConnectionString } from "./ResourceTokenUtils";
|
||||
|
||||
describe("Main", () => {
|
||||
describe("parseResourceTokenConnectionString", () => {
|
||||
it("correctly parses resource token connection string", () => {
|
||||
const connectionString =
|
||||
"AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;";
|
||||
const properties = Main.parseResourceTokenConnectionString(connectionString);
|
||||
const properties = parseResourceTokenConnectionString(connectionString);
|
||||
|
||||
expect(properties).toEqual({
|
||||
accountEndpoint: "fakeEndpoint",
|
||||
@@ -18,7 +18,7 @@ describe("Main", () => {
|
||||
it("correctly parses resource token connection string with partition key", () => {
|
||||
const connectionString =
|
||||
"type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;PartitionKey=fakePartitionKey;";
|
||||
const properties = Main.parseResourceTokenConnectionString(connectionString);
|
||||
const properties = parseResourceTokenConnectionString(connectionString);
|
||||
|
||||
expect(properties).toEqual({
|
||||
accountEndpoint: "fakeEndpoint",
|
||||
@@ -29,3 +29,16 @@ describe("Main", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("isResourceToken", () => {
|
||||
it("valid resource connection string", () => {
|
||||
const connectionString =
|
||||
"AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;";
|
||||
expect(isResourceTokenConnectionString(connectionString)).toBe(true);
|
||||
});
|
||||
|
||||
it("non-resource connection string", () => {
|
||||
const connectionString = "AccountEndpoint=https://stfaul-sql.documents.azure.com:443/;AccountKey=foo;";
|
||||
expect(isResourceTokenConnectionString(connectionString)).toBe(false);
|
||||
});
|
||||
});
|
||||
43
src/Platform/Hosted/Helpers/ResourceTokenUtils.ts
Normal file
43
src/Platform/Hosted/Helpers/ResourceTokenUtils.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export interface ParsedResourceTokenConnectionString {
|
||||
accountEndpoint: string;
|
||||
collectionId: string;
|
||||
databaseId: string;
|
||||
partitionKey?: string;
|
||||
resourceToken: string;
|
||||
}
|
||||
|
||||
export function parseResourceTokenConnectionString(connectionString: string): ParsedResourceTokenConnectionString {
|
||||
let accountEndpoint: string;
|
||||
let collectionId: string;
|
||||
let databaseId: string;
|
||||
let partitionKey: string;
|
||||
let resourceToken: string;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
connectionStringParts.forEach((part: string) => {
|
||||
if (part.startsWith("type=resource")) {
|
||||
resourceToken = part + ";";
|
||||
} else if (part.startsWith("AccountEndpoint=")) {
|
||||
accountEndpoint = part.substring(16);
|
||||
} else if (part.startsWith("DatabaseId=")) {
|
||||
databaseId = part.substring(11);
|
||||
} else if (part.startsWith("CollectionId=")) {
|
||||
collectionId = part.substring(13);
|
||||
} else if (part.startsWith("PartitionKey=")) {
|
||||
partitionKey = part.substring(13);
|
||||
} else if (part !== "") {
|
||||
resourceToken += part + ";";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
accountEndpoint,
|
||||
collectionId,
|
||||
databaseId,
|
||||
partitionKey,
|
||||
resourceToken
|
||||
};
|
||||
}
|
||||
|
||||
export function isResourceTokenConnectionString(connectionString: string): boolean {
|
||||
return connectionString && connectionString.includes("type=resource");
|
||||
}
|
||||
@@ -31,3 +31,15 @@ export function getDatabaseAccountPropertiesFromMetadata(metadata: AccessInputMe
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
export function getDatabaseAccountKindFromExperience(apiExperience: string): string {
|
||||
if (apiExperience === Constants.DefaultAccountExperience.MongoDB) {
|
||||
return Constants.AccountKind.MongoDB;
|
||||
}
|
||||
|
||||
if (apiExperience === Constants.DefaultAccountExperience.ApiForMongoDB) {
|
||||
return Constants.AccountKind.MongoDB;
|
||||
}
|
||||
|
||||
return Constants.AccountKind.GlobalDocumentDB;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AuthType } from "../../AuthType";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { configContext } from "../../ConfigContext";
|
||||
import { ApiKind, DatabaseAccount, resourceTokenConnectionStringProperties } from "../../Contracts/DataModels";
|
||||
import { ApiKind, DatabaseAccount } from "../../Contracts/DataModels";
|
||||
import { DataExplorerInputsFrame } from "../../Contracts/ViewModels";
|
||||
import Explorer from "../../Explorer/Explorer";
|
||||
import "../../Explorer/Tables/DataTable/DataTableBindingManager";
|
||||
@@ -12,38 +12,6 @@ import { extractFeatures } from "./extractFeatures";
|
||||
import { getDatabaseAccountPropertiesFromMetadata } from "./HostedUtils";
|
||||
|
||||
export default class Main {
|
||||
public static parseResourceTokenConnectionString(connectionString: string): resourceTokenConnectionStringProperties {
|
||||
let accountEndpoint: string;
|
||||
let collectionId: string;
|
||||
let databaseId: string;
|
||||
let partitionKey: string;
|
||||
let resourceToken: string;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
connectionStringParts.forEach((part: string) => {
|
||||
if (part.startsWith("type=resource")) {
|
||||
resourceToken = part + ";";
|
||||
} else if (part.startsWith("AccountEndpoint=")) {
|
||||
accountEndpoint = part.substring(16);
|
||||
} else if (part.startsWith("DatabaseId=")) {
|
||||
databaseId = part.substring(11);
|
||||
} else if (part.startsWith("CollectionId=")) {
|
||||
collectionId = part.substring(13);
|
||||
} else if (part.startsWith("PartitionKey=")) {
|
||||
partitionKey = part.substring(13);
|
||||
} else if (part !== "") {
|
||||
resourceToken += part + ";";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
accountEndpoint,
|
||||
collectionId,
|
||||
databaseId,
|
||||
partitionKey,
|
||||
resourceToken
|
||||
};
|
||||
}
|
||||
|
||||
public static initDataExplorerFrameInputs(
|
||||
explorer: Explorer,
|
||||
masterKey?: string /* master key extracted from connection string if available */,
|
||||
@@ -68,6 +36,8 @@ export default class Main {
|
||||
}
|
||||
|
||||
if (authType === AuthType.EncryptedToken) {
|
||||
// TODO: Remove window.authType
|
||||
window.authType = AuthType.EncryptedToken;
|
||||
const apiExperience: string = DefaultExperienceUtility.getDefaultExperienceFromApiKind(
|
||||
Main._accessInputMetadata.apiKind
|
||||
);
|
||||
@@ -150,29 +120,8 @@ export default class Main {
|
||||
throw new Error(`Unsupported AuthType ${authType}`);
|
||||
}
|
||||
|
||||
private static _getDatabaseAccountKindFromExperience(apiExperience: string): string {
|
||||
if (apiExperience === Constants.DefaultAccountExperience.MongoDB) {
|
||||
return Constants.AccountKind.MongoDB;
|
||||
}
|
||||
|
||||
if (apiExperience === Constants.DefaultAccountExperience.ApiForMongoDB) {
|
||||
return Constants.AccountKind.MongoDB;
|
||||
}
|
||||
|
||||
return Constants.AccountKind.GlobalDocumentDB;
|
||||
}
|
||||
|
||||
private static _getMasterKeyFromConnectionString(connectionString: string): string {
|
||||
if (!connectionString || Main._accessInputMetadata == null || Main._accessInputMetadata.apiKind !== ApiKind.Graph) {
|
||||
// client only needs master key for Graph API
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const matchedParts: string[] = connectionString.match("AccountKey=(.*);ApiKind=Gremlin;$");
|
||||
return (matchedParts.length > 1 && matchedParts[1]) || undefined;
|
||||
}
|
||||
|
||||
private static _isResourceToken(connectionString: string): boolean {
|
||||
return connectionString && connectionString.includes("type=resource");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user