Skip to content

Commit c445e6a

Browse files
authored
fix(FR-2123): replace CustomEvent notification with local Alert in LoginView (#5612)
1 parent 7b5be9d commit c445e6a

2 files changed

Lines changed: 52 additions & 25 deletions

File tree

react/src/components/LoginFormPanel.tsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
WarningTwoTone,
3131
} from '@ant-design/icons';
3232
import {
33+
Alert,
3334
App,
3435
Button,
3536
Dropdown,
@@ -52,6 +53,8 @@ type ConnectionMode = 'SESSION' | 'API';
5253
interface LoginFormPanelProps {
5354
isOpen: boolean;
5455
isLoading: boolean;
56+
loginError: { message: string; description?: string } | null;
57+
onClearLoginError?: () => void;
5558
connectionMode: ConnectionMode;
5659
loginConfig: LoginConfigState;
5760
apiEndpoint: string;
@@ -82,6 +85,8 @@ interface LoginFormPanelProps {
8285
const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
8386
isOpen,
8487
isLoading,
88+
loginError,
89+
onClearLoginError,
8590
connectionMode,
8691
loginConfig,
8792
apiEndpoint,
@@ -182,7 +187,10 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
182187
{/* SESSION login fields */}
183188
{connectionMode === 'SESSION' && (
184189
<>
185-
<Form.Item name="user_id" style={{ marginBottom: 8 }}>
190+
<Form.Item
191+
name="user_id"
192+
style={{ marginBottom: token.marginSM }}
193+
>
186194
<Input
187195
prefix={<MailOutlined />}
188196
placeholder={t('login.E-mailOrUsername')}
@@ -192,7 +200,10 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
192200
disabled={isLoading}
193201
/>
194202
</Form.Item>
195-
<Form.Item name="password" style={{ marginBottom: 8 }}>
203+
<Form.Item
204+
name="password"
205+
style={{ marginBottom: token.marginSM }}
206+
>
196207
<Input.Password
197208
prefix={<KeyOutlined />}
198209
placeholder={t('login.Password')}
@@ -202,7 +213,7 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
202213
/>
203214
</Form.Item>
204215
{otpRequired && (
205-
<Form.Item name="otp" style={{ marginBottom: 8 }}>
216+
<Form.Item name="otp" style={{ marginBottom: token.marginSM }}>
206217
<Input
207218
prefix={<LockOutlined />}
208219
placeholder={t('totp.OTP')}
@@ -217,15 +228,21 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
217228
{/* API login fields */}
218229
{connectionMode === 'API' && (
219230
<>
220-
<Form.Item name="api_key" style={{ marginBottom: 8 }}>
231+
<Form.Item
232+
name="api_key"
233+
style={{ marginBottom: token.marginSM }}
234+
>
221235
<Input
222236
prefix={<LockOutlined />}
223237
placeholder={t('login.APIKey')}
224238
maxLength={20}
225239
disabled={isLoading}
226240
/>
227241
</Form.Item>
228-
<Form.Item name="secret_key" style={{ marginBottom: 8 }}>
242+
<Form.Item
243+
name="secret_key"
244+
style={{ marginBottom: token.marginSM }}
245+
>
229246
<Input.Password
230247
prefix={<KeyOutlined />}
231248
placeholder={t('login.SecretKey')}
@@ -236,8 +253,23 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
236253
</>
237254
)}
238255

256+
{/* Login error alert */}
257+
{loginError && (
258+
<Alert
259+
type="error"
260+
showIcon
261+
title={loginError.message}
262+
description={loginError.description}
263+
style={{ marginBottom: token.marginSM }}
264+
closable={{
265+
closeIcon: true,
266+
onClose: onClearLoginError,
267+
}}
268+
/>
269+
)}
270+
239271
{/* Login button */}
240-
<Form.Item style={{ marginBottom: 8 }}>
272+
<Form.Item style={{ marginBottom: token.marginSM }}>
241273
<Button
242274
type="primary"
243275
block
@@ -251,14 +283,14 @@ const LoginFormPanel: React.FC<LoginFormPanelProps> = ({
251283

252284
{/* SSO buttons */}
253285
{loginConfig.singleSignOnVendors.includes('saml') && (
254-
<Form.Item style={{ marginBottom: 8 }}>
286+
<Form.Item style={{ marginBottom: token.marginSM }}>
255287
<Button block onClick={onSAMLLogin}>
256288
{t('login.singleSignOn.LoginWithSAML')}
257289
</Button>
258290
</Form.Item>
259291
)}
260292
{loginConfig.singleSignOnVendors.includes('openid') && (
261-
<Form.Item style={{ marginBottom: 8 }}>
293+
<Form.Item style={{ marginBottom: token.marginSM }}>
262294
<Button block onClick={onOpenIDLogin}>
263295
{t('login.singleSignOn.LoginWithRealm', {
264296
realmName: loginConfig.ssoRealmName || 'OpenID',

react/src/components/LoginView.tsx

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ const LoginView: React.FC = () => {
8181
const [blockMessage, setBlockMessage] = useState('');
8282
const [blockType, setBlockType] = useState('');
8383
const [isLoading, setIsLoading] = useState(false);
84+
const [loginError, setLoginError] = useState<{
85+
message: string;
86+
description?: string;
87+
} | null>(null);
8488
const [endpoints, setEndpoints] = useState<string[]>(() => {
8589
return (globalThis as any).backendaioptions?.get('endpoints', []) ?? [];
8690
});
@@ -132,14 +136,7 @@ const LoginView: React.FC = () => {
132136
/* webpackIgnore: true */
133137
`../../../src/plugins/${sanitizedPlugin}`
134138
).catch(() => {
135-
document.dispatchEvent(
136-
new CustomEvent('add-bai-notification', {
137-
detail: {
138-
open: true,
139-
message: t('error.LoginFailed'),
140-
},
141-
}),
142-
);
139+
setLoginError({ message: t('error.LoginFailed') });
143140
});
144141
}, [isConfigLoaded, loginPlugin, t]);
145142

@@ -210,15 +207,7 @@ const LoginView: React.FC = () => {
210207
}, []);
211208

212209
const notification = useCallback((text: string, detail?: string) => {
213-
document.dispatchEvent(
214-
new CustomEvent('add-bai-notification', {
215-
detail: {
216-
open: true,
217-
message: text,
218-
description: detail,
219-
},
220-
}),
221-
);
210+
setLoginError({ message: text, description: detail });
222211
}, []);
223212

224213
const open = useCallback(() => {
@@ -253,6 +242,7 @@ const LoginView: React.FC = () => {
253242
}
254243
setIsLoginPanelOpen(false);
255244
setIsBlockPanelOpen(false);
245+
setLoginError(null);
256246
}, []);
257247

258248
const block = useCallback((message = '', type = '') => {
@@ -513,6 +503,8 @@ const LoginView: React.FC = () => {
513503
);
514504

515505
const handleLogin = useCallback(async () => {
506+
setLoginError(null);
507+
516508
const loginAttempt = (globalThis as any).backendaioptions.get(
517509
'login_attempt',
518510
0,
@@ -695,6 +687,7 @@ const LoginView: React.FC = () => {
695687
(mode: ConnectionMode) => {
696688
if (!loginConfig.change_signin_support) return;
697689
setConnectionMode(mode);
690+
setLoginError(null);
698691
localStorage.setItem('backendaiwebui.connection_mode', mode);
699692
},
700693
[loginConfig.change_signin_support],
@@ -800,6 +793,8 @@ const LoginView: React.FC = () => {
800793
<LoginFormPanel
801794
isOpen={isLoginPanelOpen}
802795
isLoading={isLoading}
796+
loginError={loginError}
797+
onClearLoginError={() => setLoginError(null)}
803798
connectionMode={connectionMode}
804799
loginConfig={loginConfig}
805800
apiEndpoint={apiEndpoint}

0 commit comments

Comments
 (0)