From 588e91659bf887e036e2433fc543275d4983fdff Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Fri, 17 Feb 2017 11:30:38 -0600 Subject: [PATCH] Move current dashboard into dashboard reducer --- ui/spec/dashboards/reducers/uiSpec.js | 43 +++++++++++----- ui/src/dashboards/actions/index.js | 22 +++++++- ui/src/dashboards/constants/index.js | 12 +++++ ui/src/dashboards/containers/DashboardPage.js | 51 +++++++++++-------- ui/src/dashboards/reducers/ui.js | 17 ++++++- 5 files changed, 108 insertions(+), 37 deletions(-) create mode 100644 ui/src/dashboards/constants/index.js diff --git a/ui/spec/dashboards/reducers/uiSpec.js b/ui/spec/dashboards/reducers/uiSpec.js index 5ab2140805..69fe7ba2fc 100644 --- a/ui/spec/dashboards/reducers/uiSpec.js +++ b/ui/spec/dashboards/reducers/uiSpec.js @@ -1,7 +1,8 @@ -import reducer from 'src/dashboards/reducers/ui'; +import reducer from 'src/dashboards/reducers/ui' import { loadDashboards, + setDashboard, } from 'src/dashboards/actions'; const noopAction = () => { @@ -11,21 +12,37 @@ const noopAction = () => { let state = undefined; describe('DataExplorer.Reducers.UI', () => { - it('it sets the default state for UI', () => { - const actual = reducer(state, noopAction()); - const expected = { - dashboards: [], - }; - - expect(actual).to.deep.equal(expected); - }); - it('can load the dashboards', () => { - const dashboards = [{cell: {}, name: "d1"}] - const actual = reducer(state, loadDashboards(dashboards)); + const dashboard = {id: 2, cells: [], name: "d2"} + const dashboards = [ + {id: 1, cells: [], name: "d1"}, + dashboard, + ] + + const actual = reducer(state, loadDashboards(dashboards, dashboard.id)) const expected = { dashboards, + dashboard, } - expect(actual).to.deep.equal(expected); + + expect(actual).to.deep.equal(expected) + }); + + it('can set a dashboard', () => { + const d1 = {id: 2, cells: [], name: "d2"} + const d2 = {id: 2, cells: [], name: "d2"} + const dashboards = [ + d1, + d2, + ] + + const loadedState = reducer(state, loadDashboards(dashboards, d1.id)) + const actual = reducer(loadedState, setDashboard(d2.id)) + const expected = { + dashboards, + dashboard: d2, + } + + expect(actual).to.deep.equal(expected) }); }); diff --git a/ui/src/dashboards/actions/index.js b/ui/src/dashboards/actions/index.js index 2db6612061..a6902d939a 100644 --- a/ui/src/dashboards/actions/index.js +++ b/ui/src/dashboards/actions/index.js @@ -1,8 +1,28 @@ -export function loadDashboards(dashboards) { +import {getDashboards as getDashboardsAPI} from 'src/dashboards/apis' + +export function loadDashboards(dashboards, dashboardID) { return { type: 'LOAD_DASHBOARDS', payload: { dashboards, + dashboardID, }, } } + +export function setDashboard(dashboardID) { + return { + type: 'SET_DASHBOARD', + payload: { + dashboardID, + }, + } +} + +export function getDashboards(dashboardID) { + return (dispatch) => { + getDashboardsAPI().then(({data: {dashboards}}) => { + dispatch(loadDashboards(dashboards, dashboardID)) + }); + } +} diff --git a/ui/src/dashboards/constants/index.js b/ui/src/dashboards/constants/index.js new file mode 100644 index 0000000000..8e751072ee --- /dev/null +++ b/ui/src/dashboards/constants/index.js @@ -0,0 +1,12 @@ +export const EMPTY_DASHBOARD = { + id: 0, + name: '', + cells: [ + { + x: 0, + y: 0, + queries: [], + name: 'Loading...', + }, + ], +} diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index c2d29d05f5..f0afaac1cb 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -2,7 +2,6 @@ import React, {PropTypes} from 'react'; import {Link} from 'react-router'; import {connect} from 'react-redux' import {bindActionCreators} from 'redux'; -import _ from 'lodash'; import Header from 'src/dashboards/components/DashboardHeader'; import EditHeader from 'src/dashboards/components/DashboardHeaderEdit'; @@ -11,7 +10,6 @@ import timeRanges from 'hson!../../shared/data/timeRanges.hson'; import * as dashboardActionCreators from 'src/dashboards/actions'; -import {getDashboards} from '../apis'; import {presentationButtonDispatcher} from 'shared/dispatchers' const { @@ -39,12 +37,17 @@ const DashboardPage = React.createClass({ pathname: string.isRequired, }).isRequired, dashboardActions: shape({ - loadDashboards: func.isRequired, + getDashboards: func.isRequired, + setDashboard: func.isRequired, }).isRequired, dashboards: arrayOf(shape({ id: number.isRequired, cells: arrayOf(shape({})).isRequired, })).isRequired, + dashboard: shape({ + id: number.isRequired, + cells: arrayOf(shape({})).isRequired, + }).isRequired, inPresentationMode: bool.isRequired, handleClickPresentationButton: func, }, @@ -53,34 +56,36 @@ const DashboardPage = React.createClass({ const fifteenMinutesIndex = 1; return { - dashboard: null, timeRange: timeRanges[fifteenMinutesIndex], isEditMode: this.props.location.pathname.includes('/edit'), }; }, componentDidMount() { - const {params: {dashboardID}, dashboardActions: {loadDashboards}} = this.props; + const { + params: {dashboardID}, + dashboardActions: {getDashboards}, + } = this.props; - getDashboards().then(({data: {dashboards}}) => { - loadDashboards(dashboards) - this.setState({ - dashboard: _.find(dashboards, (d) => d.id.toString() === dashboardID), - }); - }); + getDashboards(dashboardID) }, componentWillReceiveProps(nextProps) { const {location: {pathname}} = this.props - const {location: {pathname: nextPathname}, params: {dashboardID: nextID}} = nextProps + const { + location: {pathname: nextPathname}, + params: {dashboardID: nextID}, + dashboardActions: {setDashboard}, + } = nextProps if (nextPathname.pathname === pathname) { return } + setDashboard(nextID) + this.setState({ isEditMode: nextPathname.includes('/edit'), - dashboard: _.find(this.state.dashboards, (d) => d.id.toString() === nextID), }) }, @@ -90,20 +95,17 @@ const DashboardPage = React.createClass({ }, render() { - const {timeRange, isEditMode, dashboard} = this.state; + const {timeRange, isEditMode} = this.state; const { dashboards, + dashboard, params: {sourceID}, inPresentationMode, handleClickPresentationButton, source, } = this.props - if (!dashboard) { - return null - } - return (
{ @@ -141,10 +143,15 @@ const DashboardPage = React.createClass({ }, }); -const mapStateToProps = (state) => ({ - inPresentationMode: state.appUI.presentationMode, - dashboards: state.dashboardUI.dashboards, -}) +const mapStateToProps = (state) => { + const {appUI, dashboardUI: {dashboards, dashboard}} = state + + return { + inPresentationMode: appUI.presentationMode, + dashboards, + dashboard, + } +} const mapDispatchToProps = (dispatch) => ({ handleClickPresentationButton: presentationButtonDispatcher(dispatch), diff --git a/ui/src/dashboards/reducers/ui.js b/ui/src/dashboards/reducers/ui.js index e0a63363ce..d9de09f26c 100644 --- a/ui/src/dashboards/reducers/ui.js +++ b/ui/src/dashboards/reducers/ui.js @@ -1,17 +1,32 @@ +import _ from 'lodash'; +import {EMPTY_DASHBOARD} from 'src/dashboards/constants' + + const initialState = { dashboards: [], + dashboard: EMPTY_DASHBOARD, }; export default function ui(state = initialState, action) { switch (action.type) { case 'LOAD_DASHBOARDS': { - const {dashboards} = action.payload; + const {dashboards, dashboardID} = action.payload; const newState = { dashboards, + dashboard: _.find(dashboards, (d) => d.id === +dashboardID), }; return {...state, ...newState}; } + + case 'SET_DASHBOARD': { + const {dashboardID} = action.payload + const newState = { + dashboard: _.find(state.dashboards, (d) => d.id === +dashboardID), + }; + + return {...state, ...newState} + } } return state;