grid: minor progress

This commit is contained in:
Torkel Ödegaard 2017-10-10 09:34:14 +02:00
parent a867dc069b
commit 207773e07e
8 changed files with 176 additions and 145 deletions

View File

@ -0,0 +1,11 @@
export interface PanelModel {
id: number;
x: number;
y: number;
width: number;
height: number;
type: string;
title: string;
}

View File

@ -1,146 +1,148 @@
import config from 'app/core/config';
import angular from 'angular';
import coreModule from 'app/core/core_module';
import {PanelContainer} from './dashgrid/PanelContainer';
import {DashboardModel} from './model';
import {PanelModel} from './PanelModel';
export class DashboardCtrl {
export class DashboardCtrl implements PanelContainer {
dashboard: DashboardModel;
dashboardViewState: any;
loadedFallbackDashboard: boolean;
/** @ngInject */
constructor(
private $scope,
$rootScope,
keybindingSrv,
timeSrv,
variableSrv,
alertingSrv,
dashboardSrv,
unsavedChangesSrv,
dynamicDashboardSrv,
dashboardViewStateSrv,
panelLoader,
contextSrv,
alertSrv,
$timeout) {
private $rootScope,
private keybindingSrv,
private timeSrv,
private variableSrv,
private alertingSrv,
private dashboardSrv,
private unsavedChangesSrv,
private dynamicDashboardSrv,
private dashboardViewStateSrv,
private panelLoader) {
// temp hack due to way dashboards are loaded
// can't use controllerAs on route yet
$scope.ctrl = this;
$scope.editor = { index: 0 };
// funcs called from React component bindings and needs this binding
this.getPanelContainer = this.getPanelContainer.bind(this);
}
var resizeEventTimeout;
setupDashboard(data) {
try {
this.setupDashboardInternal(data);
} catch (err) {
this.onInitFailed(err, 'Dashboard init failed', true);
}
}
$scope.setupDashboard = function(data) {
try {
$scope.setupDashboardInternal(data);
} catch (err) {
$scope.onInitFailed(err, 'Dashboard init failed', true);
}
};
setupDashboardInternal(data) {
const dashboard = this.dashboardSrv.create(data.dashboard, data.meta);
this.dashboardSrv.setCurrent(dashboard);
$scope.setupDashboardInternal = function(data) {
var dashboard = dashboardSrv.create(data.dashboard, data.meta);
dashboardSrv.setCurrent(dashboard);
// init services
this.timeSrv.init(dashboard);
this.alertingSrv.init(dashboard, data.alerts);
// init services
timeSrv.init(dashboard);
alertingSrv.init(dashboard, data.alerts);
// template values service needs to initialize completely before
// the rest of the dashboard can load
this.variableSrv.init(dashboard)
// template values failes are non fatal
.catch(this.onInitFailed.bind(this, 'Templating init failed', false))
// continue
.finally(() => {
this.dashboard = dashboard;
// template values service needs to initialize completely before
// the rest of the dashboard can load
variableSrv.init(dashboard)
// template values failes are non fatal
.catch($scope.onInitFailed.bind(this, 'Templating init failed', false))
// continue
.finally(function() {
dynamicDashboardSrv.init(dashboard);
dynamicDashboardSrv.process();
this.dynamicDashboardSrv.init(dashboard);
this.dynamicDashboardSrv.process();
unsavedChangesSrv.init(dashboard, $scope);
this.unsavedChangesSrv.init(dashboard, this.$scope);
$scope.dashboard = dashboard;
$scope.dashboardMeta = dashboard.meta;
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
// TODO refactor ViewStateSrv
this.$scope.dashboard = dashboard;
this.dashboardViewState = this.dashboardViewStateSrv.create(this.$scope);
keybindingSrv.setupDashboardBindings($scope, dashboard);
this.keybindingSrv.setupDashboardBindings(this.$scope, dashboard);
$scope.dashboard.updateSubmenuVisibility();
$scope.setWindowTitleAndTheme();
this.dashboard.updateSubmenuVisibility();
this.setWindowTitleAndTheme();
$scope.appEvent("dashboard-initialized", $scope.dashboard);
})
.catch($scope.onInitFailed.bind(this, 'Dashboard init failed', true));
};
this.$scope.appEvent("dashboard-initialized", dashboard);
})
.catch(this.onInitFailed.bind(this, 'Dashboard init failed', true));
}
$scope.onInitFailed = function(msg, fatal, err) {
console.log(msg, err);
onInitFailed(msg, fatal, err) {
console.log(msg, err);
if (err.data && err.data.message) {
err.message = err.data.message;
} else if (!err.message) {
err = {message: err.toString()};
}
if (err.data && err.data.message) {
err.message = err.data.message;
} else if (!err.message) {
err = {message: err.toString()};
}
$scope.appEvent("alert-error", [msg, err.message]);
this.$scope.appEvent("alert-error", [msg, err.message]);
// protect against recursive fallbacks
if (fatal && !$scope.loadedFallbackDashboard) {
$scope.loadedFallbackDashboard = true;
$scope.setupDashboard({dashboard: {title: 'Dashboard Init failed'}});
}
};
// protect against recursive fallbacks
if (fatal && !this.loadedFallbackDashboard) {
this.loadedFallbackDashboard = true;
this.setupDashboard({dashboard: {title: 'Dashboard Init failed'}});
}
}
$scope.templateVariableUpdated = function() {
dynamicDashboardSrv.process();
};
templateVariableUpdated() {
this.dynamicDashboardSrv.process();
}
$scope.setWindowTitleAndTheme = function() {
window.document.title = config.window_title_prefix + $scope.dashboard.title;
};
setWindowTitleAndTheme() {
window.document.title = config.window_title_prefix + this.dashboard.title;
}
$scope.broadcastRefresh = function() {
$rootScope.$broadcast('refresh');
};
showJsonEditor(evt, options) {
var editScope = this.$rootScope.$new();
editScope.object = options.object;
editScope.updateHandler = options.updateHandler;
this.$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope });
}
$scope.addRowDefault = function() {
$scope.dashboard.addEmptyRow();
};
getDashboard() {
return this.dashboard;
}
$scope.showJsonEditor = function(evt, options) {
var editScope = $rootScope.$new();
editScope.object = options.object;
editScope.updateHandler = options.updateHandler;
$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope });
};
getPanelLoader() {
return this.panelLoader;
}
$scope.registerWindowResizeEvent = function() {
angular.element(window).bind('resize', function() {
$timeout.cancel(resizeEventTimeout);
resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200);
});
getPanels() {
return this.dashboard.panels;
}
$scope.$on('$destroy', function() {
angular.element(window).unbind('resize');
$scope.dashboard.destroy();
});
};
panelPossitionUpdated(panel: PanelModel) {
console.log('panel pos updated', panel);
}
$scope.timezoneChanged = function() {
$rootScope.$broadcast("refresh");
};
timezoneChanged() {
this.$rootScope.$broadcast("refresh");
}
$scope.onFolderChange = function(folder) {
$scope.dashboard.folderId = folder.id;
$scope.dashboard.meta.folderId = folder.id;
$scope.dashboard.meta.folderTitle= folder.title;
};
onFolderChange(folder) {
this.dashboard.folderId = folder.id;
this.dashboard.meta.folderId = folder.id;
this.dashboard.meta.folderTitle= folder.title;
}
$scope.getPanelLoader = function() {
return panelLoader;
};
getPanelContainer() {
console.log('DashboardCtrl:getPanelContainer()');
return this;
}
init(dashboard) {
this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor);
this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated);
this.$scope.setupDashboard(dashboard);
this.$scope.registerWindowResizeEvent();
this.setupDashboard(dashboard);
}
}

View File

@ -1,13 +1,12 @@
import React from 'react';
import coreModule from 'app/core/core_module';
import ReactGridLayout from 'react-grid-layout';
import {DashboardModel} from '../model';
import {CELL_HEIGHT, CELL_VMARGIN} from '../model';
import {DashboardPanel} from './DashboardPanel';
import {PanelLoader} from './PanelLoader';
import {PanelContainer} from './PanelContainer';
import sizeMe from 'react-sizeme';
const COLUMN_COUNT = 12;
const ROW_HEIGHT = 30;
function GridWrapper({size, layout, onLayoutChange, children}) {
if (size.width === 0) {
@ -23,9 +22,9 @@ function GridWrapper({size, layout, onLayoutChange, children}) {
isDraggable={true}
isResizable={true}
measureBeforeMount={false}
margin={[10, 10]}
margin={[CELL_VMARGIN, CELL_VMARGIN]}
cols={COLUMN_COUNT}
rowHeight={ROW_HEIGHT}
rowHeight={CELL_HEIGHT}
draggableHandle=".grid-drag-handle"
layout={layout}
onLayoutChange={onLayoutChange}>
@ -37,21 +36,24 @@ function GridWrapper({size, layout, onLayoutChange, children}) {
const SizedReactLayoutGrid = sizeMe({monitorWidth: true})(GridWrapper);
export interface DashboardGridProps {
dashboard: DashboardModel;
getPanelLoader: () => PanelLoader;
getPanelContainer: () => PanelContainer;
}
export class DashboardGrid extends React.Component<DashboardGridProps, any> {
gridToPanelMap: any;
panelContainer: PanelContainer;
constructor(props) {
super(props);
this.panelContainer = this.props.getPanelContainer();
this.onLayoutChange = this.onLayoutChange.bind(this);
}
buildLayout() {
const layout = [];
for (let panel of this.props.dashboard.panels) {
const panels = this.panelContainer.getPanels();
for (let panel of panels) {
layout.push({
i: panel.id.toString(),
x: panel.x,
@ -60,21 +62,28 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
h: panel.height,
});
}
console.log(layout);
console.log('layout', layout);
return layout;
}
onLayoutChange() {}
renderPanels() {
const panels = this.panelContainer.getPanels();
const panelElements = [];
for (let panel of this.props.dashboard.panels) {
for (let panel of panels) {
panelElements.push(
<div key={panel.id.toString()} className="panel">
<DashboardPanel panel={panel} getPanelLoader={this.props.getPanelLoader} dashboard={this.props.dashboard} />
<DashboardPanel
panel={panel}
getPanelContainer={this.props.getPanelContainer}
/>
</div>,
);
}
return panelElements;
}
@ -88,8 +97,5 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
}
coreModule.directive('dashboardGrid', function(reactDirective) {
return reactDirective(DashboardGrid, [
['dashboard', {watchDepth: 'reference'}],
['getPanelLoader', {watchDepth: 'reference', wrapApply: false}],
]);
return reactDirective(DashboardGrid, [['getPanelContainer', {watchDepth: 'reference', wrapApply: false}]]);
});

View File

@ -1,14 +1,16 @@
import React from 'react';
import {PanelLoader} from './PanelLoader';
import {PanelModel} from '../PanelModel';
import {PanelContainer} from './PanelContainer';
import {AttachedPanel} from './PanelLoader';
export interface DashboardPanelProps {
panel: any;
dashboard: any;
getPanelLoader: () => PanelLoader;
panel: PanelModel;
getPanelContainer: () => PanelContainer;
}
export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
private element: any;
element: any;
attachedPanel: AttachedPanel;
constructor(props) {
super(props);
@ -16,8 +18,17 @@ export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
}
componentDidMount() {
var loader = this.props.getPanelLoader();
loader.load(this.element, this.props.panel, this.props.dashboard);
const panelContainer = this.props.getPanelContainer();
const dashboard = panelContainer.getDashboard();
const loader = panelContainer.getPanelLoader();
this.attachedPanel = loader.load(this.element, this.props.panel, dashboard);
}
componentWillUnmount() {
if (this.attachedPanel) {
this.attachedPanel.destroy();
}
}
render() {

View File

@ -0,0 +1,11 @@
import {PanelModel} from '../PanelModel';
import {DashboardModel}  from '../model';
import {PanelLoader} from './PanelLoader';
export interface PanelContainer {
getPanels(): PanelModel[];
getPanelLoader(): PanelLoader;
getDashboard(): DashboardModel;
panelPossitionUpdated(panel: PanelModel);
}

View File

@ -23,6 +23,7 @@ export class PanelLoader {
return {
destroy: () => {
console.log('AttachedPanel:Destroy, id' + panel.id);
panelScope.$destroy();
compiledElem.remove();
}

View File

@ -1,5 +1,3 @@
///<reference path="../../headers/common.d.ts" />
import angular from 'angular';
import moment from 'moment';
import _ from 'lodash';
@ -8,18 +6,9 @@ import $ from 'jquery';
import {DEFAULT_ANNOTATION_COLOR} from 'app/core/utils/colors';
import {Emitter, contextSrv, appEvents} from 'app/core/core';
import {DashboardRow} from './row/row_model';
import {PanelModel} from './PanelModel';
import sortByKeys from 'app/core/utils/sort_by_keys';
export interface Panel {
id: number;
x: number;
y: number;
width: number;
height: number;
type: string;
title: string;
}
export const CELL_HEIGHT = 30;
export const CELL_VMARGIN = 15;
@ -50,7 +39,7 @@ export class DashboardModel {
events: any;
editMode: boolean;
folderId: number;
panels: Panel[];
panels: PanelModel[];
constructor(data, meta?) {
if (!data) {

View File

@ -1,15 +1,15 @@
<div dash-class ng-if="dashboard">
<dashnav dashboard="dashboard"></dashnav>
<div dash-class ng-if="ctrl.dashboard">
<dashnav dashboard="ctrl.dashboard"></dashnav>
<div class="scroll-canvas scroll-canvas--dashboard">
<div gemini-scrollbar>
<div dash-editor-view class="dash-edit-view"></div>
<div class="dashboard-container">
<dashboard-submenu ng-if="dashboard.meta.submenuEnabled" dashboard="dashboard"></dashboard-submenu>
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
</dashboard-submenu>
<!-- <dash&#45;grid dashboard="dashboard"></dash&#45;grid> -->
<dashboard-grid dashboard="dashboard" get-panel-loader="getPanelLoader">
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
</dashboard-grid>
</div>