mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(explore): make it possible to close left pane of split view (#16155)
* feat(explore): make it possible to close left pane of split view * Use action's type prop instead of enum
This commit is contained in:
@@ -108,11 +108,9 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{exploreId === 'right' && (
|
<a className="explore-toolbar-header-close" onClick={() => this.props.closeSplit(exploreId)}>
|
||||||
<a className="explore-toolbar-header-close" onClick={this.props.closeSplit}>
|
<i className="fa fa-times fa-fw" />
|
||||||
<i className="fa fa-times fa-fw" />
|
</a>
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="explore-toolbar-item">
|
<div className="explore-toolbar-item">
|
||||||
|
|||||||
@@ -24,16 +24,9 @@ import { LogLevel } from 'app/core/logs_model';
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
SplitClose = 'explore/SPLIT_CLOSE',
|
|
||||||
SplitOpen = 'explore/SPLIT_OPEN',
|
SplitOpen = 'explore/SPLIT_OPEN',
|
||||||
ResetExplore = 'explore/RESET_EXPLORE',
|
ResetExplore = 'explore/RESET_EXPLORE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitCloseAction {
|
|
||||||
type: ActionTypes.SplitClose;
|
|
||||||
payload: {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SplitOpenAction {
|
export interface SplitOpenAction {
|
||||||
type: ActionTypes.SplitOpen;
|
type: ActionTypes.SplitOpen;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -167,6 +160,10 @@ export interface SetQueriesPayload {
|
|||||||
queries: DataQuery[];
|
queries: DataQuery[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SplitCloseActionPayload {
|
||||||
|
itemId: ExploreId;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SplitOpenPayload {
|
export interface SplitOpenPayload {
|
||||||
itemState: ExploreItemState;
|
itemState: ExploreItemState;
|
||||||
}
|
}
|
||||||
@@ -350,7 +347,7 @@ export const setQueriesAction = actionCreatorFactory<SetQueriesPayload>('explore
|
|||||||
/**
|
/**
|
||||||
* Close the split view and save URL state.
|
* Close the split view and save URL state.
|
||||||
*/
|
*/
|
||||||
export const splitCloseAction = noPayloadActionCreatorFactory('explore/SPLIT_CLOSE').create();
|
export const splitCloseAction = actionCreatorFactory<SplitCloseActionPayload>('explore/SPLIT_CLOSE').create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the split view and copy the left state to be the right state.
|
* Open the split view and copy the left state to be the right state.
|
||||||
@@ -395,7 +392,11 @@ export const toggleLogLevelAction = actionCreatorFactory<ToggleLogLevelPayload>(
|
|||||||
export const resetExploreAction = noPayloadActionCreatorFactory('explore/RESET_EXPLORE').create();
|
export const resetExploreAction = noPayloadActionCreatorFactory('explore/RESET_EXPLORE').create();
|
||||||
export const queriesImportedAction = actionCreatorFactory<QueriesImportedPayload>('explore/QueriesImported').create();
|
export const queriesImportedAction = actionCreatorFactory<QueriesImportedPayload>('explore/QueriesImported').create();
|
||||||
|
|
||||||
export type HigherOrderAction = SplitCloseAction | SplitOpenAction | ResetExploreAction | ActionOf<any>;
|
export type HigherOrderAction =
|
||||||
|
| ActionOf<SplitCloseActionPayload>
|
||||||
|
| SplitOpenAction
|
||||||
|
| ResetExploreAction
|
||||||
|
| ActionOf<any>;
|
||||||
|
|
||||||
export type Action =
|
export type Action =
|
||||||
| ActionOf<AddQueryRowPayload>
|
| ActionOf<AddQueryRowPayload>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { ThunkAction } from 'redux-thunk';
|
|
||||||
|
|
||||||
// Services & Utils
|
// Services & Utils
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
@@ -23,7 +22,6 @@ import {
|
|||||||
import { updateLocation } from 'app/core/actions';
|
import { updateLocation } from 'app/core/actions';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { StoreState } from 'app/types';
|
|
||||||
import {
|
import {
|
||||||
RawTimeRange,
|
RawTimeRange,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
@@ -35,7 +33,6 @@ import {
|
|||||||
} from '@grafana/ui/src/types';
|
} from '@grafana/ui/src/types';
|
||||||
import { ExploreId, ExploreUrlState, RangeScanner, ResultType, QueryOptions, ExploreUIState } from 'app/types/explore';
|
import { ExploreId, ExploreUrlState, RangeScanner, ResultType, QueryOptions, ExploreUIState } from 'app/types/explore';
|
||||||
import {
|
import {
|
||||||
Action,
|
|
||||||
updateDatasourceInstanceAction,
|
updateDatasourceInstanceAction,
|
||||||
changeQueryAction,
|
changeQueryAction,
|
||||||
changeSizeAction,
|
changeSizeAction,
|
||||||
@@ -71,10 +68,9 @@ import {
|
|||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory';
|
import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory';
|
||||||
import { LogsDedupStrategy } from 'app/core/logs_model';
|
import { LogsDedupStrategy } from 'app/core/logs_model';
|
||||||
|
import { ThunkResult } from 'app/types';
|
||||||
import { parseTime } from '../TimePicker';
|
import { parseTime } from '../TimePicker';
|
||||||
|
|
||||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates UI state and save it to the URL
|
* Updates UI state and save it to the URL
|
||||||
*/
|
*/
|
||||||
@@ -645,9 +641,9 @@ export function setQueries(exploreId: ExploreId, rawQueries: DataQuery[]): Thunk
|
|||||||
/**
|
/**
|
||||||
* Close the split view and save URL state.
|
* Close the split view and save URL state.
|
||||||
*/
|
*/
|
||||||
export function splitClose(): ThunkResult<void> {
|
export function splitClose(itemId: ExploreId): ThunkResult<void> {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(splitCloseAction());
|
dispatch(splitCloseAction({ itemId }));
|
||||||
dispatch(stateSave());
|
dispatch(stateSave());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import { itemReducer, makeExploreItemState, exploreReducer, makeInitialUpdateState } from './reducers';
|
import {
|
||||||
import { ExploreId, ExploreItemState, ExploreUrlState } from 'app/types/explore';
|
itemReducer,
|
||||||
|
makeExploreItemState,
|
||||||
|
exploreReducer,
|
||||||
|
makeInitialUpdateState,
|
||||||
|
initialExploreState,
|
||||||
|
} from './reducers';
|
||||||
|
import { ExploreId, ExploreItemState, ExploreUrlState, ExploreState } from 'app/types/explore';
|
||||||
import { reducerTester } from 'test/core/redux/reducerTester';
|
import { reducerTester } from 'test/core/redux/reducerTester';
|
||||||
import { scanStartAction, scanStopAction } from './actionTypes';
|
import { scanStartAction, scanStopAction, splitOpenAction, splitCloseAction } from './actionTypes';
|
||||||
import { Reducer } from 'redux';
|
import { Reducer } from 'redux';
|
||||||
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
|
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
|
||||||
import { updateLocation } from 'app/core/actions/location';
|
import { updateLocation } from 'app/core/actions/location';
|
||||||
@@ -76,6 +82,82 @@ export const setup = (urlStateOverrides?: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('Explore reducer', () => {
|
describe('Explore reducer', () => {
|
||||||
|
describe('split view', () => {
|
||||||
|
it("should make right pane a duplicate of the given item's state on split open", () => {
|
||||||
|
const leftItemMock = {
|
||||||
|
containerWidth: 100,
|
||||||
|
} as ExploreItemState;
|
||||||
|
|
||||||
|
const initalState = {
|
||||||
|
split: null,
|
||||||
|
left: leftItemMock as ExploreItemState,
|
||||||
|
right: makeExploreItemState(),
|
||||||
|
} as ExploreState;
|
||||||
|
|
||||||
|
reducerTester()
|
||||||
|
.givenReducer(exploreReducer as Reducer<ExploreState, ActionOf<any>>, initalState)
|
||||||
|
.whenActionIsDispatched(splitOpenAction({ itemState: leftItemMock }))
|
||||||
|
.thenStateShouldEqual({
|
||||||
|
split: true,
|
||||||
|
left: leftItemMock,
|
||||||
|
right: leftItemMock,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('split close', () => {
|
||||||
|
it('should keep right pane as left when left is closed', () => {
|
||||||
|
const leftItemMock = {
|
||||||
|
containerWidth: 100,
|
||||||
|
} as ExploreItemState;
|
||||||
|
|
||||||
|
const rightItemMock = {
|
||||||
|
containerWidth: 200,
|
||||||
|
} as ExploreItemState;
|
||||||
|
|
||||||
|
const initalState = {
|
||||||
|
split: null,
|
||||||
|
left: leftItemMock,
|
||||||
|
right: rightItemMock,
|
||||||
|
} as ExploreState;
|
||||||
|
|
||||||
|
// closing left item
|
||||||
|
reducerTester()
|
||||||
|
.givenReducer(exploreReducer as Reducer<ExploreState, ActionOf<any>>, initalState)
|
||||||
|
.whenActionIsDispatched(splitCloseAction({ itemId: ExploreId.left }))
|
||||||
|
.thenStateShouldEqual({
|
||||||
|
split: false,
|
||||||
|
left: rightItemMock,
|
||||||
|
right: initialExploreState.right,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should reset right pane when it is closed ', () => {
|
||||||
|
const leftItemMock = {
|
||||||
|
containerWidth: 100,
|
||||||
|
} as ExploreItemState;
|
||||||
|
|
||||||
|
const rightItemMock = {
|
||||||
|
containerWidth: 200,
|
||||||
|
} as ExploreItemState;
|
||||||
|
|
||||||
|
const initalState = {
|
||||||
|
split: null,
|
||||||
|
left: leftItemMock,
|
||||||
|
right: rightItemMock,
|
||||||
|
} as ExploreState;
|
||||||
|
|
||||||
|
// closing left item
|
||||||
|
reducerTester()
|
||||||
|
.givenReducer(exploreReducer as Reducer<ExploreState, ActionOf<any>>, initalState)
|
||||||
|
.whenActionIsDispatched(splitCloseAction({ itemId: ExploreId.right }))
|
||||||
|
.thenStateShouldEqual({
|
||||||
|
split: false,
|
||||||
|
left: leftItemMock,
|
||||||
|
right: initialExploreState.right,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when updateLocation is dispatched', () => {
|
describe('when updateLocation is dispatched', () => {
|
||||||
describe('and payload does not contain a query', () => {
|
describe('and payload does not contain a query', () => {
|
||||||
it('then it should just return state', () => {
|
it('then it should just return state', () => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { ExploreItemState, ExploreState, QueryTransaction, ExploreId, ExploreUpdateState } from 'app/types/explore';
|
import { ExploreItemState, ExploreState, QueryTransaction, ExploreId, ExploreUpdateState } from 'app/types/explore';
|
||||||
import { DataQuery } from '@grafana/ui/src/types';
|
import { DataQuery } from '@grafana/ui/src/types';
|
||||||
|
|
||||||
import { HigherOrderAction, ActionTypes } from './actionTypes';
|
import { HigherOrderAction, ActionTypes, SplitCloseActionPayload, splitCloseAction } from './actionTypes';
|
||||||
import { reducerFactory } from 'app/core/redux';
|
import { reducerFactory } from 'app/core/redux';
|
||||||
import {
|
import {
|
||||||
addQueryRowAction,
|
addQueryRowAction,
|
||||||
@@ -560,8 +560,17 @@ export const updateChildRefreshState = (
|
|||||||
*/
|
*/
|
||||||
export const exploreReducer = (state = initialExploreState, action: HigherOrderAction): ExploreState => {
|
export const exploreReducer = (state = initialExploreState, action: HigherOrderAction): ExploreState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.SplitClose: {
|
case splitCloseAction.type: {
|
||||||
return { ...state, split: false };
|
const { itemId } = action.payload as SplitCloseActionPayload;
|
||||||
|
const targetSplit = {
|
||||||
|
left: itemId === ExploreId.left ? state.right : state.left,
|
||||||
|
right: initialExploreState.right,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...targetSplit,
|
||||||
|
split: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case ActionTypes.SplitOpen: {
|
case ActionTypes.SplitOpen: {
|
||||||
|
|||||||
Reference in New Issue
Block a user