Skip to content

Commit 0bf686f

Browse files
authored
feat(explore): Add label for explore visualize (#99274)
This adds a label before each visualize labeling them from A onwards. Each label is also clickable to toggle the chart visibility. Closes EXP-493
1 parent 1622d81 commit 0bf686f

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

static/app/views/explore/components/toolbar/toolbarVisualize/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type {ReactNode} from 'react';
12
import styled from '@emotion/styled';
23

34
import {Button} from 'sentry/components/core/button';
@@ -39,6 +40,7 @@ interface ToolbarVisualizeDropdownProps {
3940
onChangeArgument: (index: number, option: SelectOption<SelectKey>) => void;
4041
onDelete: () => void;
4142
parsedFunction: ParsedFunction | null;
43+
label?: ReactNode;
4244
}
4345

4446
export function ToolbarVisualizeDropdown({
@@ -49,6 +51,7 @@ export function ToolbarVisualizeDropdown({
4951
onChangeArgument,
5052
onDelete,
5153
parsedFunction,
54+
label,
5255
}: ToolbarVisualizeDropdownProps) {
5356
const aggregateFunc = parsedFunction?.name;
5457
const aggregateDefinition = aggregateFunc
@@ -57,6 +60,7 @@ export function ToolbarVisualizeDropdown({
5760

5861
return (
5962
<ToolbarRow>
63+
{label}
6064
<AggregateCompactSelect
6165
searchable
6266
options={aggregateOptions}

static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import {useCallback, useMemo} from 'react';
1+
import {useCallback, useMemo, type ReactNode} from 'react';
22

33
import {ArithmeticBuilder} from 'sentry/components/arithmeticBuilder';
44
import type {Expression} from 'sentry/components/arithmeticBuilder/expression';
55
import type {FunctionArgument} from 'sentry/components/arithmeticBuilder/types';
66
import {Button} from 'sentry/components/core/button';
7+
import {Flex} from 'sentry/components/core/layout';
78
import {IconDelete} from 'sentry/icons/iconDelete';
89
import {t} from 'sentry/locale';
910
import {EQUATION_PREFIX, stripEquationPrefix} from 'sentry/utils/discover/fields';
@@ -21,12 +22,14 @@ interface VisualizeEquationProps {
2122
onDelete: () => void;
2223
onReplace: (visualize: Visualize) => void;
2324
visualize: Visualize;
25+
label?: ReactNode;
2426
}
2527

2628
export function VisualizeEquation({
2729
onDelete,
2830
onReplace,
2931
visualize,
32+
label,
3033
}: VisualizeEquationProps) {
3134
const expression = stripEquationPrefix(visualize.yAxis);
3235

@@ -77,14 +80,17 @@ export function VisualizeEquation({
7780

7881
return (
7982
<ToolbarRow>
80-
<ArithmeticBuilder
81-
aggregations={ALLOWED_EXPLORE_EQUATION_AGGREGATES}
82-
functionArguments={functionArguments}
83-
getFieldDefinition={getSpanFieldDefinition}
84-
expression={expression}
85-
setExpression={handleExpressionChange}
86-
getSuggestedKey={getSuggestedAttribute}
87-
/>
83+
{label}
84+
<Flex flex={1}>
85+
<ArithmeticBuilder
86+
aggregations={ALLOWED_EXPLORE_EQUATION_AGGREGATES}
87+
functionArguments={functionArguments}
88+
getFieldDefinition={getSpanFieldDefinition}
89+
expression={expression}
90+
setExpression={handleExpressionChange}
91+
getSuggestedKey={getSuggestedAttribute}
92+
/>
93+
</Flex>
8894
<Button
8995
borderless
9096
icon={<IconDelete />}

static/app/views/explore/toolbar/toolbarVisualize.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import type {MouseEventHandler, ReactNode} from 'react';
12
import {useCallback, useMemo} from 'react';
3+
import styled from '@emotion/styled';
24
import cloneDeep from 'lodash/cloneDeep';
35

46
import type {SelectKey, SelectOption} from 'sentry/components/core/compactSelect';
7+
import {IconHide} from 'sentry/icons/iconHide';
58
import {EQUATION_PREFIX, parseFunction} from 'sentry/utils/discover/fields';
69
import {ALLOWED_EXPLORE_VISUALIZE_AGGREGATES} from 'sentry/utils/fields';
710
import {
@@ -71,6 +74,19 @@ export function ToolbarVisualize({
7174
[setVisualizes, visualizes]
7275
);
7376

77+
const toggleVisibility = useCallback(
78+
(group: number) => {
79+
const newVisualizes = visualizes.map((visualize, i) => {
80+
if (i === group) {
81+
visualize = visualize.replace({visible: !visualize.visible});
82+
}
83+
return visualize.serialize();
84+
});
85+
setVisualizes(newVisualizes);
86+
},
87+
[setVisualizes, visualizes]
88+
);
89+
7490
const onDelete = useCallback(
7591
(group: number) => {
7692
const newVisualizes = visualizes
@@ -87,13 +103,22 @@ export function ToolbarVisualize({
87103
<ToolbarSection data-test-id="section-visualizes">
88104
<ToolbarVisualizeHeader />
89105
{visualizes.map((visualize, group) => {
106+
const label = (
107+
<VisualizeLabel
108+
index={group}
109+
visualize={visualize}
110+
onClick={() => toggleVisibility(group)}
111+
/>
112+
);
113+
90114
if (isVisualizeEquation(visualize)) {
91115
return (
92116
<VisualizeEquationInput
93117
key={group}
94118
onDelete={() => onDelete(group)}
95119
onReplace={newVisualize => replaceOverlay(group, newVisualize)}
96120
visualize={visualize}
121+
label={label}
97122
/>
98123
);
99124
}
@@ -105,6 +130,7 @@ export function ToolbarVisualize({
105130
onDelete={() => onDelete(group)}
106131
onReplace={newVisualize => replaceOverlay(group, newVisualize)}
107132
visualize={visualize}
133+
label={label}
108134
/>
109135
);
110136
})}
@@ -126,6 +152,7 @@ export function ToolbarVisualize({
126152

127153
interface VisualizeDropdownProps {
128154
canDelete: boolean;
155+
label: ReactNode;
129156
onDelete: () => void;
130157
onReplace: (visualize: Visualize) => void;
131158
visualize: Visualize;
@@ -136,6 +163,7 @@ function VisualizeDropdown({
136163
onDelete,
137164
onReplace,
138165
visualize,
166+
label,
139167
}: VisualizeDropdownProps) {
140168
const {tags: stringTags} = useTraceItemTags('string');
141169
const {tags: numberTags} = useTraceItemTags('number');
@@ -200,6 +228,36 @@ function VisualizeDropdown({
200228
onChangeArgument={onChangeArgument}
201229
onDelete={onDelete}
202230
parsedFunction={parsedFunction}
231+
label={label}
203232
/>
204233
);
205234
}
235+
236+
interface VisualizeLabelProps {
237+
index: number;
238+
onClick: MouseEventHandler<HTMLDivElement>;
239+
visualize: Visualize;
240+
}
241+
242+
function VisualizeLabel({index, onClick, visualize}: VisualizeLabelProps) {
243+
const label = visualize.visible ? (
244+
String.fromCharCode('A'.charCodeAt(0) + index)
245+
) : (
246+
<IconHide />
247+
);
248+
249+
return <Label onClick={onClick}>{label}</Label>;
250+
}
251+
252+
const Label = styled('div')`
253+
cursor: pointer;
254+
border-radius: ${p => p.theme.borderRadius};
255+
background-color: ${p => p.theme.purple100};
256+
color: ${p => p.theme.purple300};
257+
font-weight: ${p => p.theme.fontWeight.bold};
258+
width: 24px;
259+
height: 36px;
260+
display: flex;
261+
justify-content: center;
262+
align-items: center;
263+
`;

0 commit comments

Comments
 (0)