WIP persist dashboard position to server
parent
0d0a3e1e54
commit
d3c1f6c31a
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue