mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 00:55:47 -06:00
* Added RefreshButton * Added RefreshSelect * Added RefreshSelectButton * Added RefreshPicker * Removed the magic string Paused * Minor style changes and using Off instead of Pause * Added HeadlessSelect * Added HeadlessSelect story * Added SelectButton * Removed RefreshSelectButton * Added TimePicker and moved ClickOutsideWrapper to ui/components * Added TimePickerPopOver * Added react-calendar * Missed yarn lock file * Added inputs to popover * Added TimePicker and RefreshPicker to DashNav * Moved TimePicker and RefreshPicker to app/core * Added react-calendar to app and removed from ui/components * Fixed PopOver onClick * Moved everything back to ui components because of typings problems * Exporing RefreshPicker and TimePicker * Added Apply and inputs * Added typings * Added TimePickerInput and logic * Fixed parsing of string to Moments * Fixed range string * Styling and connecting the calendars and inputs * Changed Calendar styling * Added backward forward and zoom * Fixed responsive styles * Moved TimePicker and RefreshPicker into app core * Renamed menuIsOpen to isOpen * Changed from className={} to className="" * Moved Popover to TimePickerOptionGroup * Renamed all PopOver to Popover * Renamed popOver to popover and some minor refactorings * Renamed files with git mv * Added ButtonSelect and refactored RefreshPicker * Refactored TimePicker to use new ButtonSelect * Removed HeadlessSelect as suggested * fix: Fix typings and misc errors after rebase * wip: Enable time picker on dashboard and add tooltip * Merge branch 'master' into hugoh/new-timepicker-and-unified-component # Conflicts: # packages/grafana-ui/package.json # packages/grafana-ui/src/components/Input/Input.test.tsx # packages/grafana-ui/src/components/Input/Input.tsx # packages/grafana-ui/src/utils/validate.ts # public/app/features/dashboard/panel_editor/QueryOptions.tsx # yarn.lock * fix: Snapshot update * Move TimePicker default options into the TimePicker as statics, pass the tooltipContent down the line when wanted and wrap the button in a tooltip element * fix: Override internal state prop if we provide one in a prop * Updated snapshots * Let dashnav control refreshPicker state * feat: Add a stringToMs function * wip: RefreshPicker * wip: Move RefreshPicker to @grafana/ui * wip: Move TimePicker to @grafana/ui * wip: Remove comments * wip: Add refreshPicker to explore * wip: Use default intervals if the prop is missing * wip: Nicer way of setting defaults * fix: Control the select component * wip: Add onMoveForward/onMoveBack * Remove code related to the new time picker and refresh picker from dashnav * Fix: Typings after merge * chore: Minor fix after merge * chore: Remove _.map usage * chore: Moved refresh-picker logic out of the refresh picker since it will work a little differently in explore and dashboards until we have replaced the TimeSrv * feat: Add an Interval component to @grafana/ui * chore: Remove intervalId from redux state and move setInterval logic from ExploreToolbar to its own Interval component * feat: Add refreshInterval to Explore's URL state * feat: Pick up refreshInterval from url on page load * fix: Set default refreshInterval when no value can be retained from URL * fix: Update test initial state with refreshInterval * fix: Handle URLs before RefreshPicker * fix: Move RefreshInterval to url position 3 since the segments can take multiple positions * fix: A better way of detecting urls without RefreshInterval in Explore * chore: Some Explore typings * fix: Attach refresh picker to interval picker * chore: Sass fix for refresh button border radius * fix: Remove refreshInterval from URL * fix: Intervals now start when previous interval is finished * fix: Use clearTimeout instead of clearInterval * fix: Make sure there's a delay set before adding a timeout when we have slow explore queries * wip: Add refresh picker to dashboard * feat: Add util for removing keys with empty values * feat: RefreshPicker in dashboards and tmp rem out old RefreshPicker * fix: Remove the jumpy:ness in the refreshpicker * Changed placement and made it hide when your in dashboard settings * chore: Move logic related to refresh picker out of DashNav to its own component * feat: Add tooltip to refreshpicker * fix: Fix bug with refreshpicker not updating when setting to 'off' * fix: Make it possible to override refresh intervals using the dashboard intervals * chore: Change name of Interval to SetInterval to align with ecmascripts naming since its basically the same but declarative and async * fix: Use default intervals when auto refresh is empty in dashboard settings * fix: Hide time/interval picker when hidden is true on the model, such as on the home dashboard * fix: Interval picker will have to handle location changes since timeSrv wont * RefreshPicker: Refactoring refresh picker * RefreshPicker: minor refactoring
238 lines
7.1 KiB
TypeScript
238 lines
7.1 KiB
TypeScript
import React, { PureComponent } from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { hot } from 'react-hot-loader';
|
|
|
|
import { ExploreId } from 'app/types/explore';
|
|
import { DataSourceSelectItem, RawTimeRange, TimeRange, ClickOutsideWrapper } from '@grafana/ui';
|
|
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
|
import { StoreState } from 'app/types/store';
|
|
import {
|
|
changeDatasource,
|
|
clearQueries,
|
|
splitClose,
|
|
runQueries,
|
|
splitOpen,
|
|
changeRefreshInterval,
|
|
} from './state/actions';
|
|
import TimePicker from './TimePicker';
|
|
import { RefreshPicker, SetInterval } from '@grafana/ui';
|
|
|
|
enum IconSide {
|
|
left = 'left',
|
|
right = 'right',
|
|
}
|
|
|
|
const createResponsiveButton = (options: {
|
|
splitted: boolean;
|
|
title: string;
|
|
onClick: () => void;
|
|
buttonClassName?: string;
|
|
iconClassName?: string;
|
|
iconSide?: IconSide;
|
|
}) => {
|
|
const defaultOptions = {
|
|
iconSide: IconSide.left,
|
|
};
|
|
const props = { ...options, defaultOptions };
|
|
const { title, onClick, buttonClassName, iconClassName, splitted, iconSide } = props;
|
|
|
|
return (
|
|
<button className={`btn navbar-button ${buttonClassName ? buttonClassName : ''}`} onClick={onClick}>
|
|
{iconClassName && iconSide === IconSide.left ? <i className={`${iconClassName} icon-margin-right`} /> : null}
|
|
<span className="btn-title">{!splitted ? title : ''}</span>
|
|
{iconClassName && iconSide === IconSide.right ? <i className={`${iconClassName} icon-margin-left`} /> : null}
|
|
</button>
|
|
);
|
|
};
|
|
|
|
interface OwnProps {
|
|
exploreId: ExploreId;
|
|
timepickerRef: React.RefObject<TimePicker>;
|
|
onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void;
|
|
}
|
|
|
|
interface StateProps {
|
|
datasourceMissing: boolean;
|
|
exploreDatasources: DataSourceSelectItem[];
|
|
loading: boolean;
|
|
range: RawTimeRange;
|
|
selectedDatasource: DataSourceSelectItem;
|
|
splitted: boolean;
|
|
refreshInterval: string;
|
|
}
|
|
|
|
interface DispatchProps {
|
|
changeDatasource: typeof changeDatasource;
|
|
clearAll: typeof clearQueries;
|
|
runQueries: typeof runQueries;
|
|
closeSplit: typeof splitClose;
|
|
split: typeof splitOpen;
|
|
changeRefreshInterval: typeof changeRefreshInterval;
|
|
}
|
|
|
|
type Props = StateProps & DispatchProps & OwnProps;
|
|
|
|
export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
|
|
constructor(props: Props) {
|
|
super(props);
|
|
}
|
|
|
|
onChangeDatasource = async option => {
|
|
this.props.changeDatasource(this.props.exploreId, option.value);
|
|
};
|
|
|
|
onClearAll = () => {
|
|
this.props.clearAll(this.props.exploreId);
|
|
};
|
|
|
|
onRunQuery = () => {
|
|
return this.props.runQueries(this.props.exploreId);
|
|
};
|
|
|
|
onCloseTimePicker = () => {
|
|
this.props.timepickerRef.current.setState({ isOpen: false });
|
|
};
|
|
|
|
onChangeRefreshInterval = (item: string) => {
|
|
const { changeRefreshInterval, exploreId } = this.props;
|
|
changeRefreshInterval(exploreId, item);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
datasourceMissing,
|
|
exploreDatasources,
|
|
closeSplit,
|
|
exploreId,
|
|
loading,
|
|
range,
|
|
selectedDatasource,
|
|
splitted,
|
|
timepickerRef,
|
|
refreshInterval,
|
|
onChangeTime,
|
|
split,
|
|
} = this.props;
|
|
|
|
return (
|
|
<div className={splitted ? 'explore-toolbar splitted' : 'explore-toolbar'}>
|
|
<div className="explore-toolbar-item">
|
|
<div className="explore-toolbar-header">
|
|
<div className="explore-toolbar-header-title">
|
|
{exploreId === 'left' && (
|
|
<span className="navbar-page-btn">
|
|
<i className="gicon gicon-explore" />
|
|
Explore
|
|
</span>
|
|
)}
|
|
</div>
|
|
{splitted && (
|
|
<a className="explore-toolbar-header-close" onClick={() => closeSplit(exploreId)}>
|
|
<i className="fa fa-times fa-fw" />
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="explore-toolbar-item">
|
|
<div className="explore-toolbar-content">
|
|
{!datasourceMissing ? (
|
|
<div className="explore-toolbar-content-item">
|
|
<div className="datasource-picker">
|
|
<DataSourcePicker
|
|
onChange={this.onChangeDatasource}
|
|
datasources={exploreDatasources}
|
|
current={selectedDatasource}
|
|
/>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
{exploreId === 'left' && !splitted ? (
|
|
<div className="explore-toolbar-content-item">
|
|
{createResponsiveButton({
|
|
splitted,
|
|
title: 'Split',
|
|
onClick: split,
|
|
iconClassName: 'fa fa-fw fa-columns icon-margin-right',
|
|
iconSide: IconSide.left,
|
|
})}
|
|
</div>
|
|
) : null}
|
|
<div className="explore-toolbar-content-item timepicker">
|
|
<ClickOutsideWrapper onClick={this.onCloseTimePicker}>
|
|
<TimePicker ref={timepickerRef} range={range} onChangeTime={onChangeTime} />
|
|
</ClickOutsideWrapper>
|
|
|
|
<RefreshPicker
|
|
onIntervalChanged={this.onChangeRefreshInterval}
|
|
onRefresh={this.onRunQuery}
|
|
value={refreshInterval}
|
|
tooltip="Refresh"
|
|
/>
|
|
{refreshInterval && <SetInterval func={this.onRunQuery} interval={refreshInterval} />}
|
|
</div>
|
|
|
|
<div className="explore-toolbar-content-item">
|
|
<button className="btn navbar-button navbar-button--no-icon" onClick={this.onClearAll}>
|
|
Clear All
|
|
</button>
|
|
</div>
|
|
<div className="explore-toolbar-content-item">
|
|
{createResponsiveButton({
|
|
splitted,
|
|
title: 'Run Query',
|
|
onClick: this.onRunQuery,
|
|
buttonClassName: 'navbar-button--secondary',
|
|
iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon',
|
|
iconSide: IconSide.right,
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => {
|
|
const splitted = state.explore.split;
|
|
const exploreItem = state.explore[exploreId];
|
|
const {
|
|
datasourceInstance,
|
|
datasourceMissing,
|
|
exploreDatasources,
|
|
queryTransactions,
|
|
range,
|
|
refreshInterval,
|
|
} = exploreItem;
|
|
const selectedDatasource = datasourceInstance
|
|
? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name)
|
|
: undefined;
|
|
const loading = queryTransactions.some(qt => !qt.done);
|
|
|
|
return {
|
|
datasourceMissing,
|
|
exploreDatasources,
|
|
loading,
|
|
range,
|
|
selectedDatasource,
|
|
splitted,
|
|
refreshInterval,
|
|
};
|
|
};
|
|
|
|
const mapDispatchToProps: DispatchProps = {
|
|
changeDatasource,
|
|
changeRefreshInterval,
|
|
clearAll: clearQueries,
|
|
runQueries,
|
|
closeSplit: splitClose,
|
|
split: splitOpen,
|
|
};
|
|
|
|
export const ExploreToolbar = hot(module)(
|
|
connect(
|
|
mapStateToProps,
|
|
mapDispatchToProps
|
|
)(UnConnectedExploreToolbar)
|
|
);
|