diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/AppRouter.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/AppRouter.tsx
index 92e9f2f7daf..d7b014fbb1e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/AppRouter.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/AppRouter.tsx
@@ -13,11 +13,12 @@
import { isNil } from 'lodash';
import React, { useCallback, useEffect } from 'react';
-import { useLocation } from 'react-router-dom';
+import { Switch, useLocation } from 'react-router-dom';
import { useAnalytics } from 'use-analytics';
import { CustomEventTypes } from '../../generated/analytics/webAnalyticEventData';
import { useApplicationStore } from '../../hooks/useApplicationStore';
import AppContainer from '../AppContainer/AppContainer';
+import Loader from '../common/Loader/Loader';
import { UnAuthenticatedAppRouter } from './UnAuthenticatedAppRouter';
const AppRouter = () => {
@@ -26,7 +27,7 @@ const AppRouter = () => {
// web analytics instance
const analytics = useAnalytics();
- const { isAuthenticated } = useApplicationStore();
+ const { isAuthenticated, isApplicationLoading } = useApplicationStore();
useEffect(() => {
const { pathname } = location;
@@ -64,7 +65,22 @@ const AppRouter = () => {
return () => targetNode.removeEventListener('click', handleClickEvent);
}, [handleClickEvent]);
- return isAuthenticated ? : ;
+ /**
+ * isApplicationLoading is true when the application is loading in AuthProvider
+ * and is false when the application is loaded.
+ * If the application is loading, show the loader.
+ * If the user is authenticated, show the AppContainer.
+ * If the user is not authenticated, show the UnAuthenticatedAppRouter.
+ * */
+ if (isApplicationLoading) {
+ return ;
+ }
+
+ return (
+
+ {isAuthenticated ? : }
+
+ );
};
export default AppRouter;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/UnAuthenticatedAppRouter.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/UnAuthenticatedAppRouter.tsx
index b5aff0d81cf..81ded35bde0 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/UnAuthenticatedAppRouter.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AppRouter/UnAuthenticatedAppRouter.tsx
@@ -42,7 +42,7 @@ const BasicSignupPage = withSuspenseFallback(
);
export const UnAuthenticatedAppRouter = () => {
- const { authConfig, isSigningIn } = useApplicationStore();
+ const { authConfig, isSigningUp } = useApplicationStore();
const isBasicAuthProvider =
authConfig &&
@@ -78,7 +78,7 @@ export const UnAuthenticatedAppRouter = () => {
component={SamlCallback}
path={[ROUTES.SAML_CALLBACK, ROUTES.AUTH_CALLBACK]}
/>
- {!isSigningIn && (
+ {!isSigningUp && (
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/BasicAuthAuthenticator.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/BasicAuthAuthenticator.tsx
index 09cf9ca3740..977ab62debe 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/BasicAuthAuthenticator.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/BasicAuthAuthenticator.tsx
@@ -25,6 +25,7 @@ import {
} from '../../../rest/auth-API';
import { useApplicationStore } from '../../../hooks/useApplicationStore';
+import Loader from '../../common/Loader/Loader';
import { useBasicAuth } from '../AuthProviders/BasicAuthProvider';
interface BasicAuthenticatorInterface {
@@ -41,6 +42,7 @@ const BasicAuthenticator = forwardRef(
getRefreshToken,
setRefreshToken,
setOidcToken,
+ isApplicationLoading,
} = useApplicationStore();
const handleSilentSignIn = async (): Promise => {
@@ -73,6 +75,17 @@ const BasicAuthenticator = forwardRef(
},
}));
+ /**
+ * isApplicationLoading is true when the application is loading in AuthProvider
+ * and is false when the application is loaded.
+ * If the application is loading, show the loader.
+ * If the user is authenticated, show the AppContainer.
+ * If the user is not authenticated, show the UnAuthenticatedAppRouter.
+ * */
+ if (isApplicationLoading) {
+ return ;
+ }
+
return {children};
}
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/GenericAuthenticator.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/GenericAuthenticator.tsx
index 10a77b5ade8..2afe02205b8 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/GenericAuthenticator.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/GenericAuthenticator.tsx
@@ -25,7 +25,7 @@ export const GenericAuthenticator = forwardRef(
({ children }: { children: ReactNode }, ref) => {
const {
setIsAuthenticated,
- setIsSigningIn,
+ setIsSigningUp,
removeOidcToken,
setOidcToken,
} = useApplicationStore();
@@ -33,7 +33,7 @@ export const GenericAuthenticator = forwardRef(
const handleLogin = () => {
setIsAuthenticated(false);
- setIsSigningIn(true);
+ setIsSigningUp(true);
window.location.assign('api/v1/auth/login');
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/OidcAuthenticator.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/OidcAuthenticator.tsx
index bb1d7436c92..080298ed20a 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/OidcAuthenticator.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/OidcAuthenticator.tsx
@@ -65,13 +65,13 @@ const OidcAuthenticator = forwardRef(
) => {
const {
isAuthenticated,
- setIsAuthenticated,
- isSigningIn,
- setIsSigningIn,
+ isSigningUp,
+ setIsSigningUp,
updateAxiosInterceptors,
currentUser,
newUser,
setOidcToken,
+ isApplicationLoading,
} = useApplicationStore();
const history = useHistory();
const userManager = useMemo(
@@ -80,7 +80,7 @@ const OidcAuthenticator = forwardRef(
);
const login = () => {
- setIsSigningIn(true);
+ setIsSigningUp(true);
};
const logout = () => {
@@ -113,16 +113,23 @@ const OidcAuthenticator = forwardRef(
return (
<>
+ {/* render sign in page if user is not authenticated and not signing up
+ * else redirect to my data page as user is authenticated and not signing up
+ */}
- {!isAuthenticated && !isSigningIn ? (
+ {!isAuthenticated && !isSigningUp ? (
) : (
)}
- {!isSigningIn ? (
+
+ {/* render the sign in route only if user is not signing up */}
+ {!isSigningUp ? (
) : null}
+
+ {/* callback route to handle the auth flow after user has successfully provided their consent */}
(
@@ -135,7 +142,6 @@ const OidcAuthenticator = forwardRef(
}}
onSuccess={(user) => {
setOidcToken(user.id_token);
- setIsAuthenticated(true);
onLoginSuccess(user as OidcUser);
}}
/>
@@ -143,6 +149,7 @@ const OidcAuthenticator = forwardRef(
)}
/>
+ {/* silent callback route to handle the silent auth flow */}
(
@@ -163,15 +170,21 @@ const OidcAuthenticator = forwardRef(
>
)}
/>
+
+ {/* render the children only if user is authenticated */}
{isAuthenticated ? (
{children}
- ) : !isSigningIn && isEmpty(currentUser) && isEmpty(newUser) ? (
+ ) : // render the sign in page if user is not authenticated and not signing up
+ !isSigningUp && isEmpty(currentUser) && isEmpty(newUser) ? (
) : (
+ // render the authenticator component to handle the auth flow while user is signing in
)}
- {isSigningIn && }
+
+ {/* show loader when application is loading and user is signing up*/}
+ {isApplicationLoading && isSigningUp && }
>
);
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.test.tsx
index f78735f194c..935c9f1a50d 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.test.tsx
@@ -42,7 +42,6 @@ Object.defineProperty(window, 'localStorage', {
});
const mockUseAuth0 = useAuth0 as jest.Mock;
-const mockSetIsAuthenticated = jest.fn();
const mockHandleSuccessfulLogin = jest.fn();
jest.mock('@auth0/auth0-react', () => ({
@@ -53,7 +52,6 @@ jest.mock('../../../../hooks/useApplicationStore', () => {
return {
useApplicationStore: jest.fn(() => ({
authConfig: {},
- setIsAuthenticated: mockSetIsAuthenticated,
handleSuccessfulLogin: mockHandleSuccessfulLogin,
setOidcToken: jest.fn(),
})),
@@ -108,8 +106,6 @@ describe('Test Auth0Callback component', () => {
// eslint-disable-next-line no-undef
await new Promise(process.nextTick);
- expect(mockSetIsAuthenticated).toHaveBeenCalledTimes(1);
- expect(mockSetIsAuthenticated).toHaveBeenCalledWith(true);
expect(mockHandleSuccessfulLogin).toHaveBeenCalledTimes(1);
expect(mockHandleSuccessfulLogin).toHaveBeenCalledWith({
id_token: 'raw_id_token',
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.tsx
index a7560ca12bd..5bbff633223 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppCallbacks/Auth0Callback/Auth0Callback.tsx
@@ -20,13 +20,11 @@ import { OidcUser } from '../../AuthProviders/AuthProvider.interface';
const Auth0Callback: VFC = () => {
const { isAuthenticated, user, getIdTokenClaims, error } = useAuth0();
- const { setIsAuthenticated, handleSuccessfulLogin, setOidcToken } =
- useApplicationStore();
+ const { handleSuccessfulLogin, setOidcToken } = useApplicationStore();
if (isAuthenticated) {
getIdTokenClaims()
.then((token) => {
setOidcToken(token?.__raw || '');
- setIsAuthenticated(true);
const oidcUser: OidcUser = {
id_token: token?.__raw || '',
scope: '',
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.interface.ts
index ee60fbdefc4..5e4b2c0dbec 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.interface.ts
@@ -52,8 +52,8 @@ export interface IAuthContext {
setIsAuthenticated: (authenticated: boolean) => void;
authConfig?: AuthenticationConfiguration;
authorizerConfig?: AuthorizerConfiguration;
- isSigningIn: boolean;
- setIsSigningIn: (authenticated: boolean) => void;
+ isSigningUp: boolean;
+ setIsSigningUp: (isSigningUp: boolean) => void;
onLoginHandler: () => void;
onLogoutHandler: () => void;
currentUser?: User;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.tsx
index b7f720a9fdd..712a049e617 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/AuthProvider.tsx
@@ -109,16 +109,18 @@ export const AuthProvider = ({
setHelperFunctionsRef,
setCurrentUser,
updateNewUser: setNewUserProfile,
- setIsAuthenticated: setIsUserAuthenticated,
+ setIsAuthenticated,
authConfig,
setAuthConfig,
setAuthorizerConfig,
- setIsSigningIn,
+ setIsSigningUp,
setJwtPrincipalClaims,
removeRefreshToken,
removeOidcToken,
getOidcToken,
getRefreshToken,
+ isApplicationLoading,
+ setApplicationLoading,
} = useApplicationStore();
const { activeDomain } = useDomainStore();
@@ -127,7 +129,6 @@ export const AuthProvider = ({
const { t } = useTranslation();
const [timeoutId, setTimeoutId] = useState();
- const [loading, setLoading] = useState(false);
const [msalInstance, setMsalInstance] = useState();
const authenticatorRef = useRef(null);
@@ -140,7 +141,7 @@ export const AuthProvider = ({
const clientType = authConfig?.clientType ?? ClientType.Public;
const onLoginHandler = () => {
- setLoading(true);
+ setApplicationLoading(true);
authenticatorRef.current?.invokeLogin();
@@ -151,7 +152,7 @@ export const AuthProvider = ({
clearTimeout(timeoutId);
authenticatorRef.current?.invokeLogout();
- setIsUserAuthenticated(false);
+ setIsAuthenticated(false);
// reset the user details on logout
setCurrentUser({} as User);
@@ -162,7 +163,7 @@ export const AuthProvider = ({
// remove the refresh token on logout
removeRefreshToken();
- setLoading(false);
+ setApplicationLoading(false);
}, [timeoutId]);
const onRenewIdTokenHandler = () => {
@@ -191,8 +192,8 @@ export const AuthProvider = ({
const resetUserDetails = (forceLogout = false) => {
setCurrentUser({} as User);
removeOidcToken();
- setIsUserAuthenticated(false);
- setLoading(false);
+ setIsAuthenticated(false);
+ setApplicationLoading(false);
clearTimeout(timeoutId);
if (forceLogout) {
onLogoutHandler();
@@ -203,12 +204,12 @@ export const AuthProvider = ({
};
const getLoggedInUserDetails = async () => {
- setLoading(true);
+ setApplicationLoading(true);
try {
const res = await getLoggedInUser({ fields: userAPIQueryFields });
if (res) {
setCurrentUser(res);
- setIsUserAuthenticated(true);
+ setIsAuthenticated(true);
} else {
resetUserDetails();
}
@@ -224,7 +225,7 @@ export const AuthProvider = ({
);
}
} finally {
- setLoading(false);
+ setApplicationLoading(false);
}
};
@@ -357,15 +358,15 @@ export const AuthProvider = ({
}, [timeoutId]);
const handleFailedLogin = () => {
- setIsSigningIn(false);
- setIsUserAuthenticated(false);
- setLoading(false);
+ setIsSigningUp(false);
+ setIsAuthenticated(false);
+ setApplicationLoading(false);
history.push(ROUTES.SIGNIN);
};
const handleSuccessfulLogin = async (user: OidcUser) => {
- setLoading(true);
- setIsUserAuthenticated(true);
+ setApplicationLoading(true);
+ setIsAuthenticated(true);
const fields =
authConfig?.provider === AuthProviderEnum.Basic
? userAPIQueryFields + ',' + isEmailVerifyField
@@ -389,7 +390,7 @@ export const AuthProvider = ({
if (err && err.response && err.response.status === 404) {
setNewUserProfile(user.profile);
setCurrentUser({} as User);
- setIsSigningIn(true);
+ setIsSigningUp(true);
history.push(ROUTES.SIGNUP);
} else {
// eslint-disable-next-line no-console
@@ -397,7 +398,7 @@ export const AuthProvider = ({
history.push(ROUTES.SIGNIN);
}
} finally {
- setLoading(false);
+ setApplicationLoading(false);
}
};
@@ -548,7 +549,7 @@ export const AuthProvider = ({
updateAuthInstance(configJson);
if (!getOidcToken()) {
handleStoreProtectedRedirectPath();
- setLoading(false);
+ setApplicationLoading(false);
} else {
if (location.pathname !== ROUTES.AUTH_CALLBACK) {
getLoggedInUserDetails();
@@ -556,7 +557,7 @@ export const AuthProvider = ({
}
} else {
// provider is either null or not supported
- setLoading(false);
+ setApplicationLoading(false);
showErrorToast(
t('message.configured-sso-provider-is-not-supported', {
provider: authConfig?.provider,
@@ -564,11 +565,11 @@ export const AuthProvider = ({
);
}
} else {
- setLoading(false);
+ setApplicationLoading(false);
showErrorToast(t('message.auth-configuration-missing'));
}
} catch (error) {
- setLoading(false);
+ setApplicationLoading(false);
showErrorToast(
error as AxiosError,
t('server.entity-fetch-error', {
@@ -580,7 +581,11 @@ export const AuthProvider = ({
const getProtectedApp = () => {
// Show loader if application in loading state
- const childElement = loading ? : children;
+ const childElement = isApplicationLoading ? (
+
+ ) : (
+ children
+ );
if (clientType === ClientType.Confidential) {
return (
@@ -691,11 +696,11 @@ export const AuthProvider = ({
return cleanup;
}, []);
- const isLoading =
+ const isConfigLoading =
!authConfig ||
(authConfig.provider === AuthProviderEnum.Azure && !msalInstance);
- return <>{isLoading ? : getProtectedApp()}>;
+ return <>{isConfigLoading ? : getProtectedApp()}>;
};
export default AuthProvider;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/OktaAuthProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/OktaAuthProvider.tsx
index af6f740d46b..c90e9b4a634 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/OktaAuthProvider.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AuthProviders/OktaAuthProvider.tsx
@@ -31,8 +31,7 @@ export const OktaAuthProvider: FunctionComponent = ({
children,
onLoginSuccess,
}: Props) => {
- const { authConfig, setIsAuthenticated, setOidcToken } =
- useApplicationStore();
+ const { authConfig, setOidcToken } = useApplicationStore();
const { clientId, issuer, redirectUri, scopes, pkce } =
authConfig as OktaAuthOptions;
@@ -63,7 +62,6 @@ export const OktaAuthProvider: FunctionComponent = ({
_oktaAuth
.getUser()
.then((info) => {
- setIsAuthenticated(true);
const user = {
id_token: idToken,
scope: scopes,
diff --git a/openmetadata-ui/src/main/resources/ui/src/hooks/useApplicationStore.ts b/openmetadata-ui/src/main/resources/ui/src/hooks/useApplicationStore.ts
index 8aaa3fd1f95..a9756729fd3 100644
--- a/openmetadata-ui/src/main/resources/ui/src/hooks/useApplicationStore.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/hooks/useApplicationStore.ts
@@ -31,6 +31,7 @@ export const OM_SESSION_KEY = 'om-session';
export const useApplicationStore = create()(
persist(
(set, get) => ({
+ isApplicationLoading: false,
theme: getThemeConfig(),
applicationConfig: {
customTheme: getThemeConfig(),
@@ -40,7 +41,7 @@ export const useApplicationStore = create()(
isAuthenticated: Boolean(getOidcToken()),
authConfig: undefined,
authorizerConfig: undefined,
- isSigningIn: false,
+ isSigningUp: false,
jwtPrincipalClaims: [],
userProfilePics: {},
cachedEntityData: {},
@@ -77,8 +78,12 @@ export const useApplicationStore = create()(
setIsAuthenticated: (authenticated: boolean) => {
set({ isAuthenticated: authenticated });
},
- setIsSigningIn: (signingIn: boolean) => {
- set({ isSigningIn: signingIn });
+ setIsSigningUp: (signingUp: boolean) => {
+ set({ isSigningUp: signingUp });
+ },
+
+ setApplicationLoading: (loading: boolean) => {
+ set({ isApplicationLoading: loading });
},
onLoginHandler: () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/interface/store.interface.ts b/openmetadata-ui/src/main/resources/ui/src/interface/store.interface.ts
index 31bbff7090f..da54d84dc16 100644
--- a/openmetadata-ui/src/main/resources/ui/src/interface/store.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/interface/store.interface.ts
@@ -42,6 +42,8 @@ export interface ApplicationStore
extends IAuthContext,
LogoConfiguration,
LoginConfiguration {
+ isApplicationLoading: boolean;
+ setApplicationLoading: (loading: boolean) => void;
userProfilePics: Record;
cachedEntityData: Record;
selectedPersona: EntityReference;
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.test.tsx
index 66c8775cf6a..df986ebf3b6 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.test.tsx
@@ -33,7 +33,7 @@ jest.mock('react-router-dom', () => ({
jest.mock('../../hooks/useApplicationStore', () => ({
useApplicationStore: jest.fn(() => ({
- setIsSigningIn: jest.fn(),
+ setIsSigningUp: jest.fn(),
newUser: {
name: '',
email: '',
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.tsx
index 2f7d6a25e36..db0743d0a34 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/SignUp/SignUpPage.tsx
@@ -41,7 +41,7 @@ const SignUp = () => {
const { t } = useTranslation();
const history = useHistory();
const {
- setIsSigningIn,
+ setIsSigningUp,
jwtPrincipalClaims = [],
authorizerConfig,
updateCurrentUser,
@@ -67,7 +67,7 @@ const SignUp = () => {
if (urlPathname) {
setUrlPathnameExpiryAfterRoute(urlPathname);
}
- setIsSigningIn(false);
+ setIsSigningUp(false);
history.push(ROUTES.HOME);
} catch (error) {
showErrorToast(