Commit 2e77bd0c by Torkel Ödegaard

grid: progress on react grid

parent 10a35043
...@@ -123,7 +123,7 @@ function ($, angular, coreModule, _) { ...@@ -123,7 +123,7 @@ function ($, angular, coreModule, _) {
}, 10); }, 10);
} }
scope.$watch("dashboardViewState.state.editview", function(newValue, oldValue) { scope.$watch("ctrl.dashboardViewState.state.editview", function(newValue, oldValue) {
if (newValue) { if (newValue) {
showEditorPane(null, {editview: newValue}); showEditorPane(null, {editview: newValue});
} else if (oldValue) { } else if (oldValue) {
......
...@@ -8,7 +8,6 @@ export interface GridPos { ...@@ -8,7 +8,6 @@ export interface GridPos {
} }
const notPersistedProperties: {[str: string]: boolean} = { const notPersistedProperties: {[str: string]: boolean} = {
"model": true,
"events": true, "events": true,
}; };
...@@ -19,26 +18,26 @@ export class PanelModel { ...@@ -19,26 +18,26 @@ export class PanelModel {
title: string; title: string;
events: Emitter; events: Emitter;
constructor(private model) { constructor(model) {
this.events = new Emitter();
// copy properties from persisted model // copy properties from persisted model
for (var property in model) { for (var property in model) {
this[property] = model[property]; this[property] = model[property];
} }
this.events = new Emitter();
} }
getSaveModel() { getSaveModel() {
this.model = {}; const model: any = {};
for (var property in this) { for (var property in this) {
if (notPersistedProperties[property] || !this.hasOwnProperty(property)) { if (notPersistedProperties[property] || !this.hasOwnProperty(property)) {
console.log('PanelModel.getSaveModel() skiping property', property);
continue; continue;
} }
this.model[property] = this[property]; model[property] = this[property];
} }
return this.model;
return model;
} }
updateGridPos(newPos: GridPos) { updateGridPos(newPos: GridPos) {
......
...@@ -25,6 +25,7 @@ define([ ...@@ -25,6 +25,7 @@ define([
'./repeat_option/repeat_option', './repeat_option/repeat_option',
'./dashgrid/DashboardGrid', './dashgrid/DashboardGrid',
'./dashgrid/PanelLoader', './dashgrid/PanelLoader',
'./row/add_panel',
'./acl/acl', './acl/acl',
'./folder_picker/picker', './folder_picker/picker',
'./folder_modal/folder' './folder_modal/folder'
......
...@@ -3,12 +3,12 @@ import config from 'app/core/config'; ...@@ -3,12 +3,12 @@ import config from 'app/core/config';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import {PanelContainer} from './dashgrid/PanelContainer'; import {PanelContainer} from './dashgrid/PanelContainer';
import {DashboardModel} from './model'; import {DashboardModel} from './model';
import {PanelModel} from './PanelModel';
export class DashboardCtrl implements PanelContainer { export class DashboardCtrl implements PanelContainer {
dashboard: DashboardModel; dashboard: DashboardModel;
dashboardViewState: any; dashboardViewState: any;
loadedFallbackDashboard: boolean; loadedFallbackDashboard: boolean;
editTab: number;
/** @ngInject */ /** @ngInject */
constructor( constructor(
...@@ -27,6 +27,9 @@ export class DashboardCtrl implements PanelContainer { ...@@ -27,6 +27,9 @@ export class DashboardCtrl implements PanelContainer {
// can't use controllerAs on route yet // can't use controllerAs on route yet
$scope.ctrl = this; $scope.ctrl = this;
// TODO: break out settings view to separate view & controller
this.editTab = 0;
// funcs called from React component bindings and needs this binding // funcs called from React component bindings and needs this binding
this.getPanelContainer = this.getPanelContainer.bind(this); this.getPanelContainer = this.getPanelContainer.bind(this);
} }
...@@ -116,15 +119,6 @@ export class DashboardCtrl implements PanelContainer { ...@@ -116,15 +119,6 @@ export class DashboardCtrl implements PanelContainer {
return this.panelLoader; return this.panelLoader;
} }
getPanels() {
return this.dashboard.panels;
}
panelPossitionUpdated(panel: PanelModel) {
//console.log('panel pos updated', panel);
//this.$rootScope.$broadcast('render');
}
timezoneChanged() { timezoneChanged() {
this.$rootScope.$broadcast("refresh"); this.$rootScope.$broadcast("refresh");
} }
......
...@@ -3,13 +3,14 @@ import coreModule from 'app/core/core_module'; ...@@ -3,13 +3,14 @@ import coreModule from 'app/core/core_module';
import ReactGridLayout from 'react-grid-layout'; import ReactGridLayout from 'react-grid-layout';
import {CELL_HEIGHT, CELL_VMARGIN} from '../model'; import {CELL_HEIGHT, CELL_VMARGIN} from '../model';
import {DashboardPanel} from './DashboardPanel'; import {DashboardPanel} from './DashboardPanel';
import {DashboardModel} from '../model';
import {PanelContainer} from './PanelContainer'; import {PanelContainer} from './PanelContainer';
import {PanelModel} from '../PanelModel'; import {PanelModel} from '../PanelModel';
import sizeMe from 'react-sizeme'; import sizeMe from 'react-sizeme';
const COLUMN_COUNT = 12; const COLUMN_COUNT = 12;
function GridWrapper({size, layout, onLayoutChange, children}) { function GridWrapper({size, layout, onLayoutChange, children, onResize}) {
if (size.width === 0) { if (size.width === 0) {
console.log('size is zero!'); console.log('size is zero!');
} }
...@@ -30,6 +31,7 @@ function GridWrapper({size, layout, onLayoutChange, children}) { ...@@ -30,6 +31,7 @@ function GridWrapper({size, layout, onLayoutChange, children}) {
rowHeight={CELL_HEIGHT} rowHeight={CELL_HEIGHT}
draggableHandle=".grid-drag-handle" draggableHandle=".grid-drag-handle"
layout={layout} layout={layout}
onResize={onResize}
onLayoutChange={onLayoutChange}> onLayoutChange={onLayoutChange}>
{children} {children}
</ReactGridLayout> </ReactGridLayout>
...@@ -45,20 +47,25 @@ export interface DashboardGridProps { ...@@ -45,20 +47,25 @@ export interface DashboardGridProps {
export class DashboardGrid extends React.Component<DashboardGridProps, any> { export class DashboardGrid extends React.Component<DashboardGridProps, any> {
gridToPanelMap: any; gridToPanelMap: any;
panelContainer: PanelContainer; panelContainer: PanelContainer;
dashboard: DashboardModel;
panelMap: {[id: string]: PanelModel}; panelMap: {[id: string]: PanelModel};
constructor(props) { constructor(props) {
super(props); super(props);
this.panelContainer = this.props.getPanelContainer(); this.panelContainer = this.props.getPanelContainer();
this.onLayoutChange = this.onLayoutChange.bind(this); this.onLayoutChange = this.onLayoutChange.bind(this);
this.onResize = this.onResize.bind(this);
// subscribe to dashboard events
this.dashboard = this.panelContainer.getDashboard();
this.dashboard.on('panel-added', this.panelAdded.bind(this));
} }
buildLayout() { buildLayout() {
const layout = []; const layout = [];
const panels = this.panelContainer.getPanels();
this.panelMap = {}; this.panelMap = {};
for (let panel of panels) { for (let panel of this.dashboard.panels) {
let stringId = panel.id.toString(); let stringId = panel.id.toString();
this.panelMap[stringId] = panel; this.panelMap[stringId] = panel;
...@@ -85,11 +92,18 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> { ...@@ -85,11 +92,18 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
} }
} }
panelAdded() {
this.forceUpdate();
}
onResize(layout, oldItem, newItem) {
this.panelMap[newItem.i].updateGridPos(newItem);
}
renderPanels() { renderPanels() {
const panels = this.panelContainer.getPanels();
const panelElements = []; const panelElements = [];
for (let panel of panels) { for (let panel of this.dashboard.panels) {
panelElements.push( panelElements.push(
<div key={panel.id.toString()} className="panel"> <div key={panel.id.toString()} className="panel">
<DashboardPanel panel={panel} getPanelContainer={this.props.getPanelContainer} /> <DashboardPanel panel={panel} getPanelContainer={this.props.getPanelContainer} />
...@@ -101,8 +115,9 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> { ...@@ -101,8 +115,9 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
} }
render() { render() {
console.log('DashboardGrid.render()');
return ( return (
<SizedReactLayoutGrid layout={this.buildLayout()} onLayoutChange={this.onLayoutChange}> <SizedReactLayoutGrid layout={this.buildLayout()} onLayoutChange={this.onLayoutChange} onResize={this.onResize}>
{this.renderPanels()} {this.renderPanels()}
</SizedReactLayoutGrid> </SizedReactLayoutGrid>
); );
......
import {PanelModel} from '../PanelModel';
import {DashboardModel}  from '../model'; import {DashboardModel}  from '../model';
import {PanelLoader} from './PanelLoader'; import {PanelLoader} from './PanelLoader';
export interface PanelContainer { export interface PanelContainer {
getPanels(): PanelModel[];
getPanelLoader(): PanelLoader; getPanelLoader(): PanelLoader;
getDashboard(): DashboardModel; getDashboard(): DashboardModel;
panelPossitionUpdated(panel: PanelModel);
} }
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
</ul> </ul>
</li> </li>
<li class="navbar-mini-btn-wrapper" ng-show="::ctrl.dashboard.meta.canSave"> <li class="navbar-mini-btn-wrapper" ng-show="::ctrl.dashboard.meta.canSave">
<button class="btn btn-secondary btn-mini" ng-click="ctrl.openEditView('add-panel')"> <button class="btn btn-secondary btn-mini" ng-click="ctrl.addPanel()">
<i class="fa fa-plus-circle"></i> Add Panel <i class="fa fa-plus-circle"></i> Add Panel
</button> </button>
</li> </li>
......
...@@ -145,6 +145,14 @@ export class DashNavCtrl { ...@@ -145,6 +145,14 @@ export class DashNavCtrl {
this.$rootScope.appEvent('show-dash-search'); this.$rootScope.appEvent('show-dash-search');
} }
addPanel() {
this.dashboard.addPanel({
type: 'graph',
gridPos: {x: 0, y: 0, w: 6, h: 5},
title: 'New Graph',
});
}
navItemClicked(navItem, evt) { navItemClicked(navItem, evt) {
if (navItem.clickHandler) { if (navItem.clickHandler) {
navItem.clickHandler(); navItem.clickHandler();
......
...@@ -180,7 +180,8 @@ export class DashboardModel { ...@@ -180,7 +180,8 @@ export class DashboardModel {
addPanel(panel) { addPanel(panel) {
panel.id = this.getNextPanelId(); panel.id = this.getNextPanelId();
this.panels.push(panel); this.panels.unshift(new PanelModel(panel));
this.events.emit('panel-added', panel);
} }
removePanel(panel, ask?) { removePanel(panel, ask?) {
...@@ -282,6 +283,14 @@ export class DashboardModel { ...@@ -282,6 +283,14 @@ export class DashboardModel {
} }
} }
on(eventName, callback) {
this.events.on(eventName, callback);
}
off(eventName, callback?) {
this.events.off(eventName, callback);
}
cycleGraphTooltip() { cycleGraphTooltip() {
this.graphTooltip = (this.graphTooltip + 1) % 3; this.graphTooltip = (this.graphTooltip + 1) % 3;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<ul class="gf-tabs"> <ul class="gf-tabs">
<li class="gf-tabs-item" ng-repeat="tab in ::['General', 'Links', 'Time picker']"> <li class="gf-tabs-item" ng-repeat="tab in ::['General', 'Links', 'Time picker']">
<a class="gf-tabs-link" ng-click="editor.index = $index" ng-class="{active: editor.index === $index}"> <a class="gf-tabs-link" ng-click="ctrl.editTab = $index" ng-class="{active: ctrl.editTab === $index}">
{{::tab}} {{::tab}}
</a> </a>
</li> </li>
...@@ -17,30 +17,30 @@ ...@@ -17,30 +17,30 @@
</div> </div>
<div class="tabbed-view-body"> <div class="tabbed-view-body">
<div ng-if="editor.index == 0"> <div ng-if="ctrl.editTab == 0">
<div class="gf-form-group section"> <div class="gf-form-group section">
<h5 class="section-heading">Details</h5> <h5 class="section-heading">Details</h5>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-7">Name</label> <label class="gf-form-label width-7">Name</label>
<input type="text" class="gf-form-input width-30" ng-model='dashboard.title'></input> <input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.title'></input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-7">Description</label> <label class="gf-form-label width-7">Description</label>
<input type="text" class="gf-form-input width-30" ng-model='dashboard.description'></input> <input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.description'></input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-7"> <label class="gf-form-label width-7">
Tags Tags
<info-popover mode="right-normal">Press enter to add a tag</info-popover> <info-popover mode="right-normal">Press enter to add a tag</info-popover>
</label> </label>
<bootstrap-tagsinput ng-model="dashboard.tags" tagclass="label label-tag" placeholder="add tags"> <bootstrap-tagsinput ng-model="ctrl.dashboard.tags" tagclass="label label-tag" placeholder="add tags">
</bootstrap-tagsinput> </bootstrap-tagsinput>
</div> </div>
<folder-picker ng-if="!dashboardMeta.isFolder" <folder-picker ng-if="!ctrl.dashboard.meta.isFolder"
initial-title="dashboardMeta.folderTitle" initial-title="ctrl.dashboard.meta.folderTitle"
on-change="onFolderChange($folder)" on-change="ctrl.onFolderChange($folder)"
label-class="width-7"> label-class="width-7">
</folder-picker> </folder-picker>
</div> </div>
...@@ -51,19 +51,19 @@ ...@@ -51,19 +51,19 @@
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-11">Timezone</label> <label class="gf-form-label width-11">Timezone</label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select ng-model="dashboard.timezone" class='gf-form-input' ng-options="f.value as f.text for f in [{value: '', text: 'Default'}, {value: 'browser', text: 'Local browser time'},{value: 'utc', text: 'UTC'}]" ng-change="timezoneChanged()"></select> <select ng-model="ctrl.dashboard.timezone" class='gf-form-input' ng-options="f.value as f.text for f in [{value: '', text: 'Default'}, {value: 'browser', text: 'Local browser time'},{value: 'utc', text: 'UTC'}]" ng-change="timezoneChanged()"></select>
</div> </div>
</div> </div>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Editable" label="Editable"
tooltip="Uncheck, then save and reload to disable all dashboard editing" tooltip="Uncheck, then save and reload to disable all dashboard editing"
checked="dashboard.editable" checked="ctrl.dashboard.editable"
label-class="width-11"> label-class="width-11">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Hide Controls" label="Hide Controls"
tooltip="Hide row controls. Shortcut: CTRL+H or CMD+H" tooltip="Hide row controls. Shortcut: CTRL+H or CMD+H"
checked="dashboard.hideControls" checked="ctrl.dashboard.hideControls"
label-class="width-11"> label-class="width-11">
</gf-form-switch> </gf-form-switch>
</div> </div>
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
</info-popover> </info-popover>
</label> </label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select ng-model="dashboard.graphTooltip" class='gf-form-input' ng-options="f.value as f.text for f in [{value: 0, text: 'Default'}, {value: 1, text: 'Shared crosshair'},{value: 2, text: 'Shared Tooltip'}]"></select> <select ng-model="ctrl.dashboard.graphTooltip" class='gf-form-input' ng-options="f.value as f.text for f in [{value: 0, text: 'Default'}, {value: 1, text: 'Shared crosshair'},{value: 2, text: 'Shared Tooltip'}]"></select>
</div> </div>
</div> </div>
</div> </div>
...@@ -90,7 +90,7 @@ ...@@ -90,7 +90,7 @@
</div> </div>
<div ng-if="editor.index == 2"> <div ng-if="editor.index == 2">
<gf-time-picker-settings dashboard="dashboard"></gf-time-picker-settings> <gf-time-picker-settings dashboard="ctrl.dashboard"></gf-time-picker-settings>
</div> </div>
</div> </div>
...@@ -178,7 +178,7 @@ export class PanelCtrl { ...@@ -178,7 +178,7 @@ export class PanelCtrl {
this.calculatePanelHeight(); this.calculatePanelHeight();
this.$timeout(() => { this.$timeout(() => {
this.render(); this.render();
}); }, 100);
} }
duplicate() { duplicate() {
......
...@@ -105,9 +105,9 @@ $tight-form-bg: $dark-3; ...@@ -105,9 +105,9 @@ $tight-form-bg: $dark-3;
$tight-form-func-bg: #333; $tight-form-func-bg: #333;
$tight-form-func-highlight-bg: #444; $tight-form-func-highlight-bg: #444;
$modal-background: $black; $modal-backdrop-bg: $dark-3;
$code-tag-bg: $gray-1; $code-tag-bg: $gray-1;
$code-tag-border: lighten($code-tag-bg, 2%); $code-tag-border: lighten($code-tag-bg, 2%);
// Lists // Lists
......
...@@ -112,9 +112,9 @@ $tight-form-bg: $gray-6; ...@@ -112,9 +112,9 @@ $tight-form-bg: $gray-6;
$tight-form-func-bg: $gray-5; $tight-form-func-bg: $gray-5;
$tight-form-func-highlight-bg: $gray-6; $tight-form-func-highlight-bg: $gray-6;
$modal-background: $body-bg; $modal-backdrop-bg: $body-bg;
$code-tag-bg: $gray-6; $code-tag-bg: $gray-6;
$code-tag-border: darken($code-tag-bg, 3%); $code-tag-border: darken($code-tag-bg, 3%);
// Lists // Lists
$grafanaListBackground: $gray-6; $grafanaListBackground: $gray-6;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: $zindex-modal-backdrop; z-index: $zindex-modal-backdrop;
background-color: $black; background-color: $modal-backdrop-bg;
} }
.modal-backdrop, .modal-backdrop,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment