Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/components/LoaderWrapper/LoaderWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ interface LoaderWrapperProps {
size?: LoaderSize;
className?: string;
children: React.ReactNode;
delay?: number;
}

export function LoaderWrapper({loading, size = 'm', className, children}: LoaderWrapperProps) {
export function LoaderWrapper({
loading,
size = 'm',
className,
children,
delay,
}: LoaderWrapperProps) {
if (loading) {
return <Loader size={size} className={className} />;
return <Loader size={size} className={className} delay={delay} />;
}
return children;
}
27 changes: 9 additions & 18 deletions src/containers/App/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ import React from 'react';

import {connect} from 'react-redux';
import type {RedirectProps} from 'react-router-dom';
import {Redirect, Route, Switch, useLocation} from 'react-router-dom';
import {Redirect, Route, Switch} from 'react-router-dom';

import {AccessDenied} from '../../components/Errors/403';
import {PageError} from '../../components/Errors/PageError/PageError';
import {LoaderWrapper} from '../../components/LoaderWrapper/LoaderWrapper';
import {useSlots} from '../../components/slots';
import type {SlotMap} from '../../components/slots/SlotMap';
import type {SlotComponent} from '../../components/slots/types';
import routes, {checkIsClustersPage} from '../../routes';
import routes from '../../routes';
import type {RootState} from '../../store';
import {authenticationApi} from '../../store/reducers/authentication/authentication';
import {
useCapabilitiesQuery,
useClusterWithoutAuthInUI,
useMetaCapabilitiesLoaded,
useMetaCapabilitiesQuery,
useMetaLoginAvailable,
} from '../../store/reducers/capabilities/hooks';
import {nodesListApi} from '../../store/reducers/nodesList';
import {uiFactory} from '../../uiFactory/uiFactory';
import {cn} from '../../utils/cn';
import {useDatabaseFromQuery} from '../../utils/hooks/useDatabaseFromQuery';
import {useMetaAuth, useMetaAuthUnavailable} from '../../utils/hooks/useMetaAuth';
import {lazyComponent} from '../../utils/lazyComponent';
import {isAccessError, isRedirectToAuth} from '../../utils/response';
import Authentication from '../Authentication/Authentication';
Expand Down Expand Up @@ -201,13 +201,9 @@ function ClustersDataWrapper({children}: {children: React.ReactNode}) {
}

function GetMetaUser({children}: {children: React.ReactNode}) {
const location = useLocation();
const metaAuth = useMetaAuth();

const isClustersPage = checkIsClustersPage(location.pathname);

const isMetaLoginAvailable = useMetaLoginAvailable();

if (isClustersPage && isMetaLoginAvailable) {
if (metaAuth) {
return <GetUser useMeta>{children}</GetUser>;
}
return children;
Expand All @@ -216,7 +212,7 @@ function GetMetaUser({children}: {children: React.ReactNode}) {
function GetUser({children, useMeta}: {children: React.ReactNode; useMeta?: boolean}) {
const database = useDatabaseFromQuery();

const {isLoading, error} = authenticationApi.useWhoamiQuery({
const {isFetching, error} = authenticationApi.useWhoamiQuery({
database,
useMeta,
});
Expand All @@ -225,7 +221,7 @@ function GetUser({children, useMeta}: {children: React.ReactNode; useMeta?: bool
const errorProps = error ? {...uiFactory.clusterOrDatabaseAccessError} : undefined;

return (
<LoaderWrapper loading={isLoading} size="l">
<LoaderWrapper loading={isFetching} size="l" delay={0}>
<PageError error={error} {...errorProps} errorPageTitle={appTitle}>
{children}
</PageError>
Expand Down Expand Up @@ -288,15 +284,10 @@ function ContentWrapper(props: ContentWrapperProps) {
const {singleClusterMode, isAuthenticated} = props;
const authUnavailable = useClusterWithoutAuthInUI();

const location = useLocation();
const isClustersPage = checkIsClustersPage(location.pathname);

const isMetaLoginAvailable = useMetaLoginAvailable();

const isClustersAuthUnavailable = isClustersPage && !isMetaLoginAvailable;
const metaAuthUnavailable = useMetaAuthUnavailable();

const renderNotAuthenticated = () => {
if (authUnavailable || isClustersAuthUnavailable) {
if (authUnavailable || metaAuthUnavailable) {
return <AccessDenied />;
}
return <Authentication />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {authenticationApi} from '../../../store/reducers/authentication/authenti
import {useClusterWithoutAuthInUI} from '../../../store/reducers/capabilities/hooks';
import {cn} from '../../../utils/cn';
import {useDatabaseFromQuery} from '../../../utils/hooks/useDatabaseFromQuery';
import {useMetaAuth, useMetaAuthUnavailable} from '../../../utils/hooks/useMetaAuth';
import i18n from '../i18n';

import './YdbInternalUser.scss';
Expand All @@ -16,6 +17,8 @@ const b = cn('kv-ydb-internal-user');
export function YdbInternalUser({login}: {login?: string}) {
const [logout] = authenticationApi.useLogoutMutation();
const authUnavailable = useClusterWithoutAuthInUI();
const metaAuthUnavailable = useMetaAuthUnavailable();
const metaAuth = useMetaAuth();
const database = useDatabaseFromQuery();

const history = useHistory();
Expand All @@ -29,11 +32,11 @@ export function YdbInternalUser({login}: {login?: string}) {
};

const handleLogout = () => {
logout(undefined);
logout({useMeta: metaAuth});
};

const renderLoginButton = () => {
if (authUnavailable) {
if (authUnavailable || metaAuthUnavailable) {
return null;
}
return (
Expand Down
10 changes: 4 additions & 6 deletions src/containers/Authentication/Authentication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {Eye, EyeSlash, Xmark} from '@gravity-ui/icons';
import {Button, Link as ExternalLink, Icon, TextInput} from '@gravity-ui/uikit';
import {useHistory, useLocation} from 'react-router-dom';

import {checkIsClustersPage, parseQuery} from '../../routes';
import {parseQuery} from '../../routes';
import {authenticationApi} from '../../store/reducers/authentication/authentication';
import {useLoginWithDatabase, useMetaLoginAvailable} from '../../store/reducers/capabilities/hooks';
import {useLoginWithDatabase} from '../../store/reducers/capabilities/hooks';
import {cn} from '../../utils/cn';
import {useMetaAuth} from '../../utils/hooks/useMetaAuth';

import {isDatabaseError, isPasswordError, isUserError} from './utils';

Expand All @@ -27,8 +28,7 @@ function Authentication({closable = false}: AuthenticationProps) {

const needDatabase = useLoginWithDatabase();

const isClustersPage = checkIsClustersPage(location.pathname);
const isMetaLoginAvailable = useMetaLoginAvailable();
const useMeta = useMetaAuth();

const [authenticate, {isLoading}] = authenticationApi.useAuthenticateMutation();

Expand Down Expand Up @@ -56,8 +56,6 @@ function Authentication({closable = false}: AuthenticationProps) {
setPasswordError('');
};

const useMeta = isClustersPage && isMetaLoginAvailable;

const onLoginClick = () => {
authenticate({user: login, password, database, useMeta})
.unwrap()
Expand Down
4 changes: 4 additions & 0 deletions src/services/api/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export class MetaAPI extends BaseYdbAPI {
return this.post(this.getPath('/meta/login'), params, {});
}

metaLogout() {
return this.post(this.getPath('/meta/logout'), {}, {});
}

metaWhoami() {
return this.post<TUserToken>(this.getPath('/meta/whoami'), {}, {});
}
Expand Down
9 changes: 7 additions & 2 deletions src/store/reducers/authentication/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,14 @@ export const authenticationApi = api.injectEndpoints({
invalidatesTags: (_, error) => (error ? [] : ['UserData']),
}),
logout: build.mutation({
queryFn: async (_, {dispatch}) => {
queryFn: async ({useMeta}: {useMeta?: boolean}, {dispatch}) => {
try {
const data = await window.api.auth.logout();
let data;
if (useMeta && window.api.meta) {
data = await window.api.meta.metaLogout();
} else {
data = await window.api.auth.logout();
}
dispatch(setIsAuthenticated(false));
return {data};
} catch (error) {
Expand Down
24 changes: 24 additions & 0 deletions src/utils/hooks/useMetaAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {useLocation} from 'react-router-dom';

import {checkIsClustersPage} from '../../routes';
import {useMetaLoginAvailable} from '../../store/reducers/capabilities/hooks';

function useMetaAuthState() {
const location = useLocation();
const isClustersPage = checkIsClustersPage(location.pathname);
const metaLoginAvailable = useMetaLoginAvailable();

return {isClustersPage, metaLoginAvailable};
}

export function useMetaAuth() {
const {isClustersPage, metaLoginAvailable} = useMetaAuthState();

return isClustersPage && metaLoginAvailable;
}

export function useMetaAuthUnavailable() {
const {isClustersPage, metaLoginAvailable} = useMetaAuthState();

return isClustersPage && !metaLoginAvailable;
}
Loading