mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Improve time range and max data points info in QueryEditor (#70867)
* Add component to display QueryOptions in editor * Display QueryOptions in QueryWrapper * Display real data for time range and max data points * Improve QueryOptions styling * Remove Portal from RelativeTimeRangePicker * Prevent RefID from hiding on small screens Fixes https://github.com/grafana/grafana/issues/70900 * Address review comments * Fix lint
This commit is contained in:
parent
f2bb9fd92a
commit
db2770d992
@ -14,7 +14,6 @@ import CustomScrollbar from '../../CustomScrollbar/CustomScrollbar';
|
|||||||
import { Field } from '../../Forms/Field';
|
import { Field } from '../../Forms/Field';
|
||||||
import { Icon } from '../../Icon/Icon';
|
import { Icon } from '../../Icon/Icon';
|
||||||
import { getInputStyles, Input } from '../../Input/Input';
|
import { getInputStyles, Input } from '../../Input/Input';
|
||||||
import { Portal } from '../../Portal/Portal';
|
|
||||||
import { Tooltip } from '../../Tooltip/Tooltip';
|
import { Tooltip } from '../../Tooltip/Tooltip';
|
||||||
import { TimePickerTitle } from '../TimeRangePicker/TimePickerTitle';
|
import { TimePickerTitle } from '../TimeRangePicker/TimePickerTitle';
|
||||||
import { TimeRangeList } from '../TimeRangePicker/TimeRangeList';
|
import { TimeRangeList } from '../TimeRangePicker/TimeRangeList';
|
||||||
@ -123,7 +122,7 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<Portal>
|
<div>
|
||||||
<div role="presentation" className={styles.backdrop} {...underlayProps} />
|
<div role="presentation" className={styles.backdrop} {...underlayProps} />
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<FocusScope contain autoFocus restoreFocus>
|
||||||
<div ref={ref} {...overlayProps} {...dialogProps}>
|
<div ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
@ -178,7 +177,7 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FocusScope>
|
</FocusScope>
|
||||||
</Portal>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
import { dateTime, getDefaultRelativeTimeRange, GrafanaTheme2, RelativeTimeRange } from '@grafana/data';
|
||||||
|
import { relativeToTimeRange } from '@grafana/data/src/datetime/rangeutil';
|
||||||
|
import { clearButtonStyles, Icon, RelativeTimeRangePicker, Toggletip, useStyles2 } from '@grafana/ui';
|
||||||
|
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
import { AlertQueryOptions, MaxDataPointsOption } from './QueryWrapper';
|
||||||
|
|
||||||
|
export interface QueryOptionsProps {
|
||||||
|
query: AlertQuery;
|
||||||
|
queryOptions: AlertQueryOptions;
|
||||||
|
onChangeTimeRange?: (timeRange: RelativeTimeRange, index: number) => void;
|
||||||
|
onChangeQueryOptions: (options: AlertQueryOptions, index: number) => void;
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const QueryOptions = ({
|
||||||
|
query,
|
||||||
|
queryOptions,
|
||||||
|
onChangeTimeRange,
|
||||||
|
onChangeQueryOptions,
|
||||||
|
index,
|
||||||
|
}: QueryOptionsProps) => {
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
const [showOptions, setShowOptions] = useState(false);
|
||||||
|
|
||||||
|
const timeRange = query.relativeTimeRange ? relativeToTimeRange(query.relativeTimeRange) : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Toggletip
|
||||||
|
content={
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div>
|
||||||
|
{onChangeTimeRange && (
|
||||||
|
<div className={styles.timeRangeContainer}>
|
||||||
|
<span className={styles.timeRangeLabel}>Time Range</span>
|
||||||
|
<RelativeTimeRangePicker
|
||||||
|
timeRange={query.relativeTimeRange ?? getDefaultRelativeTimeRange()}
|
||||||
|
onChange={(range) => onChangeTimeRange(range, index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.queryOptions}>
|
||||||
|
<MaxDataPointsOption
|
||||||
|
options={queryOptions}
|
||||||
|
onChange={(options) => onChangeQueryOptions(options, index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
closeButton={true}
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<button type="button" className={styles.actionLink} onClick={() => setShowOptions(!showOptions)}>
|
||||||
|
Options {showOptions ? <Icon name="angle-right" /> : <Icon name="angle-down" />}
|
||||||
|
</button>
|
||||||
|
</Toggletip>
|
||||||
|
|
||||||
|
<div className={styles.staticValues}>
|
||||||
|
<span>{dateTime(timeRange?.from).locale('en').fromNow(true)}</span>
|
||||||
|
{queryOptions.maxDataPoints && <span>, MD {queryOptions.maxDataPoints}</span>}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => {
|
||||||
|
const clearButton = clearButtonStyles(theme);
|
||||||
|
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
`,
|
||||||
|
timeRangeContainer: css`
|
||||||
|
display: flex;
|
||||||
|
`,
|
||||||
|
|
||||||
|
timeRangeLabel: css`
|
||||||
|
width: 20%;
|
||||||
|
`,
|
||||||
|
queryOptions: css`
|
||||||
|
margin-bottom: -${theme.spacing(2)};
|
||||||
|
|
||||||
|
label {
|
||||||
|
line-height: 12px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
staticValues: css`
|
||||||
|
color: ${theme.colors.text.secondary};
|
||||||
|
margin-right: ${theme.spacing(1)};
|
||||||
|
`,
|
||||||
|
|
||||||
|
actionLink: css`
|
||||||
|
${clearButton};
|
||||||
|
color: ${theme.colors.text.link};
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
};
|
@ -6,7 +6,6 @@ import {
|
|||||||
CoreApp,
|
CoreApp,
|
||||||
DataSourceApi,
|
DataSourceApi,
|
||||||
DataSourceInstanceSettings,
|
DataSourceInstanceSettings,
|
||||||
getDefaultRelativeTimeRange,
|
|
||||||
GrafanaTheme2,
|
GrafanaTheme2,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
PanelData,
|
PanelData,
|
||||||
@ -15,20 +14,13 @@ import {
|
|||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/experimental';
|
||||||
import { DataQuery } from '@grafana/schema';
|
import { DataQuery } from '@grafana/schema';
|
||||||
import {
|
import { GraphTresholdsStyleMode, Icon, InlineFormLabel, Input, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
GraphTresholdsStyleMode,
|
|
||||||
Icon,
|
|
||||||
InlineFormLabel,
|
|
||||||
Input,
|
|
||||||
RelativeTimeRangePicker,
|
|
||||||
Tooltip,
|
|
||||||
useStyles2,
|
|
||||||
} from '@grafana/ui';
|
|
||||||
import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow';
|
import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow';
|
||||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
import { AlertConditionIndicator } from '../expressions/AlertConditionIndicator';
|
import { AlertConditionIndicator } from '../expressions/AlertConditionIndicator';
|
||||||
|
|
||||||
|
import { QueryOptions } from './QueryOptions';
|
||||||
import { VizWrapper } from './VizWrapper';
|
import { VizWrapper } from './VizWrapper';
|
||||||
|
|
||||||
export const DEFAULT_MAX_DATA_POINTS = 43200;
|
export const DEFAULT_MAX_DATA_POINTS = 43200;
|
||||||
@ -123,18 +115,14 @@ export const QueryWrapper = ({
|
|||||||
return (
|
return (
|
||||||
<Stack direction="row" alignItems="baseline" gap={1}>
|
<Stack direction="row" alignItems="baseline" gap={1}>
|
||||||
<SelectingDataSourceTooltip />
|
<SelectingDataSourceTooltip />
|
||||||
{onChangeTimeRange && (
|
<QueryOptions
|
||||||
<RelativeTimeRangePicker
|
onChangeTimeRange={onChangeTimeRange}
|
||||||
timeRange={query.relativeTimeRange ?? getDefaultRelativeTimeRange()}
|
query={query}
|
||||||
onChange={(range) => onChangeTimeRange(range, index)}
|
queryOptions={alertQueryOptions}
|
||||||
/>
|
onChangeQueryOptions={onChangeQueryOptions}
|
||||||
)}
|
index={index}
|
||||||
<div className={styles.queryOptions}>
|
/>
|
||||||
<MaxDataPointsOption
|
|
||||||
options={alertQueryOptions}
|
|
||||||
onChange={(options) => onChangeQueryOptions(options, index)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<AlertConditionIndicator
|
<AlertConditionIndicator
|
||||||
onSetCondition={() => onSetCondition(query.refId)}
|
onSetCondition={() => onSetCondition(query.refId)}
|
||||||
enabled={condition === query.refId}
|
enabled={condition === query.refId}
|
||||||
@ -187,7 +175,7 @@ export const EmptyQueryWrapper = ({ children }: React.PropsWithChildren<{}>) =>
|
|||||||
return <div className={styles.wrapper}>{children}</div>;
|
return <div className={styles.wrapper}>{children}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function MaxDataPointsOption({
|
export function MaxDataPointsOption({
|
||||||
options,
|
options,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: {
|
||||||
@ -240,6 +228,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
margin-bottom: ${theme.spacing(1)};
|
margin-bottom: ${theme.spacing(1)};
|
||||||
border: 1px solid ${theme.colors.border.weak};
|
border: 1px solid ${theme.colors.border.weak};
|
||||||
border-radius: ${theme.shape.borderRadius(1)};
|
border-radius: ${theme.shape.borderRadius(1)};
|
||||||
|
|
||||||
|
button {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
queryOptions: css`
|
queryOptions: css`
|
||||||
margin-bottom: -${theme.spacing(2)};
|
margin-bottom: -${theme.spacing(2)};
|
||||||
|
Loading…
Reference in New Issue
Block a user