Commit 38f97d5c by Torkel Ödegaard

grid: worked on row options modal and row removal

parent df12cbc4
///<reference path="../headers/common.d.ts" />
import {Emitter} from './utils/emitter';
var appEvents = new Emitter();
......
......@@ -24,7 +24,8 @@ define([
'./repeat_option/repeat_option',
'./dashgrid/DashboardGrid',
'./dashgrid/PanelLoader',
'./row/add_panel',
'./dashgrid/RowOptions',
'./acl/acl',
'./acl/acl',
'./folder_picker/picker',
'./folder_modal/folder'
......
......@@ -7,7 +7,6 @@ import {Emitter} from 'app/core/utils/emitter';
import {contextSrv} from 'app/core/services/context_srv';
import sortByKeys from 'app/core/utils/sort_by_keys';
import {DashboardRow} from './row/row_model';
import {PanelModel} from './panel_model';
export class DashboardModel {
......@@ -20,7 +19,6 @@ export class DashboardModel {
timezone: any;
editable: any;
graphTooltip: any;
rows: DashboardRow[];
time: any;
timepicker: any;
hideControls: any;
......
import React from 'react';
import classNames from 'classnames';
import {PanelModel} from '../panel_model';
import {PanelContainer} from './PanelContainer';
import { PanelModel } from '../panel_model';
import { PanelContainer } from './PanelContainer';
import appEvents from 'app/core/app_events';
export interface DashboardRowProps {
......@@ -28,20 +28,49 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
dashboard.toggleRow(this.props.panel);
this.setState(prevState => {
return {collapsed: !prevState.collapsed};
return { collapsed: !prevState.collapsed };
});
}
openSettings() {
appEvents.emit('show-modal', {
src: 'public/app/features/dashboard/partials/shareModal.html',
scope: shareScope
templateHtml: `<row-options row="model.row" on-updated="model.onUpdated()" on-delete="model.onDelete()" dismiss="dismiss()"></row-options>`,
modalClass: 'modal--narrow',
model: {
row: this.props.panel,
onUpdated: this.forceUpdate.bind(this),
onDelete: this.onDelete.bind(this),
},
});
}
onDelete() {
let text2 = '';
if (this.props.panel.panels.length) {
text2 = 'This will also remove ' + this.props.panel.panels.length + ' panels';
}
appEvents.emit('confirm-modal', {
title: 'Delete Row',
text: 'Are you sure you want to remove this row?',
text2: text2,
icon: 'fa-trash',
onConfirm: () => {
const panelContainer = this.props.getPanelContainer();
const dashboard = panelContainer.getDashboard();
dashboard.removePanel(this.props.panel);
},
});
}
render() {
const classes = classNames({'dashboard-row': true, 'dashboard-row--collapsed': this.state.collapsed});
const chevronClass = classNames({'fa': true, 'fa-chevron-down': !this.state.collapsed, 'fa-chevron-right': this.state.collapsed});
const classes = classNames({ 'dashboard-row': true, 'dashboard-row--collapsed': this.state.collapsed });
const chevronClass = classNames({
fa: true,
'fa-chevron-down': !this.state.collapsed,
'fa-chevron-right': this.state.collapsed,
});
const hiddenPanels = this.props.panel.panels ? this.props.panel.panels.length : 0;
return (
......
///<reference path="../../../headers/common.d.ts" />
import {coreModule} from 'app/core/core';
// import VirtualScroll from 'virtual-scroll';
// console.log(VirtualScroll);
export class RowOptionsCtrl {
row: any;
dashboard: any;
rowCtrl: any;
fontSizes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
source: any;
dismiss: any;
onUpdated: any;
onDelete: any;
/** @ngInject */
constructor() {
this.row = this.rowCtrl.row;
this.dashboard = this.rowCtrl.dashboard;
this.row.titleSize = this.row.titleSize || 'h6';
this.source = this.row;
this.row = this.row.getSaveModel();
}
update() {
this.source.title = this.row.title;
this.source.repeat = this.row.repeat;
this.onUpdated();
this.dismiss();
}
delete() {
this.onDelete();
this.dismiss();
}
}
export function rowOptionsDirective() {
return {
restrict: 'E',
templateUrl: 'public/app/features/dashboard/row/options.html',
templateUrl: 'public/app/features/dashboard/partials/row_options.html',
controller: RowOptionsCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
rowCtrl: "=",
row: "=",
dismiss: "&",
onUpdated: "&",
onDelete: "&"
},
};
}
coreModule.directive('dashRowOptions', rowOptionsDirective);
coreModule.directive('rowOptions', rowOptionsDirective);
<div class="modal-body">
<div class="modal-header">
<h2 class="modal-header-title">
<i class="fa fa-copy"></i>
<span class="p-l-1">Row Options</span>
</h2>
<a class="modal-header-close" ng-click="ctrl.dismiss();">
<i class="fa fa-remove"></i>
</a>
</div>
<form name="ctrl.saveForm" ng-submit="ctrl.save()" class="modal-content" novalidate>
<div class="gf-form">
<span class="gf-form-label width-7">Title</span>
<input type="text" class="gf-form-input max-width-13" ng-model='ctrl.row.title'></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Repeat for</span>
<dash-repeat-option panel="ctrl.row"></dash-repeat-option>
</div>
<div class="gf-form-button-row">
<button type="button" class="btn btn-success" ng-click="ctrl.update()">Update</button>
<button type="button" class="btn btn-danger" ng-click="ctrl.delete()">Remove</button>
<button type="button" class="btn btn-inverse" ng-click="ctrl.dismiss()">Cancel</button>
</div>
</form>
</div>
......@@ -2,7 +2,7 @@ import {coreModule} from 'app/core/core';
var template = `
<div class="gf-form-select-wrapper max-width-13">
<select class="gf-form-input" ng-model="model.repeat" ng-options="f.value as f.text for f in variables" ng-change="optionChanged()">
<select class="gf-form-input" ng-model="panel.repeat" ng-options="f.value as f.text for f in variables" ng-change="optionChanged()">
<option value=""></option>
</div>
`;
......@@ -13,7 +13,7 @@ function dashRepeatOptionDirective(variableSrv) {
restrict: 'E',
template: template,
scope: {
model: "=",
panel: "=",
},
link: function(scope, element) {
element.css({display: 'block', width: '100%'});
......
<div class="tabbed-view-header">
<h2 class="tabbed-view-title">
Add Panel
</h2>
<input type="text" class="gf-form-input max-width-14 pull-left" ng-model='ctrl.panelSearch' give-focus='true' ng-keydown="ctrl.keyDown($event)" ng-change="ctrl.panelSearchChanged()" placeholder="panel search filter"></input>
<button class="tabbed-view-close-btn" ng-click="ctrl.dismiss();">
<i class="fa fa-remove"></i>
</button>
</div>
<div class="tabbed-view-body tabbed-view-body--small">
<div class="add-panel-panels-scroll">
<div class="add-panel-panels">
<div class="add-panel-item"
ng-repeat="panel in ctrl.panelHits"
ng-class="{active: $index === ctrl.activeIndex}"
ng-click="ctrl.addPanel(panel)"
title="{{panel.name}}">
<img class="add-panel-item-img" ng-src="{{panel.info.logos.small}}"></img>
<div class="add-panel-item-name">{{panel.name}}</div>
</div>
</div>
</div>
</div>
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import config from 'app/core/config';
import {coreModule} from 'app/core/core';
export class AddPanelCtrl {
dashboard: any;
allPanels: any;
panelHits: any;
activeIndex: any;
panelSearch: any;
/** @ngInject */
constructor(private $rootScope, dashboardSrv) {
this.dashboard = dashboardSrv.getCurrent();
this.activeIndex = 0;
this.allPanels = _.chain(config.panels)
.filter({hideFromList: false})
.map(item => item)
.orderBy('sort')
.value();
this.panelHits = this.allPanels;
}
dismiss() {
this.$rootScope.appEvent('hide-dash-editor');
}
keyDown(evt) {
if (evt.keyCode === 27) {
this.dismiss();
return;
}
if (evt.keyCode === 40 || evt.keyCode === 39) {
this.moveSelection(1);
}
if (evt.keyCode === 38 || evt.keyCode === 37) {
this.moveSelection(-1);
}
if (evt.keyCode === 13) {
var selectedPanel = this.panelHits[this.activeIndex];
if (selectedPanel) {
this.addPanel(selectedPanel);
}
}
}
moveSelection(direction) {
var max = this.panelHits.length;
var newIndex = this.activeIndex + direction;
this.activeIndex = ((newIndex %= max) < 0) ? newIndex + max : newIndex;
}
panelSearchChanged() {
var items = this.allPanels.slice();
var startsWith = [];
var contains = [];
var searchLower = this.panelSearch.toLowerCase();
var item;
while (item = items.shift()) {
var nameLower = item.name.toLowerCase();
if (nameLower.indexOf(searchLower) === 0) {
startsWith.push(item);
} else if (nameLower.indexOf(searchLower) !== -1) {
contains.push(item);
}
}
this.panelHits = startsWith.concat(contains);
this.activeIndex = 0;
}
addPanel(panelPluginInfo) {
let defaultHeight = 6;
let defaultWidth = 6;
if (panelPluginInfo.id === "singlestat") {
defaultWidth = 3;
defaultHeight = 3;
}
this.dashboard.addPanel({
type: panelPluginInfo.id,
x: 0,
y: 0,
width: defaultWidth,
height: defaultHeight,
title: 'New panel',
});
this.dismiss();
}
}
export function addPanelDirective() {
return {
restrict: 'E',
templateUrl: 'public/app/features/dashboard/row/add_panel.html',
controller: AddPanelCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {},
};
}
coreModule.directive('addPanel', addPanelDirective);
<div class="dash-row-dropview">
<a class="dash-row-dropview-close pointer" ng-click="ctrl.rowCtrl.closeDropView();">
<i class="fa fa-remove"></i>
</a>
<div>
<div class="section">
<div class="gf-form">
<span class="gf-form-label width-6">Title</span>
<input type="text" class="gf-form-input max-width-14" ng-model='ctrl.row.title'></input>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-6">Size</label>
<div class="gf-form-select-wrapper">
<select class="input-small gf-form-input" ng-model="ctrl.row.titleSize" ng-options="f for f in ctrl.fontSizes"></select>
</div>
</div>
<gf-form-switch class="gf-form" label="Show" checked="ctrl.row.showTitle">
</gf-form-switch>
</div>
</div>
<div class="section">
<div class="gf-form">
<span class="gf-form-label width-7">Height</span>
<input type="text" class="gf-form-input max-width-14" ng-model='ctrl.row.height'></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Repeat for</span>
<dash-repeat-option model="ctrl.row"></dash-repeat-option>
</div>
</div>
</div>
</div>
<div class="dash-row-header">
<a class="dash-row-header-title" ng-click="ctrl.toggleCollapse()">
<span class="dash-row-collapse-toggle pointer">
<i class="fa fa-chevron-down" ng-show="!ctrl.row.collapse"></i>
<i class="fa fa-chevron-right" ng-show="ctrl.row.collapse"></i>
</span>
<span ng-class="ctrl.row.titleSize">{{ctrl.row.title | interpolateTemplateVars:this}}</span>
</a>
</div>
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import {Emitter, appEvents, assignModelProperties} from 'app/core/core';
export class DashboardRow {
panels: any;
title: any;
showTitle: any;
titleSize: any;
events: Emitter;
span: number;
height: number;
collapse: boolean;
defaults = {
title: 'Dashboard Row',
panels: [],
showTitle: false,
titleSize: 'h6',
height: 250,
isNew: false,
repeat: null,
repeatRowId: null,
repeatIteration: null,
collapse: false,
};
constructor(private model) {
assignModelProperties(this, model, this.defaults);
this.events = new Emitter();
this.updateRowSpan();
}
getSaveModel() {
this.model = {};
assignModelProperties(this.model, this, this.defaults);
// remove properties that dont server persisted purpose
delete this.model.isNew;
return this.model;
}
updateRowSpan() {
this.span = 0;
for (let panel of this.panels) {
this.span += panel.span;
}
}
panelSpanChanged(alwaysSendEvent?) {
var oldSpan = this.span;
this.updateRowSpan();
if (alwaysSendEvent || oldSpan !== this.span) {
this.events.emit('span-changed');
}
}
addPanel(panel) {
var rowSpan = this.span;
var panelCount = this.panels.length;
var space = (12 - rowSpan) - panel.span;
// try to make room of there is no space left
if (space <= 0) {
if (panelCount === 1) {
this.panels[0].span = 6;
panel.span = 6;
} else if (panelCount === 2) {
this.panels[0].span = 4;
this.panels[1].span = 4;
panel.span = 4;
} else if (panelCount === 3) {
this.panels[0].span = 3;
this.panels[1].span = 3;
this.panels[2].span = 3;
panel.span = 3;
}
}
this.panels.push(panel);
this.events.emit('panel-added', panel);
this.panelSpanChanged();
}
removePanel(panel, ask?) {
if (ask !== false) {
var text2, confirmText;
if (panel.alert) {
text2 = "Panel includes an alert rule, removing panel will also remove alert rule";
confirmText = "YES";
}
appEvents.emit('confirm-modal', {
title: 'Remove Panel',
text: 'Are you sure you want to remove this panel?',
text2: text2,
icon: 'fa-trash',
confirmText: confirmText,
yesText: 'Remove',
onConfirm: () => {
this.removePanel(panel, false);
}
});
return;
}
var index = _.indexOf(this.panels, panel);
this.panels.splice(index, 1);
this.events.emit('panel-removed', panel);
this.panelSpanChanged();
}
movePanel(fromIndex, toIndex) {
this.panels.splice(toIndex, 0, this.panels.splice(fromIndex, 1)[0]);
}
destroy() {
this.events.removeAllListeners();
}
copyPropertiesFromRowSource(source) {
this.height = source.height;
this.title = source.title;
this.showTitle = source.showTitle;
this.titleSize = source.titleSize;
}
toggleCollapse() {
this.collapse = !this.collapse;
}
}
......@@ -16,7 +16,7 @@
<h5 class="section-heading">Repeat</h5>
<div class="gf-form">
<span class="gf-form-label width-9">For each value of</span>
<dash-repeat-option model="ctrl.panel"></dash-repeat-option>
<dash-repeat-option panel="ctrl.panel"></dash-repeat-option>
</div>
<div class="gf-form" ng-show="ctrl.panel.repeat">
<span class="gf-form-label width-9">Min width</span>
......
.gicon {
line-height: 1;
display: inline-block;
width: 1.2057142857em;
height: 1.2057142857em;
width: 1.1057142857em;
height: 1.1057142857em;
text-align: center;
background-repeat: no-repeat;
background-position: center;
......
......@@ -21,10 +21,6 @@
}
}
.react-grid-item {
overflow: hidden;
}
.theme-dark {
.react-grid-item > .react-resizable-handle {
background-image: url('../img/resize-handle-white.svg');
......
......@@ -14,7 +14,7 @@
"forin": false,
"indent": [true, "spaces", 2],
"label-position": true,
"max-line-length": [true, 140],
"max-line-length": [true, 150],
"member-access": false,
"no-arg": true,
"no-bitwise": true,
......
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