mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 02:41:39 +00:00
Compare commits
3 Commits
master
...
ashleyst/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48950613a7 | ||
|
|
2bd913acbb | ||
|
|
4866d3c902 |
@@ -238,6 +238,15 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
||||
updateConfigContext({ platform });
|
||||
}
|
||||
}
|
||||
if (window.location.origin !== configContext.hostedExplorerURL) {
|
||||
if (window.location.origin === "https://localhost:1234") {
|
||||
// Special case for localhost, we need to send them to 'hostedExplorer.html'.
|
||||
updateConfigContext({ hostedExplorerURL: "https://localhost:1234/hostedExplorer.html" });
|
||||
} else {
|
||||
const newOrigin = window.location.origin.endsWith("/") ? window.location.origin : `${window.location.origin}/`;
|
||||
updateConfigContext({ hostedExplorerURL: newOrigin });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("No configuration file found using defaults");
|
||||
}
|
||||
@@ -245,3 +254,4 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
||||
}
|
||||
|
||||
export { configContext };
|
||||
|
||||
|
||||
@@ -1,20 +1,43 @@
|
||||
import { PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||
import { AuthType } from "AuthType";
|
||||
import { configContext } from "ConfigContext";
|
||||
import { userContext } from "UserContext";
|
||||
import * as React from "react";
|
||||
|
||||
export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.append("openFrom", "portal");
|
||||
|
||||
let hasAccountContext = false;
|
||||
let requiresConnectionString = false;
|
||||
|
||||
if (userContext.authType === AuthType.AAD) {
|
||||
if (userContext.subscriptionId && userContext.databaseAccount) {
|
||||
searchParams.append("subscription", userContext.subscriptionId);
|
||||
searchParams.append("account", userContext.databaseAccount.name);
|
||||
searchParams.append("authType", "entra");
|
||||
hasAccountContext = true;
|
||||
}
|
||||
} else if (userContext.authType === AuthType.MasterKey || userContext.authType === AuthType.ResourceToken) {
|
||||
requiresConnectionString = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ padding: "34px" }}>
|
||||
<Stack tokens={{ childrenGap: 10 }}>
|
||||
<Text>
|
||||
Open this database account in a new browser tab with Cosmos DB Explorer. You can connect using your
|
||||
Microsoft account or a connection string.
|
||||
Open this database account in a new browser tab with Cosmos DB Explorer.
|
||||
{requiresConnectionString && " You'll need to provide a connection string."}
|
||||
{hasAccountContext && " You may be prompted to sign in with Entra ID again."}
|
||||
</Text>
|
||||
<Text>
|
||||
Open tabs and queries will not be carried over, but you can still access them in this tab.
|
||||
</Text>
|
||||
<Stack horizontal tokens={{ childrenGap: 10 }}>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
window.open("https://cosmos.azure.com/", "_blank");
|
||||
}}
|
||||
href={`${configContext.hostedExplorerURL}?${searchParams.toString()}`}
|
||||
target="_blank"
|
||||
text="Open"
|
||||
iconProps={{ iconName: "OpenInNewWindow" }}
|
||||
/>
|
||||
|
||||
@@ -33,7 +33,7 @@ const App: React.FunctionComponent = () => {
|
||||
// For showing/hiding panel
|
||||
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
||||
const config = useConfig();
|
||||
const { isLoggedIn, armToken, graphToken, account, tenantId, logout, login, switchTenant, authFailure } =
|
||||
const { isLoggedIn, armToken, graphToken, account, tenantId, logout, forgetUser, login, switchTenant, authFailure } =
|
||||
useAADAuth();
|
||||
const [databaseAccount, setDatabaseAccount] = React.useState<DatabaseAccount>();
|
||||
const [authType, setAuthType] = React.useState<AuthType>(encryptedToken ? AuthType.EncryptedToken : undefined);
|
||||
|
||||
@@ -9,7 +9,6 @@ import "../less/index.less";
|
||||
|
||||
const Index = (): JSX.Element => {
|
||||
const [navigationSelection, setNavigationSelection] = useState("quickstart");
|
||||
|
||||
const quickstart_click = () => {
|
||||
setNavigationSelection("quickstart");
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
import { DefaultButton, IButtonStyles, IContextualMenuItem } from "@fluentui/react";
|
||||
import { urlContext } from "Utils/UrlContext";
|
||||
import * as React from "react";
|
||||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
@@ -50,12 +51,12 @@ interface Props {
|
||||
export const AccountSwitcher: FunctionComponent<Props> = ({ armToken, setDatabaseAccount }: Props) => {
|
||||
const subscriptions = useSubscriptions(armToken);
|
||||
const [selectedSubscriptionId, setSelectedSubscriptionId] = useState<string>(() =>
|
||||
localStorage.getItem("cachedSubscriptionId"),
|
||||
urlContext.subscription || localStorage.getItem("cachedSubscriptionId"),
|
||||
);
|
||||
const selectedSubscription = subscriptions?.find((sub) => sub.subscriptionId === selectedSubscriptionId);
|
||||
const accounts = useDatabaseAccounts(selectedSubscription?.subscriptionId, armToken);
|
||||
const [selectedAccountName, setSelectedAccountName] = useState<string>(() =>
|
||||
localStorage.getItem("cachedDatabaseAccountName"),
|
||||
urlContext.account || localStorage.getItem("cachedDatabaseAccountName"),
|
||||
);
|
||||
const selectedAccount = accounts?.find((account) => account.name === selectedAccountName);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useBoolean } from "@fluentui/react-hooks";
|
||||
import { userContext } from "UserContext";
|
||||
import { useNewPortalBackendEndpoint } from "Utils/EndpointUtils";
|
||||
import { OpenedFrom, RequestedAuthType, urlContext } from "Utils/UrlContext";
|
||||
import * as React from "react";
|
||||
import ConnectImage from "../../../../images/HdeConnectCosmosDB.svg";
|
||||
import ErrorImage from "../../../../images/error.svg";
|
||||
@@ -69,7 +70,9 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
||||
}: Props) => {
|
||||
const [isFormVisible, { setTrue: showForm }] = useBoolean(false);
|
||||
const [errorMessage, setErrorMessage] = React.useState("");
|
||||
const enableConnectionStringLogin = !userContext.features.disableConnectionStringLogin;
|
||||
const enableConnectionStringLogin =
|
||||
urlContext.authType !== RequestedAuthType.Entra &&
|
||||
!userContext.features.disableConnectionStringLogin;
|
||||
|
||||
return (
|
||||
<div id="connectExplorer" className="connectExplorerContainer" style={{ display: "flex" }}>
|
||||
@@ -137,6 +140,11 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
||||
Connect to your account with connection string
|
||||
</p>
|
||||
)}
|
||||
{urlContext.openFrom === OpenedFrom.Portal && (
|
||||
<p className="switchConnectTypeText">
|
||||
Click sign in to continue your session from the Azure Portal.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -192,3 +192,4 @@ function apiType(account: DatabaseAccount | undefined): ApiType {
|
||||
}
|
||||
|
||||
export { updateUserContext, userContext };
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.micr
|
||||
|
||||
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
||||
|
||||
export const allowedHostedExplorerEndpoints: ReadonlyArray<string> = ["https://cosmos.azure.com/"];
|
||||
export const allowedHostedExplorerEndpoints: ReadonlyArray<string> = ["https://cosmos.azure.com/", "https://localhost:1234/"];
|
||||
|
||||
export const allowedMsalRedirectEndpoints: ReadonlyArray<string> = [
|
||||
"https://cosmos-explorer-preview.azurewebsites.net/",
|
||||
|
||||
17
src/Utils/UrlContext.ts
Normal file
17
src/Utils/UrlContext.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
export enum OpenedFrom {
|
||||
Portal = "portal",
|
||||
}
|
||||
|
||||
export enum RequestedAuthType {
|
||||
Entra = "entra",
|
||||
ConnectionString = "connectionstring",
|
||||
}
|
||||
|
||||
export const urlContext = {
|
||||
openFrom: urlParams.get("openFrom") as OpenedFrom,
|
||||
authType: urlParams.get("authType") as RequestedAuthType,
|
||||
subscription: urlParams.get("subscription"),
|
||||
account: urlParams.get("account"),
|
||||
};
|
||||
@@ -38,6 +38,7 @@ export function useAADAuth(): ReturnType {
|
||||
const [authFailure, setAuthFailure] = React.useState<AadAuthFailure>(undefined);
|
||||
|
||||
msalInstance.setActiveAccount(account);
|
||||
|
||||
const login = React.useCallback(async () => {
|
||||
const response = await msalInstance.loginPopup({
|
||||
redirectUri: configContext.msalRedirectURI,
|
||||
@@ -47,13 +48,13 @@ export function useAADAuth(): ReturnType {
|
||||
setAccount(response.account);
|
||||
setTenantId(response.tenantId);
|
||||
localStorage.setItem("cachedTenantId", response.tenantId);
|
||||
}, []);
|
||||
}, [setLoggedIn, setAccount, setTenantId]);
|
||||
|
||||
const logout = React.useCallback(() => {
|
||||
setLoggedOut();
|
||||
localStorage.removeItem("cachedTenantId");
|
||||
msalInstance.logoutRedirect();
|
||||
}, []);
|
||||
}, [setLoggedOut]);
|
||||
|
||||
const switchTenant = React.useCallback(
|
||||
async (id) => {
|
||||
@@ -66,7 +67,7 @@ export function useAADAuth(): ReturnType {
|
||||
setAccount(response.account);
|
||||
localStorage.setItem("cachedTenantId", response.tenantId);
|
||||
},
|
||||
[account, tenantId],
|
||||
[setTenantId, setAccount],
|
||||
);
|
||||
|
||||
const acquireTokens = React.useCallback(async () => {
|
||||
@@ -123,6 +124,19 @@ export function useAADAuth(): ReturnType {
|
||||
}
|
||||
}, [account, tenantId, acquireTokens, authFailure]);
|
||||
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
// If we're on a redirect, handle it
|
||||
const response = await msalInstance.handleRedirectPromise();
|
||||
if (response) {
|
||||
setLoggedIn();
|
||||
setAccount(response.account);
|
||||
setTenantId(response.tenantId);
|
||||
localStorage.setItem("cachedTenantId", response.tenantId);
|
||||
}
|
||||
})()
|
||||
}, [setLoggedIn])
|
||||
|
||||
return {
|
||||
account,
|
||||
tenantId,
|
||||
|
||||
Reference in New Issue
Block a user