Skip to content

Commit 9ceaf8d

Browse files
committed
fix(admin-ui): show message based on error code in Admin UI #1316
Signed-off-by: Jeet Viramgama <[email protected]>
1 parent a0429f1 commit 9ceaf8d

File tree

8 files changed

+128
-96
lines changed

8 files changed

+128
-96
lines changed

admin-ui/app/images/backend-down.png

4.51 KB
Loading

admin-ui/app/redux/api/backend-api.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@ export const fetchApiTokenWithDefaultScopes = async () => {
8484
'Problems getting API access token in order to process api calls.',
8585
error,
8686
)
87-
return -1
87+
return error
8888
})
8989
}

admin-ui/app/redux/features/authSlice.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ const initialState = {
1010
permissions: [],
1111
location: {},
1212
config: {},
13-
backendIsUp: true,
1413
defaultToken: null,
1514
codeChallenge: null,
1615
codeChallengeMethod: 'S256',
1716
codeVerifier: null,
17+
backendStatus: {
18+
active: true,
19+
errorMessage: null,
20+
statusCode: null
21+
},
1822
}
1923

2024
const authSlice = createSlice({
@@ -24,13 +28,15 @@ const authSlice = createSlice({
2428
getOAuth2Config: (state, action) => {
2529
state.defaultToken = action.payload
2630
},
31+
setBackendStatus: (state, action) => {
32+
state.backendStatus.active = action.payload.active
33+
state.backendStatus.errorMessage = action.payload.errorMessage
34+
state.backendStatus.statusCode = action.payload.statusCode
35+
},
2736
getOAuth2ConfigResponse: (state, action) => {
2837
if (action.payload?.config && action.payload?.config !== -1) {
2938
const newDataConfigObject = { ...state.config, ...action.payload.config }
3039
state.config = newDataConfigObject
31-
state.backendIsUp = true
32-
} else {
33-
state.backendIsUp = false
3440
}
3541
},
3642
setOAuthState: (state, action) => {
@@ -93,6 +99,7 @@ export const {
9399
setApiDefaultToken,
94100
getRandomChallengePair,
95101
getRandomChallengePairResponse,
102+
setBackendStatus
96103
} = authSlice.actions
97104
export default authSlice.reducer
98105
reducerRegistry.register('authReducer', authSlice.reducer)

admin-ui/app/redux/sagas/AuthSaga.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getAPIAccessTokenResponse,
99
getUserLocationResponse,
1010
getRandomChallengePairResponse,
11+
setBackendStatus,
1112
} from '../features/authSlice'
1213

1314
import {
@@ -21,8 +22,14 @@ import {
2122
import {RandomHashGenerator} from 'Utils/RandomHashGenerator'
2223

2324
function* getApiTokenWithDefaultScopes() {
24-
const response = yield call(fetchApiTokenWithDefaultScopes)
25-
return response.access_token
25+
const response = yield call(fetchApiTokenWithDefaultScopes)
26+
27+
if (response?.access_token) {
28+
return response.access_token
29+
} else if(response?.name === "AxiosError") {
30+
yield(put(setBackendStatus({ active: false, errorMessage: response?.response?.data?.responseMessage, statusCode: response?.response?.status })))
31+
return null
32+
}
2633
}
2734

2835
function* getOAuth2ConfigWorker({ payload }) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { Box } from '@mui/material'
2+
import React from 'react'
3+
import { useSelector } from 'react-redux'
4+
5+
function GluuServiceDownModal({ message = '', statusCode }) {
6+
const { authServerHost } = useSelector((state) => state.authReducer.config)
7+
8+
const handleRefresh = () => {
9+
const host = authServerHost ? `${authServerHost}/admin` : null
10+
11+
if (host) {
12+
window.location.href = host
13+
} else {
14+
window.location.reload()
15+
}
16+
}
17+
18+
return (
19+
<Box
20+
sx={{
21+
position: 'absolute',
22+
top: 0,
23+
bottom: 0,
24+
right: 0,
25+
left: 0,
26+
backgroundColor: '#110000',
27+
color: 'white',
28+
justifyContent: 'center',
29+
alignItems: 'center',
30+
display: 'flex',
31+
flexDirection: 'column',
32+
}}
33+
>
34+
<Box sx={{ position: 'absolute', top: 0, left: 0 }}>
35+
<img
36+
src={require('Images/logos/logo192.png')}
37+
style={{
38+
width: '120px',
39+
height: 'auto',
40+
margin: 50,
41+
}}
42+
/>
43+
</Box>
44+
45+
<div
46+
style={{
47+
position: 'absolute',
48+
top: 0,
49+
bottom: 0,
50+
right: 0,
51+
left: 0,
52+
color: 'white',
53+
justifyContent: 'center',
54+
alignItems: 'center',
55+
display: 'flex',
56+
maxWidth: '60%',
57+
maxHeight: '60%',
58+
margin: 'auto',
59+
gap: '40px',
60+
flexWrap: 'wrap'
61+
}}
62+
>
63+
<img
64+
src={require('Images/backend-down.png')}
65+
style={{
66+
width: 'auto',
67+
height: 'auto',
68+
fill: '#fff'
69+
}}
70+
/>
71+
<Box display='flex' alignItems='start' flexDirection='column' gap={2} maxWidth={{ sm: '100%', md: '70%' }}>
72+
{statusCode ? <h2 style={{ color: 'white', fontWeight: 'bolder', }}>Error code: {statusCode}</h2> : null}
73+
<h3
74+
style={{
75+
color: 'white',
76+
fontWeight: 'bolder',
77+
}}
78+
>
79+
{message}
80+
</h3>
81+
<button
82+
style={{
83+
border: 0,
84+
backgroundColor: 'transparent',
85+
color: 'white',
86+
textDecoration: 'underline',
87+
}}
88+
onClick={handleRefresh}
89+
>
90+
Try Again
91+
</button>
92+
</Box>
93+
</div>
94+
</Box>
95+
)
96+
}
97+
98+
export default GluuServiceDownModal

admin-ui/app/utils/ApiKeyRedirect.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import ApiKey from './LicenseScreens/ApiKey'
55
import GluuErrorModal from '../routes/Apps/Gluu/GluuErrorModal'
66
import UploadSSA from './UploadSSA'
77
import { useSelector } from 'react-redux'
8+
import GluuServiceDownModal from '../routes/Apps/Gluu/GluuServiceDownModal'
89

910
function ApiKeyRedirect({
10-
backendIsUp,
1111
isLicenseValid,
1212
islicenseCheckResultLoaded,
1313
isLicenseActivationResultLoaded,
@@ -17,6 +17,7 @@ function ApiKeyRedirect({
1717
const { t } = useTranslation()
1818
const { isTimeout } = useSelector((state) => state.initReducer)
1919
const { isValidatingFlow, isNoValidLicenseKeyFound, isUnderThresholdLimit } = useSelector((state) => state.licenseReducer)
20+
const backendStatus = useSelector((state) => state.authReducer.backendStatus)
2021

2122
return (
2223
<React.Fragment>
@@ -27,7 +28,7 @@ function ApiKeyRedirect({
2728
<>
2829
{!isLicenseValid && islicenseCheckResultLoaded && isConfigValid && !isValidatingFlow && isNoValidLicenseKeyFound ? (
2930
<ApiKey />
30-
) : (
31+
) : backendStatus.active && (
3132
<div
3233
style={{
3334
backgroundColor: 'transparent',
@@ -53,11 +54,11 @@ function ApiKeyRedirect({
5354
</>
5455
)}
5556

56-
{!backendIsUp && (
57-
<GluuErrorModal
58-
message={'The UI backend service is down'}
59-
description={
60-
'It may due to any of the following reason <br/>1. Admin UI Backend is down. <br/>2. Unable to get license credentials from Gluu server.<br/>Please contact the site administrator or check server logs.'
57+
{!backendStatus.active && (
58+
<GluuServiceDownModal
59+
statusCode={backendStatus.statusCode}
60+
message={
61+
backendStatus.errorMessage || 'Gluu Flex Admin UI is not getting any response from the backend (Jans Config Api).'
6162
}
6263
/>
6364
)}

admin-ui/app/utils/AppAuthProvider.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default function AppAuthProvider(props) {
2121
const location = useLocation()
2222
const [showContent, setShowContent] = useState(false)
2323
const [roleNotFound, setRoleNotFound] = useState(false)
24-
const { config, userinfo, userinfo_jwt, token, backendIsUp, codeChallenge, codeVerifier, codeChallengeMethod } = useSelector(
24+
const { config, userinfo, userinfo_jwt, token, codeChallenge, codeVerifier, codeChallengeMethod } = useSelector(
2525
(state) => state.authReducer
2626
)
2727
const {
@@ -149,7 +149,6 @@ export default function AppAuthProvider(props) {
149149
{showContent && props.children}
150150
{!showContent && (
151151
<ApiKeyRedirect
152-
backendIsUp={backendIsUp}
153152
isLicenseValid={isLicenseValid}
154153
redirectUrl={config.redirectUrl}
155154
isConfigValid={isConfigValid}

admin-ui/app/utils/ViewRedirect.js

-80
This file was deleted.

0 commit comments

Comments
 (0)