Skip to content

Commit f92f597

Browse files
committed
fix: refactor
1 parent 16b0195 commit f92f597

File tree

13 files changed

+280
-158
lines changed

13 files changed

+280
-158
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {Flex, Text} from '@gravity-ui/uikit';
2+
3+
import {getProgressStyle} from './progressUtils';
4+
import type {ProgressContainerProps} from './types';
5+
6+
export function ProgressContainer({
7+
children,
8+
displayText,
9+
withValue = false,
10+
className,
11+
width,
12+
}: ProgressContainerProps) {
13+
const progressStyle = getProgressStyle(width);
14+
15+
return (
16+
<Flex alignItems="center" gap="2" className={className}>
17+
<div style={progressStyle}>{children}</div>
18+
{withValue && displayText && (
19+
<Text variant="body-1" color="secondary">
20+
{displayText}
21+
</Text>
22+
)}
23+
</Flex>
24+
);
25+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {SingleProgress} from './SingleProgress';
2+
import {StackProgress} from './StackProgress';
3+
import type {ProgressWrapperProps} from './types';
4+
5+
export function ProgressWrapper(props: ProgressWrapperProps) {
6+
if ('stack' in props && props.stack) {
7+
return <StackProgress {...props} />;
8+
}
9+
return <SingleProgress {...props} />;
10+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from 'react';
2+
3+
import {Progress} from '@gravity-ui/uikit';
4+
5+
import {defaultFormatProgressValues} from '../../utils/progress';
6+
import {safeParseNumber} from '../../utils/utils';
7+
8+
import {ProgressContainer} from './ProgressContainer';
9+
import i18n from './i18n';
10+
import {
11+
PROGRESS_SIZE,
12+
calculateProgressWidth,
13+
formatDisplayValues,
14+
formatProgressText,
15+
isValidValue,
16+
} from './progressUtils';
17+
import type {ProgressWrapperSingleProps} from './types';
18+
19+
export function SingleProgress({
20+
value,
21+
capacity,
22+
formatValues = defaultFormatProgressValues,
23+
className,
24+
width,
25+
size = PROGRESS_SIZE,
26+
withValue = false,
27+
}: ProgressWrapperSingleProps) {
28+
if (!isValidValue(value)) {
29+
return <div className={className}>{i18n('alert_no-data')}</div>;
30+
}
31+
32+
const numericValue = safeParseNumber(value);
33+
const numericCapacity = safeParseNumber(capacity);
34+
const clampedFillWidth = calculateProgressWidth(numericValue, numericCapacity);
35+
36+
const [valueText, capacityText] = React.useMemo(() => {
37+
return formatDisplayValues(value, capacity, formatValues);
38+
}, [formatValues, value, capacity]);
39+
40+
const displayText = React.useMemo(() => {
41+
return formatProgressText(valueText, capacityText, numericCapacity, i18n);
42+
}, [valueText, capacityText, numericCapacity]);
43+
44+
return (
45+
<ProgressContainer
46+
displayText={displayText}
47+
withValue={withValue}
48+
className={className}
49+
width={width}
50+
>
51+
<Progress value={clampedFillWidth} theme="success" size={size} />
52+
</ProgressContainer>
53+
);
54+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React from 'react';
2+
3+
import {Progress} from '@gravity-ui/uikit';
4+
5+
import {defaultFormatProgressValues} from '../../utils/progress';
6+
import {safeParseNumber} from '../../utils/utils';
7+
import {getMemorySegmentColor} from '../MemoryViewer/utils';
8+
9+
import {ProgressContainer} from './ProgressContainer';
10+
import i18n from './i18n';
11+
import {
12+
MAX_PERCENTAGE,
13+
PROGRESS_SIZE,
14+
formatDisplayValues,
15+
formatProgressText,
16+
} from './progressUtils';
17+
import type {ProgressWrapperStackProps} from './types';
18+
19+
export function StackProgress({
20+
stack,
21+
totalCapacity,
22+
formatValues = defaultFormatProgressValues,
23+
className,
24+
width,
25+
size = PROGRESS_SIZE,
26+
withValue = false,
27+
}: ProgressWrapperStackProps) {
28+
const displaySegments = stack.filter((segment) => !segment.isInfo && segment.value > 0);
29+
30+
if (displaySegments.length === 0) {
31+
return <div className={className}>{i18n('alert_no-data')}</div>;
32+
}
33+
34+
const totalValue = displaySegments.reduce((sum, segment) => sum + segment.value, 0);
35+
const numericTotalCapacity = safeParseNumber(totalCapacity);
36+
const maxValue = numericTotalCapacity || totalValue;
37+
38+
const stackElements = displaySegments.map((segment) => ({
39+
value: maxValue > 0 ? (segment.value / maxValue) * MAX_PERCENTAGE : 0,
40+
color: getMemorySegmentColor(segment.key),
41+
title: segment.label,
42+
}));
43+
44+
const [totalValueText, totalCapacityText] = React.useMemo(() => {
45+
return formatDisplayValues(totalValue, numericTotalCapacity || totalValue, formatValues);
46+
}, [formatValues, totalValue, numericTotalCapacity]);
47+
48+
const displayText = React.useMemo(() => {
49+
return formatProgressText(
50+
totalValueText,
51+
totalCapacityText,
52+
numericTotalCapacity || 0,
53+
i18n,
54+
);
55+
}, [totalValueText, totalCapacityText, numericTotalCapacity]);
56+
57+
return (
58+
<ProgressContainer
59+
displayText={displayText}
60+
withValue={withValue}
61+
className={className}
62+
width={width}
63+
>
64+
<Progress value={MAX_PERCENTAGE} stack={stackElements} size={size} />
65+
</ProgressContainer>
66+
);
67+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"alert_no-data": "no data",
3+
"context_capacity-usage": "{{value}} of {{capacity}}"
4+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import {registerKeysets} from '../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'progress-wrapper';
6+
7+
const keysets = {
8+
en,
9+
};
10+
11+
export default registerKeysets(COMPONENT, keysets);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Main component - public API
2+
export {ProgressWrapper} from './ProgressWrapper';
3+
4+
// Individual components - for direct usage if needed
5+
export {SingleProgress} from './SingleProgress';
6+
export {StackProgress} from './StackProgress';
7+
export {ProgressContainer} from './ProgressContainer';
8+
9+
// Types - for consumers
10+
export type {
11+
ProgressWrapperProps,
12+
ProgressWrapperSingleProps,
13+
ProgressWrapperStackProps,
14+
ProgressContainerProps,
15+
} from './types';
16+
17+
// Utils - for advanced usage
18+
export * from './progressUtils';
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type {FormatProgressViewerValues} from '../../utils/progress';
2+
import {isNumeric, safeParseNumber} from '../../utils/utils';
3+
4+
// Constants that were previously in TenantStorage/constants
5+
export const DEFAULT_PROGRESS_WIDTH = 400;
6+
export const MAX_PERCENTAGE = 100;
7+
export const MIN_PERCENTAGE = 0;
8+
export const PROGRESS_SIZE = 's';
9+
10+
export const isValidValue = (val?: number | string): boolean =>
11+
isNumeric(val) && safeParseNumber(val) >= 0;
12+
13+
export function calculateProgressWidth(value: number, capacity: number): number {
14+
const rawPercentage =
15+
capacity > 0 ? Math.floor((value / capacity) * MAX_PERCENTAGE) : MAX_PERCENTAGE;
16+
const fillWidth = Math.max(MIN_PERCENTAGE, rawPercentage);
17+
return Math.min(fillWidth, MAX_PERCENTAGE);
18+
}
19+
20+
export function getProgressStyle(width?: number | 'full') {
21+
const isFullWidth = width === 'full';
22+
const validatedWidth = isFullWidth ? 0 : Math.max(0, width || DEFAULT_PROGRESS_WIDTH);
23+
24+
return {
25+
width: isFullWidth ? '100%' : `${validatedWidth}px`,
26+
flex: isFullWidth ? '1' : 'none',
27+
};
28+
}
29+
30+
export function formatProgressText(
31+
valueText: string | number | undefined,
32+
capacityText: string | number | undefined,
33+
numericCapacity: number,
34+
i18n: any,
35+
): string {
36+
if (numericCapacity <= 0) {
37+
return String(valueText);
38+
}
39+
return i18n('context_capacity-usage', {value: valueText, capacity: capacityText});
40+
}
41+
42+
export function formatDisplayValues(
43+
value: number | string | undefined,
44+
capacity: number | string | undefined,
45+
formatValues?: FormatProgressViewerValues,
46+
): [string | number | undefined, string | number | undefined] {
47+
if (formatValues) {
48+
const result = formatValues(Number(value), Number(capacity));
49+
return [result[0], result[1]] as [string | number | undefined, string | number | undefined];
50+
}
51+
return [value, capacity];
52+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type {ProgressSize} from '@gravity-ui/uikit';
2+
3+
import type {FormatProgressViewerValues} from '../../utils/progress';
4+
import type {MemorySegment} from '../MemoryViewer/utils';
5+
6+
export interface ProgressWrapperBaseProps {
7+
formatValues?: FormatProgressViewerValues;
8+
className?: string;
9+
width?: number | 'full';
10+
size?: ProgressSize;
11+
withValue?: boolean;
12+
}
13+
14+
export interface ProgressWrapperSingleProps extends ProgressWrapperBaseProps {
15+
value?: number | string;
16+
capacity?: number | string;
17+
stack?: never;
18+
}
19+
20+
export interface ProgressWrapperStackProps extends ProgressWrapperBaseProps {
21+
stack: MemorySegment[];
22+
totalCapacity?: number | string;
23+
value?: never;
24+
capacity?: never;
25+
}
26+
27+
export type ProgressWrapperProps = ProgressWrapperSingleProps | ProgressWrapperStackProps;
28+
29+
export interface ProgressContainerProps {
30+
children: React.ReactNode;
31+
displayText?: string;
32+
withValue?: boolean;
33+
className?: string;
34+
width?: number | 'full';
35+
}

src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/MemoryDetailsSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import {Text} from '@gravity-ui/uikit';
22

33
import i18n from '../../../../../components/MemoryViewer/i18n';
44
import {getMemorySegments} from '../../../../../components/MemoryViewer/utils';
5+
import {ProgressWrapper} from '../../../../../components/ProgressWrapper';
56
import type {TMemoryStats} from '../../../../../types/api/nodes';
67
import {formatBytes} from '../../../../../utils/bytesParsers';
78
import {cn} from '../../../../../utils/cn';
8-
import {ProgressWrapper} from '../TenantStorage/ProgressWrapper';
99

1010
import {MemorySegmentItem} from './MemorySegmentItem';
1111

0 commit comments

Comments
 (0)