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
36 changes: 30 additions & 6 deletions src/containers/Versions/NodesTreeTitle/NodesTreeTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react';

import {ChevronDown, ChevronUp, Database} from '@gravity-ui/icons';
import {ClipboardButton, Flex, Icon, Text} from '@gravity-ui/uikit';
import {ArrowRight, ChevronDown, ChevronUp, Database} from '@gravity-ui/icons';
import {Button, ClipboardButton, Flex, Icon, Text} from '@gravity-ui/uikit';
import {useHistory} from 'react-router-dom';

import {VersionsBar} from '../../../components/VersionsBar/VersionsBar';
import {cn} from '../../../utils/cn';
import type {PreparedNodeSystemState} from '../../../utils/nodes';
import type {PreparedVersion} from '../../../utils/versions/types';
import {getTenantPath} from '../../Tenant/TenantPages';
import i18n from '../i18n';
import type {GroupedNodesItem} from '../types';

Expand Down Expand Up @@ -35,6 +37,8 @@ export const NodesTreeTitle = ({
preparedVersions,
onClick,
}: NodesTreeTitleProps) => {
const history = useHistory();

const handleClick = React.useCallback<React.MouseEventHandler<HTMLDivElement>>(
(event) => {
const shouldSkip = event.nativeEvent.composedPath().some(isActiveButtonTarget);
Expand All @@ -59,6 +63,28 @@ export const NodesTreeTitle = ({
}
}, [items, nodes]);

const renderNodesCount = () => {
if (isDatabase) {
return (
<Button
size="s"
onClick={() =>
history.push(getTenantPath({database: title, diagnosticsTab: 'nodes'}))
}
>
{i18n('nodes-count', {count: nodesAmount})}
<Icon data={ArrowRight} />
</Button>
);
}

return (
<Text variant="body-2" color="hint">
{i18n('nodes-count', {count: nodesAmount})}
</Text>
);
};

return (
<div className={b('overview')} onClick={handleClick}>
<Flex gap={2} alignItems={'center'}>
Expand All @@ -77,12 +103,10 @@ export const NodesTreeTitle = ({
/>
</React.Fragment>
) : null}
<Text variant="body-2" color="hint">
{i18n('nodes-count', {count: nodesAmount})}
</Text>
{renderNodesCount()}
</Flex>
<Flex alignItems={'center'} gap={4}>
{preparedVersions ? (
{isDatabase && preparedVersions ? (
<div className={b('version-progress')}>
<VersionsBar preparedVersions={preparedVersions} withTitles={false} />
</div>
Expand Down
4 changes: 0 additions & 4 deletions src/containers/Versions/Versions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
font-size: var(--ydb-info-viewer-font-size);
line-height: var(--ydb-info-viewer-line-height);

&__controls {
margin-bottom: var(--g-spacing-3);
}
&__overall {
margin-top: var(--g-spacing-4);
margin-bottom: var(--g-spacing-6);
}
}
223 changes: 75 additions & 148 deletions src/containers/Versions/Versions.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import {ChevronsCollapseVertical, ChevronsExpandVertical} from '@gravity-ui/icons';
import {Button, Flex, Icon, SegmentedRadioGroup, Select, Text} from '@gravity-ui/uikit';
import {Button, Flex, Icon, Select, Text} from '@gravity-ui/uikit';
import {StringParam, useQueryParams} from 'use-query-params';
import {z} from 'zod';

Expand All @@ -15,10 +15,9 @@ import {useAutoRefreshInterval} from '../../utils/hooks';
import type {PreparedVersion, VersionsDataMap} from '../../utils/versions/types';

import {GroupedNodesTree} from './GroupedNodesTree/GroupedNodesTree';
import type {NodeType} from './constants';
import {NODE_TYPES, NODE_TYPES_TITLE} from './constants';
import {getGroupedStorageNodes, getGroupedTenantNodes, getOtherNodes} from './groupNodes';
import i18n from './i18n';
import type {GroupedNodesItem} from './types';
import {GroupByValue} from './types';
import {useGetPreparedVersions, useVersionsDataMap} from './utils';

Expand Down Expand Up @@ -62,20 +61,15 @@ interface VersionsProps {
versionsDataMap?: VersionsDataMap;
}

const nodeTypeSchema = z.nativeEnum(NODE_TYPES).catch(NODE_TYPES.storage);
const groupByValueSchema = z.nativeEnum(GroupByValue).catch(GroupByValue.VERSION);

function Versions({preparedVersions, nodes, versionsDataMap}: VersionsProps) {
const [{nodeType: rawNodeType, groupBy: rawGroupByValue}, setQueryParams] = useQueryParams({
nodeType: StringParam,
const [{groupBy: rawGroupByValue}, setQueryParams] = useQueryParams({
groupBy: StringParam,
});

const nodeType = nodeTypeSchema.parse(rawNodeType);
const groupByValue = groupByValueSchema.parse(rawGroupByValue);

const [expanded, setExpanded] = React.useState(false);

const tenantNodes = React.useMemo(() => {
return getGroupedTenantNodes(nodes, versionsDataMap, groupByValue);
}, [groupByValue, nodes, versionsDataMap]);
Expand All @@ -89,167 +83,100 @@ function Versions({preparedVersions, nodes, versionsDataMap}: VersionsProps) {
const handleGroupByValueChange = (value: string) => {
setQueryParams({groupBy: value as GroupByValue}, 'replaceIn');
};
const handleNodeTypeChange = (value: string) => {
setQueryParams({nodeType: value as NodeType}, 'replaceIn');
};

const renderExpandButton = () => {
const renderGroupControl = () => {
const options = [
{value: GroupByValue.TENANT, content: i18n('title_database')},
{value: GroupByValue.VERSION, content: i18n('title_version')},
];
return (
<Button onClick={() => setExpanded((value) => !value)}>
<Icon data={expanded ? ChevronsCollapseVertical : ChevronsExpandVertical} />
{expanded ? i18n('action_collapse') : i18n('action_expand')}
</Button>
<Select
label={i18n('group-by')}
value={[groupByValue]}
options={options}
onUpdate={(values) => handleGroupByValueChange(values[0])}
width={200}
size="m"
/>
);
};

const renderNodeTypeRadio = () => {
const options = [
<SegmentedRadioGroup.Option value={NODE_TYPES.storage}>
{NODE_TYPES_TITLE.storage}
</SegmentedRadioGroup.Option>,
<SegmentedRadioGroup.Option value={NODE_TYPES.database}>
{NODE_TYPES_TITLE.database}
</SegmentedRadioGroup.Option>,
];
return (
<Flex className={b()} direction={'column'} gap={6}>
<Flex gap={3} direction={'column'} className={b('overall')}>
<Text variant="subheader-3">{i18n('title_overall')}</Text>
<VersionsBar preparedVersions={preparedVersions} size="m" />
</Flex>

if (otherNodes?.length) {
options.push(
<SegmentedRadioGroup.Option value={NODE_TYPES.other}>
{NODE_TYPES_TITLE.other}
</SegmentedRadioGroup.Option>,
);
}
<VersionsSection sectionTitle={i18n('title_storage-nodes')} nodes={storageNodes} />
<VersionsSection
sectionTitle={i18n('title_database-nodes')}
nodes={tenantNodes}
renderControls={renderGroupControl}
/>
<VersionsSection sectionTitle={i18n('title_other-nodes')} nodes={otherNodes} />
</Flex>
);
}

return (
<SegmentedRadioGroup value={nodeType} onUpdate={handleNodeTypeChange}>
{options}
</SegmentedRadioGroup>
);
};
function VersionsSection({
sectionTitle,
renderControls,
nodes,
}: {
sectionTitle: string;
renderControls?: () => React.ReactNode;
nodes?: GroupedNodesItem[];
}) {
const [expanded, setExpanded] = React.useState(false);

const renderGroupControl = () => {
if (nodeType === NODE_TYPES.database) {
const options = [
{value: GroupByValue.TENANT, content: i18n('title_database')},
{value: GroupByValue.VERSION, content: i18n('title_version')},
];
return (
<Select
label={i18n('group-by')}
value={[groupByValue]}
options={options}
onUpdate={(values) => handleGroupByValueChange(values[0])}
width={200}
size="m"
/>
);
}
if (!nodes?.length) {
return null;
};
const renderControls = () => {
}

const renderExpandButton = () => {
return (
<Flex gap={3} className={b('controls')}>
{renderNodeTypeRadio()}
{renderGroupControl()}
{renderExpandButton()}
</Flex>
<Button onClick={() => setExpanded((value) => !value)}>
<Icon data={expanded ? ChevronsCollapseVertical : ChevronsExpandVertical} />
{expanded ? i18n('action_collapse') : i18n('action_expand')}
</Button>
);
};

const renderStorageNodes = () => {
if (storageNodes?.length) {
return storageNodes.map(({title, nodes: itemNodes, items, versionColor}) => (
const renderNodes = () => {
return nodes.map(
({
title,
isDatabase,
nodes: itemNodes,
items,
versionColor,
preparedVersions: nodesVersions,
}) => (
<GroupedNodesTree
key={`storage-nodes-${title}`}
key={title}
title={title}
isDatabase={isDatabase}
nodes={itemNodes}
items={items}
expanded={expanded}
versionColor={versionColor}
expanded={expanded}
preparedVersions={nodesVersions}
/>
));
}
return null;
};
const renderDatabaseNodes = () => {
if (tenantNodes?.length) {
return tenantNodes.map(
({
title,
isDatabase,
nodes: itemNodes,
items,
versionColor,
preparedVersions: nodesVersions,
}) => (
<GroupedNodesTree
key={`tenant-nodes-${title}`}
title={title}
isDatabase={isDatabase}
nodes={itemNodes}
items={items}
expanded={expanded}
versionColor={versionColor}
preparedVersions={nodesVersions}
/>
),
);
}
return null;
};

const renderOtherNodes = () => {
if (otherNodes?.length) {
return otherNodes.map(
({
title,
nodes: itemNodes,
items,
versionColor,
preparedVersions: nodesVersions,
}) => (
<GroupedNodesTree
key={`other-nodes-${title}`}
title={title}
nodes={itemNodes}
items={items}
versionColor={versionColor}
expanded={expanded}
preparedVersions={nodesVersions}
/>
),
);
}
return null;
};

const renderContent = () => {
switch (nodeType) {
case NODE_TYPES.storage:
return renderStorageNodes();
case NODE_TYPES.database:
return renderDatabaseNodes();
case NODE_TYPES.other:
return renderOtherNodes();
default:
return null;
}
),
);
};

const overallContent = (
<Flex gap={3} direction={'column'} className={b('overall')}>
<Text variant="subheader-3">{i18n('title_overall')}</Text>
<VersionsBar preparedVersions={preparedVersions} size="m" />
</Flex>
);

return (
<div className={b()}>
{overallContent}
{renderControls()}
<Flex direction={'column'} gap={3}>
{renderContent()}
<Flex gap={3} direction={'column'}>
<Flex justifyContent={'space-between'}>
<Flex gap={3}>
<Text variant="subheader-3">{sectionTitle}</Text>
{renderControls?.()}
</Flex>
{renderExpandButton()}
</Flex>
</div>
{renderNodes()}
</Flex>
);
}
17 changes: 0 additions & 17 deletions src/containers/Versions/constants.ts

This file was deleted.

Loading