Skip to content

Commit

Permalink
Merge branch 'main' into astandrik.enable-autorefresh-for-paginated-t…
Browse files Browse the repository at this point in the history
…ables-1070-2
  • Loading branch information
astandrik authored Aug 14, 2024
2 parents 224b793 + 89804af commit d2ad13d
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 110 deletions.
7 changes: 6 additions & 1 deletion src/components/Errors/PageError/PageError.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@ export function PageError({title, description, error, children, ...restProps}: P
}

export function isAccessError(error: unknown) {
return Boolean(error && typeof error === 'object' && 'status' in error && error.status === 403);
return Boolean(
error &&
typeof error === 'object' &&
'status' in error &&
(error.status === 403 || error.status === 401),
);
}
55 changes: 36 additions & 19 deletions src/containers/App/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,45 @@ type RouteSlot = {
path: string;
slot: SlotComponent<any>;
component: React.ComponentType<any>;
wrapper?: React.ComponentType<any>;
exact?: boolean;
};
const routesSlots: RouteSlot[] = [
{
path: routes.cluster,
slot: ClusterSlot,
component: lazyComponent(() => import('../Cluster/Cluster'), 'Cluster'),
wrapper: DataWrapper,
},
{
path: routes.tenant,
slot: TenantSlot,
component: lazyComponent(() => import('../Tenant/Tenant'), 'Tenant'),
wrapper: DataWrapper,
},
{
path: routes.node,
slot: NodeSlot,
component: lazyComponent(() => import('../Node/Node'), 'Node'),
wrapper: DataWrapper,
},
{
path: routes.pDisk,
slot: PDiskPageSlot,
component: lazyComponent(() => import('../PDiskPage/PDiskPage'), 'PDiskPage'),
wrapper: DataWrapper,
},
{
path: routes.vDisk,
slot: VDiskPageSlot,
component: lazyComponent(() => import('../VDiskPage/VDiskPage'), 'VDiskPage'),
wrapper: DataWrapper,
},
{
path: routes.tablet,
slot: TabletSlot,
component: lazyComponent(() => import('../Tablet'), 'Tablet'),
wrapper: DataWrapper,
},
{
path: routes.tabletsFilters,
Expand All @@ -83,6 +90,7 @@ const routesSlots: RouteSlot[] = [
() => import('../TabletsFilters/TabletsFilters'),
'TabletsFilters',
),
wrapper: DataWrapper,
},
];

Expand All @@ -105,7 +113,12 @@ function renderRouteSlot(slots: SlotMap, route: RouteSlot) {
} else {
content = slot.rendered;
}
return <main className={b('main')}>{content}</main>;
const Wrapper = route.wrapper ?? React.Fragment;
return (
<main className={b('main')}>
<Wrapper>{content}</Wrapper>
</main>
);
}}
/>
);
Expand Down Expand Up @@ -144,29 +157,33 @@ export function Content(props: ContentProps) {
{additionalRoutes?.rendered}
{/* Single cluster routes */}
<Route key="single-cluster">
<GetUser>
<GetNodesList />
<GetCapabilities />
<Header mainPage={mainPage} />
<Switch>
{routesSlots.map((route) => {
return renderRouteSlot(slots, route);
})}
<Route
path={redirectProps.from || redirectProps.path}
exact={redirectProps.exact}
strict={redirectProps.strict}
render={() => (
<Redirect to={redirectProps.to} push={redirectProps.push} />
)}
/>
</Switch>
</GetUser>
<Header mainPage={mainPage} />
<Switch>
{routesSlots.map((route) => {
return renderRouteSlot(slots, route);
})}
<Route
path={redirectProps.from || redirectProps.path}
exact={redirectProps.exact}
strict={redirectProps.strict}
render={() => <Redirect to={redirectProps.to} push={redirectProps.push} />}
/>
</Switch>
</Route>
</Switch>
);
}

function DataWrapper({children}: {children: React.ReactNode}) {
return (
<GetUser>
<GetNodesList />
<GetCapabilities />
{children}
</GetUser>
);
}

function GetUser({children}: {children: React.ReactNode}) {
const {isLoading, error} = authenticationApi.useWhoamiQuery(undefined);

Expand Down
5 changes: 5 additions & 0 deletions src/containers/Tenant/Acl/Acl.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
&__result {
padding-bottom: var(--g-spacing-4);
padding-left: var(--g-spacing-2);

&_no-title {
margin-top: var(--g-spacing-3);
}
}
&__definition-content {
display: flex;
flex-direction: column;
align-items: flex-end;
}
&__list-title {
margin: var(--g-spacing-3) 0 var(--g-spacing-5);
Expand Down
74 changes: 51 additions & 23 deletions src/containers/Tenant/Acl/Acl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';

import {DefinitionList} from '@gravity-ui/components';
import type {DefinitionListItem} from '@gravity-ui/components';
import {SquareCheck} from '@gravity-ui/icons';
import {Icon} from '@gravity-ui/uikit';

import {ResponseError} from '../../../components/Errors/ResponseError';
import {Loader} from '../../../components/Loader';
Expand Down Expand Up @@ -94,6 +96,7 @@ function getAclListItems(acl?: TACE[]): DefinitionListItem[] {
return {
name: Subject,
content: <DefinitionValue value={definedDataEntries[0][1]} />,
multilineName: true,
};
}
return {
Expand All @@ -105,6 +108,7 @@ function getAclListItems(acl?: TACE[]): DefinitionListItem[] {
return {
name: aclParamToName[key],
content: <DefinitionValue value={value} />,
multilineName: true,
};
}
return undefined;
Expand All @@ -121,8 +125,22 @@ function getOwnerItem(owner?: string): DefinitionListItem[] {
}
return [
{
name: <span className={b('owner')}>{preparedOwner}</span>,
content: <span className={b('owner')}>{i18n('title_owner')}</span>,
name: preparedOwner,
content: i18n('title_owner'),
multilineName: true,
},
];
}

function getInterruptInheritanceItem(flag?: boolean): DefinitionListItem[] {
if (!flag) {
return [];
}
return [
{
name: i18n('title_interupt-inheritance'),
content: <Icon data={SquareCheck} size={20} />,
multilineName: true,
},
];
}
Expand All @@ -132,13 +150,15 @@ export const Acl = ({path, database}: {path: string; database: string}) => {

const loading = isFetching && !currentData;

const {acl, effectiveAcl, owner} = currentData || {};
const {acl, effectiveAcl, owner, interruptInheritance} = currentData || {};

const aclListItems = getAclListItems(acl);
const effectiveAclListItems = getAclListItems(effectiveAcl);

const ownerItem = getOwnerItem(owner);

const interruptInheritanceItem = getInterruptInheritanceItem(interruptInheritance);

if (loading) {
return <Loader />;
}
Expand All @@ -155,26 +175,34 @@ export const Acl = ({path, database}: {path: string; database: string}) => {

return (
<div className={b()}>
{accessRightsItems.length ? (
<React.Fragment>
<div className={b('list-title')}>{i18n('title_rights')}</div>
<DefinitionList
items={accessRightsItems}
nameMaxWidth={200}
className={b('result')}
/>
</React.Fragment>
) : null}
{effectiveAclListItems.length ? (
<React.Fragment>
<div className={b('list-title')}>{i18n('title_effective-rights')}</div>
<DefinitionList
items={effectiveAclListItems}
nameMaxWidth={200}
className={b('result')}
/>
</React.Fragment>
) : null}
<AclDefinitionList items={interruptInheritanceItem} />
<AclDefinitionList items={accessRightsItems} title={i18n('title_rights')} />
<AclDefinitionList
items={effectiveAclListItems}
title={i18n('title_effective-rights')}
/>
</div>
);
};

interface AclDefinitionListProps {
items: DefinitionListItem[];
title?: string;
}

function AclDefinitionList({items, title}: AclDefinitionListProps) {
if (!items.length) {
return null;
}
return (
<React.Fragment>
{title && <div className={b('list-title')}>{title}</div>}
<DefinitionList
items={items}
nameMaxWidth={200}
className={b('result', {'no-title': !title})}
responsive
/>
</React.Fragment>
);
}
1 change: 1 addition & 0 deletions src/containers/Tenant/Acl/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"title_rights": "Access Rights",
"title_effective-rights": "Effective Access Rights",
"title_owner": "Owner",
"title_interupt-inheritance": "Interrupt inheritance",
"description_empty": "No Acl data"
}
36 changes: 12 additions & 24 deletions src/containers/Tenant/ObjectSummary/ObjectSummary.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react';

import {HelpPopover} from '@gravity-ui/components';
import {LayoutHeaderCellsLargeFill} from '@gravity-ui/icons';
import {Button, Icon, Tabs} from '@gravity-ui/uikit';
import {Tabs} from '@gravity-ui/uikit';
import qs from 'qs';
import {Link, useLocation} from 'react-router-dom';
import {StringParam, useQueryParam} from 'use-query-params';
Expand All @@ -16,13 +15,9 @@ import {LinkWithIcon} from '../../../components/LinkWithIcon/LinkWithIcon';
import {Loader} from '../../../components/Loader';
import SplitPane from '../../../components/SplitPane';
import routes, {createExternalUILink, createHref} from '../../../routes';
import {setShowPreview, useGetSchemaQuery} from '../../../store/reducers/schema/schema';
import {
TENANT_PAGES_IDS,
TENANT_QUERY_TABS_ID,
TENANT_SUMMARY_TABS_IDS,
} from '../../../store/reducers/tenant/constants';
import {setQueryTab, setSummaryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
import {useGetSchemaQuery} from '../../../store/reducers/schema/schema';
import {TENANT_SUMMARY_TABS_IDS} from '../../../store/reducers/tenant/constants';
import {setSummaryTab} from '../../../store/reducers/tenant/tenant';
import {EPathSubType, EPathType} from '../../../types/api/schema';
import {cn} from '../../../utils/cn';
import {
Expand All @@ -41,6 +36,7 @@ import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
import {TENANT_INFO_TABS, TENANT_SCHEMA_TAB, TenantTabsGroups} from '../TenantPages';
import i18n from '../i18n';
import {getSummaryControls} from '../utils/controls';
import {
PaneVisibilityActionTypes,
PaneVisibilityToggleButtons,
Expand Down Expand Up @@ -84,6 +80,7 @@ export function ObjectSummary({
isCollapsed,
}: ObjectSummaryProps) {
const dispatch = useTypedDispatch();
const [, setCurrentPath] = useQueryParam('schema', StringParam);
const [commonInfoVisibilityState, dispatchCommonInfoVisibilityState] = React.useReducer(
paneVisibilityToggleReducerCreator(DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED),
undefined,
Expand Down Expand Up @@ -326,25 +323,16 @@ export function ObjectSummary({
dispatchCommonInfoVisibilityState(PaneVisibilityActionTypes.clear);
};

const onOpenPreview = () => {
dispatch(setShowPreview(true));
dispatch(setTenantPage(TENANT_PAGES_IDS.query));
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
};

const renderCommonInfoControls = () => {
const showPreview = isTableType(type) && !isIndexTableType(subType);
return (
<React.Fragment>
{showPreview && (
<Button
view="flat-secondary"
onClick={onOpenPreview}
title={i18n('summary.showPreview')}
>
<Icon data={LayoutHeaderCellsLargeFill} />
</Button>
)}
{showPreview &&
getSummaryControls(
dispatch,
{setActivePath: setCurrentPath},
'm',
)(path, 'preview')}
<ClipboardButton
text={path}
view="flat-secondary"
Expand Down
6 changes: 5 additions & 1 deletion src/containers/Tenant/Query/Preview/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ export const Preview = ({database, path, type}: PreviewProps) => {
const query = `--!syntax_v1\nselect * from \`${path}\` limit 32`;
const {currentData, isFetching, error} = previewApi.useSendQueryQuery(
{database, query, action: isExternalTableType(type) ? 'execute-query' : 'execute-scan'},
{pollingInterval: autoRefreshInterval, skip: !isPreviewAvailable},
{
pollingInterval: autoRefreshInterval,
skip: !isPreviewAvailable,
refetchOnMountOrArgChange: true,
},
);
const loading = isFetching && currentData === undefined;
const data = currentData ?? {};
Expand Down
4 changes: 2 additions & 2 deletions src/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {useCreateDirectoryFeatureAvailable} from '../../../../store/reducers/cap
import {schemaApi} from '../../../../store/reducers/schema/schema';
import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
import {useQueryExecutionSettings, useTypedDispatch} from '../../../../utils/hooks';
import {getSchemaControls} from '../../utils/controls';
import {isChildlessPathType, mapPathTypeToNavigationTreeType} from '../../utils/schema';
import {getActions} from '../../utils/schemaActions';
import {getControls} from '../../utils/schemaControls';
import {CreateDirectoryDialog} from '../CreateDirectoryDialog/CreateDirectoryDialog';

interface SchemaTreeProps {
Expand Down Expand Up @@ -118,7 +118,7 @@ export function SchemaTree(props: SchemaTreeProps) {
? handleOpenCreateDirectoryDialog
: undefined,
})}
renderAdditionalNodeElements={getControls(dispatch, {
renderAdditionalNodeElements={getSchemaControls(dispatch, {
setActivePath: onActivePathUpdate,
})}
activePath={currentPath}
Expand Down
Loading

0 comments on commit d2ad13d

Please sign in to comment.