datatrails: improve width responsiveness for breakdown label selector (#81838)

* fix: make datatrails breakdown label selector responsive
This commit is contained in:
Darren Janeczek 2024-02-06 08:08:57 -05:00 committed by GitHub
parent cf616d5074
commit 16df04e260
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 22 deletions

View File

@ -19,11 +19,12 @@ import {
SceneQueryRunner,
VariableDependencyConfig,
} from '@grafana/scenes';
import { Button, Field, Select, RadioButtonGroup, useStyles2 } from '@grafana/ui';
import { Button, Field, useStyles2 } from '@grafana/ui';
import { ALL_VARIABLE_VALUE } from 'app/features/variables/constants';
import { getAutoQueriesForMetric } from '../AutomaticMetricQueries/AutoQueryEngine';
import { AutoQueryDef } from '../AutomaticMetricQueries/types';
import { BreakdownLabelSelector } from '../BreakdownLabelSelector';
import { MetricScene } from '../MetricScene';
import { trailDS, VAR_FILTERS, VAR_GROUP_BY, VAR_GROUP_BY_EXP } from '../shared';
import { getColorByIndex } from '../utils';
@ -129,25 +130,16 @@ export class BreakdownScene extends SceneObjectBase<BreakdownSceneState> {
const { labels, body, loading, value } = model.useState();
const styles = useStyles2(getStyles);
const useHorizontalLabelSelector = labels.length <= 6;
return (
<div className={styles.container}>
{loading && <div>Loading...</div>}
<div className={styles.controls}>
{!loading && (
<div className={styles.controlsLeft}>
<Field label="By label">
{useHorizontalLabelSelector ? (
<RadioButtonGroup options={labels} value={value} onChange={model.onChange} />
) : (
<Select
options={labels}
value={value}
onChange={(selected) => model.onChange(selected.value)}
className={styles.select}
/>
)}
<BreakdownLabelSelector options={labels} value={value} onChange={model.onChange} />
</Field>
</div>
)}
{body instanceof LayoutSwitcher && (
<div className={styles.controlsRight}>
@ -174,10 +166,6 @@ function getStyles(theme: GrafanaTheme2) {
display: 'flex',
paddingTop: theme.spacing(0),
}),
tabHeading: css({
paddingRight: theme.spacing(2),
fontWeight: theme.typography.fontWeightMedium,
}),
controls: css({
flexGrow: 0,
display: 'flex',
@ -185,12 +173,16 @@ function getStyles(theme: GrafanaTheme2) {
gap: theme.spacing(2),
}),
controlsRight: css({
flexGrow: 1,
flexGrow: 0,
display: 'flex',
justifyContent: 'flex-end',
}),
select: css({
minWidth: theme.spacing(16),
controlsLeft: css({
display: 'flex',
justifyContent: 'flex-left',
justifyItems: 'left',
width: '100%',
flexDirection: 'column',
}),
};
}

View File

@ -0,0 +1,60 @@
import { css } from '@emotion/css';
import { useResizeObserver } from '@react-aria/utils';
import React, { useEffect, useRef, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Select, RadioButtonGroup, useStyles2, useTheme2, measureText } from '@grafana/ui';
type Props = {
options: Array<SelectableValue<string>>;
value?: string;
onChange: (label: string | undefined) => void;
};
export function BreakdownLabelSelector({ options, value, onChange }: Props) {
const styles = useStyles2(getStyles);
const theme = useTheme2();
const [labelSelectorRequiredWidth, setLabelSelectorRequiredWidth] = useState<number>(0);
const [availableWidth, setAvailableWidth] = useState<number>(0);
const useHorizontalLabelSelector = availableWidth > labelSelectorRequiredWidth;
const controlsContainer = useRef<HTMLDivElement>(null);
useResizeObserver({
ref: controlsContainer,
onResize: () => {
const element = controlsContainer.current;
if (element) {
setAvailableWidth(element.clientWidth);
}
},
});
useEffect(() => {
const { fontSize } = theme.typography;
const text = options.map((option) => option.label || option.value || '').join(' ');
const textWidth = measureText(text, fontSize).width;
const additionalWidthPerItem = 32;
setLabelSelectorRequiredWidth(textWidth + additionalWidthPerItem * options.length);
}, [options, theme]);
return (
<div ref={controlsContainer}>
{useHorizontalLabelSelector ? (
<RadioButtonGroup {...{ options, value, onChange }} />
) : (
<Select {...{ options, value }} onChange={(selected) => onChange(selected.value)} className={styles.select} />
)}
</div>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
select: css({
maxWidth: theme.spacing(16),
}),
};
}