Files
grafana/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
Dominik Prokop 73eab8fcd6 DashboardScene: Data source and query options edit for a panel (#79267)
* Scenes bump

* Refactor query group components so that they are reusable

* Basic queries rendering and datasource change

* Store last used ds in local storage

* maxDataPoints and minInterval queries options

* Progress on query options

* Query options tests

* Allow panel inspection / queries inspection from panel edit

* Add counters to data pane tabs

* Betterer update

* Handle data source changes

* Minor fixes

* Data source change tests

* Handle scenario of data source change when transformations are in place

* Review comment

* Fix test
2023-12-19 05:51:19 -08:00

124 lines
4.0 KiB
TypeScript

import { css } from '@emotion/css';
import React from 'react';
import { dateMath, getDefaultTimeRange, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data';
import {
SceneComponentProps,
sceneGraph,
SceneTimeRangeLike,
SceneTimeRangeState,
SceneTimeRangeTransformerBase,
} from '@grafana/scenes';
import { Icon, PanelChrome, TimePickerTooltip, Tooltip, useStyles2 } from '@grafana/ui';
import { TimeOverrideResult } from 'app/features/dashboard/utils/panel';
export interface PanelTimeRangeState extends SceneTimeRangeState {
timeFrom?: string;
timeShift?: string;
hideTimeOverride?: boolean;
timeInfo?: string;
}
export class PanelTimeRange extends SceneTimeRangeTransformerBase<PanelTimeRangeState> implements SceneTimeRangeLike {
public static Component = PanelTimeRangeRenderer;
public constructor(state: Partial<PanelTimeRangeState> = {}) {
super({
...state,
// This time range is not valid until activation
from: 'now-6h',
to: 'now',
value: getDefaultTimeRange(),
});
this.addActivationHandler(() => this._onActivate());
}
private _onActivate() {
this._subs.add(
this.subscribeToState((n, p) => {
// Listen to own changes and update time info when required
if (n.timeFrom !== p.timeFrom || n.timeShift !== p.timeShift) {
const { timeInfo } = this.getTimeOverride(this.getAncestorTimeRange().state.value);
this.setState({ timeInfo });
}
})
);
}
protected ancestorTimeRangeChanged(timeRange: SceneTimeRangeState): void {
const overrideResult = this.getTimeOverride(timeRange.value);
this.setState({ value: overrideResult.timeRange, timeInfo: overrideResult.timeInfo });
}
private getTimeOverride(parentTimeRange: TimeRange): TimeOverrideResult {
const { timeFrom, timeShift } = this.state;
const newTimeData = { timeInfo: '', timeRange: parentTimeRange };
if (timeFrom) {
const timeFromInterpolated = sceneGraph.interpolate(this, this.state.timeFrom);
const timeFromInfo = rangeUtil.describeTextRange(timeFromInterpolated);
if (timeFromInfo.invalid) {
newTimeData.timeInfo = 'invalid time override';
return newTimeData;
}
// Only evaluate if the timeFrom if parent time is relative
if (rangeUtil.isRelativeTimeRange(parentTimeRange.raw)) {
newTimeData.timeInfo = timeFromInfo.display;
newTimeData.timeRange = {
from: dateMath.parse(timeFromInfo.from)!,
to: dateMath.parse(timeFromInfo.to)!,
raw: { from: timeFromInfo.from, to: timeFromInfo.to },
};
}
}
if (timeShift) {
const timeShiftInterpolated = sceneGraph.interpolate(this, this.state.timeShift);
const timeShiftInfo = rangeUtil.describeTextRange(timeShiftInterpolated);
if (timeShiftInfo.invalid) {
newTimeData.timeInfo = 'invalid timeshift';
return newTimeData;
}
const timeShift = '-' + timeShiftInterpolated;
newTimeData.timeInfo += ' timeshift ' + timeShift;
const from = dateMath.parseDateMath(timeShift, newTimeData.timeRange.from, false)!;
const to = dateMath.parseDateMath(timeShift, newTimeData.timeRange.to, true)!;
newTimeData.timeRange = { from, to, raw: { from, to } };
}
return newTimeData;
}
}
function PanelTimeRangeRenderer({ model }: SceneComponentProps<PanelTimeRange>) {
const { timeInfo, hideTimeOverride } = model.useState();
const styles = useStyles2(getStyles);
if (!timeInfo || hideTimeOverride) {
return null;
}
return (
<Tooltip content={<TimePickerTooltip timeRange={model.state.value} timeZone={model.getTimeZone()} />}>
<PanelChrome.TitleItem className={styles.timeshift}>
<Icon name="clock-nine" size="sm" /> {timeInfo}
</PanelChrome.TitleItem>
</Tooltip>
);
}
const getStyles = (theme: GrafanaTheme2) => {
return {
timeshift: css({
color: theme.colors.text.link,
gap: theme.spacing(0.5),
whiteSpace: 'nowrap',
}),
};
};