Prometheus: Metrics browser layout (#35035)

* Metrics browser layout

* Simplified layout
This commit is contained in:
David 2021-06-04 16:50:17 +02:00 committed by GitHub
parent 7a304223e6
commit aae6e86547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -13,6 +13,8 @@ const MAX_LABEL_COUNT = 10000;
const MAX_VALUE_COUNT = 50000; const MAX_VALUE_COUNT = 50000;
const EMPTY_SELECTOR = '{}'; const EMPTY_SELECTOR = '{}';
const METRIC_LABEL = '__name__'; const METRIC_LABEL = '__name__';
const LIST_ITEM_SIZE = 25;
export const LAST_USED_LABELS_KEY = 'grafana.datasources.prometheus.browser.labels'; export const LAST_USED_LABELS_KEY = 'grafana.datasources.prometheus.browser.labels';
export interface BrowserProps { export interface BrowserProps {
@ -105,7 +107,7 @@ export function facetLabels(
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
wrapper: css` wrapper: css`
background-color: ${theme.colors.bg2}; background-color: ${theme.colors.bg2};
padding: ${theme.spacing.md}; padding: ${theme.spacing.sm};
width: 100%; width: 100%;
`, `,
list: css` list: css`
@ -114,6 +116,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
flex-wrap: wrap; flex-wrap: wrap;
max-height: 200px; max-height: 200px;
overflow: auto; overflow: auto;
align-content: flex-start;
`, `,
section: css` section: css`
& + & { & + & {
@ -177,6 +180,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
* to create a single, generic component. * to create a single, generic component.
*/ */
export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserProps, BrowserState> { export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserProps, BrowserState> {
valueListsRef = React.createRef<HTMLDivElement>();
state: BrowserState = { state: BrowserState = {
labels: [] as SelectableLabel[], labels: [] as SelectableLabel[],
labelSearchTerm: '', labelSearchTerm: '',
@ -439,7 +443,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
const { languageProvider } = this.props; const { languageProvider } = this.props;
this.setState({ validationStatus: `Validating selector ${selector}`, error: '' }); this.setState({ validationStatus: `Validating selector ${selector}`, error: '' });
const streams = await languageProvider.fetchSeries(selector); const streams = await languageProvider.fetchSeries(selector);
this.setState({ validationStatus: `Selector is valid (${streams.length} streams found)` }); this.setState({ validationStatus: `Selector is valid (${streams.length} series found)` });
} }
render() { render() {
@ -479,12 +483,14 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
} }
const selector = buildSelector(this.state.labels); const selector = buildSelector(this.state.labels);
const empty = selector === EMPTY_SELECTOR; const empty = selector === EMPTY_SELECTOR;
const metricCount = metrics?.values?.length || 0;
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<HorizontalGroup align="flex-start" spacing="lg"> <HorizontalGroup align="flex-start" spacing="lg">
<div> <div>
<div className={styles.section}> <div className={styles.section}>
<Label description="Which metric do you want to use?">1. Select metric to search in</Label> <Label description="Once a metric is selected only possible labels are shown.">1. Select a metric</Label>
<div> <div>
<Input <Input
onChange={this.onChangeMetricSearch} onChange={this.onChangeMetricSearch}
@ -494,9 +500,9 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
</div> </div>
<div role="list" className={styles.valueListWrapper}> <div role="list" className={styles.valueListWrapper}>
<FixedSizeList <FixedSizeList
height={550} height={Math.min(450, metricCount * LIST_ITEM_SIZE)}
itemCount={metrics?.values?.length || 0} itemCount={metricCount}
itemSize={25} itemSize={LIST_ITEM_SIZE}
itemKey={(i) => (metrics!.values as FacettableValue[])[i].name} itemKey={(i) => (metrics!.values as FacettableValue[])[i].name}
width={300} width={300}
className={styles.valueList} className={styles.valueList}
@ -526,7 +532,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
<div> <div>
<div className={styles.section}> <div className={styles.section}>
<Label description="Which labels would you like to consider for your search?"> <Label description="Once label values are selected, only possible label combinations are shown.">
2. Select labels to search in 2. Select labels to search in
</Label> </Label>
<div> <div>
@ -536,7 +542,8 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
value={labelSearchTerm} value={labelSearchTerm}
/> />
</div> </div>
<div className={styles.list}> {/* Using fixed height here to prevent jumpy layout */}
<div className={styles.list} style={{ height: 120 }}>
{nonMetricLabels.map((label) => ( {nonMetricLabels.map((label) => (
<PromLabel <PromLabel
key={label.name} key={label.name}
@ -552,8 +559,8 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
</div> </div>
</div> </div>
<div className={styles.section}> <div className={styles.section}>
<Label description="Choose the label values that you would like to use for the query. Use the search field to find values across selected labels."> <Label description="Use the search field to find values across selected labels.">
3. Find values for the selected labels 3. Select (multiple) values for your labels
</Label> </Label>
<div> <div>
<Input <Input
@ -562,7 +569,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
value={valueSearchTerm} value={valueSearchTerm}
/> />
</div> </div>
<div className={styles.valueListArea}> <div className={styles.valueListArea} ref={this.valueListsRef}>
{selectedLabels.map((label) => ( {selectedLabels.map((label) => (
<div <div
role="list" role="list"
@ -582,7 +589,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
/> />
</div> </div>
<FixedSizeList <FixedSizeList
height={200} height={Math.min(200, LIST_ITEM_SIZE * (label.values?.length || 0))}
itemCount={label.values?.length || 0} itemCount={label.values?.length || 0}
itemSize={25} itemSize={25}
itemKey={(i) => (label.values as FacettableValue[])[i].name} itemKey={(i) => (label.values as FacettableValue[])[i].name}
@ -622,7 +629,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
{validationStatus && <div className={styles.validationStatus}>{validationStatus}</div>} {validationStatus && <div className={styles.validationStatus}>{validationStatus}</div>}
<HorizontalGroup> <HorizontalGroup>
<Button aria-label="Use selector for query button" disabled={empty} onClick={this.onClickRunQuery}> <Button aria-label="Use selector for query button" disabled={empty} onClick={this.onClickRunQuery}>
Run query Use query
</Button> </Button>
<Button <Button
aria-label="Use selector as metrics button" aria-label="Use selector as metrics button"
@ -630,7 +637,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
disabled={empty} disabled={empty}
onClick={this.onClickRunRateQuery} onClick={this.onClickRunRateQuery}
> >
Run rate query Use as rate query
</Button> </Button>
<Button <Button
aria-label="Validate submit button" aria-label="Validate submit button"