mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Synchronise time ranges in split mode (#19274)
* Explore: create connected sync button when screen is splitted * Explore: create attachable button to TimePicker * WIP/Explore: set up redux boilerplate for synced state * WIP/Explore: add toggling functionality to sync buttons * WIP/Explore: Fix styling issue * First pass solution working * Explore: Clean up, update comments * Explore: refactore Timepicker, remove newly introduced class names * Explore: refactore ExploreTimeControls * Explore: more semantic variables naming * Explore: run query on syncable item when synced times activated * Explore: Add tooltip to sync times button * Explore: Remove typo * Explore: check exploreId * Explore: refactor ExploreTimeControls * Explore: refactor to include suggested changes * Explore: Create TimeSyncButton component, update colors * Explore: Toggle tooltip, use stylesFactory
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
// Libraries
|
||||
import React, { PureComponent, createRef } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import classNames from 'classnames';
|
||||
|
||||
// Components
|
||||
import { ButtonSelect } from '../Select/ButtonSelect';
|
||||
@@ -11,15 +14,41 @@ import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'
|
||||
import { isDateTime, DateTime } from '@grafana/data';
|
||||
import { rangeUtil } from '@grafana/data';
|
||||
import { rawToTimeRange } from './time';
|
||||
import { withTheme } from '../../themes/ThemeContext';
|
||||
|
||||
// Types
|
||||
import { TimeRange, TimeOption, TimeZone, TIME_FORMAT, SelectableValue } from '@grafana/data';
|
||||
import { dateMath } from '@grafana/data';
|
||||
import { TimeRange, TimeOption, TimeZone, TIME_FORMAT, SelectableValue, dateMath } from '@grafana/data';
|
||||
import { GrafanaTheme } from '../../types/theme';
|
||||
import { Themeable } from '../../types';
|
||||
|
||||
export interface Props {
|
||||
const getStyles = memoizeOne((theme: GrafanaTheme) => {
|
||||
return {
|
||||
timePickerSynced: css`
|
||||
label: timePickerSynced;
|
||||
border-color: ${theme.colors.orangeDark};
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
color: ${theme.colors.orangeDark};
|
||||
&:focus,
|
||||
:hover {
|
||||
color: ${theme.colors.orangeDark};
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
`,
|
||||
noRightBorderStyle: css`
|
||||
label: noRightBorderStyle;
|
||||
border-right: 0;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export interface Props extends Themeable {
|
||||
value: TimeRange;
|
||||
selectOptions: TimeOption[];
|
||||
timeZone?: TimeZone;
|
||||
timeSyncButton?: JSX.Element;
|
||||
isSynced?: boolean;
|
||||
onChange: (timeRange: TimeRange) => void;
|
||||
onMoveBackward: () => void;
|
||||
onMoveForward: () => void;
|
||||
@@ -70,7 +99,7 @@ const defaultZoomOutTooltip = () => {
|
||||
export interface State {
|
||||
isCustomOpen: boolean;
|
||||
}
|
||||
export class TimePicker extends PureComponent<Props, State> {
|
||||
class UnThemedTimePicker extends PureComponent<Props, State> {
|
||||
pickerTriggerRef = createRef<HTMLDivElement>();
|
||||
|
||||
state: State = {
|
||||
@@ -120,7 +149,19 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { selectOptions: selectTimeOptions, value, onMoveBackward, onMoveForward, onZoom, timeZone } = this.props;
|
||||
const {
|
||||
selectOptions: selectTimeOptions,
|
||||
value,
|
||||
onMoveBackward,
|
||||
onMoveForward,
|
||||
onZoom,
|
||||
timeZone,
|
||||
timeSyncButton,
|
||||
isSynced,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
const styles = getStyles(theme);
|
||||
const { isCustomOpen } = this.state;
|
||||
const options = this.mapTimeOptionsToSelectableValues(selectTimeOptions);
|
||||
const currentOption = options.find(item => isTimeOptionEqualToTimeRange(item.value, value));
|
||||
@@ -152,7 +193,10 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
</button>
|
||||
)}
|
||||
<ButtonSelect
|
||||
className="time-picker-button-select"
|
||||
className={classNames('time-picker-button-select', {
|
||||
[`btn--radius-right-0 ${styles.noRightBorderStyle}`]: timeSyncButton,
|
||||
[styles.timePickerSynced]: timeSyncButton ? isSynced : null,
|
||||
})}
|
||||
value={currentOption}
|
||||
label={label}
|
||||
options={options}
|
||||
@@ -161,6 +205,9 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
iconClass={'fa fa-clock-o fa-fw'}
|
||||
tooltipContent={<TimePickerTooltipContent timeRange={value} />}
|
||||
/>
|
||||
|
||||
{timeSyncButton}
|
||||
|
||||
{isAbsolute && (
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={onMoveForward}>
|
||||
<i className="fa fa-chevron-right" />
|
||||
@@ -195,3 +242,5 @@ const TimePickerTooltipContent = ({ timeRange }: { timeRange: TimeRange }) => (
|
||||
function isTimeOptionEqualToTimeRange(option: TimeOption, range: TimeRange): boolean {
|
||||
return range.raw.from === option.from && range.raw.to === option.to;
|
||||
}
|
||||
|
||||
export const TimePicker = withTheme(UnThemedTimePicker);
|
||||
|
||||
Reference in New Issue
Block a user