Skip to content

Commit bd2f64f

Browse files
committed
Add line width setting for wizard line charts
1 parent 89e9f59 commit bd2f64f

File tree

21 files changed

+572
-166
lines changed

21 files changed

+572
-166
lines changed

src/server/modes/charts/plugins/datalens/preparers/line/gravity-charts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ export function prepareGravityChartLine(args: PrepareFunctionArgs) {
204204
shapeValue: graph.shapeValue,
205205
},
206206
rangeSlider,
207+
lineWidth: graph.lineWidth,
207208
};
208209
});
209210

src/server/modes/charts/plugins/datalens/utils/shape-helpers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,21 @@ export const mapAndShapeGraph = ({
4747

4848
graph.dashStyle = SHAPES_IN_ORDER[shapeIndex % SHAPES_IN_ORDER.length];
4949
}
50+
51+
if (
52+
shapesConfig &&
53+
shapesConfig.mountedShapesLineWidths &&
54+
title &&
55+
shapesConfig.mountedShapesLineWidths[title]
56+
) {
57+
const lineWidth = shapesConfig.mountedShapesLineWidths?.[title] as number;
58+
59+
graph.lineWidth = lineWidth;
60+
graph.states = {
61+
hover: {
62+
lineWidth: lineWidth + 2,
63+
},
64+
};
65+
}
5066
});
5167
};

src/shared/constants/qa/wizard.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,7 @@ export const enum ChartSettingsDialogQA {
195195
IndicatorTitleMode = 'indicator-title-mode',
196196
PreserveWhiteSpace = 'preserve-white-space',
197197
}
198+
199+
export const enum LineWidthSelectQa {
200+
Option = 'line-width-select-option',
201+
}

src/shared/types/config/wizard/v15.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ export type V15ColorsConfig = {
311311

312312
export type V15ShapesConfig = {
313313
mountedShapes?: Record<string, string>;
314+
mountedShapesLineWidths?: Record<string, number>;
314315
fieldGuid?: string;
315316
};
316317

src/shared/types/wizard/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ export type Sort = Field & {
510510

511511
export interface ShapesConfig {
512512
mountedShapes?: Record<string, string>;
513+
mountedShapesLineWidths?: Record<string, number>;
513514
fieldGuid?: string;
514515
}
515516

src/ui/components/NumberFormatSettings/NumberInput/NumberInput.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@
1515
-moz-appearance: textfield;
1616
}
1717
/* stylelint-enable */
18+
&__text-input > span {
19+
border-left: none;
20+
border-right: none;
21+
}
1822
}

src/ui/components/NumberFormatSettings/NumberInput/NumberInput.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ interface NumberInputProps {
1111
min?: number;
1212
onChange: (value: number) => void;
1313
qa?: string;
14+
className?: string;
15+
buttonClassName?: string;
16+
inputClassName?: string;
1417
}
1518

1619
const b = block('wizard-number-input');
@@ -21,6 +24,9 @@ const NumberInput: React.FC<NumberInputProps> = ({
2124
onChange,
2225
max = Infinity,
2326
min = -Infinity,
27+
className,
28+
buttonClassName,
29+
inputClassName,
2430
qa,
2531
}) => {
2632
const onBlur = React.useCallback(() => {
@@ -41,11 +47,20 @@ const NumberInput: React.FC<NumberInputProps> = ({
4147
onChange(newValue);
4248
}, [min, onChange, value]);
4349

44-
const memorizedInputAttrs = React.useMemo(() => ({min, max}), [min, max]);
50+
const memorizedInputAttrs: React.InputHTMLAttributes<HTMLInputElement> = React.useMemo(
51+
() => ({min, max, style: {textAlign: 'center'}}),
52+
[min, max],
53+
);
4554

4655
return (
47-
<div className={b()}>
48-
<Button pin="round-brick" onClick={onMinus}>
56+
<div className={b({}, className)}>
57+
<Button
58+
className={b('button', buttonClassName)}
59+
view="outlined"
60+
pin="round-brick"
61+
disabled={value === min}
62+
onClick={onMinus}
63+
>
4964
-
5065
</Button>
5166
<TextInput
@@ -56,8 +71,15 @@ const NumberInput: React.FC<NumberInputProps> = ({
5671
value={String(value)}
5772
onBlur={onBlur}
5873
onUpdate={onInput}
74+
className={b('text-input', inputClassName)}
5975
/>
60-
<Button pin="brick-round" onClick={onPlus}>
76+
<Button
77+
className={b('button', buttonClassName)}
78+
view="outlined"
79+
pin="brick-round"
80+
disabled={value === max}
81+
onClick={onPlus}
82+
>
6183
+
6284
</Button>
6385
</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.dl-dialog-line-width {
2+
&__number-input {
3+
max-width: 136px;
4+
width: 136px;
5+
}
6+
7+
&__number-input-button {
8+
width: 45px;
9+
}
10+
11+
&__number-input-value {
12+
width: 46px;
13+
}
14+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
3+
import {Flex, Text} from '@gravity-ui/uikit';
4+
import block from 'bem-cn-lite';
5+
import NumberInput from 'ui/components/NumberFormatSettings/NumberInput/NumberInput';
6+
import {LINE_WIDTH_MAX_VALUE, LINE_WIDTH_MIN_VALUE} from 'ui/units/wizard/constants/shapes';
7+
8+
import {LineWidthSelect} from '../../../LineWidthSelect/LineWidthSelect';
9+
10+
import './DialogLineWidth.scss';
11+
12+
const b = block('dl-dialog-line-width');
13+
14+
interface DialogLineWidthProps {
15+
value: number;
16+
onChange: (lineWidth: number) => void;
17+
}
18+
19+
// TODO: Fix in a separate branch
20+
const I18N_STUB = {
21+
'dialog-line-width-title': 'Толщина линии',
22+
};
23+
24+
export const DialogLineWidth = React.memo(({value, onChange}: DialogLineWidthProps) => {
25+
return (
26+
<Flex className={b()} direction="column" gap={2}>
27+
<Flex direction="row" alignItems="center" justifyContent="space-between">
28+
<Text variant="body-1">{I18N_STUB['dialog-line-width-title']}</Text>
29+
<LineWidthSelect value={value} onChange={onChange} />
30+
</Flex>
31+
<Flex direction="row" alignItems="center" justifyContent="flex-end">
32+
<NumberInput
33+
value={value}
34+
min={LINE_WIDTH_MIN_VALUE}
35+
max={LINE_WIDTH_MAX_VALUE}
36+
className={b('number-input')}
37+
buttonClassName={b('number-input-button')}
38+
inputClassName={b('number-input-value')}
39+
onChange={onChange}
40+
/>
41+
</Flex>
42+
</Flex>
43+
);
44+
});
45+
46+
DialogLineWidth.displayName = 'DialogLineWidth';

src/ui/units/wizard/components/Dialogs/DialogShapes/DialogShapes.tsx

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

33
import {Shapes4} from '@gravity-ui/icons';
4-
import {Button, Dialog, Icon} from '@gravity-ui/uikit';
4+
import {Button, Dialog, Flex, Icon} from '@gravity-ui/uikit';
55
import block from 'bem-cn-lite';
66
import DialogManager from 'components/DialogManager/DialogManager';
77
import {i18n} from 'i18n';
88
import type {DatasetOptions, Field, FilterField, ShapesConfig, Update} from 'shared';
9+
import {LINE_WIDTH_DEFAULT_VALUE} from 'ui/units/wizard/constants/shapes';
910

1011
import type {PaletteTypes} from '../../../constants';
1112

13+
import {DialogLineWidth} from './DialogLineWidth/DialogLineWidth';
1214
import DialogShapesPalette from './DialogShapesPalette/DialogShapesPalette';
15+
import {DialogValueList} from './DialogValueList/DialogValueList';
1316

1417
import './DialogShapes.scss';
1518

@@ -40,6 +43,7 @@ export type OpenDialogShapesArgs = {
4043

4144
export type ShapesState = {
4245
mountedShapes: Record<string, string>;
46+
mountedShapesLineWidths: Record<string, number>;
4347
selectedValue: string | null;
4448
};
4549

@@ -58,12 +62,22 @@ const DialogShapes: React.FC<Props> = ({
5862
onCancel,
5963
paletteType,
6064
}: Props) => {
61-
const [shapesState, setShapesState] = React.useState<ShapesState>({
62-
selectedValue: null,
63-
mountedShapes:
65+
const [shapesState, setShapesState] = React.useState<ShapesState>(() => {
66+
const mountedShapes =
6467
shapesConfig.mountedShapes && Object.keys(shapesConfig.mountedShapes)
6568
? shapesConfig.mountedShapes
66-
: {},
69+
: {};
70+
const mountedShapesLineWidths = Object.keys(mountedShapes).reduce((acc, shapeKey) => {
71+
const shapeLineWidth = shapesConfig.mountedShapesLineWidths?.[shapeKey];
72+
73+
return {...acc, [shapeKey]: shapeLineWidth || LINE_WIDTH_DEFAULT_VALUE};
74+
}, {});
75+
76+
return {
77+
selectedValue: null,
78+
mountedShapes,
79+
mountedShapesLineWidths,
80+
};
6781
});
6882

6983
const onPaletteItemClick = React.useCallback(
@@ -75,18 +89,32 @@ const DialogShapes: React.FC<Props> = ({
7589
}
7690

7791
const mountedShapes = {...shapesState.mountedShapes};
92+
const mountedShapesLineWidths = {...shapesState.mountedShapesLineWidths};
7893
const isDefaultValue = shape === 'auto';
7994
if (isDefaultValue) {
8095
delete mountedShapes[selectedValue];
8196
} else {
8297
mountedShapes[selectedValue] = shape;
98+
mountedShapesLineWidths[selectedValue] =
99+
mountedShapesLineWidths[selectedValue] || LINE_WIDTH_DEFAULT_VALUE;
83100
}
84101

85-
setShapesState((prevState) => ({...prevState, mountedShapes}));
102+
setShapesState((prevState) => ({...prevState, mountedShapes, mountedShapesLineWidths}));
86103
},
87104
[shapesState],
88105
);
89106

107+
const onLineWidthChange = React.useCallback((nextLineWidth: number) => {
108+
setShapesState((prevState) => ({
109+
...prevState,
110+
lineWidth: nextLineWidth,
111+
mountedShapesLineWidths: {
112+
...prevState.mountedShapesLineWidths,
113+
...(prevState.selectedValue ? {[prevState.selectedValue]: nextLineWidth} : {}),
114+
},
115+
}));
116+
}, []);
117+
90118
const onReset = React.useCallback(() => {
91119
setShapesState((prevState) => ({...prevState, mountedShapes: {}}));
92120
}, []);
@@ -102,11 +130,23 @@ const DialogShapes: React.FC<Props> = ({
102130
const onApplyButtonClick = React.useCallback(() => {
103131
const shapesConfig: ShapesConfig = {
104132
mountedShapes: shapesState.mountedShapes,
133+
mountedShapesLineWidths: shapesState.mountedShapesLineWidths,
105134
fieldGuid: item.guid,
106135
};
107136
onApply(shapesConfig);
108137
onClose();
109-
}, [item.guid, onApply, onClose, shapesState.mountedShapes]);
138+
}, [
139+
item.guid,
140+
onApply,
141+
onClose,
142+
shapesState.mountedShapes,
143+
shapesState.mountedShapesLineWidths,
144+
]);
145+
146+
const selectedShapeLineWidth =
147+
shapesState.selectedValue && shapesState.mountedShapesLineWidths[shapesState.selectedValue]
148+
? shapesState.mountedShapesLineWidths[shapesState.selectedValue]
149+
: LINE_WIDTH_DEFAULT_VALUE;
110150

111151
return (
112152
<Dialog onClose={onClose} open={true}>
@@ -120,23 +160,33 @@ const DialogShapes: React.FC<Props> = ({
120160
caption={i18n('wizard', 'label_shapes-settings')}
121161
/>
122162
<Dialog.Body>
123-
<DialogShapesPalette
163+
<DialogValueList
164+
item={item}
165+
items={items}
166+
distincts={distincts}
167+
filters={filters}
124168
parameters={parameters}
125169
dashboardParameters={dashboardParameters}
170+
updates={updates}
171+
options={options}
172+
datasetId={datasetId}
126173
shapesState={shapesState}
174+
paletteType={paletteType}
127175
setShapesState={(state) =>
128176
setShapesState((prevState) => ({...prevState, ...state}))
129177
}
130-
onPaletteItemClick={onPaletteItemClick}
131-
distincts={distincts}
132-
items={items}
133-
item={item}
134-
datasetId={datasetId}
135-
updates={updates}
136-
filters={filters}
137-
options={options}
138-
paletteType={paletteType}
139178
/>
179+
<Flex direction="column" gap={4} spacing={{py: '5', px: '6'}}>
180+
<DialogLineWidth
181+
value={selectedShapeLineWidth}
182+
onChange={onLineWidthChange}
183+
/>
184+
<DialogShapesPalette
185+
shapesState={shapesState}
186+
onPaletteItemClick={onPaletteItemClick}
187+
paletteType={paletteType}
188+
/>
189+
</Flex>
140190
</Dialog.Body>
141191
<Dialog.Footer
142192
preset="default"

0 commit comments

Comments
 (0)