Skip to content

Commit d1d86cc

Browse files
authored
Merge 973b3c6 into dd0108a
2 parents dd0108a + 973b3c6 commit d1d86cc

File tree

32 files changed

+798
-726
lines changed

32 files changed

+798
-726
lines changed

src/components/DiagnosticCard/DiagnosticCard.scss

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/components/DiagnosticCard/DiagnosticCard.tsx

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/components/DoughnutMetrics/DoughnutMetrics.scss

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,75 @@
11
.ydb-doughnut-metrics {
22
--doughnut-border: 16px;
3-
--doughnut-color: var(--ydb-color-status-green);
4-
--doughnut-backdrop-color: var(--g-color-base-positive-light);
3+
--doughnut-width: 100px;
4+
--doughnut-wrapper-indent: calc(var(--doughnut-border) + 5px);
5+
--doughnut-color: var(--g-color-base-positive-heavy);
6+
--doughnut-backdrop-color: var(--g-color-base-generic);
57
--doughnut-overlap-color: var(--g-color-base-positive-heavy-hover);
8+
--doughnut-text-color: var(--g-color-text-positive-heavy);
9+
610
&__doughnut {
711
position: relative;
812

9-
width: 100px;
13+
width: var(--doughnut-width);
1014
aspect-ratio: 1;
1115

1216
border-radius: 50%;
17+
mask: radial-gradient(circle at center, transparent 46%, #000 46.5%);
1318

1419
transform: rotate(180deg);
15-
&::before {
16-
display: block;
17-
18-
height: calc(100% - calc(var(--doughnut-border) * 2));
20+
}
1921

20-
content: '';
22+
// Size modifiers - using visually centered values
23+
&__doughnut_size_small {
24+
--doughnut-border: 12px;
25+
--doughnut-width: 65px;
26+
--doughnut-wrapper-indent: 15px;
27+
}
2128

22-
border-radius: 50%;
23-
background-color: var(--g-color-base-background);
29+
&__doughnut_size_medium {
30+
--doughnut-border: 16px;
31+
--doughnut-width: 100px;
32+
--doughnut-wrapper-indent: calc(var(--doughnut-border) + 5px);
33+
}
2434

25-
transform: translate(var(--doughnut-border), var(--doughnut-border));
26-
aspect-ratio: 1;
27-
}
35+
&__doughnut_size_large {
36+
--doughnut-border: 20px;
37+
--doughnut-width: 130px;
38+
--doughnut-wrapper-indent: 25px;
2839
}
29-
&__doughnut_status_warning {
30-
--doughnut-color: var(--ydb-color-status-yellow);
31-
--doughnut-backdrop-color: var(--g-color-base-warning-light);
40+
41+
&_status_warning {
42+
--doughnut-color: var(--g-color-base-warning-heavy);
3243
--doughnut-overlap-color: var(--g-color-base-warning-heavy-hover);
44+
--doughnut-text-color: var(--g-color-text-warning);
3345
}
34-
&__doughnut_status_danger {
35-
--doughnut-color: var(--ydb-color-status-red);
36-
--doughnut-backdrop-color: var(--g-color-base-danger-light);
46+
&_status_danger {
47+
--doughnut-color: var(--g-color-base-danger-heavy);
3748
--doughnut-overlap-color: var(--g-color-base-danger-heavy-hover);
49+
--doughnut-text-color: var(--g-color-base-danger-heavy);
3850
}
3951
&__text-wrapper {
40-
--wrapper-indent: calc(var(--doughnut-border) + 5px);
41-
4252
position: absolute;
43-
top: var(--wrapper-indent);
44-
right: var(--wrapper-indent);
53+
z-index: 1;
54+
top: var(--doughnut-wrapper-indent);
55+
left: var(--doughnut-wrapper-indent);
4556

4657
display: flex;
4758
flex-direction: column;
4859
justify-content: center;
4960
align-items: center;
5061

51-
width: calc(100% - calc(var(--wrapper-indent) * 2));
62+
width: calc(100% - calc(var(--doughnut-wrapper-indent) * 2));
5263

5364
text-align: center;
5465

55-
transform: rotate(180deg);
5666
aspect-ratio: 1;
5767
}
68+
5869
&__value {
59-
position: absolute;
60-
bottom: 20px;
70+
color: var(--doughnut-text-color);
6171
}
72+
6273
&__legend-note {
6374
display: flex;
6475
}

src/components/DoughnutMetrics/DoughnutMetrics.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import './DoughnutMetrics.scss';
1010

1111
const b = cn('ydb-doughnut-metrics');
1212

13+
const SizeContext = React.createContext<'small' | 'medium' | 'large'>('medium');
14+
1315
interface LegendProps {
1416
children?: React.ReactNode;
1517
variant?: TextProps['variant'];
@@ -31,9 +33,19 @@ function Legend({children, variant = 'subheader-3', color = 'primary', note}: Le
3133
</Flex>
3234
);
3335
}
34-
function Value({children, variant = 'subheader-2'}: LegendProps) {
36+
function Value({children, variant}: LegendProps) {
37+
const size = React.useContext(SizeContext);
38+
39+
const sizeVariantMap = {
40+
small: 'subheader-1',
41+
medium: 'subheader-2',
42+
large: 'subheader-3',
43+
} as const;
44+
45+
const finalVariant = variant || sizeVariantMap[size];
46+
3547
return (
36-
<Text variant={variant} className={b('value')}>
48+
<Text variant={finalVariant} className={b('value')}>
3749
{children}
3850
</Text>
3951
);
@@ -44,9 +56,16 @@ interface DoughnutProps {
4456
fillWidth: number;
4557
children?: React.ReactNode;
4658
className?: string;
59+
size?: 'small' | 'medium' | 'large';
4760
}
4861

49-
export function DoughnutMetrics({status, fillWidth, children, className}: DoughnutProps) {
62+
export function DoughnutMetrics({
63+
status,
64+
fillWidth,
65+
children,
66+
className,
67+
size = 'medium',
68+
}: DoughnutProps) {
5069
let filledDegrees = fillWidth * 3.6;
5170
let doughnutFillVar = 'var(--doughnut-color)';
5271
let doughnutBackdropVar = 'var(--doughnut-backdrop-color)';
@@ -57,17 +76,17 @@ export function DoughnutMetrics({status, fillWidth, children, className}: Doughn
5776
doughnutFillVar = 'var(--doughnut-overlap-color)';
5877
}
5978

79+
const doughnutStyle: React.CSSProperties = {
80+
background: `conic-gradient(${doughnutFillVar} 0deg ${filledDegrees}deg, ${doughnutBackdropVar} ${filledDegrees}deg 360deg)`,
81+
};
82+
6083
return (
61-
<div className={b(null, className)}>
62-
<div
63-
style={{
64-
background: `conic-gradient(${doughnutFillVar} 0deg ${filledDegrees}deg, ${doughnutBackdropVar} ${filledDegrees}deg 360deg)`,
65-
}}
66-
className={b('doughnut', {status})}
67-
>
84+
<SizeContext.Provider value={size}>
85+
<div className={b({status}, className)} style={{position: 'relative'}}>
86+
<div style={doughnutStyle} className={b('doughnut', {size})}></div>
6887
<div className={b('text-wrapper')}>{children}</div>
6988
</div>
70-
</div>
89+
</SizeContext.Provider>
7190
);
7291
}
7392

src/components/MetricChart/MetricChart.scss

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
display: flex;
33
flex-direction: column;
44

5-
padding: var(--g-spacing-4) var(--g-spacing-4) var(--g-spacing-2);
5+
width: 100%;
6+
padding: 0;
67

7-
border: 1px solid var(--g-color-line-generic);
8-
border-radius: 8px;
8+
border: none;
99

10-
&_noBorder {
11-
padding: 0;
12-
13-
border: none;
10+
&__toolbar {
11+
margin-bottom: 10px;
1412
}
1513

1614
&__chart {

src/components/MetricChart/MetricChart.tsx

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import React from 'react';
33
import ChartKit, {settings} from '@gravity-ui/chartkit';
44
import type {YagrWidgetData} from '@gravity-ui/chartkit/yagr';
55
import {YagrPlugin} from '@gravity-ui/chartkit/yagr';
6+
import {Flex} from '@gravity-ui/uikit';
67

78
import {cn} from '../../utils/cn';
89
import type {TimeFrame} from '../../utils/timeframes';
910
import {ResponseError} from '../Errors/ResponseError';
1011
import {Loader} from '../Loader';
12+
import {TimeFrameDropdown} from '../TimeFrameDropdown/TimeFrameDropdown';
1113

1214
import {colorToRGBA, colors} from './colors';
1315
import {getDefaultDataFormatter} from './getDefaultDataFormatter';
@@ -23,6 +25,9 @@ import './MetricChart.scss';
2325

2426
const b = cn('ydb-metric-chart');
2527

28+
// Constants
29+
const DEFAULT_EFFECTIVE_WIDTH = 600; // Used for maxDataPoints calculation when using fullWidth
30+
2631
settings.set({plugins: [YagrPlugin]});
2732

2833
const prepareWidgetData = (
@@ -102,17 +107,18 @@ const emptyChartData: PreparedMetricsData = {timeline: [], metrics: []};
102107

103108
interface DiagnosticsChartProps {
104109
database: string;
105-
106110
metrics: MetricDescription[];
107-
timeFrame?: TimeFrame;
108111

109-
autorefresh?: number;
112+
/** Default timeframe for uncontrolled usage */
113+
defaultTimeFrame?: TimeFrame;
110114

115+
/** Callback for timeframe changes - required when using controlled mode */
116+
onTimeFrameChange?: (timeFrame: TimeFrame) => void;
117+
118+
autorefresh?: number;
111119
height?: number;
112120
width?: number;
113-
114121
chartOptions?: ChartOptions;
115-
116122
onChartDataStatusChange?: OnChartDataStatusChange;
117123

118124
/**
@@ -122,33 +128,26 @@ interface DiagnosticsChartProps {
122128
*/
123129
isChartVisible?: boolean;
124130

125-
/** Remove border from chart */
126-
noBorder?: boolean;
127-
128-
/** Make chart take full width of container */
129-
fullWidth?: boolean;
130-
131-
/** Render custom toolbar content to the right of chart title */
132-
renderChartToolbar?: () => React.ReactNode;
131+
/** Chart title displayed in the toolbar */
132+
title: string;
133133
}
134134

135135
export const MetricChart = ({
136136
database,
137137
metrics,
138-
timeFrame = '1h',
138+
defaultTimeFrame = '1h',
139139
autorefresh,
140140
width = 400,
141141
height = width / 1.5,
142142
chartOptions,
143143
onChartDataStatusChange,
144144
isChartVisible,
145-
noBorder,
146-
fullWidth,
147-
renderChartToolbar,
145+
title,
148146
}: DiagnosticsChartProps) => {
147+
const [timeFrame, setTimeFrame] = React.useState<TimeFrame>(defaultTimeFrame);
148+
149149
// Use a reasonable default for maxDataPoints when fullWidth is true
150-
const effectiveWidth = fullWidth ? 600 : width;
151-
const maxDataPoints = effectiveWidth / 2;
150+
const maxDataPoints = DEFAULT_EFFECTIVE_WIDTH / 2;
152151

153152
const {currentData, error, isFetching, status} = chartApi.useGetChartDataQuery(
154153
// maxDataPoints param is calculated based on width
@@ -171,6 +170,13 @@ export const MetricChart = ({
171170

172171
const convertedData = prepareWidgetData(currentData || emptyChartData, chartOptions);
173172

173+
const renderToolbar = () => (
174+
<Flex className={b('toolbar')} justifyContent="space-between" alignItems="center">
175+
<div>{title}</div>
176+
<TimeFrameDropdown value={timeFrame} onChange={setTimeFrame} />
177+
</Flex>
178+
);
179+
174180
const renderContent = () => {
175181
if (loading) {
176182
return <Loader />;
@@ -190,13 +196,12 @@ export const MetricChart = ({
190196

191197
return (
192198
<div
193-
className={b({noBorder})}
199+
className={b()}
194200
style={{
195201
height,
196-
width: fullWidth ? '100%' : width,
197202
}}
198203
>
199-
{renderChartToolbar?.()}
204+
{renderToolbar()}
200205
{renderContent()}
201206
</div>
202207
);

0 commit comments

Comments
 (0)