WIP persist dashboard position to server

pull/10616/head
Andrew Watkins 2017-02-22 09:36:48 -06:00
parent 0d0a3e1e54
commit d3c1f6c31a
4 changed files with 52 additions and 33 deletions

View File

@ -6,3 +6,11 @@ export function getDashboards() {
url: `/chronograf/v1/dashboards`, url: `/chronograf/v1/dashboards`,
}); });
} }
export function updateDashboardPosition(dashboard) {
return AJAX({
method: 'PUT',
url: dashboard.links.self,
data: dashboard,
});
}

View File

@ -8,6 +8,7 @@ const Dashboard = ({
dashboard, dashboard,
isEditMode, isEditMode,
inPresentationMode, inPresentationMode,
onPositionChange,
source, source,
timeRange, timeRange,
}) => { }) => {
@ -19,29 +20,17 @@ const Dashboard = ({
<div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}> <div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}>
<div className="container-fluid full-width"> <div className="container-fluid full-width">
{isEditMode ? <Visualizations/> : null} {isEditMode ? <Visualizations/> : null}
{Dashboard.renderDashboard(dashboard, timeRange, source)} {Dashboard.renderDashboard(dashboard, timeRange, source, onPositionChange)}
</div> </div>
</div> </div>
) )
} }
Dashboard.renderDashboard = (dashboard, timeRange, source) => { Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => {
const autoRefreshMs = 15000 const autoRefreshMs = 15000
const cellWidth = 4
const cellHeight = 4
const pageWidth = 12
const cells = dashboard.cells.map((cell, i) => { const cells = dashboard.cells.map((cell, i) => {
const cellCount = i + 1; i = `${i}`
const cellConversion = { const dashboardCell = {...cell, i}
w: cellWidth,
h: cellHeight,
x: (cellCount * cellWidth % pageWidth),
y: Math.floor(cellCount * cellWidth / pageWidth) * cellHeight,
i: i.toString(),
}
const dashboardCell = {...cell, ...cellConversion}
dashboardCell.queries.forEach((q) => { dashboardCell.queries.forEach((q) => {
q.text = q.query; q.text = q.query;
q.database = source.telegraf; q.database = source.telegraf;
@ -55,12 +44,14 @@ Dashboard.renderDashboard = (dashboard, timeRange, source) => {
cells={cells} cells={cells}
autoRefreshMs={autoRefreshMs} autoRefreshMs={autoRefreshMs}
source={source.links.proxy} source={source.links.proxy}
onPositionChange={onPositionChange}
/> />
) )
} }
const { const {
bool, bool,
func,
shape, shape,
string, string,
} = PropTypes } = PropTypes
@ -69,6 +60,7 @@ Dashboard.propTypes = {
dashboard: shape({}).isRequired, dashboard: shape({}).isRequired,
isEditMode: bool, isEditMode: bool,
inPresentationMode: bool, inPresentationMode: bool,
onPositionChange: func,
source: shape({ source: shape({
links: shape({ links: shape({
proxy: string, proxy: string,

View File

@ -1,14 +1,15 @@
import React, {PropTypes} from 'react'; import React, {PropTypes} from 'react'
import {Link} from 'react-router'; import {Link} from 'react-router'
import {connect} from 'react-redux' import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'; import {bindActionCreators} from 'redux'
import Header from 'src/dashboards/components/DashboardHeader'; import Header from 'src/dashboards/components/DashboardHeader'
import EditHeader from 'src/dashboards/components/DashboardHeaderEdit'; import EditHeader from 'src/dashboards/components/DashboardHeaderEdit'
import Dashboard from 'src/dashboards/components/Dashboard'; import Dashboard from 'src/dashboards/components/Dashboard'
import timeRanges from 'hson!../../shared/data/timeRanges.hson'; import timeRanges from 'hson!../../shared/data/timeRanges.hson'
import * as dashboardActionCreators from 'src/dashboards/actions'; import {updateDashboardPosition} from 'src/dashboards/apis'
import * as dashboardActionCreators from 'src/dashboards/actions'
import {presentationButtonDispatcher} from 'shared/dispatchers' import {presentationButtonDispatcher} from 'shared/dispatchers'
@ -86,6 +87,10 @@ const DashboardPage = React.createClass({
this.props.dashboardActions.setTimeRange(timeRange) this.props.dashboardActions.setTimeRange(timeRange)
}, },
handleUpdatePosition(cells) {
updateDashboardPosition({...this.props.dashboard, cells})
},
render() { render() {
const { const {
dashboards, dashboards,
@ -129,6 +134,7 @@ const DashboardPage = React.createClass({
inPresentationMode={inPresentationMode} inPresentationMode={inPresentationMode}
source={source} source={source}
timeRange={timeRange} timeRange={timeRange}
onPositionChange={this.handleUpdatePosition}
/> />
</div> </div>
); );

View File

@ -10,8 +10,8 @@ const RefreshingLineGraph = AutoRefresh(LineGraph);
const RefreshingSingleStat = AutoRefresh(SingleStat); const RefreshingSingleStat = AutoRefresh(SingleStat);
const { const {
children,
arrayOf, arrayOf,
func,
node, node,
number, number,
shape, shape,
@ -51,6 +51,7 @@ export const LayoutRenderer = React.createClass({
autoRefreshMs: number.isRequired, autoRefreshMs: number.isRequired,
host: string, host: string,
source: string, source: string,
onPositionChange: func,
}, },
getInitialState() { getInitialState() {
@ -121,6 +122,17 @@ export const LayoutRenderer = React.createClass({
}); });
}, },
handleLayoutChange(layout) {
this.triggerWindowResize()
const newCells = this.props.cells.map((cell) => {
const l = layout.find((ly) => ly.i === cell.i)
const newLayout = {x: l.x, y: l.y, h: l.h, w: l.w}
return {...cell, ...newLayout}
})
this.props.onPositionChange(newCells)
},
render() { render() {
const layoutMargin = 4; const layoutMargin = 4;
return ( return (
@ -131,19 +143,20 @@ export const LayoutRenderer = React.createClass({
margin={[layoutMargin, layoutMargin]} margin={[layoutMargin, layoutMargin]}
containerPadding={[0, 0]} containerPadding={[0, 0]}
useCSSTransforms={false} useCSSTransforms={false}
onResize={triggerWindowResize} onResize={this.triggerWindowResize}
onLayoutChange={triggerWindowResize} onLayoutChange={this.handleLayoutChange}
> >
{this.generateVisualizations()} {this.generateVisualizations()}
</GridLayout> </GridLayout>
); );
},
function triggerWindowResize() {
// Hack to get dygraphs to fit properly during and after resize (dispatchEvent is a global method on window). triggerWindowResize() {
const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent' // Hack to get dygraphs to fit properly during and after resize (dispatchEvent is a global method on window).
evt.initCustomEvent('resize', false, false, null); const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'
dispatchEvent(evt); evt.initCustomEvent('resize', false, false, null);
} dispatchEvent(evt);
}, },
}); });