Commit e54c868e by Rashid Khan

Added pulldowns for query and filter. Added filter notifications, moved…

Added pulldowns for query and filter. Added filter notifications, moved timepicker to navbar, reimplemented auto refresh
parent d5bc550b
...@@ -295,7 +295,6 @@ function($, _, moment) { ...@@ -295,7 +295,6 @@ function($, _, moment) {
} else if (c === '-') { } else if (c === '-') {
type = 2; type = 2;
} else { } else {
console.log("no type");
return false; return false;
} }
...@@ -311,7 +310,6 @@ function($, _, moment) { ...@@ -311,7 +310,6 @@ function($, _, moment) {
if (type === 0) { if (type === 0) {
// rounding is only allowed on whole numbers // rounding is only allowed on whole numbers
if (num !== 1) { if (num !== 1) {
console.log("nbad rounding");
return false; return false;
} }
} }
...@@ -373,7 +371,6 @@ function($, _, moment) { ...@@ -373,7 +371,6 @@ function($, _, moment) {
} }
break; break;
default: default:
console.log("unknown unit");
return false; return false;
} }
} }
......
define([ define([
'./dash', './dash',
'./dashLoader', './dashLoader',
'./row' './row',
'./pulldown'
], function () {}); ], function () {});
\ No newline at end of file
...@@ -11,13 +11,20 @@ function (angular, _) { ...@@ -11,13 +11,20 @@ function (angular, _) {
$scope.loader = dashboard.current.loader; $scope.loader = dashboard.current.loader;
$scope.init = function() { $scope.init = function() {
$scope.advancedLoad = false;
$scope.advancedSave = false;
$scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
$scope.gist = $scope.gist || {}; $scope.gist = $scope.gist || {};
$scope.elasticsearch = $scope.elasticsearch || {}; $scope.elasticsearch = $scope.elasticsearch || {};
}; };
$scope.showDropdown = function(type) { $scope.showDropdown = function(type) {
var _l = $scope.loader; if(_.isUndefined(dashboard.current.loader)) {
return true;
}
var _l = dashboard.current.loader;
if(type === 'load') { if(type === 'load') {
return (_l.load_elasticsearch || _l.load_gist || _l.load_local); return (_l.load_elasticsearch || _l.load_gist || _l.load_local);
} }
......
define([
'angular',
'app',
'underscore'
],
function (angular, app, _) {
'use strict';
var module = angular.module('kibana.controllers');
module.controller('PulldownCtrl', function($scope, $rootScope, $timeout,ejsResource, querySrv) {
var _d = {
collapse: false,
notice: false,
};
_.defaults($scope.pulldown,_d);
$scope.init = function() {
$scope.querySrv = querySrv;
// Provide a combined skeleton for panels that must interact with panel and row.
// This might create name spacing issues.
$scope.panel = $scope.pulldown;
$scope.row = $scope.pulldown;
};
$scope.toggle_pulldown = function(pulldown) {
pulldown.collapse = pulldown.collapse ? false : true;
if (!pulldown.collapse) {
$timeout(function() {
$scope.$broadcast('render');
});
} else {
$scope.row.notice = false;
}
};
$scope.init();
}
);
});
\ No newline at end of file
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
"query": "*", "query": "*",
"alias": "", "alias": "",
"color": "#7EB26D", "color": "#7EB26D",
"id": 0 "id": 0,
"pin": false,
"type": "lucene"
} }
}, },
"ids": [ "ids": [
...@@ -22,24 +24,12 @@ ...@@ -22,24 +24,12 @@
}, },
"filter": { "filter": {
"idQueue": [ "idQueue": [
0,
1, 1,
2 2
], ],
"list": { "list": {},
"0": { "ids": []
"from": "2013-07-27T22:08:06.800Z",
"to": "2013-07-27T23:08:06.801Z",
"field": "@timestamp",
"type": "time",
"mandate": "must",
"active": true,
"alias": "",
"id": 0
}
},
"ids": [
0
]
} }
}, },
"rows": [ "rows": [
...@@ -77,7 +67,8 @@ ...@@ -77,7 +67,8 @@
"style": {}, "style": {},
"status": "Stable" "status": "Stable"
} }
] ],
"notice": false
} }
], ],
"editable": false, "editable": false,
...@@ -85,5 +76,73 @@ ...@@ -85,5 +76,73 @@
"interval": "none", "interval": "none",
"pattern": "[logstash-]YYYY.MM.DD", "pattern": "[logstash-]YYYY.MM.DD",
"default": "_all" "default": "_all"
},
"style": "dark",
"failover": false,
"panel_hints": true,
"pulldowns": [
{
"type": "query",
"collapse": true,
"notice": false,
"query": "*",
"pinned": true,
"history": [],
"remember": 10
},
{
"type": "filtering",
"collapse": true,
"notice": false
} }
],
"nav": [
{
"type": "timepicker2",
"collapse": false,
"notice": false,
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"timefield": "@timestamp",
"now": true,
"filter_id": 0
}
],
"loader": {
"save_gist": false,
"save_elasticsearch": true,
"save_local": true,
"save_default": true,
"save_temp": true,
"save_temp_ttl_enable": true,
"save_temp_ttl": "30d",
"load_gist": true,
"load_elasticsearch": true,
"load_elasticsearch_size": 20,
"load_local": true,
"hide": false
},
"refresh": false
} }
\ No newline at end of file
/* global _, kbn */ /* global _ */
/* /*
* Complex scripted Logstash dashboard * Complex scripted Logstash dashboard
...@@ -29,7 +29,7 @@ var dashboard, queries, _d_timespan; ...@@ -29,7 +29,7 @@ var dashboard, queries, _d_timespan;
var ARGS; var ARGS;
// Set a default timespan if one isn't specified // Set a default timespan if one isn't specified
_d_timespan = '1h'; _d_timespan = '1d';
// Intialize a skeleton with nothing but a rows array and service object // Intialize a skeleton with nothing but a rows array and service object
dashboard = { dashboard = {
...@@ -85,12 +85,11 @@ dashboard.services.query = { ...@@ -85,12 +85,11 @@ dashboard.services.query = {
}; };
// Lets also add a default time filter, the value of which can be specified by the user // Lets also add a default time filter, the value of which can be specified by the user
// This isn't strictly needed, but it gets rid of the info alert about the missing time filter
dashboard.services.filter = { dashboard.services.filter = {
list: { list: {
0: { 0: {
from: kbn.time_ago(ARGS.from||_d_timespan), from: "now-"+(ARGS.from||_d_timespan),
to: new Date(), to: "now",
field: ARGS.timefield||"@timestamp", field: ARGS.timefield||"@timestamp",
type: "time", type: "time",
active: true, active: true,
...@@ -103,19 +102,6 @@ dashboard.services.filter = { ...@@ -103,19 +102,6 @@ dashboard.services.filter = {
// Ok, lets make some rows. The Filters row is collapsed by default // Ok, lets make some rows. The Filters row is collapsed by default
dashboard.rows = [ dashboard.rows = [
{ {
title: "Time span",
height: "30px"
},
{
title: "Query",
height: "30px"
},
{
title: "Filters",
height: "100px",
collapse: true
},
{
title: "Chart", title: "Chart",
height: "300px" height: "300px"
}, },
...@@ -125,37 +111,8 @@ dashboard.rows = [ ...@@ -125,37 +111,8 @@ dashboard.rows = [
} }
]; ];
// Setup some panels. A query panel and a filter panel on the same row
dashboard.rows[0].panels = [
{
title: "Set time filter",
type: 'timepicker',
span: 6,
timespan: ARGS.from||_d_timespan
}
];
// Add a filtering panel to the 3rd row
dashboard.rows[1].panels = [
{
title: 'search',
type: 'query',
span: 12
}
];
// Add a filtering panel to the 3rd row
dashboard.rows[2].panels = [
{
title: 'filters (applied globally)',
type: 'filtering',
span: 12
}
];
// And a histogram that allows the user to specify the interval and time field // And a histogram that allows the user to specify the interval and time field
dashboard.rows[3].panels = [ dashboard.rows[0].panels = [
{ {
title: 'events over time', title: 'events over time',
type: 'histogram', type: 'histogram',
...@@ -166,7 +123,7 @@ dashboard.rows[3].panels = [ ...@@ -166,7 +123,7 @@ dashboard.rows[3].panels = [
]; ];
// And a table row where you can specify field and sort order // And a table row where you can specify field and sort order
dashboard.rows[4].panels = [ dashboard.rows[1].panels = [
{ {
title: 'all events', title: 'all events',
type: 'table', type: 'table',
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
"query": "{{ARGS.query || '*'}}", "query": "{{ARGS.query || '*'}}",
"alias": "", "alias": "",
"color": "#7EB26D", "color": "#7EB26D",
"id": 0 "id": 0,
"pin": false,
"type": "lucene"
} }
}, },
"ids": [ "ids": [
...@@ -23,10 +25,10 @@ ...@@ -23,10 +25,10 @@
], ],
"list": { "list": {
"0": { "0": {
"from": "2013-07-30T18:58:13.977Z",
"to": "2013-07-30T19:58:13.977Z",
"field": "@timestamp",
"type": "time", "type": "time",
"field": "@timestamp",
"from": "now-{{ARGS.from || '24h'}}",
"to": "now",
"mandate": "must", "mandate": "must",
"active": true, "active": true,
"alias": "", "alias": "",
...@@ -40,90 +42,6 @@ ...@@ -40,90 +42,6 @@
}, },
"rows": [ "rows": [
{ {
"title": "Options",
"height": "50px",
"editable": true,
"collapse": false,
"collapsable": true,
"panels": [
{
"title": "Set time span",
"error": "",
"span": 6,
"editable": true,
"group": [
"default"
],
"type": "timepicker",
"mode": "relative",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"timespan": "{{ARGS.from || '1h'}}",
"timefield": "@timestamp",
"timeformat": "",
"refresh": {
"enable": false,
"interval": 30,
"min": 3
},
"filter_id": 0,
"status": "Stable"
}
]
},
{
"title": "Query",
"height": "50px",
"editable": true,
"collapse": false,
"collapsable": true,
"panels": [
{
"title": "Search",
"error": false,
"span": 12,
"editable": true,
"group": [
"default"
],
"type": "query",
"label": "Search",
"history": [],
"remember": 10,
"pinned": true,
"query": "*"
}
]
},
{
"title": "Filters",
"height": "50px",
"editable": true,
"collapse": true,
"collapsable": true,
"panels": [
{
"title": "dashboard filters",
"error": false,
"span": 12,
"editable": true,
"group": [
"default"
],
"type": "filtering"
}
]
},
{
"title": "Graph", "title": "Graph",
"height": "350px", "height": "350px",
"editable": true, "editable": true,
...@@ -142,7 +60,7 @@ ...@@ -142,7 +60,7 @@
"value_field": null, "value_field": null,
"auto_int": true, "auto_int": true,
"resolution": 100, "resolution": 100,
"interval": "30s", "interval": "10m",
"fill": 3, "fill": 3,
"linewidth": 3, "linewidth": 3,
"timezone": "browser", "timezone": "browser",
...@@ -163,9 +81,30 @@ ...@@ -163,9 +81,30 @@
0 0
] ]
}, },
"title": "Events over time" "title": "Events over time",
"intervals": [
"auto",
"1s",
"1m",
"5m",
"10m",
"30m",
"1h",
"3h",
"12h",
"1d",
"1w",
"1M",
"1y"
],
"options": true,
"tooltip": {
"value_type": "cumulative",
"query_as_alias": false
} }
] }
],
"notice": false
}, },
{ {
"title": "Events", "title": "Events",
...@@ -207,9 +146,12 @@ ...@@ -207,9 +146,12 @@
] ]
}, },
"field_list": true, "field_list": true,
"status": "Stable" "status": "Stable",
"trimFactor": 300,
"normTimes": true
} }
] ],
"notice": false
} }
], ],
"editable": true, "editable": true,
...@@ -218,5 +160,72 @@ ...@@ -218,5 +160,72 @@
"interval": "day", "interval": "day",
"pattern": "[logstash-]YYYY.MM.DD", "pattern": "[logstash-]YYYY.MM.DD",
"default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED" "default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED"
},
"style": "dark",
"panel_hints": true,
"pulldowns": [
{
"type": "query",
"collapse": false,
"notice": false,
"query": "*",
"pinned": true,
"history": [],
"remember": 10
},
{
"type": "filtering",
"collapse": true,
"notice": false
} }
],
"nav": [
{
"type": "timepicker2",
"collapse": false,
"notice": false,
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"timefield": "@timestamp",
"now": true,
"filter_id": 0
}
],
"loader": {
"save_gist": false,
"save_elasticsearch": true,
"save_local": true,
"save_default": true,
"save_temp": true,
"save_temp_ttl_enable": true,
"save_temp_ttl": "30d",
"load_gist": true,
"load_elasticsearch": true,
"load_elasticsearch_size": 20,
"load_local": true,
"hide": false
},
"refresh": false
} }
\ No newline at end of file
...@@ -10,6 +10,7 @@ function (angular) { ...@@ -10,6 +10,7 @@ function (angular) {
return { return {
restrict: 'E', restrict: 'E',
link: function($scope, elem, attr) { link: function($scope, elem, attr) {
// once we have the template, scan it for controllers and // once we have the template, scan it for controllers and
// load the module.js if we have any // load the module.js if we have any
......
<div class="row-fluid"> <div class="row-fluid">
<div class="span2"> <div class="span2">
<label class="small">Mode</label> <label class="small">Mode</label>
<select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in ['count','min','mean','max','total']"></select> <select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in ['count','min','mean','max','total','change']"></select>
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Time Field</label> <label class="small">Time Field</label>
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
<span ng-show="panel.legend" class="small"><span ng-show="panel.value_field && panel.mode != 'count'">{{panel.value_field}}</span> {{panel.mode}} per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> hits)</span> <span ng-show="panel.legend" class="small"><span ng-show="panel.value_field && panel.mode != 'count'">{{panel.value_field}}</span> {{panel.mode}} per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> hits)</span>
</div> </div>
<form class="form-inline bordered histogram-options" ng-show="options"> <form class="form-inline bordered histogram-options" ng-show="options">
<span>
<div class="checkbox"> <div class="checkbox">
<label class="small"> <label class="small">
<input type="checkbox" ng-model="panel.bars" ng-checked="panel.bars" ng-change="render()"> <input type="checkbox" ng-model="panel.bars" ng-checked="panel.bars" ng-change="render()">
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
Stack Stack
</label> </label>
</div> </div>
</span>
<span ng-show="panel.stack"> <span ng-show="panel.stack">
<div class="checkbox"> <div class="checkbox">
<label style="white-space:nowrap" class="small"> <label style="white-space:nowrap" class="small">
......
...@@ -308,8 +308,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -308,8 +308,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
} }
filterSrv.set({ filterSrv.set({
type:'time', type:'time',
from:moment.utc(_from), from:moment.utc(_from).toDate(),
to:moment.utc(_to), to:moment.utc(_to).toDate(),
field:$scope.panel.time_field field:$scope.panel.time_field
}); });
}; };
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
</th> </th>
</thead> </thead>
<tbody ng-repeat="event in data | slice:panel.offset:panel.offset+panel.size" ng-class-odd="'odd'"> <tbody ng-repeat="event in data| slice:panel.offset:panel.offset+panel.size" ng-class-odd="'odd'">
<tr ng-click="toggle_details(event)" class="pointer"> <tr ng-click="toggle_details(event)" class="pointer">
<td ng-show="panel.fields.length<1">{{event._source|stringify|tableTruncate:panel.trimFactor:1}}</td> <td ng-show="panel.fields.length<1">{{event._source|stringify|tableTruncate:panel.trimFactor:1}}</td>
<td ng-show="panel.fields.length>0" ng-repeat="field in panel.fields" ng-bind-html-unsafe="(event.kibana.highlight[field]||event.kibana._source[field]) |tableHighlight | tableTruncate:panel.trimFactor:panel.fields.length"></td> <td ng-show="panel.fields.length>0" ng-repeat="field in panel.fields" ng-bind-html-unsafe="(event.kibana.highlight[field]||event.kibana._source[field]) |tableHighlight | tableTruncate:panel.trimFactor:panel.fields.length"></td>
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
<th>Action</th> <th>Action</th>
<th>Value</th> <th>Value</th>
</thead> </thead>
<tr ng-repeat="(key,value) in event.kibana._source" ng-class-odd="'odd'"> <tr ng-repeat="(key,value) in event.kibana._source track by $index" ng-class-odd="'odd'">
<td>{{key}}</td> <td>{{key}}</td>
<td style="white-space:nowrap"> <td style="white-space:nowrap">
<i class='icon-search pointer' ng-click="build_search(key,value)" bs-tooltip="'Add filter to match this value'"></i> <i class='icon-search pointer' ng-click="build_search(key,value)" bs-tooltip="'Add filter to match this value'"></i>
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
<div class="timepicker-from-column"> <div class="timepicker-from-column">
<label class="small">From</label> <label class="small">From</label>
<div class="fake-input timepicker-input"> <div class="fake-input timepicker-input">
<input class="timepicker-date" type="text" ng-change="validate(temptime)" ng-model="temptime.from.date" data-date-format="mm/dd/yyyy" required bs-datepicker />@ <input class="timepicker-date" type="text" ng-change="validate(temptime)" ng-model="temptime.from.date" data-date-format="yyyy-mm-dd" required bs-datepicker />@
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.hour" required ng-pattern="patterns.hour" onClick="this.select();"/>: <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.hour" required ng-pattern="patterns.hour" onClick="this.select();"/>:
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.minute" required ng-pattern="patterns.minute" onClick="this.select();"/>: <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.minute" required ng-pattern="patterns.minute" onClick="this.select();"/>:
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.second" required ng-pattern="patterns.second" onClick="this.select();"/>. <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.from.second" required ng-pattern="patterns.second" onClick="this.select();"/>.
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
<div class="fake-input timepicker-input"> <div class="fake-input timepicker-input">
<div ng-hide="panel.now"> <div ng-hide="panel.now">
<input class="timepicker-date" type="text" ng-change="validate(temptime)" ng-model="temptime.to.date" data-date-format="mm/dd/yyyy" required bs-datepicker />@ <input class="timepicker-date" type="text" ng-change="validate(temptime)" ng-model="temptime.to.date" data-date-format="yyyy-mm-dd" required bs-datepicker />@
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.hour" required ng-pattern="patterns.hour" onClick="this.select();"/>: <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.hour" required ng-pattern="patterns.hour" onClick="this.select();"/>:
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.minute" required ng-pattern="patterns.minute" onClick="this.select();"/>: <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.minute" required ng-pattern="patterns.minute" onClick="this.select();"/>:
<input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.second" required ng-pattern="patterns.second" onClick="this.select();"/>. <input class="timepicker-hms" type="text" maxlength="2" ng-change="validate(temptime)" ng-model="temptime.to.second" required ng-pattern="patterns.second" onClick="this.select();"/>.
......
<div class="row-fluid"> <div class="row-fluid">
<div class="span6"> <div class="span4">
<label class="small">Relative time options <small>comma seperated</small></label> <label class="small">Relative time options <small>comma seperated</small></label>
<input type="text" array-join class="input-large" ng-model="panel.time_options"> <input type="text" array-join class="input-large" ng-model="panel.time_options">
</div> </div>
<div class="span3"> <div class="span4">
<label class="small">Auto-refresh options <small>comma seperated</small></label>
<input type="text" array-join class="input-large" ng-model="panel.refresh_intervals">
</div>
<div class="span2">
<label class="small">Time Field</label> <label class="small">Time Field</label>
<input type="text" class="input-small" ng-model="panel.timefield"> <input type="text" class="input-small" ng-model="panel.timefield">
</div> </div>
......
...@@ -14,9 +14,10 @@ ...@@ -14,9 +14,10 @@
<form name="input" style="margin:3px 0 0 0"> <form name="input" style="margin:3px 0 0 0">
<ul class="nav nav-pills timepicker-dropdown"> <ul class="nav nav-pills timepicker-dropdown">
<li class="dropdown" bs-tooltip="(time.from.date | date:'yyyy-MM-dd HH:mm:ss.sss') + ' to ' +(time.to.date | date:'yyyy-MM-dd HH:mm:ss.sss')" data-placement="bottom" ng-click="dismiss();"> <li class="dropdown" bs-tooltip="(time.from.date | date:'yyyy-MM-dd HH:mm:ss.sss') + ' to ' +(time.to.date | date:'yyyy-MM-dd HH:mm:ss.sss')" data-placement="bottom" ng-click="dismiss();">
<a class="dropdown-toggle timepicker-dropdown" data-toggle="dropdown" href="#"> <a class="dropdown-toggle timepicker-dropdown" data-toggle="dropdown" href="#">
<span class="small" ng-show="filterSrv.idsByType('time').length"> <span ng-show="filterSrv.idsByType('time').length">
<span class="pointer" ng-hide="panel.now">{{time.from.date | date:'MMM d, y HH:mm:ss'}}</span> <span class="pointer" ng-hide="panel.now">{{time.from.date | date:'MMM d, y HH:mm:ss'}}</span>
<span class="pointer" ng-show="panel.now">{{time.from.date | moment:'ago'}}</span> <span class="pointer" ng-show="panel.now">{{time.from.date | moment:'ago'}}</span>
to to
...@@ -24,14 +25,27 @@ ...@@ -24,14 +25,27 @@
<span class="pointer" ng-show="panel.now">{{time.to.date | moment:'ago'}}</span> <span class="pointer" ng-show="panel.now">{{time.to.date | moment:'ago'}}</span>
</span> </span>
<span ng-hide="filterSrv.idsByType('time').length">Set a time filter</span> <span ng-hide="filterSrv.idsByType('time').length">Set a time filter</span>
<i class="small icon-caret-down"></i> <span ng-show="dashboard.current.refresh" class="text-warning">refreshed every {{dashboard.current.refresh}} </span>
<i class="icon-caret-down"></i>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat='timespan in panel.time_options'> <!-- Relative time options -->
<li ng-repeat='timespan in panel.time_options track by $index'>
<a ng-click="setRelativeFilter(timespan)">Last {{timespan}}</a> <a ng-click="setRelativeFilter(timespan)">Last {{timespan}}</a>
</li> </li>
<!-- Auto refresh submenu -->
<li class="dropdown-submenu">
<a href="#">Auto-Refresh</a>
<ul class="dropdown-menu">
<li><a ng-click="dashboard.set_interval(false)">Off</a></li>
<li ng-repeat="interval in panel.refresh_intervals track by $index"><a ng-click="dashboard.set_interval(interval)">Every {{interval}}</a></li>
</ul>
</li>
<li><a ng-click="customTime()">Custom</a></li> <li><a ng-click="customTime()">Custom</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
......
...@@ -36,16 +36,10 @@ function (angular, app, _, moment, kbn) { ...@@ -36,16 +36,10 @@ function (angular, app, _, moment, kbn) {
// Set and populate defaults // Set and populate defaults
var _d = { var _d = {
status : "Stable", status : "Stable",
mode : "relative",
time_options : ['5m','15m','1h','6h','12h','24h','2d','7d','30d'], time_options : ['5m','15m','1h','6h','12h','24h','2d','7d','30d'],
timespan : '15m', refresh_intervals : ['5s','10s','30s','1m','5m','15m','30m','1h','2h','1d'],
timefield : '@timestamp',
timeformat : "", timefield : '@timestamp'
refresh : {
enable : false,
interval: 30,
min : 3
}
}; };
_.defaults($scope.panel,_d); _.defaults($scope.panel,_d);
...@@ -212,9 +206,7 @@ function (angular, app, _, moment, kbn) { ...@@ -212,9 +206,7 @@ function (angular, app, _, moment, kbn) {
// Do not use the results of this function unless you plan to use setHour/Minutes/etc on the result // Do not use the results of this function unless you plan to use setHour/Minutes/etc on the result
var datepickerToLocal = function(date) { var datepickerToLocal = function(date) {
console.log(date);
date = moment(date).clone().toDate(); date = moment(date).clone().toDate();
console.log(moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)).toDate());
return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)).toDate(); return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)).toDate();
}; };
......
<li ng-controller="RowCtrl"><kibana-simple-panel type="'timepicker2'" ng-cloak></kibana-simple-panel></li> <style>
.noarrow>a:after {
display: none !important;
}
</style>
<li><a bs-tooltip="'Goto saved default'" data-placement="bottom" href='#/dashboard'><i class='icon-home'></i></a></li> <li ng-repeat="pulldown in dashboard.current.nav" ng-controller="PulldownCtrl"><kibana-simple-panel type="pulldown.type" panel="pulldown" ng-cloak></kibana-simple-panel></li>
<li><a bs-tooltip="'Goto saved default'" data-placement="bottom" href='#/dashboard'><i class='icon-home'></i></a></li>
<li class="dropdown" bs-tooltip="'Load'" data-placement="bottom" ng-show="showDropdown('load')" > <li class="dropdown" bs-tooltip="'Load'" data-placement="bottom" ng-show="showDropdown('load')" >
<a href="#" class="dropdown-toggle" data-toggle="dropdown" ng-click="elasticsearch_dblist('title:'+elasticsearch.query+'*')"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" ng-click="elasticsearch_dblist('title:'+elasticsearch.query+'*')">
<i class='icon-folder-open'></i> <i class='icon-folder-open'></i>
</a> </a>
<ul class="dropdown-menu" style="padding:10px">
<li ng-show='dashboard.current.loader.load_elasticsearch'>
<form class="nomargin">
<input type="text" ng-model="elasticsearch.query" ng-change="elasticsearch_dblist('title:'+elasticsearch.query+'*')" placeholder="Type to filter"/>
</form>
<h6 ng-hide="elasticsearch.dashboards.length">No dashboards matching your query found</h6>
<table class="table table-condensed table-striped">
<tr ng-repeat="row in elasticsearch.dashboards | orderBy:['_id']">
<td><a ng-click="elasticsearch_delete(row._id)"><i class="icon-remove"></i></a></td>
<td><a href="#/dashboard/elasticsearch/{{row._id}}">{{row._id}}</a></td>
<td><a><i class="icon-share" ng-click="share = dashboard.share_link(row._id,'elasticsearch',row._id)" bs-modal="'app/panels/dashcontrol/share.html'"></i></a></td>
</tr>
</table>
</li>
<li class="dropdown-submenu noarrow">
<a tabindex="-1" href="#" class="small" style="padding:0"><i class="icon-caret-left"></i> Advanced</a>
<ul class="dropdown-menu" style="padding:10px"> <ul class="dropdown-menu" style="padding:10px">
<li ng-show='loader.load_local'> <li ng-show='dashboard.current.loader.load_local'>
<h5>Local File <tip>Load dashboard JSON layout from file</tip></h5> <h5>Local File <tip>Load dashboard JSON layout from file</tip></h5>
<form> <form>
<input type="file" id="dashupload" dash-upload /><br> <input type="file" id="dashupload" dash-upload /><br>
</form> </form>
</li> </li>
<li ng-show='loader.load_gist'> <li ng-show='dashboard.current.loader.load_gist'>
<h5>Gist <tip>Enter a gist number or url</tip></h5> <h5>Gist <tip>Enter a gist number or url</tip></h5>
<form> <form>
<input type="text" ng-model="gist.url"/ placeholder="Gist number or URL"><br> <input type="text" ng-model="gist.url"/ placeholder="Gist number or URL"><br>
<button class="btn" ng-click="gist_dblist(dashboard.gist_id(gist.url))" ng-show="dashboard.is_gist(gist.url)"><i class="icon-github-alt"></i> Get gist:{{gist.url | gistid}}</button> <button class="btn" ng-click="gist_dblist(dashboard.gist_id(gist.url))" ng-show="dashboard.is_gist(gist.url)"><i class="icon-github-alt"></i> Get gist:{{gist.url | gistid}}</button>
<h6 ng-show="gist.files.length">Dashboards in gist:{{gist.url | gistid}} <small>click to load</small></h6> <h6 ng-show="gist.files.length">Dashboards in gist:{{gist.url | gistid}} <small>click to load</small></h6>
<h6 ng-hide="gist.files.length">No gist dashboards found</h6> <h6 ng-hide="gist.files.length || !gist.url.length">No gist dashboards found</h6>
<table class="table table-condensed table-striped"> <table class="table table-condensed table-striped">
<tr ng-repeat="file in gist.files"> <tr ng-repeat="file in gist.files">
<td><a ng-click="dashboard.dash_load(file)">{{file.title}}</a></td> <td><a ng-click="dashboard.dash_load(file)">{{file.title}}</a></td>
...@@ -27,53 +51,57 @@ ...@@ -27,53 +51,57 @@
</table> </table>
</form> </form>
</li> </li>
<li ng-show='loader.load_elasticsearch'> </ul>
<h5>Elasticsearch</h5>
<form>
<input type="text" ng-model="elasticsearch.query" ng-change="elasticsearch_dblist('title:'+elasticsearch.query+'*')" placeholder="Type to filter"/>
</form>
<h6 ng-show="elasticsearch.dashboards.length">Elasticsearch stored dashboards</h6>
<h6 ng-hide="elasticsearch.dashboards.length">No dashboards matching your query found</h6>
<table class="table table-condensed table-striped">
<tr ng-repeat="row in elasticsearch.dashboards | orderBy:['_id']">
<td><a ng-click="elasticsearch_delete(row._id)"><i class="icon-remove"></i></a></td>
<td><a href="#/dashboard/elasticsearch/{{row._id}}">{{row._id}}</a></td>
<td><a><i class="icon-share" ng-click="share = dashboard.share_link(row._id,'elasticsearch',row._id)" bs-modal="'app/panels/dashcontrol/share.html'"></i></a></td>
</tr>
</table>
</li> </li>
</ul> </ul>
</li> </li>
<li class="dropdown" bs-tooltip="'Save'" data-placement="bottom" ng-show="showDropdown('save')"> <li class="dropdown" bs-tooltip="'Save'" data-placement="bottom" ng-show="showDropdown('save')">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class='icon-save'></i> <i class='icon-save'></i>
</a> </a>
<ul class="dropdown-menu" style="padding:10px"> <ul class="dropdown-menu" style="padding:10px">
<li ng-show="loader.save_default || loader.save_local">
<h5>Locally</h5> <li ng-show="dashboard.current.loader.save_elasticsearch">
<ul class="unstyled"> <form class="input-append nomargin">
<li><a class="link" ng-show="loader.save_local" ng-click="dashboard.to_file()"><i class="icon-download"></i> Export to File</a> <tip>Export layout, not data, to file</tip></li> <input class='input-medium' ng-model="dashboard.current.title" type="text" ng-model="elasticsearch.title"/>
<li><a class="link" ng-show="loader.save_default" ng-click="set_default()"><i class="icon-bookmark"></i> Set as Browser Default</a> <tip>Store dashboard preference to browser's localStorage</tip></li> <button class="btn" ng-click="elasticsearch_save('dashboard')"><i class="icon-save"></i></button>
<li><a class="link" ng-show="loader.save_default" ng-click="purge_default()"><i class="icon-ban-circle"></i> Clear Browser Default</a></li> </form>
</ul>
</li> </li>
<li ng-show="loader.save_gist">
<h5>Gist</h5> <li class="dropdown-submenu noarrow">
<a tabindex="-1" href="#" class="small" style="padding:0"><i class="icon-caret-left"></i> Advanced</a>
<ul class="dropdown-menu">
<li ng-show="dashboard.current.loader.save_default">
<a class="link" ng-click="set_default()">Set as my home</a>
</li>
<li ng-show="dashboard.current.loader.save_default">
<a class="link" ng-click="purge_default()">Clear my home</a>
</li>
<li ng-show="dashboard.current.loader.save_local">
<a class="link" ng-click="dashboard.to_file()">Export schema</a>
</li>
<li ng-show="dashboard.current.loader.save_gist" style="margin:10px">
<h6>Gist</h6>
<form class="input-append"> <form class="input-append">
<input class='input-medium' placeholder='Title' type="text" ng-model="gist.title"/> <input class='input-medium' placeholder='Title' type="text" ng-model="gist.title"/>
<button class="btn" ng-click="save_gist()"><i class="icon-github-alt"></i></button> <button class="btn" ng-click="save_gist()"><i class="icon-github-alt"></i></button>
</form><br> </form><br>
<small ng-show="gist.last">Last gist: <a target="_blank" href="{{gist.last}}">{{gist.last}}</a></small> <small ng-show="gist.last">Last gist: <a target="_blank" href="{{gist.last}}">{{gist.last}}</a></small>
</li> </li>
<li ng-show="loader.save_elasticsearch"> </ul>
<h5>Elasticsearch</h5>
<form class="input-append">
<input class='input-medium' placeholder="{{dashboard.current.title}}" type="text" ng-model="elasticsearch.title"/>
<button class="btn" ng-click="elasticsearch_save('dashboard')"><i class="icon-save"></i></button>
</form>
</li> </li>
</ul> </ul>
</li> </li>
<li ng-show="showDropdown('share')"><a bs-tooltip="'Share'" data-placement="bottom" ng-click="elasticsearch_save('temp',loader.save_temp_ttl)" bs-modal="'app/partials/dashLoaderShare.html'"><i class='icon-share'></i></a></li> <li ng-show="showDropdown('share')"><a bs-tooltip="'Share'" data-placement="bottom" ng-click="elasticsearch_save('temp',dashboard.current.loader.save_temp_ttl)" bs-modal="'app/partials/dashLoaderShare.html'"><i class='icon-share'></i></a></li>
<li ng-show="dashboard.current.editable" bs-tooltip="'Configure dashboard'" data-placement="bottom"><a href='#' bs-modal="'app/partials/dasheditor.html'"><i class='icon-cog pointer'></i></a></li>
<li ng-show="dashboard.current.editable "bs-tooltip="'Configure dashboard'" data-placement="bottom"><a href='#' bs-modal="'app/partials/dasheditor.html'"><i class='icon-cog pointer'></i></a></li>
<!-- is there a better way to repeat without actually affecting the page? --> <!-- is there a better way to repeat without actually affecting the page? -->
<nil ng-repeat="row in dashboard.current.pulldowns" ng-controller="RowCtrl"> <nil ng-repeat="pulldown in dashboard.current.pulldowns" ng-controller="PulldownCtrl">
<div class="top-row-open" ng-hide="row.collapse"> <div class="top-row-open" ng-hide="pulldown.collapse">
<kibana-simple-panel type="row.type" ng-cloak></kibana-simple-panel> <kibana-simple-panel type="pulldown.type" ng-cloak></kibana-simple-panel>
</div> </div>
<div class="top-row-close pointer" ng-click="toggle_row(row);dismiss();" bs-tooltip="'Toggle '+row.type" data-placement="bottom"> <div class="top-row-close pointer" ng-click="toggle_pulldown(pulldown);dismiss();" bs-tooltip="'Toggle '+pulldown.type" data-placement="bottom">
<span class="small row-text">{{row.type}}</span> <span class="small row-text">{{pulldown.type}}</span>
<i class="small" ng-class="{'icon-expand':row.collapse,'icon-collapse-top':!row.collapse}"></i> <i class="small" ng-class="{'icon-expand':pulldown.collapse,'icon-collapse-top':!pulldown.collapse}"></i>
<i class="small icon-circle text-warning" ng-show="row.notice && row.collapse"></i> <i class="small icon-star text-warning" ng-show="row.notice && pulldown.collapse"></i>
</div> </div>
</nil> </nil>
......
<div class="modal-body"> <div class="modal-body">
<div class="pull-right editor-title">Dashboard settings</div> <div class="pull-right editor-title">Dashboard settings</div>
<div ng-model="editor.index" bs-tabs> <div ng-model="editor.index" bs-tabs style="text-transform:capitalize;">
<div ng-repeat="tab in ['General','Index','Rows','Controls']" data-title="{{tab}}"> <div ng-repeat="tab in ['General','Index','Rows','Controls']" data-title="{{tab}}">
</div> </div>
<div ng-repeat="tab in dashboard.current.nav" data-title="{{tab.type}}">
</div>
</div> </div>
<div ng-show="editor.index == 0"> <div ng-show="editor.index == 0">
...@@ -103,45 +105,48 @@ ...@@ -103,45 +105,48 @@
<h5>Allow saving to</h5> <h5>Allow saving to</h5>
<div class="row-fluid"> <div class="row-fluid">
<div class="span2"> <div class="span2">
<label class="small">File</label><input type="checkbox" ng-model="loader.save_local" ng-checked="loader.save_local"> <label class="small">File</label><input type="checkbox" ng-model="dashboard.current.loader.save_local" ng-checked="dashboard.current.loader.save_local">
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Browser</label><input type="checkbox" ng-model="loader.save_default" ng-checked="loader.save_default"> <label class="small">Browser</label><input type="checkbox" ng-model="dashboard.current.loader.save_default" ng-checked="dashboard.current.loader.save_default">
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Gist <tip>Requires your domain to be OAUTH registered with Github<tip></label><input type="checkbox" ng-model="loader.save_gist" ng-checked="loader.save_gist"> <label class="small">Gist <tip>Requires your domain to be OAUTH registered with Github<tip></label><input type="checkbox" ng-model="dashboard.current.loader.save_gist" ng-checked="dashboard.current.loader.save_gist">
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Elasticsearch</label><input type="checkbox" ng-model="loader.save_elasticsearch" ng-checked="loader.save_elasticsearch"> <label class="small">Elasticsearch</label><input type="checkbox" ng-model="dashboard.current.loader.save_elasticsearch" ng-checked="dashboard.current.loader.save_elasticsearch">
</div> </div>
</div> </div>
<h5>Allow loading from</h5> <h5>Allow loading from</h5>
<div class="row-fluid"> <div class="row-fluid">
<div class="span2"> <div class="span2">
<label class="small">Local file</label><input type="checkbox" ng-model="loader.load_local" ng-checked="loader.load_local"> <label class="small">Local file</label><input type="checkbox" ng-model="dashboard.current.loader.load_local" ng-checked="dashboard.current.loader.load_local">
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Gist</label><input type="checkbox" ng-model="loader.load_gist" ng-checked="loader.load_gist"> <label class="small">Gist</label><input type="checkbox" ng-model="dashboard.current.loader.load_gist" ng-checked="dashboard.current.loader.load_gist">
</div> </div>
<div class="span2"> <div class="span2">
<label class="small">Elasticsearch</label><input type="checkbox" ng-model="loader.load_elasticsearch" ng-checked="loader.load_elasticsearch"> <label class="small">Elasticsearch</label><input type="checkbox" ng-model="dashboard.current.loader.load_elasticsearch" ng-checked="dashboard.current.loader.load_elasticsearch">
</div> </div>
<div class="span3" ng-show="loader.load.elasticsearch"> <div class="span3" ng-show="dashboard.current.loader.load.elasticsearch">
<label class="small">ES list size</label><input class="input-mini" type="number" ng-model="loader.load_elasticsearch_size"> <label class="small">ES list size</label><input class="input-mini" type="number" ng-model="dashboard.current.loader.load_elasticsearch_size">
</div> </div>
</div> </div>
<h5>Sharing</h5> <h5>Sharing</h5>
<div class="row-fluid"> <div class="row-fluid">
<div class="span2" > <div class="span2" >
<label class="small">Allow Sharing <tip>Allow generating adhoc links to dashboards</tip></label><input type="checkbox" ng-model="loader.save_temp" ng-checked="loader.save_temp"> <label class="small">Allow Sharing <tip>Allow generating adhoc links to dashboards</tip></label><input type="checkbox" ng-model="dashboard.current.loader.save_temp" ng-checked="dashboard.current.loader.save_temp">
</div>
<div class="span2" ng-show="dashboard.current.loader.save_temp">
<label class="small">TTL <tip>Expire temp urls</tip></label><input type="checkbox" ng-model="dashboard.current.loader.save_temp_ttl_enable">
</div> </div>
<div class="span2" ng-show="loader.save_temp"> <div class="span5" ng-show="dashboard.current.loader.save_temp &amp;&amp; dashboard.current.loader.save_temp_ttl_enable">
<label class="small">TTL <tip>Expire temp urls</tip></label><input type="checkbox" ng-model="loader.save_temp_ttl_enable"> <label class="small">TTL Duration <tip>Elasticsearch date math, eg: 1m,1d,1w,30d </tip></label><input class="input-small" type="text" ng-model="dashboard.current.loader.save_temp_ttl">
</div> </div>
<div class="span5" ng-show="loader.save_temp &amp;&amp; loader.save_temp_ttl_enable">
<label class="small">TTL Duration <tip>Elasticsearch date math, eg: 1m,1d,1w,30d </tip></label><input class="input-small" type="text" ng-model="loader.save_temp_ttl">
</div> </div>
</div> </div>
<div ng-repeat="pulldown in dashboard.current.nav" ng-controller="PulldownCtrl" ng-include="'./app/panels/'+pulldown.type+'/editor.html'" ng-show="editor.index == 4+$index">
</div> </div>
</div> </div>
......
...@@ -13,7 +13,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -13,7 +13,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
var module = angular.module('kibana.services'); var module = angular.module('kibana.services');
module.service('dashboard', function($routeParams, $http, $rootScope, $injector, $location, module.service('dashboard', function(
$routeParams, $http, $rootScope, $injector, $location, $timeout,
ejsResource, timer, kbnIndex, alertSrv ejsResource, timer, kbnIndex, alertSrv
) { ) {
// A hash of defaults to use when loading a dashboard // A hash of defaults to use when loading a dashboard
...@@ -33,6 +34,11 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -33,6 +34,11 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
type: 'filtering' type: 'filtering'
} }
], ],
nav: [
{
type: 'timepicker2'
}
],
services: {}, services: {},
loader: { loader: {
save_gist: false, save_gist: false,
...@@ -42,10 +48,10 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -42,10 +48,10 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
save_temp: true, save_temp: true,
save_temp_ttl_enable: true, save_temp_ttl_enable: true,
save_temp_ttl: '30d', save_temp_ttl: '30d',
load_gist: true, load_gist: false,
load_elasticsearch: true, load_elasticsearch: true,
load_elasticsearch_size: 20, load_elasticsearch_size: 20,
load_local: true, load_local: false,
hide: false hide: false
}, },
index: { index: {
...@@ -53,6 +59,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -53,6 +59,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
pattern: '_all', pattern: '_all',
default: 'INDEX_MISSING' default: 'INDEX_MISSING'
}, },
refresh: false
}; };
// An elasticJS client to use // An elasticJS client to use
...@@ -172,6 +179,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -172,6 +179,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
self.indices = [dashboard.index.default]; self.indices = [dashboard.index.default];
} }
// Set the current dashboard
self.current = _.clone(dashboard); self.current = _.clone(dashboard);
// Ok, now that we've setup the current dashboard, we can inject our services // Ok, now that we've setup the current dashboard, we can inject our services
...@@ -182,11 +190,16 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -182,11 +190,16 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
querySrv.init(); querySrv.init();
filterSrv.init(); filterSrv.init();
// If there's an index interval set and no existing time filter, send a refresh to set one // If there's an interval set, the indices have not been calculated yet,
// so there is no data. Call refresh to calculate the indices and notify the panels.
if(dashboard.index.interval !== 'none') { if(dashboard.index.interval !== 'none') {
self.refresh(); self.refresh();
} }
if(dashboard.refresh) {
self.set_interval(dashboard.refresh);
}
return true; return true;
}; };
...@@ -420,6 +433,23 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -420,6 +433,23 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
return false; return false;
}); });
}; };
this.set_interval = function (interval) {
self.current.refresh = interval;
if(interval) {
var _i = kbn.interval_to_ms(interval);
timer.cancel(self.refresh_timer);
self.refresh_timer = timer.register($timeout(function() {
self.set_interval(interval);
self.refresh();
},_i));
self.refresh();
} else {
timer.cancel(self.refresh_timer);
}
};
}); });
}); });
\ No newline at end of file
...@@ -7,26 +7,20 @@ function (angular, _) { ...@@ -7,26 +7,20 @@ function (angular, _) {
var module = angular.module('kibana.services'); var module = angular.module('kibana.services');
module.service('panelMove', function(dashboard, $rootScope, alertSrv) { module.service('panelMove', function(dashboard, $rootScope) {
/* each of these can take event,ui,data parameters */ /* each of these can take event,ui,data parameters */
var notices = [];
this.onStart = function() { this.onStart = function() {
dashboard.panelDragging = true; dashboard.panelDragging = true;
notices.push(alertSrv.set('Moving','Drop this panel into an available space, or on top of another panel','info'));
$rootScope.$apply(); $rootScope.$apply();
}; };
this.onOver = function() { this.onOver = function() {
notices.push(alertSrv.set('Add panel',
'Drop to add panel to this row. Panel will use row height, but retain their span','success'));
$rootScope.$apply(); $rootScope.$apply();
}; };
this.onOut = function() { this.onOut = function() {
clearNotices({severity:'success'});
$rootScope.$apply(); $rootScope.$apply();
}; };
...@@ -63,21 +57,12 @@ function (angular, _) { ...@@ -63,21 +57,12 @@ function (angular, _) {
}; };
var cleanup = function () { var cleanup = function () {
_.each(notices, function(n){
alertSrv.clear(n);
});
_.each(dashboard.current.rows, function(row) { _.each(dashboard.current.rows, function(row) {
row.panels = _.without(row.panels,{}); row.panels = _.without(row.panels,{});
row.panels = _.compact(row.panels); row.panels = _.compact(row.panels);
}); });
}; };
var clearNotices = function(options) {
_.each(_.where(notices,options), function(n) {
alertSrv.clear(n);
});
};
}); });
}); });
\ No newline at end of file
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
<link rel="stylesheet" href="css/bootstrap-responsive.min.css"> <link rel="stylesheet" href="css/bootstrap-responsive.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css"> <link rel="stylesheet" href="css/font-awesome.min.css">
<div ng-repeat='alert in dashAlerts.list' class="alert-{{alert.severity}} dashboard-notice" ng-show="$last" style="position:fixed"> <div ng-repeat='alert in dashAlerts.list' class="alert-{{alert.severity}} dashboard-notice" ng-show="$last">
<button type="button" class="close" ng-click="dashAlerts.clear(alert)" style="padding-right:50px">&times;</button> <button type="button" class="close" ng-click="dashAlerts.clear(alert)" style="padding-right:50px">&times;</button>
<strong>{{alert.title}}</strong> <span ng-bind-html-unsafe='alert.text'></span> <div style="padding-right:10px" class='pull-right small'> {{$index + 1}} alert(s) </div> <strong>{{alert.title}}</strong> <span ng-bind-html-unsafe='alert.text'></span> <div style="padding-right:10px" class='pull-right small'> {{$index + 1}} alert(s) </div>
</div> </div>
......
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