Made ExplorerToolbar connected and refactored away responsabilities from Explore

This commit is contained in:
Hugo Häggmark 2019-01-24 13:19:33 +01:00
parent 21df0c90a9
commit 1e6d50df7a
2 changed files with 76 additions and 85 deletions

View File

@ -9,7 +9,6 @@ import { AutoSizer } from 'react-virtualized';
import store from 'app/core/store'; import store from 'app/core/store';
// Components // Components
import { DataSourceSelectItem } from '@grafana/ui/src/types';
import { Alert } from './Error'; import { Alert } from './Error';
import ErrorBoundary from './ErrorBoundary'; import ErrorBoundary from './ErrorBoundary';
import GraphContainer from './GraphContainer'; import GraphContainer from './GraphContainer';
@ -20,18 +19,13 @@ import TimePicker, { parseTime } from './TimePicker';
// Actions // Actions
import { import {
changeDatasource,
changeSize, changeSize,
changeTime, changeTime,
clearQueries,
initializeExplore, initializeExplore,
modifyQueries, modifyQueries,
runQueries,
scanStart, scanStart,
scanStop, scanStop,
setQueries, setQueries,
splitClose,
splitOpen,
} from './state/actions'; } from './state/actions';
// Types // Types
@ -44,24 +38,19 @@ import { ExploreToolbar } from './ExploreToolbar';
interface ExploreProps { interface ExploreProps {
StartPage?: any; StartPage?: any;
changeDatasource: typeof changeDatasource;
changeSize: typeof changeSize; changeSize: typeof changeSize;
changeTime: typeof changeTime; changeTime: typeof changeTime;
clearQueries: typeof clearQueries;
datasourceError: string; datasourceError: string;
datasourceInstance: any; datasourceInstance: any;
datasourceLoading: boolean | null; datasourceLoading: boolean | null;
datasourceMissing: boolean; datasourceMissing: boolean;
exploreDatasources: DataSourceSelectItem[];
exploreId: ExploreId; exploreId: ExploreId;
initialDatasource?: string; initialDatasource?: string;
initialQueries: DataQuery[]; initialQueries: DataQuery[];
initializeExplore: typeof initializeExplore; initializeExplore: typeof initializeExplore;
initialized: boolean; initialized: boolean;
loading: boolean;
modifyQueries: typeof modifyQueries; modifyQueries: typeof modifyQueries;
range: RawTimeRange; range: RawTimeRange;
runQueries: typeof runQueries;
scanner?: RangeScanner; scanner?: RangeScanner;
scanning?: boolean; scanning?: boolean;
scanRange?: RawTimeRange; scanRange?: RawTimeRange;
@ -69,8 +58,6 @@ interface ExploreProps {
scanStop: typeof scanStop; scanStop: typeof scanStop;
setQueries: typeof setQueries; setQueries: typeof setQueries;
split: boolean; split: boolean;
splitClose: typeof splitClose;
splitOpen: typeof splitOpen;
showingStartPage?: boolean; showingStartPage?: boolean;
supportsGraph: boolean | null; supportsGraph: boolean | null;
supportsLogs: boolean | null; supportsLogs: boolean | null;
@ -145,10 +132,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
this.el = el; this.el = el;
}; };
onChangeDatasource = async option => {
this.props.changeDatasource(this.props.exploreId, option.value);
};
onChangeTime = (range: TimeRange, changedByScanner?: boolean) => { onChangeTime = (range: TimeRange, changedByScanner?: boolean) => {
if (this.props.scanning && !changedByScanner) { if (this.props.scanning && !changedByScanner) {
this.onStopScanning(); this.onStopScanning();
@ -156,23 +139,11 @@ export class Explore extends React.PureComponent<ExploreProps> {
this.props.changeTime(this.props.exploreId, range); this.props.changeTime(this.props.exploreId, range);
}; };
onClickClear = () => {
this.props.clearQueries(this.props.exploreId);
};
onClickCloseSplit = () => {
this.props.splitClose();
};
// Use this in help pages to set page to a single query // Use this in help pages to set page to a single query
onClickExample = (query: DataQuery) => { onClickExample = (query: DataQuery) => {
this.props.setQueries(this.props.exploreId, [query]); this.props.setQueries(this.props.exploreId, [query]);
}; };
onClickSplit = () => {
this.props.splitOpen();
};
onClickLabel = (key: string, value: string) => { onClickLabel = (key: string, value: string) => {
this.onModifyQueries({ type: 'ADD_FILTER', key, value }); this.onModifyQueries({ type: 'ADD_FILTER', key, value });
}; };
@ -204,10 +175,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
this.props.scanStop(this.props.exploreId); this.props.scanStop(this.props.exploreId);
}; };
onSubmit = () => {
this.props.runQueries(this.props.exploreId);
};
render() { render() {
const { const {
StartPage, StartPage,
@ -215,11 +182,8 @@ export class Explore extends React.PureComponent<ExploreProps> {
datasourceError, datasourceError,
datasourceLoading, datasourceLoading,
datasourceMissing, datasourceMissing,
exploreDatasources,
exploreId, exploreId,
loading,
initialQueries, initialQueries,
range,
showingStartPage, showingStartPage,
split, split,
supportsGraph, supportsGraph,
@ -227,30 +191,10 @@ export class Explore extends React.PureComponent<ExploreProps> {
supportsTable, supportsTable,
} = this.props; } = this.props;
const exploreClass = split ? 'explore explore-split' : 'explore'; const exploreClass = split ? 'explore explore-split' : 'explore';
const selectedDatasource = datasourceInstance
? exploreDatasources.find(d => d.name === datasourceInstance.name)
: undefined;
const timepicker = <TimePicker ref={this.timepickerRef} range={range} onChangeTime={this.onChangeTime} />;
return ( return (
<div className={exploreClass} ref={this.getRef}> <div className={exploreClass} ref={this.getRef}>
<ExploreToolbar <ExploreToolbar exploreId={exploreId} timepickerRef={this.timepickerRef} onChangeTime={this.onChangeTime} />
datasourceMissing={datasourceMissing}
exploreDatasources={exploreDatasources}
exploreId={exploreId}
loading={loading}
range={range}
selectedDatasource={selectedDatasource}
splitted={split}
timepicker={timepicker}
onChangeDatasource={this.onChangeDatasource}
onClearAll={this.onClickClear}
onCloseSplit={this.onClickCloseSplit}
onChangeTime={this.onChangeTime}
onRunQuery={this.onSubmit}
onSplit={this.onClickSplit}
/>
{datasourceLoading ? <div className="explore-container">Loading datasource...</div> : null} {datasourceLoading ? <div className="explore-container">Loading datasource...</div> : null}
{datasourceMissing ? ( {datasourceMissing ? (
<div className="explore-container">Please add a datasource that supports Explore (e.g., Prometheus).</div> <div className="explore-container">Please add a datasource that supports Explore (e.g., Prometheus).</div>
@ -307,30 +251,24 @@ function mapStateToProps(state: StoreState, { exploreId }) {
datasourceInstance, datasourceInstance,
datasourceLoading, datasourceLoading,
datasourceMissing, datasourceMissing,
exploreDatasources,
initialDatasource, initialDatasource,
initialQueries, initialQueries,
initialized, initialized,
queryTransactions,
range, range,
showingStartPage, showingStartPage,
supportsGraph, supportsGraph,
supportsLogs, supportsLogs,
supportsTable, supportsTable,
} = item; } = item;
const loading = queryTransactions.some(qt => !qt.done);
return { return {
StartPage, StartPage,
datasourceError, datasourceError,
datasourceInstance, datasourceInstance,
datasourceLoading, datasourceLoading,
datasourceMissing, datasourceMissing,
exploreDatasources,
initialDatasource, initialDatasource,
initialQueries, initialQueries,
initialized, initialized,
loading,
queryTransactions,
range, range,
showingStartPage, showingStartPage,
split, split,
@ -341,18 +279,13 @@ function mapStateToProps(state: StoreState, { exploreId }) {
} }
const mapDispatchToProps = { const mapDispatchToProps = {
changeDatasource,
changeSize, changeSize,
changeTime, changeTime,
clearQueries,
initializeExplore, initializeExplore,
modifyQueries, modifyQueries,
runQueries,
scanStart, scanStart,
scanStop, scanStop,
setQueries, setQueries,
splitClose,
splitOpen,
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(Explore)); export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(Explore));

View File

@ -1,7 +1,13 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { ExploreId } from 'app/types/explore'; import { ExploreId } from 'app/types/explore';
import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui';
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { StoreState } from 'app/types/store';
import { changeDatasource, clearQueries, splitClose, runQueries, splitOpen } from './state/actions';
import TimePicker from './TimePicker';
const createResponsiveButton = (options: { const createResponsiveButton = (options: {
splitted: boolean; splitted: boolean;
@ -20,37 +26,58 @@ const createResponsiveButton = (options: {
); );
}; };
interface Props { interface OwnProps {
exploreId: ExploreId;
timepickerRef: React.RefObject<TimePicker>;
onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void;
}
interface StateProps {
datasourceMissing: boolean; datasourceMissing: boolean;
exploreDatasources: DataSourceSelectItem[]; exploreDatasources: DataSourceSelectItem[];
exploreId: ExploreId;
loading: boolean; loading: boolean;
range: RawTimeRange; range: RawTimeRange;
selectedDatasource: DataSourceSelectItem; selectedDatasource: DataSourceSelectItem;
splitted: boolean; splitted: boolean;
timepicker: JSX.Element;
onChangeDatasource: (option) => void;
onClearAll: () => void;
onCloseSplit: () => void;
onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void;
onRunQuery: () => void;
onSplit: () => void;
} }
export class ExploreToolbar extends PureComponent<Props, {}> { interface DispatchProps {
changeDatasource: typeof changeDatasource;
clearAll: typeof clearQueries;
runQuery: typeof runQueries;
closeSplit: typeof splitClose;
split: typeof splitOpen;
}
type Props = StateProps & DispatchProps & OwnProps;
export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
constructor(props) { constructor(props) {
super(props); super(props);
} }
onChangeDatasource = async option => {
this.props.changeDatasource(this.props.exploreId, option.value);
};
onClearAll = () => {
this.props.clearAll(this.props.exploreId);
};
onRunQuery = () => {
this.props.runQuery(this.props.exploreId);
};
render() { render() {
const { const {
datasourceMissing, datasourceMissing,
exploreDatasources, exploreDatasources,
exploreId, exploreId,
loading, loading,
range,
selectedDatasource, selectedDatasource,
splitted, splitted,
timepicker, timepickerRef,
} = this.props; } = this.props;
return ( return (
@ -67,7 +94,7 @@ export class ExploreToolbar extends PureComponent<Props, {}> {
</div> </div>
<div className="toolbar-header-close"> <div className="toolbar-header-close">
{exploreId === 'right' && ( {exploreId === 'right' && (
<a onClick={this.props.onCloseSplit}> <a onClick={this.props.closeSplit}>
<i className="fa fa-window-close fa-fw" /> <i className="fa fa-window-close fa-fw" />
</a> </a>
)} )}
@ -80,7 +107,7 @@ export class ExploreToolbar extends PureComponent<Props, {}> {
<div className="toolbar-content-item"> <div className="toolbar-content-item">
<div className="datasource-picker"> <div className="datasource-picker">
<DataSourcePicker <DataSourcePicker
onChange={this.props.onChangeDatasource} onChange={this.onChangeDatasource}
datasources={exploreDatasources} datasources={exploreDatasources}
current={selectedDatasource} current={selectedDatasource}
/> />
@ -92,14 +119,16 @@ export class ExploreToolbar extends PureComponent<Props, {}> {
{createResponsiveButton({ {createResponsiveButton({
splitted, splitted,
title: 'Split', title: 'Split',
onClick: this.props.onSplit, onClick: this.props.split,
iconClassName: 'fa fa-fw fa-columns', iconClassName: 'fa fa-fw fa-columns',
})} })}
</div> </div>
) : null} ) : null}
<div className="toolbar-content-item timepicker">{timepicker}</div> <div className="toolbar-content-item timepicker">
<TimePicker ref={timepickerRef} range={range} onChangeTime={this.props.onChangeTime} />
</div>
<div className="toolbar-content-item"> <div className="toolbar-content-item">
<button className="btn navbar-button navbar-button--no-icon" onClick={this.props.onClearAll}> <button className="btn navbar-button navbar-button--no-icon" onClick={this.onClearAll}>
Clear All Clear All
</button> </button>
</div> </div>
@ -107,7 +136,7 @@ export class ExploreToolbar extends PureComponent<Props, {}> {
{createResponsiveButton({ {createResponsiveButton({
splitted, splitted,
title: 'Run Query', title: 'Run Query',
onClick: this.props.onRunQuery, onClick: this.onRunQuery,
buttonClassName: 'navbar-button--primary', buttonClassName: 'navbar-button--primary',
iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon', iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon',
})} })}
@ -118,3 +147,32 @@ export class ExploreToolbar extends PureComponent<Props, {}> {
); );
} }
} }
const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => {
const splitted = state.explore.split;
const exploreItem = state.explore[exploreId];
const { datasourceInstance, datasourceMissing, exploreDatasources, queryTransactions, range } = 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,
};
};
const mapDispatchToProps: DispatchProps = {
changeDatasource,
clearAll: clearQueries,
runQuery: runQueries,
closeSplit: splitClose,
split: splitOpen,
};
export const ExploreToolbar = hot(module)(connect(mapStateToProps, mapDispatchToProps)(UnConnectedExploreToolbar));