WIP persist dashboard position to server
parent
0d0a3e1e54
commit
d3c1f6c31a
|
@ -6,3 +6,11 @@ export function getDashboards() {
|
|||
url: `/chronograf/v1/dashboards`,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateDashboardPosition(dashboard) {
|
||||
return AJAX({
|
||||
method: 'PUT',
|
||||
url: dashboard.links.self,
|
||||
data: dashboard,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ const Dashboard = ({
|
|||
dashboard,
|
||||
isEditMode,
|
||||
inPresentationMode,
|
||||
onPositionChange,
|
||||
source,
|
||||
timeRange,
|
||||
}) => {
|
||||
|
@ -19,29 +20,17 @@ const Dashboard = ({
|
|||
<div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}>
|
||||
<div className="container-fluid full-width">
|
||||
{isEditMode ? <Visualizations/> : null}
|
||||
{Dashboard.renderDashboard(dashboard, timeRange, source)}
|
||||
{Dashboard.renderDashboard(dashboard, timeRange, source, onPositionChange)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Dashboard.renderDashboard = (dashboard, timeRange, source) => {
|
||||
Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => {
|
||||
const autoRefreshMs = 15000
|
||||
const cellWidth = 4
|
||||
const cellHeight = 4
|
||||
const pageWidth = 12
|
||||
|
||||
const cells = dashboard.cells.map((cell, i) => {
|
||||
const cellCount = i + 1;
|
||||
const cellConversion = {
|
||||
w: cellWidth,
|
||||
h: cellHeight,
|
||||
x: (cellCount * cellWidth % pageWidth),
|
||||
y: Math.floor(cellCount * cellWidth / pageWidth) * cellHeight,
|
||||
i: i.toString(),
|
||||
}
|
||||
|
||||
const dashboardCell = {...cell, ...cellConversion}
|
||||
i = `${i}`
|
||||
const dashboardCell = {...cell, i}
|
||||
dashboardCell.queries.forEach((q) => {
|
||||
q.text = q.query;
|
||||
q.database = source.telegraf;
|
||||
|
@ -55,12 +44,14 @@ Dashboard.renderDashboard = (dashboard, timeRange, source) => {
|
|||
cells={cells}
|
||||
autoRefreshMs={autoRefreshMs}
|
||||
source={source.links.proxy}
|
||||
onPositionChange={onPositionChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const {
|
||||
bool,
|
||||
func,
|
||||
shape,
|
||||
string,
|
||||
} = PropTypes
|
||||
|
@ -69,6 +60,7 @@ Dashboard.propTypes = {
|
|||
dashboard: shape({}).isRequired,
|
||||
isEditMode: bool,
|
||||
inPresentationMode: bool,
|
||||
onPositionChange: func,
|
||||
source: shape({
|
||||
links: shape({
|
||||
proxy: string,
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import {Link} from 'react-router';
|
||||
import React, {PropTypes} from 'react'
|
||||
import {Link} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {bindActionCreators} from 'redux'
|
||||
|
||||
import Header from 'src/dashboards/components/DashboardHeader';
|
||||
import EditHeader from 'src/dashboards/components/DashboardHeaderEdit';
|
||||
import Dashboard from 'src/dashboards/components/Dashboard';
|
||||
import timeRanges from 'hson!../../shared/data/timeRanges.hson';
|
||||
import Header from 'src/dashboards/components/DashboardHeader'
|
||||
import EditHeader from 'src/dashboards/components/DashboardHeaderEdit'
|
||||
import Dashboard from 'src/dashboards/components/Dashboard'
|
||||
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'
|
||||
|
||||
|
@ -86,6 +87,10 @@ const DashboardPage = React.createClass({
|
|||
this.props.dashboardActions.setTimeRange(timeRange)
|
||||
},
|
||||
|
||||
handleUpdatePosition(cells) {
|
||||
updateDashboardPosition({...this.props.dashboard, cells})
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
dashboards,
|
||||
|
@ -129,6 +134,7 @@ const DashboardPage = React.createClass({
|
|||
inPresentationMode={inPresentationMode}
|
||||
source={source}
|
||||
timeRange={timeRange}
|
||||
onPositionChange={this.handleUpdatePosition}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ const RefreshingLineGraph = AutoRefresh(LineGraph);
|
|||
const RefreshingSingleStat = AutoRefresh(SingleStat);
|
||||
|
||||
const {
|
||||
children,
|
||||
arrayOf,
|
||||
func,
|
||||
node,
|
||||
number,
|
||||
shape,
|
||||
|
@ -51,6 +51,7 @@ export const LayoutRenderer = React.createClass({
|
|||
autoRefreshMs: number.isRequired,
|
||||
host: string,
|
||||
source: string,
|
||||
onPositionChange: func,
|
||||
},
|
||||
|
||||
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() {
|
||||
const layoutMargin = 4;
|
||||
return (
|
||||
|
@ -131,19 +143,20 @@ export const LayoutRenderer = React.createClass({
|
|||
margin={[layoutMargin, layoutMargin]}
|
||||
containerPadding={[0, 0]}
|
||||
useCSSTransforms={false}
|
||||
onResize={triggerWindowResize}
|
||||
onLayoutChange={triggerWindowResize}
|
||||
onResize={this.triggerWindowResize}
|
||||
onLayoutChange={this.handleLayoutChange}
|
||||
>
|
||||
{this.generateVisualizations()}
|
||||
</GridLayout>
|
||||
);
|
||||
},
|
||||
|
||||
function triggerWindowResize() {
|
||||
|
||||
triggerWindowResize() {
|
||||
// Hack to get dygraphs to fit properly during and after resize (dispatchEvent is a global method on window).
|
||||
const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'
|
||||
evt.initCustomEvent('resize', false, false, null);
|
||||
dispatchEvent(evt);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue