diff --git a/src/containers/App/Content.tsx b/src/containers/App/Content.tsx
index 7c4ea4cc36..3003cf0c6d 100644
--- a/src/containers/App/Content.tsx
+++ b/src/containers/App/Content.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import {connect} from 'react-redux';
import type {RedirectProps} from 'react-router-dom';
-import {Redirect, Route, Switch} from 'react-router-dom';
+import {Redirect, Route, Switch, useLocation} from 'react-router-dom';
import {AccessDenied} from '../../components/Errors/403';
import {PageError} from '../../components/Errors/PageError/PageError';
@@ -10,7 +10,7 @@ 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 from '../../routes';
+import routes, {checkIsClustersPage} from '../../routes';
import type {RootState} from '../../store';
import {authenticationApi} from '../../store/reducers/authentication/authentication';
import {
@@ -18,6 +18,7 @@ import {
useClusterWithoutAuthInUI,
useMetaCapabilitiesLoaded,
useMetaCapabilitiesQuery,
+ useMetaLoginAvailable,
} from '../../store/reducers/capabilities/hooks';
import {nodesListApi} from '../../store/reducers/nodesList';
import {uiFactory} from '../../uiFactory/uiFactory';
@@ -160,7 +161,7 @@ export function Content(props: ContentProps) {
exact: true,
component: Clusters,
slot: ClustersSlot,
- wrapper: GetMetaCapabilities,
+ wrapper: ClustersDataWrapper,
})}
{/* Single cluster routes */}
{routesSlots.map((route) => {
@@ -191,9 +192,34 @@ function DataWrapper({children}: {children: React.ReactNode}) {
);
}
-function GetUser({children}: {children: React.ReactNode}) {
+function ClustersDataWrapper({children}: {children: React.ReactNode}) {
+ return (
+
+ {children}
+
+ );
+}
+
+function GetMetaUser({children}: {children: React.ReactNode}) {
+ const location = useLocation();
+
+ const isClustersPage = checkIsClustersPage(location.pathname);
+
+ const isMetaLoginAvailable = useMetaLoginAvailable();
+
+ if (isClustersPage && isMetaLoginAvailable) {
+ return {children};
+ }
+ return children;
+}
+
+function GetUser({children, useMeta}: {children: React.ReactNode; useMeta?: boolean}) {
const database = useDatabaseFromQuery();
- const {isLoading, error} = authenticationApi.useWhoamiQuery({database});
+
+ const {isLoading, error} = authenticationApi.useWhoamiQuery({
+ database,
+ useMeta,
+ });
const {appTitle} = useAppTitle();
const errorProps = error ? {...uiFactory.clusterOrDatabaseAccessError} : undefined;
@@ -262,8 +288,15 @@ 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 renderNotAuthenticated = () => {
- if (authUnavailable) {
+ if (authUnavailable || isClustersAuthUnavailable) {
return ;
}
return ;
diff --git a/src/containers/Authentication/Authentication.tsx b/src/containers/Authentication/Authentication.tsx
index 5f87792b4b..3d32d337a8 100644
--- a/src/containers/Authentication/Authentication.tsx
+++ b/src/containers/Authentication/Authentication.tsx
@@ -4,9 +4,9 @@ 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 {parseQuery} from '../../routes';
+import {checkIsClustersPage, parseQuery} from '../../routes';
import {authenticationApi} from '../../store/reducers/authentication/authentication';
-import {useLoginWithDatabase} from '../../store/reducers/capabilities/hooks';
+import {useLoginWithDatabase, useMetaLoginAvailable} from '../../store/reducers/capabilities/hooks';
import {cn} from '../../utils/cn';
import {isDatabaseError, isPasswordError, isUserError} from './utils';
@@ -27,7 +27,10 @@ function Authentication({closable = false}: AuthenticationProps) {
const needDatabase = useLoginWithDatabase();
- const [authenticate, {isLoading}] = authenticationApi.useAuthenticateMutation(undefined);
+ const isClustersPage = checkIsClustersPage(location.pathname);
+ const isMetaLoginAvailable = useMetaLoginAvailable();
+
+ const [authenticate, {isLoading}] = authenticationApi.useAuthenticateMutation();
const {returnUrl, database: databaseFromQuery} = parseQuery(location);
@@ -53,8 +56,10 @@ function Authentication({closable = false}: AuthenticationProps) {
setPasswordError('');
};
+ const useMeta = isClustersPage && isMetaLoginAvailable;
+
const onLoginClick = () => {
- authenticate({user: login, password, database})
+ authenticate({user: login, password, database, useMeta})
.unwrap()
.then(() => {
if (returnUrl) {
diff --git a/src/containers/Header/Header.tsx b/src/containers/Header/Header.tsx
index 2df3a5a174..0cb76136f8 100644
--- a/src/containers/Header/Header.tsx
+++ b/src/containers/Header/Header.tsx
@@ -15,6 +15,7 @@ import {useHistory, useLocation} from 'react-router-dom';
import {getConnectToDBDialog} from '../../components/ConnectToDB/ConnectToDBDialog';
import {InternalLink} from '../../components/InternalLink';
+import {checkIsClustersPage, checkIsTenantPage} from '../../routes';
import {
useAddClusterFeatureAvailable,
useDatabasesAvailable,
@@ -64,8 +65,8 @@ function Header() {
const location = useLocation();
const history = useHistory();
- const isDatabasePage = location.pathname === '/tenant';
- const isClustersPage = location.pathname === '/clusters';
+ const isDatabasePage = checkIsTenantPage(location.pathname);
+ const isClustersPage = checkIsClustersPage(location.pathname);
const {isLoading: isClustersLoading, error: clustersError} =
clustersApi.useGetClustersListQuery(undefined, {
diff --git a/src/routes.ts b/src/routes.ts
index 0fdeb78bd9..73baf6d7e4 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -146,3 +146,11 @@ type TabletPageQuery = QueryParamsTypeFromQueryObject(this.getPath('/meta/whoami'), {}, {});
+ }
+
getMetaCapabilities() {
return this.get(
this.getPath('/capabilities'),
diff --git a/src/store/reducers/authentication/authentication.ts b/src/store/reducers/authentication/authentication.ts
index ee9f307e57..9965a05144 100644
--- a/src/store/reducers/authentication/authentication.ts
+++ b/src/store/reducers/authentication/authentication.ts
@@ -52,9 +52,17 @@ export const {selectIsUserAllowedToMakeChanges, selectIsViewerUser, selectUser}
export const authenticationApi = api.injectEndpoints({
endpoints: (build) => ({
whoami: build.query({
- queryFn: async ({database}: {database?: string}, {dispatch}) => {
+ queryFn: async (
+ {database, useMeta}: {database?: string; useMeta?: boolean},
+ {dispatch},
+ ) => {
try {
- const data = await window.api.viewer.whoami({database});
+ let data: TUserToken;
+ if (useMeta && window.api.meta) {
+ data = await window.api.meta.metaWhoami();
+ } else {
+ data = await window.api.viewer.whoami({database});
+ }
dispatch(setUser(data));
return {data};
} catch (error) {
@@ -68,11 +76,17 @@ export const authenticationApi = api.injectEndpoints({
}),
authenticate: build.mutation({
queryFn: async (
- params: {user: string; password: string; database?: string},
+ params: {user: string; password: string; database?: string; useMeta?: boolean},
{dispatch},
) => {
try {
- const data = await window.api.auth.authenticate(params);
+ const {useMeta, ...rest} = params;
+ let data;
+ if (useMeta) {
+ data = await window.api.meta?.metaAuthenticate(rest);
+ } else {
+ data = await window.api.auth.authenticate(rest);
+ }
dispatch(setIsAuthenticated(true));
return {data};
} catch (error) {
diff --git a/src/store/reducers/capabilities/hooks.ts b/src/store/reducers/capabilities/hooks.ts
index 4fe87b3fae..54d5658441 100644
--- a/src/store/reducers/capabilities/hooks.ts
+++ b/src/store/reducers/capabilities/hooks.ts
@@ -176,3 +176,7 @@ export const useClusterEventsAvailable = () => {
export const useDatabasesAvailable = () => {
return useGetMetaFeatureVersion('/meta/databases') >= 1;
};
+
+export const useMetaLoginAvailable = () => {
+ return useGetMetaFeatureVersion('/meta/login') >= 1;
+};
diff --git a/src/types/api/capabilities.ts b/src/types/api/capabilities.ts
index 728085ab5f..d28c1453ed 100644
--- a/src/types/api/capabilities.ts
+++ b/src/types/api/capabilities.ts
@@ -52,4 +52,5 @@ export type MetaCapability =
| '/meta/update_cluster'
| '/meta/delete_cluster'
| '/meta/events'
+ | '/meta/login'
| '/meta/databases';