Skip to content

Commit

Permalink
feat: add storage group page (#1289)
Browse files Browse the repository at this point in the history
  • Loading branch information
astandrik authored Sep 17, 2024
1 parent 6acbc71 commit 8e05166
Show file tree
Hide file tree
Showing 21 changed files with 587 additions and 38 deletions.
14 changes: 0 additions & 14 deletions src/components/PDiskInfo/PDiskInfo.scss
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
.ydb-pdisk-info {
&__wrapper {
display: flex;
flex-flow: row wrap;
gap: 7px;
}

&__col {
display: flex;
flex-direction: column;
gap: 7px;

width: 500px;
}

&__links {
display: flex;
flex-flow: row wrap;
Expand Down
14 changes: 8 additions & 6 deletions src/components/PDiskInfo/PDiskInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {Flex} from '@gravity-ui/uikit';

import {getPDiskPagePath} from '../../routes';
import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication';
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
Expand Down Expand Up @@ -199,15 +201,15 @@ export function PDiskInfo<T extends PreparedPDisk>({
});

return (
<div className={b('wrapper', className)}>
<div className={b('col')}>
<Flex className={className} gap={2} direction="row" wrap>
<Flex direction="column" gap={2} width={500}>
<InfoViewer info={generalInfo} renderEmptyState={() => null} />
<InfoViewer info={spaceInfo} renderEmptyState={() => null} />
</div>
<div className={b('col')}>
</Flex>
<Flex direction="column" gap={2} width={500}>
<InfoViewer info={statusInfo} renderEmptyState={() => null} />
<InfoViewer info={additionalInfo} renderEmptyState={() => null} />
</div>
</div>
</Flex>
</Flex>
);
}
168 changes: 168 additions & 0 deletions src/components/StorageGroupInfo/StorageGroupInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {Flex} from '@gravity-ui/uikit';

import type {PreparedStorageGroup} from '../../store/reducers/storage/types';
import {valueIsDefined} from '../../utils';
import {formatStorageValuesToGb} from '../../utils/dataFormatters/dataFormatters';
import {formatToMs} from '../../utils/timeParsers';
import {bytesToSpeed} from '../../utils/utils';
import {EntityStatus} from '../EntityStatus/EntityStatus';
import {InfoViewer} from '../InfoViewer';
import type {InfoViewerProps} from '../InfoViewer/InfoViewer';
import {ProgressViewer} from '../ProgressViewer/ProgressViewer';

import {storageGroupInfoKeyset} from './i18n';

interface StorageGroupInfoProps extends Omit<InfoViewerProps, 'info'> {
data?: PreparedStorageGroup;
className?: string;
}

// eslint-disable-next-line complexity
export function StorageGroupInfo({data, className, ...infoViewerProps}: StorageGroupInfoProps) {
const {
Encryption,
Overall,
DiskSpace,
MediaType,
ErasureSpecies,
Used,
Limit,
Usage,
Read,
Write,
GroupGeneration,
Latency,
AllocationUnits,
State,
MissingDisks,
Available,
LatencyPutTabletLog,
LatencyPutUserData,
LatencyGetFast,
} = data || {};

const storageGroupInfoFirstColumn = [];

if (valueIsDefined(GroupGeneration)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('group-generation'),
value: GroupGeneration,
});
}
if (valueIsDefined(ErasureSpecies)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('erasure-species'),
value: ErasureSpecies,
});
}
if (valueIsDefined(MediaType)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('media-type'),
value: MediaType,
});
}
if (valueIsDefined(Encryption)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('encryption'),
value: Encryption ? storageGroupInfoKeyset('yes') : storageGroupInfoKeyset('no'),
});
}
if (valueIsDefined(Overall)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('overall'),
value: <EntityStatus status={Overall} />,
});
}
if (valueIsDefined(State)) {
storageGroupInfoFirstColumn.push({label: storageGroupInfoKeyset('state'), value: State});
}
if (valueIsDefined(MissingDisks)) {
storageGroupInfoFirstColumn.push({
label: storageGroupInfoKeyset('missing-disks'),
value: MissingDisks,
});
}

const storageGroupInfoSecondColumn = [];

if (valueIsDefined(Used) && valueIsDefined(Limit)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('used-space'),
value: (
<ProgressViewer
value={Number(Used)}
capacity={Number(Limit)}
formatValues={formatStorageValuesToGb}
colorizeProgress={true}
/>
),
});
}
if (valueIsDefined(Available)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('available'),
value: formatStorageValuesToGb(Number(Available)),
});
}
if (valueIsDefined(Usage)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('usage'),
value: `${Usage.toFixed(2)}%`,
});
}
if (valueIsDefined(DiskSpace)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('disk-space'),
value: <EntityStatus status={DiskSpace} />,
});
}
if (valueIsDefined(Latency)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('latency'),
value: <EntityStatus status={Latency} />,
});
}
if (valueIsDefined(LatencyPutTabletLog)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('latency-put-tablet-log'),
value: formatToMs(LatencyPutTabletLog),
});
}
if (valueIsDefined(LatencyPutUserData)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('latency-put-user-data'),
value: formatToMs(LatencyPutUserData),
});
}
if (valueIsDefined(LatencyGetFast)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('latency-get-fast'),
value: formatToMs(LatencyGetFast),
});
}
if (valueIsDefined(AllocationUnits)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('allocation-units'),
value: AllocationUnits,
});
}
if (valueIsDefined(Read)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('read-throughput'),
value: bytesToSpeed(Number(Read)),
});
}
if (valueIsDefined(Write)) {
storageGroupInfoSecondColumn.push({
label: storageGroupInfoKeyset('write-throughput'),
value: bytesToSpeed(Number(Write)),
});
}

return (
<Flex className={className} gap={2} direction="row" wrap>
<InfoViewer info={storageGroupInfoFirstColumn} {...infoViewerProps} />
<InfoViewer info={storageGroupInfoSecondColumn} {...infoViewerProps} />
</Flex>
);
}
22 changes: 22 additions & 0 deletions src/components/StorageGroupInfo/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"encryption": "Encryption",
"overall": "Overall",
"disk-space": "Disk Space",
"media-type": "Media Type",
"erasure-species": "Erasure Species",
"used-space": "Used Space",
"usage": "Usage",
"read-throughput": "Read Throughput",
"write-throughput": "Write Throughput",
"yes": "Yes",
"no": "No",
"group-generation": "Group Generation",
"latency": "Latency",
"allocation-units": "Units",
"state": "State",
"missing-disks": "Missing Disks",
"available": "Available Space",
"latency-put-tablet-log": "Latency (Put Tablet Log)",
"latency-put-user-data": "Latency (Put User Data)",
"latency-get-fast": "Latency (Get Fast)"
}
7 changes: 7 additions & 0 deletions src/components/StorageGroupInfo/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {registerKeysets} from '../../../utils/i18n';

import en from './en.json';

const COMPONENT = 'storage-group-info';

export const storageGroupInfoKeyset = registerKeysets(COMPONENT, {en});
10 changes: 10 additions & 0 deletions src/containers/App/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
PDiskPageSlot,
RedirectSlot,
RoutesSlot,
StorageGroupSlot,
TabletSlot,
TenantSlot,
VDiskPageSlot,
Expand Down Expand Up @@ -76,6 +77,15 @@ const routesSlots: RouteSlot[] = [
component: lazyComponent(() => import('../VDiskPage/VDiskPage'), 'VDiskPage'),
wrapper: DataWrapper,
},
{
path: routes.storageGroup,
slot: StorageGroupSlot,
component: lazyComponent(
() => import('../StorageGroupPage/StorageGroupPage'),
'StorageGroupPage',
),
wrapper: DataWrapper,
},
{
path: routes.tablet,
slot: TabletSlot,
Expand Down
6 changes: 6 additions & 0 deletions src/containers/App/appSlots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {Cluster} from '../Cluster/Cluster';
import type {Clusters} from '../Clusters/Clusters';
import type {Node} from '../Node/Node';
import type {PDiskPage} from '../PDiskPage/PDiskPage';
import type {StorageGroupPage} from '../StorageGroupPage/StorageGroupPage';
import type {Tablet} from '../Tablet';
import type {Tenant} from '../Tenant/Tenant';
import type {VDiskPage} from '../VDiskPage/VDiskPage';
Expand Down Expand Up @@ -39,6 +40,11 @@ export const VDiskPageSlot = createSlot<{
| React.ReactNode
| ((props: {component: typeof VDiskPage} & RouteComponentProps) => React.ReactNode);
}>('vDisk');
export const StorageGroupSlot = createSlot<{
children:
| React.ReactNode
| ((props: {component: typeof StorageGroupPage} & RouteComponentProps) => React.ReactNode);
}>('storageGroup');
export const TabletSlot = createSlot<{
children:
| React.ReactNode
Expand Down
23 changes: 23 additions & 0 deletions src/containers/Header/breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
NodeBreadcrumbsOptions,
PDiskBreadcrumbsOptions,
Page,
StorageGroupBreadcrumbsOptions,
TabletBreadcrumbsOptions,
TenantBreadcrumbsOptions,
VDiskBreadcrumbsOptions,
Expand Down Expand Up @@ -156,6 +157,27 @@ const getVDiskBreadcrumbs: GetBreadcrumbs<VDiskBreadcrumbsOptions> = (options, q
return breadcrumbs;
};

const getStorageGroupBreadcrumbs: GetBreadcrumbs<StorageGroupBreadcrumbsOptions> = (
options,
query = {},
) => {
const {groupId} = options;

const breadcrumbs = getClusterBreadcrumbs(options, query);

let text = headerKeyset('breadcrumbs.storageGroup');
if (groupId) {
text += ` ${groupId}`;
}

const lastItem = {
text,
};
breadcrumbs.push(lastItem);

return breadcrumbs;
};

const getTabletBreadcrumbs: GetBreadcrumbs<TabletBreadcrumbsOptions> = (options, query = {}) => {
const {tabletId, tabletType, nodeId, nodeRole, nodeActiveTab = TABLETS, tenantName} = options;

Expand All @@ -178,6 +200,7 @@ const mapPageToGetter = {
tablet: getTabletBreadcrumbs,
tenant: getTenantBreadcrumbs,
vDisk: getVDiskBreadcrumbs,
storageGroup: getStorageGroupBreadcrumbs,
} as const;

export const getBreadcrumbs = (
Expand Down
3 changes: 2 additions & 1 deletion src/containers/Header/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"breadcrumbs.pDisk": "PDisk",
"breadcrumbs.vDisk": "VDisk",
"breadcrumbs.tablet": "Tablet",
"breadcrumbs.tablets": "Tablets"
"breadcrumbs.tablets": "Tablets",
"breadcrumbs.storageGroup": "Storage Group"
}
19 changes: 15 additions & 4 deletions src/containers/PDiskPage/PDiskPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@
.ydb-pdisk-page {
position: relative;

display: flex;
overflow: auto;
flex-direction: column;
gap: 20px;

height: 100%;
padding: 20px;

&__info-content {
position: sticky;
left: 0;

display: flex;
flex-direction: column;
gap: 20px;

padding: 20px;
}

&__tabs-content {
padding-left: 20px;
}

&__meta,
&__title,
Expand Down
18 changes: 10 additions & 8 deletions src/containers/PDiskPage/PDiskPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,16 @@ export function PDiskPage() {

return (
<div className={pdiskPageCn(null)}>
{renderHelmet()}
{renderPageMeta()}
{renderPageTitle()}
{renderControls()}
{renderError()}
{renderInfo()}
{renderTabs()}
{renderTabsContent()}
<div className={pdiskPageCn('info-content')}>
{renderHelmet()}
{renderPageMeta()}
{renderPageTitle()}
{renderControls()}
{renderError()}
{renderInfo()}
{renderTabs()}
</div>
<div className={pdiskPageCn('tabs-content')}>{renderTabsContent()}</div>
</div>
);
}
Loading

0 comments on commit 8e05166

Please sign in to comment.