remove arm token dependency

This commit is contained in:
Bikram Choudhury
2025-10-27 16:12:54 +05:30
parent 6483bd146d
commit e002a4505c
17 changed files with 129 additions and 118 deletions
+10 -1
View File
@@ -24,5 +24,14 @@
"source.organizeImports": "explicit" "source.organizeImports": "explicit"
}, },
"typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.importModuleSpecifier": "non-relative",
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode",
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
}
} }
+8
View File
@@ -36,6 +36,14 @@ export interface DatabaseAccountSystemData {
export interface DatabaseAccountBackupPolicy { export interface DatabaseAccountBackupPolicy {
type: string; type: string;
/* periodicModeProperties?: {
backupIntervalInMinutes: number;
backupRetentionIntervalInHours: number;
backupStorageRedundancy: string;
};
continuousModeProperties?: {
tier: string;
}; */
} }
export interface DatabaseAccountExtendedProperties { export interface DatabaseAccountExtendedProperties {
@@ -1,7 +1,5 @@
import React from "react"; import React from "react";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { useAADAuth } from "../../../hooks/useAADAuth";
import { useConfig } from "../../../hooks/useConfig";
import { CopyJobMigrationType } from "../Enums"; import { CopyJobMigrationType } from "../Enums";
import { CopyJobContextProviderType, CopyJobContextState, CopyJobFlowType } from "../Types"; import { CopyJobContextProviderType, CopyJobContextState, CopyJobFlowType } from "../Types";
@@ -39,24 +37,15 @@ const getInitialCopyJobState = (): CopyJobContextState => {
} }
const CopyJobContextProvider: React.FC<CopyJobContextProviderProps> = (props) => { const CopyJobContextProvider: React.FC<CopyJobContextProviderProps> = (props) => {
const config = useConfig();
const { isLoggedIn, armToken, account } = useAADAuth(config);
const principalId = account?.localAccountId ?? "";
const [copyJobState, setCopyJobState] = React.useState<CopyJobContextState>(getInitialCopyJobState()); const [copyJobState, setCopyJobState] = React.useState<CopyJobContextState>(getInitialCopyJobState());
const [flow, setFlow] = React.useState<CopyJobFlowType | null>(null); const [flow, setFlow] = React.useState<CopyJobFlowType | null>(null);
if (!isLoggedIn || !armToken) {
// Add a shimmer or loader here
return null;
}
const resetCopyJobState = () => { const resetCopyJobState = () => {
setCopyJobState(getInitialCopyJobState()); setCopyJobState(getInitialCopyJobState());
} }
return ( return (
<CopyJobContext.Provider value={{ principalId, armToken, copyJobState, setCopyJobState, flow, setFlow, resetCopyJobState }}> <CopyJobContext.Provider value={{ copyJobState, setCopyJobState, flow, setFlow, resetCopyJobState }}>
{props.children} {props.children}
</CopyJobContext.Provider> </CopyJobContext.Provider>
); );
@@ -79,3 +79,12 @@ export function extractErrorMessage(error: CopyJobErrorType): CopyJobErrorType {
} }
} }
export function getAccountDetailsFromResourceId(accountId: string | undefined) {
if (!accountId) {
return null;
}
const pattern = new RegExp('/subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft\\.DocumentDB/databaseAccounts/([^/]+)', 'i');
const matches = accountId.match(pattern);
const [_, subscriptionId, resourceGroup, accountName] = matches || [];
return { subscriptionId, resourceGroup, accountName };
}
@@ -25,7 +25,7 @@ export interface PermissionSectionConfig {
Component: React.ComponentType Component: React.ComponentType
disabled: boolean; disabled: boolean;
completed?: boolean; completed?: boolean;
validate?: (state: CopyJobContextState, armToken?: string) => boolean | Promise<boolean>; validate?: (state: CopyJobContextState) => boolean | Promise<boolean>;
} }
// Section IDs for maintainability // Section IDs for maintainability
@@ -66,10 +66,9 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
title: ContainerCopyMessages.readPermissionAssigned.title, title: ContainerCopyMessages.readPermissionAssigned.title,
Component: AddReadPermissionToDefaultIdentity, Component: AddReadPermissionToDefaultIdentity,
disabled: true, disabled: true,
validate: async (state: CopyJobContextState, armToken?: string) => { validate: async (state: CopyJobContextState) => {
const principalId = state?.target?.account?.identity?.principalId; const principalId = state?.target?.account?.identity?.principalId;
const rolesAssigned = await fetchRoleAssignments( const rolesAssigned = await fetchRoleAssignments(
armToken,
state.source?.subscription?.subscriptionId, state.source?.subscription?.subscriptionId,
state.source?.account?.resourceGroup, state.source?.account?.resourceGroup,
state.source?.account?.name, state.source?.account?.name,
@@ -77,7 +76,6 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
); );
const roleDefinitions = await fetchRoleDefinitions( const roleDefinitions = await fetchRoleDefinitions(
armToken,
rolesAssigned ?? [] rolesAssigned ?? []
); );
return checkTargetHasReaderRoleOnSource(roleDefinitions ?? []); return checkTargetHasReaderRoleOnSource(roleDefinitions ?? []);
@@ -127,10 +125,7 @@ export function checkTargetHasReaderRoleOnSource(roleDefinitions: RoleDefinition
* Returns the permission sections configuration for the Assign Permissions screen. * Returns the permission sections configuration for the Assign Permissions screen.
* Memoizes derived values for performance and decouples logic for testability. * Memoizes derived values for performance and decouples logic for testability.
*/ */
const usePermissionSections = ( const usePermissionSections = (state: CopyJobContextState): PermissionSectionConfig[] => {
state: CopyJobContextState,
armToken: string,
): PermissionSectionConfig[] => {
const { validationCache, setValidationCache } = useCopyJobPrerequisitesCache(); const { validationCache, setValidationCache } = useCopyJobPrerequisitesCache();
const [permissionSections, setPermissionSections] = useState<PermissionSectionConfig[] | null>(null); const [permissionSections, setPermissionSections] = useState<PermissionSectionConfig[] | null>(null);
const isValidatingRef = useRef(false); const isValidatingRef = useRef(false);
@@ -169,7 +164,7 @@ const usePermissionSections = (
} }
// We've reached the first non-cached section - validate it // We've reached the first non-cached section - validate it
if (section.validate) { if (section.validate) {
const isValid = await section.validate(state, armToken); const isValid = await section.validate(state);
newValidationCache.set(section.id, isValid); newValidationCache.set(section.id, isValid);
result.push({ ...section, completed: isValid }); result.push({ ...section, completed: isValid });
// Stop validation if current section failed // Stop validation if current section failed
@@ -197,7 +192,7 @@ const usePermissionSections = (
return () => { return () => {
isValidatingRef.current = false; isValidatingRef.current = false;
} }
}, [state, armToken, sectionToValidate]); }, [state, sectionToValidate]);
return permissionSections ?? []; return permissionSections ?? [];
}; };
@@ -39,8 +39,8 @@ const PermissionSection: React.FC<PermissionSectionConfig> = ({
); );
const AssignPermissions = () => { const AssignPermissions = () => {
const { armToken, copyJobState } = useCopyJobContext(); const { copyJobState } = useCopyJobContext();
const permissionSections = usePermissionSections(copyJobState, armToken); const permissionSections = usePermissionSections(copyJobState);
const [openItems, setOpenItems] = React.useState<string[]>([]); const [openItems, setOpenItems] = React.useState<string[]>([]);
const indentLevels = React.useMemo<IndentLevel[]>( const indentLevels = React.useMemo<IndentLevel[]>(
@@ -48,10 +48,6 @@ const AssignPermissions = () => {
[] []
); );
/* const onMoveToNextSection: AccordionToggleEventHandler<string> = useCallback((_event, data) => {
setOpenItems(data.openItems);
}, []); */
useEffect(() => { useEffect(() => {
const firstIncompleteSection = permissionSections.find(section => !section.completed); const firstIncompleteSection = permissionSections.find(section => !section.completed);
const nextOpenItems = firstIncompleteSection ? [firstIncompleteSection.id] : []; const nextOpenItems = firstIncompleteSection ? [firstIncompleteSection.id] : [];
@@ -15,11 +15,11 @@ interface SelectAccountProps { }
const SelectAccount = React.memo( const SelectAccount = React.memo(
(_props: SelectAccountProps) => { (_props: SelectAccountProps) => {
const { armToken, copyJobState, setCopyJobState } = useCopyJobContext(); const { copyJobState, setCopyJobState } = useCopyJobContext();
const selectedSubscriptionId = copyJobState?.source?.subscription?.subscriptionId; const selectedSubscriptionId = copyJobState?.source?.subscription?.subscriptionId;
const subscriptions: Subscription[] = useSubscriptions(armToken); const subscriptions: Subscription[] = useSubscriptions();
const allAccounts: DatabaseAccount[] = useDatabaseAccounts(selectedSubscriptionId, armToken); const allAccounts: DatabaseAccount[] = useDatabaseAccounts(selectedSubscriptionId);
const sqlApiOnlyAccounts: DatabaseAccount[] = allAccounts?.filter(account => account.type === "SQL" || account.kind === "GlobalDocumentDB"); const sqlApiOnlyAccounts: DatabaseAccount[] = allAccounts?.filter(account => account.type === "SQL" || account.kind === "GlobalDocumentDB");
const { subscriptionOptions, accountOptions } = useDropdownOptions(subscriptions, sqlApiOnlyAccounts); const { subscriptionOptions, accountOptions } = useDropdownOptions(subscriptions, sqlApiOnlyAccounts);
@@ -11,7 +11,7 @@ import { useMemoizedSourceAndTargetData } from "./memoizedData";
interface SelectSourceAndTargetContainersProps { } interface SelectSourceAndTargetContainersProps { }
const SelectSourceAndTargetContainers = (_props: SelectSourceAndTargetContainersProps) => { const SelectSourceAndTargetContainers = (_props: SelectSourceAndTargetContainersProps) => {
const { armToken, copyJobState, setCopyJobState } = useCopyJobContext(); const { copyJobState, setCopyJobState } = useCopyJobContext();
const { const {
source, source,
target, target,
@@ -19,7 +19,7 @@ const SelectSourceAndTargetContainers = (_props: SelectSourceAndTargetContainers
sourceContainerParams, sourceContainerParams,
targetDbParams, targetDbParams,
targetContainerParams targetContainerParams
} = useMemoizedSourceAndTargetData(copyJobState, armToken); } = useMemoizedSourceAndTargetData(copyJobState);
// Custom hooks // Custom hooks
const sourceDatabases = useDatabases(...sourceDbParams) || []; const sourceDatabases = useDatabases(...sourceDbParams) || [];
@@ -1,57 +1,64 @@
import React from "react"; import React from "react";
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
import { CopyJobContextState, DatabaseParams, DataContainerParams } from "../../../Types"; import { CopyJobContextState, DatabaseParams, DataContainerParams } from "../../../Types";
export function useMemoizedSourceAndTargetData(copyJobState: CopyJobContextState, armToken: string) { export function useMemoizedSourceAndTargetData(copyJobState: CopyJobContextState) {
const { source, target } = copyJobState ?? {}; const { source, target } = copyJobState ?? {};
const selectedSourceAccount = source?.account; const selectedSourceAccount = source?.account;
const selectedTargetAccount = target?.account; const selectedTargetAccount = target?.account;
const {
subscriptionId: sourceSubscriptionId,
resourceGroup: sourceResourceGroup,
accountName: sourceAccountName
} = getAccountDetailsFromResourceId(selectedSourceAccount?.id);
const {
subscriptionId: targetSubscriptionId,
resourceGroup: targetResourceGroup,
accountName: targetAccountName
} = getAccountDetailsFromResourceId(selectedTargetAccount?.id);
const sourceDbParams = React.useMemo( const sourceDbParams = React.useMemo(
() => () =>
[ [
armToken, sourceSubscriptionId,
source?.subscription?.subscriptionId, sourceResourceGroup,
selectedSourceAccount?.resourceGroup, sourceAccountName,
selectedSourceAccount?.name,
'SQL', 'SQL',
] as DatabaseParams, ] as DatabaseParams,
[armToken, source?.subscription?.subscriptionId, selectedSourceAccount] [sourceSubscriptionId, sourceResourceGroup, sourceAccountName]
); );
const sourceContainerParams = React.useMemo( const sourceContainerParams = React.useMemo(
() => () =>
[ [
armToken, sourceSubscriptionId,
source?.subscription?.subscriptionId, sourceResourceGroup,
selectedSourceAccount?.resourceGroup, sourceAccountName,
selectedSourceAccount?.name,
source?.databaseId, source?.databaseId,
'SQL', 'SQL',
] as DataContainerParams, ] as DataContainerParams,
[armToken, source?.subscription?.subscriptionId, selectedSourceAccount, source?.databaseId] [sourceSubscriptionId, sourceResourceGroup, sourceAccountName, source?.databaseId]
); );
const targetDbParams = React.useMemo( const targetDbParams = React.useMemo(
() => [ () => [
armToken, targetSubscriptionId,
target?.subscriptionId, targetResourceGroup,
selectedTargetAccount?.resourceGroup, targetAccountName,
selectedTargetAccount?.name,
'SQL', 'SQL',
] as DatabaseParams, ] as DatabaseParams,
[armToken, target?.subscriptionId, selectedTargetAccount] [targetSubscriptionId, targetResourceGroup, targetAccountName]
); );
const targetContainerParams = React.useMemo( const targetContainerParams = React.useMemo(
() => [ () => [
armToken, targetSubscriptionId,
target?.subscriptionId, targetResourceGroup,
selectedTargetAccount?.resourceGroup, targetAccountName,
selectedTargetAccount?.name,
target?.databaseId, target?.databaseId,
'SQL', 'SQL',
] as DataContainerParams, ] as DataContainerParams,
[armToken, target?.subscriptionId, selectedTargetAccount, target?.databaseId] [targetSubscriptionId, targetResourceGroup, targetAccountName, target?.databaseId]
); );
return { source, target, sourceDbParams, sourceContainerParams, targetDbParams, targetContainerParams }; return { source, target, sourceDbParams, sourceContainerParams, targetDbParams, targetContainerParams };
@@ -28,14 +28,12 @@ export type DropdownOptionType = {
}; };
export type DatabaseParams = [ export type DatabaseParams = [
string,
string | undefined, string | undefined,
string | undefined, string | undefined,
string | undefined, string | undefined,
ApiType ApiType
]; ];
export type DataContainerParams = [ export type DataContainerParams = [
string,
string | undefined, string | undefined,
string | undefined, string | undefined,
string | undefined, string | undefined,
@@ -80,8 +78,6 @@ export interface CopyJobFlowType {
} }
export interface CopyJobContextProviderType { export interface CopyJobContextProviderType {
principalId: string;
armToken: string;
flow: CopyJobFlowType; flow: CopyJobFlowType;
setFlow: React.Dispatch<React.SetStateAction<CopyJobFlowType>>; setFlow: React.Dispatch<React.SetStateAction<CopyJobFlowType>>;
copyJobState: CopyJobContextState | null; copyJobState: CopyJobContextState | null;
+3 -3
View File
@@ -78,13 +78,13 @@ const App: React.FunctionComponent = () => {
} }
StyleConstants.updateStyles(); StyleConstants.updateStyles();
const explorer = useKnockoutExplorer(config?.platform); const explorer = useKnockoutExplorer(config?.platform);
// console.log("Using config: ", config); console.log("Using config: ", config);
if (!explorer) { if (!explorer) {
return <LoadingExplorer />; return <LoadingExplorer />;
} }
// console.log("Using explorer: ", explorer); console.log("Using explorer: ", explorer);
// console.log("Using userContext: ", userContext); console.log("Using userContext: ", userContext);
return ( return (
<KeyboardShortcutRoot> <KeyboardShortcutRoot>
+9
View File
@@ -0,0 +1,9 @@
import { userContext } from "UserContext";
export function getCopyJobAuthorizationHeader(token: string = ""): Headers {
const headers = new Headers();
const authToken = token ? `Bearer ${token}` : userContext.authorizationToken;
headers.append("Authorization", authToken);
headers.append("Content-Type", "application/json");
return headers;
}
+3 -12
View File
@@ -1,8 +1,8 @@
import { configContext } from "ConfigContext"; import { configContext } from "ConfigContext";
import { armRequest } from "Utils/arm/request"; import { armRequest } from "Utils/arm/request";
import { getCopyJobAuthorizationHeader } from "../CopyJobAuthUtils";
export type FetchAccountDetailsParams = { export type FetchAccountDetailsParams = {
armToken: string;
subscriptionId: string; subscriptionId: string;
resourceGroupName: string; resourceGroupName: string;
accountName: string; accountName: string;
@@ -43,13 +43,6 @@ const getArmBaseUrl = (): string => {
return base.endsWith("/") ? base.slice(0, -1) : base; return base.endsWith("/") ? base.slice(0, -1) : base;
}; };
const createAuthHeaders = (armToken: string): Headers => {
const headers = new Headers();
headers.append("Authorization", `Bearer ${armToken}`);
headers.append("Content-Type", "application/json");
return headers;
};
const buildArmUrl = (path: string): string => const buildArmUrl = (path: string): string =>
`${getArmBaseUrl()}${path}?api-version=${apiVersion}`; `${getArmBaseUrl()}${path}?api-version=${apiVersion}`;
@@ -64,7 +57,6 @@ const handleResponse = async (response: Response, context: string) => {
}; };
export const fetchRoleAssignments = async ( export const fetchRoleAssignments = async (
armToken: string,
subscriptionId: string, subscriptionId: string,
resourceGroupName: string, resourceGroupName: string,
accountName: string, accountName: string,
@@ -74,7 +66,7 @@ export const fetchRoleAssignments = async (
`/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlRoleAssignments` `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlRoleAssignments`
); );
const response = await fetch(uri, { method: "GET", headers: createAuthHeaders(armToken) }); const response = await fetch(uri, { method: "GET", headers: getCopyJobAuthorizationHeader() });
const data = await handleResponse(response, "role assignments"); const data = await handleResponse(response, "role assignments");
return (data.value || []).filter( return (data.value || []).filter(
@@ -84,13 +76,12 @@ export const fetchRoleAssignments = async (
}; };
export const fetchRoleDefinitions = async ( export const fetchRoleDefinitions = async (
armToken: string,
roleAssignments: RoleAssignmentType[] roleAssignments: RoleAssignmentType[]
): Promise<RoleDefinitionType[]> => { ): Promise<RoleDefinitionType[]> => {
const roleDefinitionIds = roleAssignments.map(assignment => assignment.properties.roleDefinitionId); const roleDefinitionIds = roleAssignments.map(assignment => assignment.properties.roleDefinitionId);
const uniqueRoleDefinitionIds = Array.from(new Set(roleDefinitionIds)); const uniqueRoleDefinitionIds = Array.from(new Set(roleDefinitionIds));
const headers = createAuthHeaders(armToken); const headers = getCopyJobAuthorizationHeader();
const roleDefinitionUris = uniqueRoleDefinitionIds.map((id) => buildArmUrl(id)); const roleDefinitionUris = uniqueRoleDefinitionIds.map((id) => buildArmUrl(id));
const promises = roleDefinitionUris.map((url) => fetch(url, { method: "GET", headers })); const promises = roleDefinitionUris.map((url) => fetch(url, { method: "GET", headers }));
+5 -12
View File
@@ -3,10 +3,10 @@ import useSWR from "swr";
import { getCollectionEndpoint, getDatabaseEndpoint } from "../Common/DatabaseAccountUtility"; import { getCollectionEndpoint, getDatabaseEndpoint } from "../Common/DatabaseAccountUtility";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { ApiType } from "../UserContext"; import { ApiType } from "../UserContext";
import { getCopyJobAuthorizationHeader } from "../Utils/CopyJobAuthUtils";
const apiVersion = "2023-09-15"; const apiVersion = "2023-09-15";
export interface FetchDataContainersListParams { export interface FetchDataContainersListParams {
armToken: string;
subscriptionId: string; subscriptionId: string;
resourceGroupName: string; resourceGroupName: string;
databaseName: string; databaseName: string;
@@ -27,7 +27,6 @@ const buildReadDataContainersListUrl = (params: FetchDataContainersListParams):
} }
const fetchDataContainersList = async ( const fetchDataContainersList = async (
armToken: string,
subscriptionId: string, subscriptionId: string,
resourceGroupName: string, resourceGroupName: string,
accountName: string, accountName: string,
@@ -35,17 +34,13 @@ const fetchDataContainersList = async (
apiType: ApiType apiType: ApiType
): Promise<DatabaseModel[]> => { ): Promise<DatabaseModel[]> => {
const uri = buildReadDataContainersListUrl({ const uri = buildReadDataContainersListUrl({
armToken,
subscriptionId, subscriptionId,
resourceGroupName, resourceGroupName,
accountName, accountName,
databaseName, databaseName,
apiType apiType
}); });
const headers = new Headers(); const headers = getCopyJobAuthorizationHeader();
const bearer = `Bearer ${armToken}`;
headers.append("Authorization", bearer);
headers.append("Content-Type", "application/json");
const response = await fetch(uri, { const response = await fetch(uri, {
method: "GET", method: "GET",
@@ -61,7 +56,6 @@ const fetchDataContainersList = async (
}; };
export function useDataContainers( export function useDataContainers(
armToken: string,
subscriptionId: string, subscriptionId: string,
resourceGroupName: string, resourceGroupName: string,
accountName: string, accountName: string,
@@ -70,13 +64,12 @@ export function useDataContainers(
): DatabaseModel[] | undefined { ): DatabaseModel[] | undefined {
const { data } = useSWR( const { data } = useSWR(
() => ( () => (
armToken && subscriptionId && resourceGroupName && accountName && databaseName && apiType ? [ subscriptionId && resourceGroupName && accountName && databaseName && apiType ? [
"fetchContainersLinkedToDatabases", "fetchContainersLinkedToDatabases",
armToken, subscriptionId, resourceGroupName, accountName, databaseName, apiType subscriptionId, resourceGroupName, accountName, databaseName, apiType
] : undefined ] : undefined
), ),
(_, armToken, subscriptionId, resourceGroupName, accountName, databaseName, apiType) => fetchDataContainersList( (_, subscriptionId, resourceGroupName, accountName, databaseName, apiType) => fetchDataContainersList(
armToken,
subscriptionId, subscriptionId,
resourceGroupName, resourceGroupName,
accountName, accountName,
+21 -14
View File
@@ -1,6 +1,7 @@
import { HttpHeaders } from "Common/Constants"; import { HttpHeaders } from "Common/Constants";
import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph"; import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph";
import useSWR from "swr"; import useSWR from "swr";
import { userContext } from "UserContext";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { DatabaseAccount } from "../Contracts/DataModels"; import { DatabaseAccount } from "../Contracts/DataModels";
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -10,9 +11,12 @@ interface AccountListResult {
value: DatabaseAccount[]; value: DatabaseAccount[];
} }
export async function fetchDatabaseAccounts(subscriptionId: string, accessToken: string): Promise<DatabaseAccount[]> { export async function fetchDatabaseAccounts(subscriptionId: string, accessToken: string = ""): Promise<DatabaseAccount[]> {
if (!accessToken && !userContext.authorizationToken) {
return [];
}
const headers = new Headers(); const headers = new Headers();
const bearer = `Bearer ${accessToken}`; const bearer = accessToken ? `Bearer ${accessToken}` : userContext.authorizationToken;
headers.append("Authorization", bearer); headers.append("Authorization", bearer);
@@ -35,10 +39,13 @@ export async function fetchDatabaseAccounts(subscriptionId: string, accessToken:
export async function fetchDatabaseAccountsFromGraph( export async function fetchDatabaseAccountsFromGraph(
subscriptionId: string, subscriptionId: string,
accessToken: string, accessToken: string = "",
): Promise<DatabaseAccount[]> { ): Promise<DatabaseAccount[]> {
if (!accessToken && !userContext.authorizationToken) {
return [];
}
const headers = new Headers(); const headers = new Headers();
const bearer = `Bearer ${accessToken}`; const bearer = accessToken ? `Bearer ${accessToken}` : userContext.authorizationToken;
headers.append("Authorization", bearer); headers.append("Authorization", bearer);
headers.append(HttpHeaders.contentType, "application/json"); headers.append(HttpHeaders.contentType, "application/json");
@@ -54,15 +61,15 @@ export async function fetchDatabaseAccountsFromGraph(
subscriptions: [subscriptionId], subscriptions: [subscriptionId],
...(skipToken ...(skipToken
? { ? {
options: { options: {
$skipToken: skipToken, $skipToken: skipToken,
} as QueryRequestOptions, } as QueryRequestOptions,
} }
: { : {
options: { options: {
$top: 150, $top: 150,
} as QueryRequestOptions, } as QueryRequestOptions,
}), }),
}; };
const response = await fetch(managementResourceGraphAPIURL, { const response = await fetch(managementResourceGraphAPIURL, {
@@ -85,9 +92,9 @@ export async function fetchDatabaseAccountsFromGraph(
return databaseAccounts.sort((a, b) => a.name.localeCompare(b.name)); return databaseAccounts.sort((a, b) => a.name.localeCompare(b.name));
} }
export function useDatabaseAccounts(subscriptionId: string, armToken: string): DatabaseAccount[] | undefined { export function useDatabaseAccounts(subscriptionId: string, armToken: string = ""): DatabaseAccount[] | undefined {
const { data } = useSWR( const { data } = useSWR(
() => (armToken && subscriptionId ? ["databaseAccounts", subscriptionId, armToken] : undefined), () => (subscriptionId ? ["databaseAccounts", subscriptionId, armToken] : undefined),
(_, subscriptionId, armToken) => fetchDatabaseAccountsFromGraph(subscriptionId, armToken), (_, subscriptionId, armToken) => fetchDatabaseAccountsFromGraph(subscriptionId, armToken),
); );
return data; return data;
+7 -12
View File
@@ -3,10 +3,10 @@ import useSWR from "swr";
import { getDatabaseEndpoint } from "../Common/DatabaseAccountUtility"; import { getDatabaseEndpoint } from "../Common/DatabaseAccountUtility";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { ApiType } from "../UserContext"; import { ApiType } from "../UserContext";
import { getCopyJobAuthorizationHeader } from "../Utils/CopyJobAuthUtils";
const apiVersion = "2023-09-15"; const apiVersion = "2023-09-15";
export interface FetchDatabasesListParams { export interface FetchDatabasesListParams {
armToken: string;
subscriptionId: string; subscriptionId: string;
resourceGroupName: string; resourceGroupName: string;
accountName: string; accountName: string;
@@ -24,12 +24,9 @@ const buildReadDatabasesListUrl = (params: FetchDatabasesListParams): string =>
return `${armEndpoint}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/${databaseEndpoint}?api-version=${apiVersion}`; return `${armEndpoint}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/${databaseEndpoint}?api-version=${apiVersion}`;
} }
const fetchDatabasesList = async (armToken: string, subscriptionId: string, resourceGroupName: string, accountName: string, apiType: ApiType): Promise<DatabaseModel[]> => { const fetchDatabasesList = async (subscriptionId: string, resourceGroupName: string, accountName: string, apiType: ApiType): Promise<DatabaseModel[]> => {
const uri = buildReadDatabasesListUrl({ armToken, subscriptionId, resourceGroupName, accountName, apiType }); const uri = buildReadDatabasesListUrl({ subscriptionId, resourceGroupName, accountName, apiType });
const headers = new Headers(); const headers = getCopyJobAuthorizationHeader();
const bearer = `Bearer ${armToken}`;
headers.append("Authorization", bearer);
headers.append("Content-Type", "application/json");
const response = await fetch(uri, { const response = await fetch(uri, {
method: "GET", method: "GET",
@@ -45,7 +42,6 @@ const fetchDatabasesList = async (armToken: string, subscriptionId: string, reso
}; };
export function useDatabases( export function useDatabases(
armToken: string,
subscriptionId: string, subscriptionId: string,
resourceGroupName: string, resourceGroupName: string,
accountName: string, accountName: string,
@@ -53,13 +49,12 @@ export function useDatabases(
): DatabaseModel[] | undefined { ): DatabaseModel[] | undefined {
const { data } = useSWR( const { data } = useSWR(
() => ( () => (
armToken && subscriptionId && resourceGroupName && accountName && apiType ? [ subscriptionId && resourceGroupName && accountName && apiType ? [
"fetchDatabasesLinkedToResource", "fetchDatabasesLinkedToResource",
armToken, subscriptionId, resourceGroupName, accountName, apiType subscriptionId, resourceGroupName, accountName, apiType
] : undefined ] : undefined
), ),
(_, armToken, subscriptionId, resourceGroupName, accountName, apiType) => fetchDatabasesList( (_, subscriptionId, resourceGroupName, accountName, apiType) => fetchDatabasesList(
armToken,
subscriptionId, subscriptionId,
resourceGroupName, resourceGroupName,
accountName, accountName,
+13 -6
View File
@@ -1,6 +1,7 @@
import { HttpHeaders } from "Common/Constants"; import { HttpHeaders } from "Common/Constants";
import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph"; import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph";
import useSWR from "swr"; import useSWR from "swr";
import { userContext } from "UserContext";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { Subscription } from "../Contracts/DataModels"; import { Subscription } from "../Contracts/DataModels";
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -10,9 +11,12 @@ interface SubscriptionListResult {
value: Subscription[]; value: Subscription[];
} }
export async function fetchSubscriptions(accessToken: string): Promise<Subscription[]> { export async function fetchSubscriptions(accessToken: string = ""): Promise<Subscription[]> {
if (!accessToken && !userContext.authorizationToken) {
return [];
}
const headers = new Headers(); const headers = new Headers();
const bearer = `Bearer ${accessToken}`; const bearer = accessToken ? `Bearer ${accessToken}` : userContext.authorizationToken;
headers.append("Authorization", bearer); headers.append("Authorization", bearer);
@@ -35,9 +39,12 @@ export async function fetchSubscriptions(accessToken: string): Promise<Subscript
return subscriptions.sort((a, b) => a.displayName.localeCompare(b.displayName)); return subscriptions.sort((a, b) => a.displayName.localeCompare(b.displayName));
} }
export async function fetchSubscriptionsFromGraph(accessToken: string): Promise<Subscription[]> { export async function fetchSubscriptionsFromGraph(accessToken: string = ""): Promise<Subscription[]> {
if (!accessToken && !userContext.authorizationToken) {
return [];
}
const headers = new Headers(); const headers = new Headers();
const bearer = `Bearer ${accessToken}`; const bearer = accessToken ? `Bearer ${accessToken}` : userContext.authorizationToken;
headers.append("Authorization", bearer); headers.append("Authorization", bearer);
headers.append(HttpHeaders.contentType, "application/json"); headers.append(HttpHeaders.contentType, "application/json");
@@ -85,9 +92,9 @@ export async function fetchSubscriptionsFromGraph(accessToken: string): Promise<
return subscriptions.sort((a, b) => a.displayName.localeCompare(b.displayName)); return subscriptions.sort((a, b) => a.displayName.localeCompare(b.displayName));
} }
export function useSubscriptions(armToken: string): Subscription[] | undefined { export function useSubscriptions(armToken: string = ""): Subscription[] | undefined {
const { data } = useSWR( const { data } = useSWR(
() => (armToken ? ["subscriptions", armToken] : undefined), () => ["subscriptions", armToken],
(_, armToken) => fetchSubscriptionsFromGraph(armToken), (_, armToken) => fetchSubscriptionsFromGraph(armToken),
); );
return data; return data;