add dialog to select authentication method for UIA

This commit is contained in:
Ajay Bura 2026-08-10 14:09:56 +05:30
commit cbe5c79e24
3 changed files with 98 additions and 4 deletions

View file

@ -1,5 +1,20 @@
import React, { ReactNode } from 'react';
import { AuthResponse, AuthType, UIAFlow } from '../utils/matrix-uia';
import React, { ReactNode, useState } from 'react';
import {
config,
Dialog,
Header,
Text,
IconButton,
Box,
Icon,
Icons,
Button,
OverlayBackdrop,
Overlay,
OverlayCenter,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { AuthResponse, AuthType, getUIAFlowForStages, UIAFlow } from '../utils/matrix-uia';
import { useSupportedUIAFlows, useUIACompleted, useUIAFlow } from '../hooks/useUIAFlows';
import { UIAFlowOverlay } from './UIAFlowOverlay';
import { OAuthStage, PasswordStage, SSOStage } from './uia-stages';
@ -57,20 +72,97 @@ export function ActionUIA({ authData, ongoingFlow, action, onCancel }: ActionUIA
);
}
function UIAFlowPicker({
flows,
onCancel,
onSelect,
}: {
flows: UIAFlow[];
onCancel: () => void;
onSelect: (flow: UIAFlow) => void;
}) {
const passwordFlow = getUIAFlowForStages(flows, [AuthType.Password]);
const ssoFlow = getUIAFlowForStages(flows, [AuthType.Sso]);
return (
<Overlay open backdrop={<OverlayBackdrop />}>
<OverlayCenter>
<FocusTrap focusTrapOptions={{ initialFocus: false, escapeDeactivates: false }}>
<Dialog>
<Header
style={{
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
}}
variant="Surface"
size="500"
>
<Box grow="Yes">
<Text size="H4">Authentication</Text>
</Box>
<IconButton size="300" onClick={onCancel} radii="300">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
<Box
as="form"
style={{ padding: `0 ${config.space.S400} ${config.space.S400}` }}
direction="Column"
gap="400"
>
<Box direction="Column" gap="400">
<Text size="T200">Choose an authentication method to perform this action.</Text>
</Box>
<Box direction="Column" gap="200">
{passwordFlow && (
<Button variant="Primary" type="button" onClick={() => onSelect(passwordFlow)}>
<Text as="span" size="B400">
Continue with Password
</Text>
</Button>
)}
{ssoFlow && (
<Button
variant="Secondary"
fill="Soft"
type="button"
onClick={() => onSelect(ssoFlow)}
>
<Text as="span" size="B400">
Continue with SSO
</Text>
</Button>
)}
</Box>
</Box>
</Dialog>
</FocusTrap>
</OverlayCenter>
</Overlay>
);
}
type ActionUIAFlowsLoaderProps = {
authData: AuthResponse;
onCancel: () => void;
unsupported: () => ReactNode;
children: (ongoingFlow: UIAFlow) => ReactNode;
};
export function ActionUIAFlowsLoader({
authData,
onCancel,
unsupported,
children,
}: ActionUIAFlowsLoaderProps) {
const supportedFlows = useSupportedUIAFlows(authData.flows ?? [], SUPPORTED_IN_APP_UIA_STAGES);
const ongoingFlow = supportedFlows.length > 0 ? supportedFlows[0] : undefined;
const [ongoingFlow, setOngoingFlow] = useState(
supportedFlows.length === 1 ? supportedFlows[0] : undefined
);
if (!ongoingFlow) return unsupported();
if (supportedFlows.length === 0) return unsupported();
if (!ongoingFlow) {
return <UIAFlowPicker flows={supportedFlows} onCancel={onCancel} onSelect={setOngoingFlow} />;
}
return children(ongoingFlow);
}

View file

@ -329,6 +329,7 @@ function SetupVerification({ onComplete }: SetupVerificationProps) {
{uiaData && (
<ActionUIAFlowsLoader
authData={uiaData}
onCancel={handleCancel}
unsupported={() => (
<Text size="T200" style={{ color: color.Critical.Main }}>
Authentication steps to perform this action are not supported by client.

View file

@ -219,6 +219,7 @@ export function OtherDevices({ devices, refreshDeviceList, showVerification }: O
{authData && (
<ActionUIAFlowsLoader
authData={authData}
onCancel={handleCancelAuth}
unsupported={() => (
<Text size="T200">
Authentication steps to perform this action are not supported by client.