Add files from previous commit

This commit is contained in:
Steve Faulkner
2020-12-28 18:48:30 -06:00
parent 12a44fdd42
commit ac2d645fda
6 changed files with 287 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
.connectExplorerContainer {
height: 100%;
width: 100%;
}
.connectExplorerContainer .connectExplorerFormContainer {
display: -webkit-flex;
display: -ms-flexbox;
display: -ms-flex;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: 100%;
width: 100%;
}
.connectExplorerContainer .connectExplorer {
text-align: center;
display: -webkit-flex;
display: -ms-flexbox;
display: -ms-flex;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
justify-content: center;
height: 100%;
margin-bottom: 60px;
}
.connectExplorerContainer .connectExplorer .welcomeText {
font-size: 14px;
color: #393939;
margin: 8px 8px 16px 8px;
}
.connectExplorerContainer .connectExplorer .switchConnectTypeText {
margin: 8px;
font-size: 12px;
color: #0058ad;
cursor: pointer;
}
.connectExplorerContainer .connectExplorer .connectStringText {
font-size: 12px;
color: #393939;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent {
margin: 8px;
color: #393939;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .inputToken {
width: 300px;
padding: 0px 4px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .inputToken::placeholder {
font-style: italic;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .errorDetailsInfoTooltip {
position: relative;
display: inline-block;
padding-left: 4px;
vertical-align: top;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .errorDetailsInfoTooltip:hover .errorDetails {
visibility: visible;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .errorDetailsInfoTooltip .errorDetails {
bottom: 24px;
width: 145px;
visibility: hidden;
background-color: #393939;
color: #ffffff;
position: absolute;
z-index: 1;
left: -10px;
padding: 6px;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .errorDetailsInfoTooltip .errorDetails:after {
border-width: 10px 10px 0px 10px;
bottom: -8px;
content: "";
position: absolute;
right: 100%;
border-style: solid;
left: 12px;
width: 0;
height: 0;
border-color: #3b3b3b transparent;
}
.connectExplorerContainer .connectExplorer .connectExplorerContent .errorDetailsInfoTooltip .errorImg {
height: 14px;
width: 14px;
}
.filterbtnstyle {
background: #0058ad;
width: 90px;
height: 25px;
color: white;
border: solid 1px;
}

View File

@@ -0,0 +1,52 @@
import "./ConnectScreen.less";
import * as React from "react";
import { useMsal } from "@azure/msal-react";
import { useBoolean } from "@uifabric/react-hooks";
export const ConnectScreen: React.FunctionComponent = () => {
const { instance } = useMsal();
const [isConnectionStringVisible, { setTrue: showConnectionString }] = useBoolean(false);
return (
<div id="connectExplorer" className="connectExplorerContainer" style={{ display: "flex" }}>
<div className="connectExplorerFormContainer">
<div className="connectExplorer">
<p className="connectExplorerContent">
<img src="images/HdeConnectCosmosDB.svg" alt="Azure Cosmos DB" />
</p>
<p className="welcomeText">Welcome to Azure Cosmos DB</p>
{isConnectionStringVisible ? (
<form id="connectWithConnectionString">
<p className="connectExplorerContent connectStringText">Connect to your account with connection string</p>
<p className="connectExplorerContent">
<input className="inputToken" type="text" required placeholder="Please enter a connection string" />
<span className="errorDetailsInfoTooltip" style={{ display: "none" }}>
<img className="errorImg" src="images/error.svg" alt="Error notification" />
<span className="errorDetails" />
</span>
</p>
<p className="connectExplorerContent">
<input className="filterbtnstyle" type="submit" value="Connect" />
</p>
<p className="switchConnectTypeText" onClick={() => instance.loginPopup()}>
Sign In with Azure Account
</p>
</form>
) : (
<div id="connectWithAad">
<input className="filterbtnstyle" type="button" value="Sign In" onClick={() => instance.loginPopup()} />
<p
className="switchConnectTypeText"
onClick={() => {
showConnectionString();
}}
>
Connect to your account with connection string
</p>
</div>
)}
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,8 @@
import { AccountInfo } from "@azure/msal-browser";
import { useAccount, useMsal } from "@azure/msal-react";
export function useAADAccount(): AccountInfo {
const { accounts } = useMsal();
const account = useAccount(accounts[0] || {});
return account;
}

20
src/hooks/useAADToken.tsx Normal file
View File

@@ -0,0 +1,20 @@
import { useMsal } from "@azure/msal-react";
import { useEffect, useState } from "react";
import { useAADAccount } from "./useAADAccount";
export function useAADToken(): string {
const { instance } = useMsal();
const account = useAADAccount();
const [state, setState] = useState<string>();
useEffect(() => {
console.log("Current account", account);
if (account) {
instance.acquireTokenSilent({ account, scopes: ["User.Read"] }).then(response => {
console.log("Fetched token", response.accessToken);
setState(response.accessToken);
});
}
}, [account]);
return state;
}

View File

@@ -0,0 +1,31 @@
import { useEffect, useState } from "react";
import { useAADToken } from "./useAADToken";
export async function fetchPhoto(accessToken: string): Promise<Blob | void> {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
headers.append("Content-Type", "image/jpg");
const options = {
method: "GET",
headers: headers
};
return fetch("https://graph.microsoft.com/v1.0/me/photo/$value", options)
.then(response => response.blob())
.catch(error => console.log(error));
}
export function useGraphPhoto(): string {
const token = useAADToken();
const [photo, setPhoto] = useState<string>();
useEffect(() => {
if (token) {
fetchPhoto(token).then(response => setPhoto(URL.createObjectURL(response)));
}
}, [token]);
return photo;
}

View File

@@ -0,0 +1,75 @@
import { useEffect, useState } from "react";
import { Subscription } from "../Contracts/DataModels";
import { useAADToken } from "./useAADToken";
interface SubscriptionListResult {
nextLink: string;
value: Subscription[];
}
export async function fetchSubscriptions(accessToken: string): Promise<Subscription[]> {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
let subscriptions: Array<Subscription> = [];
let nextLink = `https://management.azure.com/subscriptions?api-version=2020-01-01`;
while (nextLink) {
const response = await fetch(nextLink, { headers });
const result: SubscriptionListResult =
response.status === 204 || response.status === 304 ? undefined : await response.json();
if (!response.ok) {
throw result;
}
nextLink = result.nextLink;
const validSubscriptions = result.value.filter(
sub => sub.state === "Enabled" || sub.state === "Warned" || sub.state === "PastDue"
);
subscriptions = [...subscriptions, ...validSubscriptions];
}
return subscriptions;
}
export function useSubscriptions(): Subscription[] {
const token = useAADToken();
const [state, setState] = useState<Subscription[]>();
useEffect(() => {
if (token) {
fetchSubscriptions(token).then(response => setState(response));
}
}, [token]);
return state || [];
}
// const { accounts } = useMsal();
// const account = useAccount(accounts[0] || {});
// const { isLoading, isError, data, error } = useQuery(
// ["subscriptions", account.tenantId],
// async () => {
// let subscriptions: Array<Subscription> = [];
// const fetchHeaders = await ArmResourceUtils._getAuthHeader(ArmResourceUtils._armAuthArea, tenantId);
// let nextLink = `${ArmResourceUtils._armEndpoint}/subscriptions?api-version=${ArmResourceUtils._armApiVersion}`;
// while (nextLink) {
// const response: Response = await fetch(nextLink, { headers: fetchHeaders });
// const result: SubscriptionListResult =
// response.status === 204 || response.status === 304 ? null : await response.json();
// if (!response.ok) {
// throw result;
// }
// nextLink = result.nextLink;
// const validSubscriptions = result.value.filter(
// sub => sub.state === "Enabled" || sub.state === "Warned" || sub.state === "PastDue"
// );
// subscriptions = [...subscriptions, ...validSubscriptions];
// }
// return subscriptions;
// },
// { enabled: account.tenantId }
// );
// console.log(isLoading, isError, data, error);