Skip to content

Commit 02fc2b1

Browse files
committed
feat: redesign Storage section
1 parent b06dfdf commit 02fc2b1

File tree

16 files changed

+199
-20
lines changed

16 files changed

+199
-20
lines changed

src/components/InfoViewer/InfoViewer.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use '../../styles/mixins.scss';
2+
13
.info-viewer {
24
--ydb-info-viewer-font-size: var(--g-text-body-2-font-size);
35
--ydb-info-viewer-line-height: var(--g-text-body-2-line-height);
@@ -28,6 +30,10 @@
2830

2931
max-width: 100%;
3032
padding-top: 4px;
33+
34+
&:first-child {
35+
padding-top: 0;
36+
}
3137
}
3238

3339
&__label {
@@ -88,4 +94,18 @@
8894
}
8995
}
9096
}
97+
98+
&_variant_storage {
99+
.info-viewer__title {
100+
margin: 0 0 var(--g-spacing-3);
101+
102+
color: var(--g-color-text-primary);
103+
@include mixins.subheader-1-typography();
104+
}
105+
106+
.info-viewer__label {
107+
color: var(--g-color-text-secondary);
108+
@include mixins.body-1-typography();
109+
}
110+
}
91111
}

src/components/InfoViewer/InfoViewer.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface InfoViewerProps {
1616
info?: InfoViewerItem[];
1717
dots?: boolean;
1818
size?: 's';
19+
variant?: 'default' | 'storage';
1920
className?: string;
2021
multilineLabels?: boolean;
2122
renderEmptyState?: (props?: Pick<InfoViewerProps, 'title' | 'size'>) => React.ReactNode;
@@ -28,6 +29,7 @@ export const InfoViewer = ({
2829
info,
2930
dots = true,
3031
size,
32+
variant = 'default',
3133
className,
3234
multilineLabels,
3335
renderEmptyState,
@@ -37,7 +39,7 @@ export const InfoViewer = ({
3739
}
3840

3941
return (
40-
<div className={b({size}, className)}>
42+
<div className={b({size, variant}, className)}>
4143
{title && <div className={b('title')}>{title}</div>}
4244
{info && info.length > 0 ? (
4345
<div className={b('items')}>

src/components/ProgressViewer/ProgressViewer.scss

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,31 @@
109109
font-size: var(--g-text-body-1-font-size);
110110
line-height: 36px;
111111
}
112+
113+
&_size_storage {
114+
position: relative;
115+
116+
width: 400px;
117+
min-width: unset;
118+
height: 10px;
119+
padding: 0;
120+
121+
border-radius: var(--g-border-radius-xs);
122+
background: var(--g-color-private-white-100);
123+
124+
#{$block}__progress-container {
125+
position: relative;
126+
127+
width: 100%;
128+
height: 100%;
129+
130+
border-radius: inherit;
131+
background: inherit;
132+
}
133+
134+
#{$block}__line {
135+
border-radius: var(--g-border-radius-xs);
136+
background-color: var(--g-color-private-green-450);
137+
}
138+
}
112139
}

src/components/ProgressViewer/ProgressViewer.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
import {useTheme} from '@gravity-ui/uikit';
1+
import {Flex, Text, useTheme} from '@gravity-ui/uikit';
22

33
import {cn} from '../../utils/cn';
44
import {formatNumber, roundToPrecision} from '../../utils/dataFormatters/dataFormatters';
55
import {calculateProgressStatus} from '../../utils/progress';
66
import {isNumeric} from '../../utils/utils';
77

8+
import i18n from './i18n';
9+
810
import './ProgressViewer.scss';
911

1012
const b = cn('progress-viewer');
1113

12-
type ProgressViewerSize = 'xs' | 's' | 'ns' | 'm' | 'n' | 'l' | 'head';
14+
type ProgressViewerSize = 'xs' | 's' | 'ns' | 'm' | 'n' | 'l' | 'head' | 'storage';
1315

1416
export type FormatProgressViewerValues = (
1517
value?: number,
@@ -107,7 +109,29 @@ export function ProgressViewer({
107109
return valueText;
108110
};
109111

112+
const isStorageVariant = size === 'storage';
113+
110114
if (isNumeric(value)) {
115+
if (isStorageVariant) {
116+
const storageDisplayText =
117+
isNumeric(capacity) && !hideCapacity
118+
? i18n('value_of_capacity', {value: valueText, capacity: capacityText})
119+
: valueText;
120+
121+
return (
122+
<Flex alignItems="center" gap="2" className={className}>
123+
<div className={b({size, theme, status})}>
124+
<div className={b('progress-container')}>
125+
<div className={b('line')} style={lineStyle}></div>
126+
</div>
127+
</div>
128+
<Text variant="body-2" color="secondary">
129+
{storageDisplayText}
130+
</Text>
131+
</Flex>
132+
);
133+
}
134+
111135
return (
112136
<div className={b({size, theme, status}, className)}>
113137
<div className={b('line')} style={lineStyle}></div>
@@ -116,5 +140,5 @@ export function ProgressViewer({
116140
);
117141
}
118142

119-
return <div className={`${b({size})} ${className} error`}>no data</div>;
143+
return <div className={`${b({size})} ${className} error`}>{i18n('no-data')}</div>;
120144
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"value_of_capacity": "{{value}} of {{capacity}}",
3+
"no-data": "no data"
4+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {registerKeysets} from '../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-progress-viewer';
6+
7+
export default registerKeysets(COMPONENT, {en});

src/containers/Tenant/Diagnostics/TenantOverview/TenantDashboard/TenantDashboard.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.ydb-tenant-dashboard {
22
width: var(--diagnostics-section-table-width);
3-
margin-bottom: var(--diagnostics-section-margin);
3+
margin-bottom: var(--g-spacing-4);
44

55
&__charts {
66
display: flex;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.tenant-storage {
2+
&__tabs-container {
3+
margin-top: var(--g-spacing-3);
4+
}
5+
6+
&__tab-content {
7+
margin-top: var(--g-spacing-3);
8+
}
9+
}

src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
import React from 'react';
22

3+
import {Tab, TabList, TabProvider} from '@gravity-ui/uikit';
4+
import {useLocation} from 'react-router-dom';
5+
36
import {InfoViewer} from '../../../../../components/InfoViewer/InfoViewer';
7+
import {InternalLink} from '../../../../../components/InternalLink';
48
import {LabelWithPopover} from '../../../../../components/LabelWithPopover';
59
import {ProgressViewer} from '../../../../../components/ProgressViewer/ProgressViewer';
10+
import {parseQuery} from '../../../../../routes';
11+
import {TENANT_STORAGE_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
12+
import {setStorageTab} from '../../../../../store/reducers/tenant/tenant';
13+
import {cn} from '../../../../../utils/cn';
614
import {formatStorageValues} from '../../../../../utils/dataFormatters/dataFormatters';
15+
import {useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks';
16+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
717
import {TenantDashboard} from '../TenantDashboard/TenantDashboard';
818
import i18n from '../i18n';
9-
import {b} from '../utils';
1019

1120
import {TopGroups} from './TopGroups';
1221
import {TopTables} from './TopTables';
1322
import {storageDashboardConfig} from './storageDashboardConfig';
1423

15-
import '../TenantOverview.scss';
24+
import './TenantStorage.scss';
25+
26+
const tenantStorageCn = cn('tenant-storage');
27+
28+
const storageTabs = [
29+
{id: TENANT_STORAGE_TABS_IDS.tables, title: i18n('title_top-tables-by-size')},
30+
{id: TENANT_STORAGE_TABS_IDS.groups, title: i18n('title_top-groups-by-usage')},
31+
];
1632

1733
export interface TenantStorageMetrics {
1834
blobStorageUsed?: number;
@@ -27,8 +43,31 @@ interface TenantStorageProps {
2743
}
2844

2945
export function TenantStorage({tenantName, metrics}: TenantStorageProps) {
46+
const dispatch = useTypedDispatch();
47+
const location = useLocation();
48+
const {storageTab = TENANT_STORAGE_TABS_IDS.tables} = useTypedSelector((state) => state.tenant);
49+
3050
const {blobStorageUsed, tabletStorageUsed, blobStorageLimit, tabletStorageLimit} = metrics;
3151

52+
const queryParams = parseQuery(location);
53+
54+
React.useEffect(() => {
55+
if (!storageTab) {
56+
dispatch(setStorageTab(TENANT_STORAGE_TABS_IDS.tables));
57+
}
58+
}, [storageTab, dispatch]);
59+
60+
const renderTabContent = () => {
61+
switch (storageTab) {
62+
case TENANT_STORAGE_TABS_IDS.tables:
63+
return <TopTables database={tenantName} />;
64+
case TENANT_STORAGE_TABS_IDS.groups:
65+
return <TopGroups tenant={tenantName} />;
66+
default:
67+
return null;
68+
}
69+
};
70+
3271
const info = [
3372
{
3473
label: (
@@ -43,6 +82,7 @@ export function TenantStorage({tenantName, metrics}: TenantStorageProps) {
4382
capacity={tabletStorageLimit}
4483
formatValues={formatStorageValues}
4584
colorizeProgress={true}
85+
size="storage"
4686
/>
4787
),
4888
},
@@ -59,6 +99,7 @@ export function TenantStorage({tenantName, metrics}: TenantStorageProps) {
5999
capacity={blobStorageLimit}
60100
formatValues={formatStorageValues}
61101
colorizeProgress={true}
102+
size="storage"
62103
/>
63104
),
64105
},
@@ -67,9 +108,33 @@ export function TenantStorage({tenantName, metrics}: TenantStorageProps) {
67108
return (
68109
<React.Fragment>
69110
<TenantDashboard database={tenantName} charts={storageDashboardConfig} />
70-
<InfoViewer className={b('storage-info')} title="Storage details" info={info} />
71-
<TopTables database={tenantName} />
72-
<TopGroups tenant={tenantName} />
111+
<InfoViewer
112+
variant="storage"
113+
title={i18n('storage.storage-details-title')}
114+
info={info}
115+
/>
116+
117+
<div className={tenantStorageCn('tabs-container')}>
118+
<TabProvider value={storageTab}>
119+
<TabList size="m">
120+
{storageTabs.map(({id, title}) => {
121+
const path = getTenantPath({
122+
...queryParams,
123+
[TenantTabsGroups.storageTab]: id,
124+
});
125+
return (
126+
<Tab key={id} value={id}>
127+
<InternalLink to={path} as="tab">
128+
{title}
129+
</InternalLink>
130+
</Tab>
131+
);
132+
})}
133+
</TabList>
134+
</TabProvider>
135+
136+
<div className={tenantStorageCn('tab-content')}>{renderTabContent()}</div>
137+
</div>
73138
</React.Fragment>
74139
);
75140
}

src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import {TENANT_OVERVIEW_TABLES_SETTINGS} from '../../../../../utils/constants';
1111
import {useAutoRefreshInterval} from '../../../../../utils/hooks';
1212
import {parseQueryErrorToString} from '../../../../../utils/query';
1313
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
14-
import {getSectionTitle} from '../getSectionTitle';
15-
import i18n from '../i18n';
1614

1715
import '../TenantOverview.scss';
1816

@@ -57,14 +55,8 @@ export function TopTables({database}: TopTablesProps) {
5755
) : null,
5856
},
5957
];
60-
const title = getSectionTitle({
61-
entity: i18n('tables'),
62-
postfix: i18n('by-size'),
63-
});
64-
6558
return (
6659
<TenantOverviewTableLayout
67-
title={title}
6860
loading={loading}
6961
error={parseQueryErrorToString(error)}
7062
withData={Boolean(currentData)}

0 commit comments

Comments
 (0)