mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into add-influx-group-by
Conflicts: .gitignore src/app/partials/influxdb/editor.html src/app/services/influxdb/influxdbDatasource.js
This commit is contained in:
commit
3cc83ced93
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,7 +1,11 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.aws-config.json
|
.aws-config.json
|
||||||
dist
|
dist
|
||||||
|
|
||||||
|
# locally required config files
|
||||||
web.config
|
web.config
|
||||||
config.js
|
config.js
|
||||||
|
|
||||||
|
# Editor junk
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
*.swp
|
*.swp
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
"noempty": true,
|
"noempty": true,
|
||||||
"undef": true,
|
"undef": true,
|
||||||
"boss": true,
|
"boss": true,
|
||||||
"trailing": false,
|
"trailing": true,
|
||||||
"laxbreak": true,
|
"laxbreak": true,
|
||||||
"laxcomma": true,
|
"laxcomma": true,
|
||||||
"sub": true,
|
"sub": true,
|
||||||
"unused": true,
|
"unused": true,
|
||||||
|
"maxdepth": 5,
|
||||||
"maxlen": 140,
|
"maxlen": 140,
|
||||||
|
|
||||||
"globals": {
|
"globals": {
|
||||||
|
34
CHANGELOG.md
34
CHANGELOG.md
@ -1,5 +1,37 @@
|
|||||||
vNext
|
# vNext
|
||||||
|
|
||||||
|
#### New features or improvements
|
||||||
- New Y-axis formater for metric values that represent seconds (Issue #427) - thx @jippi
|
- New Y-axis formater for metric values that represent seconds (Issue #427) - thx @jippi
|
||||||
|
- Allow special characters in serie names (influxdb datasource), PR #390 - thx @majst01
|
||||||
|
- Refactoring of filterSrv (Issue #428), thx @Tetha
|
||||||
|
- New config for playlist feature. Set playlist_timespan to set default playlist interval (Issue #445) - thx @rmca
|
||||||
|
- New graphite function definition added isNonNull (PR #461), - thx @tmonk42
|
||||||
|
- New InfluxDB function difference add to function dropdown (PR #455)
|
||||||
|
- Added parameter to keepLastValue graphite function definition (default 100), Closes #459
|
||||||
|
- improved asset (css/js) build pipeline, added revision to css and js. Will remove issues related
|
||||||
|
to the browser cache when upgrading grafana and improve load performance (Fixes #418)
|
||||||
|
- Partial support for url encoded metrics when using Graphite datasource (PR #327) - thx @axe-felix
|
||||||
|
- Improvement to InfluxDB query editor and function/value column selection (Issue #473)
|
||||||
|
- Initial support for filtering (templated queries) for InfluxDB (PR #375) - thx @mavimo
|
||||||
|
- Row editing and adding new panel is now a lot quicker and easier with the new
|
||||||
|
row menu (Issue #475)
|
||||||
|
|
||||||
|
#### Changes
|
||||||
|
- Graphite panel is now renamed graph (Existing dashboards will still work)
|
||||||
|
- Add panel icon and Row edit button is replaced by the Row edit menu (Issue #475)
|
||||||
|
- New graphs now have a default empty query
|
||||||
|
- Add Row button now creates a row with default height of 250px (no longer opens dashboard settings modal)
|
||||||
|
|
||||||
|
#### Fixes
|
||||||
|
- Filter option loading when having muliple nested filters now works better.
|
||||||
|
Options are now reloaded correctly and there are no multiple renders/refresh inbetween (#447),
|
||||||
|
After an option is changed and a nested template param is also reloaded, if the current value
|
||||||
|
exists after the options are reloaded the current selected value is kept (Closes #447, Closes #412)
|
||||||
|
- Legend Current value did not display when value was zero, Fixes #460
|
||||||
|
- Fix to series toggling bug that caused annotations to be hidden when toggling (hiding) series. Fixes #328
|
||||||
|
- Fix for graphite function selection menu that some times draws outside screen. It now displays upward (Fixes #293)
|
||||||
|
- Fix for exclusive series toggling (hold down CTRL, SHIFT or META key) and left click a series for exclusive toggling
|
||||||
|
CTRL does not work on MAC OSX but SHIFT or META should (depending on browser) (Closes #350, Fixes #472)
|
||||||
|
|
||||||
# 1.5.4 (2014-05-13)
|
# 1.5.4 (2014-05-13)
|
||||||
### New features and improvements
|
### New features and improvements
|
||||||
|
11
package.json
11
package.json
@ -44,7 +44,11 @@
|
|||||||
"karma-mocha": "~0.1.1",
|
"karma-mocha": "~0.1.1",
|
||||||
"karma-expect": "~1.0.0",
|
"karma-expect": "~1.0.0",
|
||||||
"grunt-cli": "~0.1.13",
|
"grunt-cli": "~0.1.13",
|
||||||
"jshint-stylish": "~0.1.5"
|
"jshint-stylish": "~0.1.5",
|
||||||
|
"grunt-contrib-concat": "^0.4.0",
|
||||||
|
"grunt-angular-templates": "^0.5.5",
|
||||||
|
"grunt-usemin": "^2.1.1",
|
||||||
|
"grunt-filerev": "^0.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "0.10.x",
|
"node": "0.10.x",
|
||||||
@ -53,5 +57,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "grunt test"
|
"test": "grunt test"
|
||||||
},
|
},
|
||||||
"license": "Apache License"
|
"license": "Apache License",
|
||||||
|
"dependencies": {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,8 +98,9 @@ function (angular, $, _, appLevelRequire) {
|
|||||||
'pasvaz.bindonce'
|
'pasvaz.bindonce'
|
||||||
];
|
];
|
||||||
|
|
||||||
_.each('controllers directives factories services filters'.split(' '),
|
var module_types = ['controllers', 'directives', 'factories', 'services', 'services.dashboard', 'filters'];
|
||||||
function (type) {
|
|
||||||
|
_.each(module_types, function (type) {
|
||||||
var module_name = 'kibana.'+type;
|
var module_name = 'kibana.'+type;
|
||||||
// create the module
|
// create the module
|
||||||
app.useModule(angular.module(module_name, []));
|
app.useModule(angular.module(module_name, []));
|
||||||
@ -117,7 +118,8 @@ function (angular, $, _, appLevelRequire) {
|
|||||||
require([
|
require([
|
||||||
'controllers/all',
|
'controllers/all',
|
||||||
'directives/all',
|
'directives/all',
|
||||||
'filters/all'
|
'filters/all',
|
||||||
|
'components/partials',
|
||||||
], function () {
|
], function () {
|
||||||
|
|
||||||
// bootstrap the app
|
// bootstrap the app
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
define(['jquery','underscore','moment','chromath'],
|
define(['jquery','underscore','moment'],
|
||||||
function($, _, moment) {
|
function($, _, moment) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -294,79 +294,6 @@ function($, _, moment) {
|
|||||||
return dateTime.toDate();
|
return dateTime.toDate();
|
||||||
};
|
};
|
||||||
|
|
||||||
// LOL. hahahahaha. DIE.
|
|
||||||
kbn.flatten_json = function(object,root,array) {
|
|
||||||
if (typeof array === 'undefined') {
|
|
||||||
array = {};
|
|
||||||
}
|
|
||||||
if (typeof root === 'undefined') {
|
|
||||||
root = '';
|
|
||||||
}
|
|
||||||
for(var index in object) {
|
|
||||||
var obj = object[index];
|
|
||||||
var rootname = root.length === 0 ? index : root + '.' + index;
|
|
||||||
if(typeof obj === 'object' ) {
|
|
||||||
if(_.isArray(obj)) {
|
|
||||||
if(obj.length > 0 && typeof obj[0] === 'object') {
|
|
||||||
var strval = '';
|
|
||||||
for (var objidx = 0, objlen = obj.length; objidx < objlen; objidx++) {
|
|
||||||
if (objidx > 0) {
|
|
||||||
strval = strval + ', ';
|
|
||||||
}
|
|
||||||
|
|
||||||
strval = strval + JSON.stringify(obj[objidx]);
|
|
||||||
}
|
|
||||||
array[rootname] = strval;
|
|
||||||
} else if(obj.length === 1 && _.isNumber(obj[0])) {
|
|
||||||
array[rootname] = parseFloat(obj[0]);
|
|
||||||
} else {
|
|
||||||
array[rootname] = typeof obj === 'undefined' ? null : obj;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
kbn.flatten_json(obj,rootname,array);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
array[rootname] = typeof obj === 'undefined' ? null : obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kbn.sortObj(array);
|
|
||||||
};
|
|
||||||
|
|
||||||
kbn.xmlEnt = function(value) {
|
|
||||||
if(_.isString(value)) {
|
|
||||||
var stg1 = value.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/\r\n/g, '<br/>')
|
|
||||||
.replace(/\r/g, '<br/>')
|
|
||||||
.replace(/\n/g, '<br/>')
|
|
||||||
.replace(/\t/g, ' ')
|
|
||||||
.replace(/ /g, ' ')
|
|
||||||
.replace(/<del>/g, '<del>')
|
|
||||||
.replace(/<\/del>/g, '</del>');
|
|
||||||
return stg1;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
kbn.sortObj = function(arr) {
|
|
||||||
// Setup Arrays
|
|
||||||
var sortedKeys = [];
|
|
||||||
var sortedObj = {};
|
|
||||||
var i;
|
|
||||||
// Separate keys and sort them
|
|
||||||
for (i in arr) {
|
|
||||||
sortedKeys.push(i);
|
|
||||||
}
|
|
||||||
sortedKeys.sort();
|
|
||||||
|
|
||||||
// Reconstruct sorted obj based on keys
|
|
||||||
for (i in sortedKeys) {
|
|
||||||
sortedObj[sortedKeys[i]] = arr[sortedKeys[i]];
|
|
||||||
}
|
|
||||||
return sortedObj;
|
|
||||||
};
|
|
||||||
|
|
||||||
kbn.query_color_dot = function (color, diameter) {
|
kbn.query_color_dot = function (color, diameter) {
|
||||||
return '<div class="icon-circle" style="' + [
|
return '<div class="icon-circle" style="' + [
|
||||||
'display:inline-block',
|
'display:inline-block',
|
||||||
@ -375,42 +302,6 @@ function($, _, moment) {
|
|||||||
].join(';') + '"></div>';
|
].join(';') + '"></div>';
|
||||||
};
|
};
|
||||||
|
|
||||||
kbn.colorSteps = function(col,steps) {
|
|
||||||
|
|
||||||
var _d = steps > 5 ? 1.6/steps : 0.25, // distance between steps
|
|
||||||
_p = []; // adjustment percentage
|
|
||||||
|
|
||||||
// Create a range of numbers between -0.8 and 0.8
|
|
||||||
for(var i = 1; i<steps+1; i+=1) {
|
|
||||||
_p.push(i%2 ? ((i-1)*_d*-1)/2 : i*_d/2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the color range
|
|
||||||
return _.map(_p.sort(function(a,b){return a-b;}),function(v) {
|
|
||||||
return v<0 ? Chromath.darken(col,v*-1).toString() : Chromath.lighten(col,v).toString();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find the smallest missing number in an array
|
|
||||||
kbn.smallestMissing = function(arr,start,end) {
|
|
||||||
start = start || 0;
|
|
||||||
end = end || arr.length-1;
|
|
||||||
|
|
||||||
if(start > end) {
|
|
||||||
return end + 1;
|
|
||||||
}
|
|
||||||
if(start !== arr[start]) {
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
var middle = Math.floor((start + end) / 2);
|
|
||||||
|
|
||||||
if (arr[middle] > middle) {
|
|
||||||
return kbn.smallestMissing(arr, start, middle);
|
|
||||||
} else {
|
|
||||||
return kbn.smallestMissing(arr, middle + 1, end);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
kbn.byteFormat = function(size, decimals) {
|
kbn.byteFormat = function(size, decimals) {
|
||||||
var ext, steps = 0;
|
var ext, steps = 0;
|
||||||
|
|
||||||
|
2
src/app/components/partials.js
Normal file
2
src/app/components/partials.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
define([
|
||||||
|
], function () {});
|
@ -13,7 +13,6 @@ require.config({
|
|||||||
text: '../vendor/require/text',
|
text: '../vendor/require/text',
|
||||||
moment: '../vendor/moment',
|
moment: '../vendor/moment',
|
||||||
filesaver: '../vendor/filesaver',
|
filesaver: '../vendor/filesaver',
|
||||||
chromath: '../vendor/chromath',
|
|
||||||
angular: '../vendor/angular/angular',
|
angular: '../vendor/angular/angular',
|
||||||
'angular-dragdrop': '../vendor/angular/angular-dragdrop',
|
'angular-dragdrop': '../vendor/angular/angular-dragdrop',
|
||||||
'angular-strap': '../vendor/angular/angular-strap',
|
'angular-strap': '../vendor/angular/angular-strap',
|
||||||
@ -47,6 +46,7 @@ require.config({
|
|||||||
elasticjs: '../vendor/elasticjs/elastic-angular-client',
|
elasticjs: '../vendor/elasticjs/elastic-angular-client',
|
||||||
|
|
||||||
'bootstrap-tagsinput': '../vendor/tagsinput/bootstrap-tagsinput',
|
'bootstrap-tagsinput': '../vendor/tagsinput/bootstrap-tagsinput',
|
||||||
|
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
underscore: {
|
underscore: {
|
||||||
|
@ -25,6 +25,7 @@ function (_, crypto) {
|
|||||||
grafana_index : 'grafana-dash',
|
grafana_index : 'grafana-dash',
|
||||||
elasticsearch_all_disabled : false,
|
elasticsearch_all_disabled : false,
|
||||||
timezoneOffset : null,
|
timezoneOffset : null,
|
||||||
|
playlist_timespan : "1m",
|
||||||
unsaved_changes_warning : true
|
unsaved_changes_warning : true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ define([
|
|||||||
'jquery',
|
'jquery',
|
||||||
'config',
|
'config',
|
||||||
'underscore',
|
'underscore',
|
||||||
'services/all'
|
'services/all',
|
||||||
|
'services/dashboard/all'
|
||||||
],
|
],
|
||||||
function (angular, $, config, _) {
|
function (angular, $, config, _) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -30,7 +31,7 @@ function (angular, $, config, _) {
|
|||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
module.controller('DashCtrl', function(
|
module.controller('DashCtrl', function(
|
||||||
$scope, $rootScope, ejsResource, dashboard,
|
$scope, $rootScope, $timeout, ejsResource, dashboard, filterSrv, dashboardKeybindings,
|
||||||
alertSrv, panelMove, keyboardManager, grafanaVersion) {
|
alertSrv, panelMove, keyboardManager, grafanaVersion) {
|
||||||
|
|
||||||
$scope.requiredElasticSearchVersion = ">=0.90.3";
|
$scope.requiredElasticSearchVersion = ">=0.90.3";
|
||||||
@ -51,11 +52,19 @@ function (angular, $, config, _) {
|
|||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.config = config;
|
$scope.config = config;
|
||||||
|
|
||||||
// Make stuff, including underscore.js available to views
|
// Make stuff, including underscore.js available to views
|
||||||
$scope._ = _;
|
$scope._ = _;
|
||||||
$scope.dashboard = dashboard;
|
$scope.dashboard = dashboard;
|
||||||
$scope.dashAlerts = alertSrv;
|
$scope.dashAlerts = alertSrv;
|
||||||
|
|
||||||
|
$scope.filter = filterSrv;
|
||||||
|
$scope.filter.init(dashboard.current);
|
||||||
|
|
||||||
|
$rootScope.$on("dashboard-loaded", function(event, dashboard) {
|
||||||
|
$scope.filter.init(dashboard);
|
||||||
|
});
|
||||||
|
|
||||||
// Clear existing alerts
|
// Clear existing alerts
|
||||||
alertSrv.clearAll();
|
alertSrv.clearAll();
|
||||||
|
|
||||||
@ -66,68 +75,7 @@ function (angular, $, config, _) {
|
|||||||
$scope.bindKeyboardShortcuts();
|
$scope.bindKeyboardShortcuts();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.bindKeyboardShortcuts = function() {
|
$scope.bindKeyboardShortcuts = dashboardKeybindings.shortcuts;
|
||||||
$rootScope.$on('panel-fullscreen-enter', function() {
|
|
||||||
$rootScope.fullscreen = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootScope.$on('panel-fullscreen-exit', function() {
|
|
||||||
$rootScope.fullscreen = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootScope.$on('dashboard-saved', function() {
|
|
||||||
if ($rootScope.fullscreen) {
|
|
||||||
$rootScope.$emit('panel-fullscreen-exit');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
keyboardManager.bind('ctrl+f', function(evt) {
|
|
||||||
$rootScope.$emit('open-search', evt);
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
|
|
||||||
keyboardManager.bind('ctrl+h', function() {
|
|
||||||
var current = dashboard.current.hideControls;
|
|
||||||
dashboard.current.hideControls = !current;
|
|
||||||
dashboard.current.panel_hints = current;
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
|
|
||||||
keyboardManager.bind('ctrl+s', function(evt) {
|
|
||||||
$rootScope.$emit('save-dashboard', evt);
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
|
|
||||||
keyboardManager.bind('ctrl+r', function() {
|
|
||||||
dashboard.refresh();
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
|
|
||||||
keyboardManager.bind('ctrl+z', function(evt) {
|
|
||||||
$rootScope.$emit('zoom-out', evt);
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
|
|
||||||
keyboardManager.bind('esc', function() {
|
|
||||||
var popups = $('.popover.in');
|
|
||||||
if (popups.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$rootScope.$emit('panel-fullscreen-exit');
|
|
||||||
}, { inputDisabled: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.countWatchers = function (scopeStart) {
|
|
||||||
var q = [scopeStart || $rootScope], watchers = 0, scope;
|
|
||||||
while (q.length > 0) {
|
|
||||||
scope = q.pop();
|
|
||||||
if (scope.$$watchers) {
|
|
||||||
watchers += scope.$$watchers.length;
|
|
||||||
}
|
|
||||||
if (scope.$$childHead) {
|
|
||||||
q.push(scope.$$childHead);
|
|
||||||
}
|
|
||||||
if (scope.$$nextSibling) {
|
|
||||||
q.push(scope.$$nextSibling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.console.log(watchers);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.isPanel = function(obj) {
|
$scope.isPanel = function(obj) {
|
||||||
if(!_.isNull(obj) && !_.isUndefined(obj) && !_.isUndefined(obj.type)) {
|
if(!_.isNull(obj) && !_.isUndefined(obj) && !_.isUndefined(obj.type)) {
|
||||||
@ -137,14 +85,20 @@ function (angular, $, config, _) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.add_row = function(dash,row) {
|
$scope.add_row = function(dash, row) {
|
||||||
dash.rows.push(row);
|
dash.rows.push(row);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.add_row_default = function() {
|
||||||
|
$scope.reset_row();
|
||||||
|
$scope.row.title = 'New row';
|
||||||
|
$scope.add_row(dashboard.current, $scope.row);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.reset_row = function() {
|
$scope.reset_row = function() {
|
||||||
$scope.row = {
|
$scope.row = {
|
||||||
title: '',
|
title: '',
|
||||||
height: '150px',
|
height: '250px',
|
||||||
editable: true,
|
editable: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -196,4 +150,4 @@ function (angular, $, config, _) {
|
|||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@ function (angular, _, moment) {
|
|||||||
|
|
||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
module.controller('dashLoader', function($scope, $rootScope, $http, dashboard, alertSrv, $location, filterSrv, playlistSrv) {
|
module.controller('dashLoader', function($scope, $rootScope, $http, dashboard, alertSrv, $location, playlistSrv) {
|
||||||
$scope.loader = dashboard.current.loader;
|
$scope.loader = dashboard.current.loader;
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
@ -77,7 +77,7 @@ function (angular, _, moment) {
|
|||||||
$scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
|
$scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootScope.$emit('dashboard-saved');
|
$rootScope.$emit('dashboard-saved', dashboard.current);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ function (angular, _, moment) {
|
|||||||
// function $scope.zoom
|
// function $scope.zoom
|
||||||
// factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
|
// factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
|
||||||
$scope.zoom = function(factor) {
|
$scope.zoom = function(factor) {
|
||||||
var _range = filterSrv.timeRange();
|
var _range = this.filter.timeRange();
|
||||||
var _timespan = (_range.to.valueOf() - _range.from.valueOf());
|
var _timespan = (_range.to.valueOf() - _range.from.valueOf());
|
||||||
var _center = _range.to.valueOf() - _timespan/2;
|
var _center = _range.to.valueOf() - _timespan/2;
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ function (angular, _, moment) {
|
|||||||
_to = Date.now();
|
_to = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
filterSrv.setTime({
|
this.filter.setTime({
|
||||||
from:moment.utc(_from).toDate(),
|
from:moment.utc(_from).toDate(),
|
||||||
to:moment.utc(_to).toDate(),
|
to:moment.utc(_to).toDate(),
|
||||||
});
|
});
|
||||||
|
@ -10,9 +10,11 @@ function (angular, _, config, gfunc, Parser) {
|
|||||||
|
|
||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv) {
|
module.controller('GraphiteTargetCtrl', function($scope) {
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
|
$scope.target.target = $scope.target.target || '';
|
||||||
|
|
||||||
parseTarget();
|
parseTarget();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ function (angular, _, config, gfunc, Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var path = getSegmentPathUpTo(fromIndex + 1);
|
var path = getSegmentPathUpTo(fromIndex + 1);
|
||||||
return $scope.datasource.metricFindQuery(path)
|
return $scope.datasource.metricFindQuery($scope.filter, path)
|
||||||
.then(function(segments) {
|
.then(function(segments) {
|
||||||
if (segments.length === 0) {
|
if (segments.length === 0) {
|
||||||
$scope.segments = $scope.segments.splice(0, fromIndex);
|
$scope.segments = $scope.segments.splice(0, fromIndex);
|
||||||
@ -157,17 +159,17 @@ function (angular, _, config, gfunc, Parser) {
|
|||||||
var query = index === 0 ?
|
var query = index === 0 ?
|
||||||
'*' : getSegmentPathUpTo(index) + '.*';
|
'*' : getSegmentPathUpTo(index) + '.*';
|
||||||
|
|
||||||
return $scope.datasource.metricFindQuery(query)
|
return $scope.datasource.metricFindQuery($scope.filter, query)
|
||||||
.then(function(segments) {
|
.then(function(segments) {
|
||||||
_.each(segments, function(segment) {
|
_.each(segments, function(segment) {
|
||||||
segment.html = segment.val = segment.text;
|
segment.html = segment.val = segment.text;
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(filterSrv.list, function(filter) {
|
_.each($scope.filter.templateParameters, function( templateParameter ) {
|
||||||
segments.unshift({
|
segments.unshift({
|
||||||
type: 'template',
|
type: 'template',
|
||||||
html: '[[' + filter.name + ']]',
|
html: '[[' + templateParameter.name + ']]',
|
||||||
val: '[[' + filter.name + ']]',
|
val: '[[' + templateParameter.name + ']]',
|
||||||
expandable: true,
|
expandable: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,13 +11,15 @@ function (angular) {
|
|||||||
module.controller('InfluxTargetCtrl', function($scope, $timeout) {
|
module.controller('InfluxTargetCtrl', function($scope, $timeout) {
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
if (!$scope.target.function) {
|
$scope.target.function = $scope.target.function || 'mean';
|
||||||
$scope.target.function = 'mean';
|
$scope.target.column = $scope.target.column || 'value';
|
||||||
}
|
|
||||||
|
|
||||||
$scope.rawQuery = false;
|
$scope.rawQuery = false;
|
||||||
|
|
||||||
$scope.functions = ['count', 'mean', 'sum', 'min', 'max', 'mode', 'distinct', 'median', 'derivative', 'stddev', 'first', 'last'];
|
$scope.functions = ['count', 'mean', 'sum', 'min',
|
||||||
|
'max', 'mode', 'distinct', 'median',
|
||||||
|
'derivative', 'stddev', 'first', 'last',
|
||||||
|
'difference'];
|
||||||
$scope.operators = ['=', '=~', '>', '<', '!~', '<>'];
|
$scope.operators = ['=', '=~', '>', '<', '!~', '<>'];
|
||||||
$scope.oldSeries = $scope.target.series;
|
$scope.oldSeries = $scope.target.series;
|
||||||
$scope.$on('typeahead-updated', function(){
|
$scope.$on('typeahead-updated', function(){
|
||||||
@ -41,6 +43,11 @@ function (angular) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.changeFunction = function(func) {
|
||||||
|
$scope.target.function = func;
|
||||||
|
$scope.get_data();
|
||||||
|
};
|
||||||
|
|
||||||
// called outside of digest
|
// called outside of digest
|
||||||
$scope.listColumns = function(query, callback) {
|
$scope.listColumns = function(query, callback) {
|
||||||
if (!$scope.columnList) {
|
if (!$scope.columnList) {
|
||||||
|
@ -52,18 +52,24 @@ function (angular, _, config) {
|
|||||||
$scope.loadAll = function() {
|
$scope.loadAll = function() {
|
||||||
$scope.infoText = "Fetching all metrics from graphite...";
|
$scope.infoText = "Fetching all metrics from graphite...";
|
||||||
|
|
||||||
return $http.get(config.graphiteUrl + "/metrics/index.json")
|
getFromEachGraphite('/metrics/index.json', saveMetricsArray)
|
||||||
.then(saveMetricsArray)
|
.then( function() {
|
||||||
.then(function () {
|
|
||||||
$scope.infoText = "Indexing complete!";
|
$scope.infoText = "Indexing complete!";
|
||||||
})
|
}).then(null, function(err) {
|
||||||
.then(null, function(err) {
|
|
||||||
$scope.errorText = err;
|
$scope.errorText = err;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function saveMetricsArray(data, currentIndex)
|
function getFromEachGraphite(request, data_callback, error_callback) {
|
||||||
{
|
return $q.all( _.map( config.datasources, function( datasource ) {
|
||||||
|
if ( datasource.type = 'graphite' ) {
|
||||||
|
return $http.get( datasource.url + request )
|
||||||
|
.then( data_callback, error_callback );
|
||||||
|
}
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveMetricsArray(data, currentIndex) {
|
||||||
if (!data && !data.data && data.data.length === 0) {
|
if (!data && !data.data && data.data.length === 0) {
|
||||||
return $q.reject('No metrics from graphite');
|
return $q.reject('No metrics from graphite');
|
||||||
}
|
}
|
||||||
@ -80,6 +86,7 @@ function (angular, _, config) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteIndex()
|
function deleteIndex()
|
||||||
{
|
{
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
@ -172,9 +179,9 @@ function (angular, _, config) {
|
|||||||
|
|
||||||
function loadMetricsRecursive(metricPath)
|
function loadMetricsRecursive(metricPath)
|
||||||
{
|
{
|
||||||
return $http.get(config.graphiteUrl + '/metrics/find/?query=' + metricPath).then(receiveMetric);
|
return getFromEachGraphite( '/metrics/find/?query=' + metricPath, receiveMetric );
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
define([
|
define([
|
||||||
'angular',
|
'angular',
|
||||||
'underscore'
|
'underscore',
|
||||||
|
'config'
|
||||||
],
|
],
|
||||||
function (angular, _) {
|
function (angular, _, config) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
@ -10,7 +11,7 @@ function (angular, _) {
|
|||||||
module.controller('PlaylistCtrl', function($scope, playlistSrv) {
|
module.controller('PlaylistCtrl', function($scope, playlistSrv) {
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.timespan = "15s";
|
$scope.timespan = config.playlist_timespan;
|
||||||
$scope.loadFavorites();
|
$scope.loadFavorites();
|
||||||
$scope.$on('modal-opened', $scope.loadFavorites);
|
$scope.$on('modal-opened', $scope.loadFavorites);
|
||||||
};
|
};
|
||||||
@ -35,4 +36,4 @@ function (angular, _) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -53,10 +53,56 @@ function (angular, app, _) {
|
|||||||
$scope.$broadcast('render');
|
$scope.$broadcast('render');
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.add_panel = function(row,panel) {
|
$scope.add_panel = function(panel) {
|
||||||
|
var rowSpan = $scope.rowSpan($scope.row);
|
||||||
|
var panelCount = $scope.row.panels.length;
|
||||||
|
var space = (12 - rowSpan) - panel.span;
|
||||||
|
|
||||||
|
// try to make room of there is no space left
|
||||||
|
if (space <= 0) {
|
||||||
|
if (panelCount === 1) {
|
||||||
|
$scope.row.panels[0].span = 6;
|
||||||
|
panel.span = 6;
|
||||||
|
}
|
||||||
|
else if (panelCount === 2) {
|
||||||
|
$scope.row.panels[0].span = 4;
|
||||||
|
$scope.row.panels[1].span = 4;
|
||||||
|
panel.span = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.row.panels.push(panel);
|
$scope.row.panels.push(panel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.delete_row = function() {
|
||||||
|
if (confirm("Are you sure you want to delete this row?")) {
|
||||||
|
$scope.dashboard.current.rows = _.without($scope.dashboard.current.rows, $scope.row);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.move_row = function(direction) {
|
||||||
|
var rowsList = $scope.dashboard.current.rows;
|
||||||
|
var rowIndex = _.indexOf(rowsList, $scope.row);
|
||||||
|
var newIndex = rowIndex + direction;
|
||||||
|
if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) {
|
||||||
|
_.move(rowsList, rowIndex, rowIndex + direction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.add_panel_default = function(type) {
|
||||||
|
$scope.reset_panel(type);
|
||||||
|
$scope.add_panel($scope.panel);
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
$scope.$broadcast('render');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.set_height = function(height) {
|
||||||
|
$scope.row.height = height;
|
||||||
|
$scope.$broadcast('render');
|
||||||
|
};
|
||||||
|
|
||||||
$scope.remove_panel_from_row = function(row, panel) {
|
$scope.remove_panel_from_row = function(row, panel) {
|
||||||
if (confirm('Are you sure you want to remove this ' + panel.type + ' panel?')) {
|
if (confirm('Are you sure you want to remove this ' + panel.type + ' panel?')) {
|
||||||
row.panels = _.without(row.panels,panel);
|
row.panels = _.without(row.panels,panel);
|
||||||
|
@ -18,7 +18,7 @@ function (angular, app, _, $, gfunc) {
|
|||||||
|
|
||||||
var buttonTemplate = '<a class="grafana-target-segment grafana-target-function dropdown-toggle"' +
|
var buttonTemplate = '<a class="grafana-target-segment grafana-target-function dropdown-toggle"' +
|
||||||
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown"' +
|
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown"' +
|
||||||
' data-placement="bottom"><i class="icon-plus"></i></a>';
|
' data-placement="top"><i class="icon-plus"></i></a>';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
link: function($scope, elem) {
|
link: function($scope, elem) {
|
||||||
|
@ -15,5 +15,6 @@ define([
|
|||||||
'./bodyClass',
|
'./bodyClass',
|
||||||
'./addGraphiteFunc',
|
'./addGraphiteFunc',
|
||||||
'./graphiteFuncEditor',
|
'./graphiteFuncEditor',
|
||||||
'./grafanaVersionCheck'
|
'./grafanaVersionCheck',
|
||||||
|
'./influxdbFuncEditor'
|
||||||
], function () {});
|
], function () {});
|
17
src/app/directives/bootstrap-tagsinput.js
vendored
17
src/app/directives/bootstrap-tagsinput.js
vendored
@ -87,13 +87,12 @@ function (angular, $) {
|
|||||||
.module('kibana.directives')
|
.module('kibana.directives')
|
||||||
.directive('gfDropdown', function ($parse, $compile, $timeout) {
|
.directive('gfDropdown', function ($parse, $compile, $timeout) {
|
||||||
|
|
||||||
function buildTemplate(items, ul) {
|
function buildTemplate(items, placement) {
|
||||||
if (!ul) {
|
var upclass = placement === 'top' ? 'dropup' : '';
|
||||||
ul = [
|
var ul = [
|
||||||
'<ul class="dropdown-menu" role="menu" aria-labelledby="drop1">',
|
'<ul class="dropdown-menu ' + upclass + '" role="menu" aria-labelledby="drop1">',
|
||||||
'</ul>'
|
'</ul>'
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
angular.forEach(items, function (item, index) {
|
angular.forEach(items, function (item, index) {
|
||||||
if (item.divider) {
|
if (item.divider) {
|
||||||
@ -122,10 +121,12 @@ function (angular, $) {
|
|||||||
link: function postLink(scope, iElement, iAttrs) {
|
link: function postLink(scope, iElement, iAttrs) {
|
||||||
var getter = $parse(iAttrs.gfDropdown), items = getter(scope);
|
var getter = $parse(iAttrs.gfDropdown), items = getter(scope);
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
var dropdown = angular.element(buildTemplate(items).join(''));
|
var placement = iElement.data('placement');
|
||||||
|
var dropdown = angular.element(buildTemplate(items, placement).join(''));
|
||||||
dropdown.insertAfter(iElement);
|
dropdown.insertAfter(iElement);
|
||||||
$compile(iElement.next('ul.dropdown-menu'))(scope);
|
$compile(iElement.next('ul.dropdown-menu'))(scope);
|
||||||
});
|
});
|
||||||
|
|
||||||
iElement.addClass('dropdown-toggle').attr('data-toggle', 'dropdown');
|
iElement.addClass('dropdown-toggle').attr('data-toggle', 'dropdown');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
25
src/app/directives/grafanaGraph.js
Normal file → Executable file
25
src/app/directives/grafanaGraph.js
Normal file → Executable file
@ -10,12 +10,12 @@ function (angular, $, kbn, moment, _) {
|
|||||||
|
|
||||||
var module = angular.module('kibana.directives');
|
var module = angular.module('kibana.directives');
|
||||||
|
|
||||||
module.directive('grafanaGraph', function(filterSrv, $rootScope, dashboard) {
|
module.directive('grafanaGraph', function($rootScope, dashboard) {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
template: '<div> </div>',
|
template: '<div> </div>',
|
||||||
link: function(scope, elem) {
|
link: function(scope, elem) {
|
||||||
var data, plot;
|
var data, plot, annotations;
|
||||||
var hiddenData = {};
|
var hiddenData = {};
|
||||||
|
|
||||||
scope.$on('refresh',function() {
|
scope.$on('refresh',function() {
|
||||||
@ -35,8 +35,9 @@ function (angular, $, kbn, moment, _) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Receive render events
|
// Receive render events
|
||||||
scope.$on('render',function(event, d) {
|
scope.$on('render',function(event, renderData) {
|
||||||
data = d || data;
|
data = renderData || data;
|
||||||
|
annotations = data.annotations;
|
||||||
render_panel();
|
render_panel();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -206,13 +207,13 @@ function (angular, $, kbn, moment, _) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addAnnotations(options) {
|
function addAnnotations(options) {
|
||||||
if(!data.annotations || data.annotations.length === 0) {
|
if(!annotations || annotations.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = {};
|
var types = {};
|
||||||
|
|
||||||
_.each(data.annotations, function(event) {
|
_.each(annotations, function(event) {
|
||||||
if (!types[event.annotation.name]) {
|
if (!types[event.annotation.name]) {
|
||||||
types[event.annotation.name] = {
|
types[event.annotation.name] = {
|
||||||
level: _.keys(types).length + 1,
|
level: _.keys(types).length + 1,
|
||||||
@ -235,7 +236,7 @@ function (angular, $, kbn, moment, _) {
|
|||||||
|
|
||||||
options.events = {
|
options.events = {
|
||||||
levels: _.keys(types).length + 1,
|
levels: _.keys(types).length + 1,
|
||||||
data: data.annotations,
|
data: annotations,
|
||||||
types: types
|
types: types
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -313,7 +314,7 @@ function (angular, $, kbn, moment, _) {
|
|||||||
if (seriesInfo.alias) {
|
if (seriesInfo.alias) {
|
||||||
group = '<small style="font-size:0.9em;">' +
|
group = '<small style="font-size:0.9em;">' +
|
||||||
'<i class="icon-circle" style="color:'+item.series.color+';"></i>' + ' ' +
|
'<i class="icon-circle" style="color:'+item.series.color+';"></i>' + ' ' +
|
||||||
(seriesInfo.alias || seriesInfo.query)+
|
(decodeURIComponent(seriesInfo.alias)) +
|
||||||
'</small><br>';
|
'</small><br>';
|
||||||
} else {
|
} else {
|
||||||
group = kbn.query_color_dot(item.series.color, 15) + ' ';
|
group = kbn.query_color_dot(item.series.color, 15) + ' ';
|
||||||
@ -387,9 +388,11 @@ function (angular, $, kbn, moment, _) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
elem.bind("plotselected", function (event, ranges) {
|
elem.bind("plotselected", function (event, ranges) {
|
||||||
filterSrv.setTime({
|
scope.$apply( function() {
|
||||||
from : moment.utc(ranges.xaxis.from).toDate(),
|
scope.filter.setTime({
|
||||||
to : moment.utc(ranges.xaxis.to).toDate(),
|
from : moment.utc(ranges.xaxis.from).toDate(),
|
||||||
|
to : moment.utc(ranges.xaxis.to).toDate(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
137
src/app/directives/influxdbFuncEditor.js
Normal file
137
src/app/directives/influxdbFuncEditor.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'underscore',
|
||||||
|
'jquery',
|
||||||
|
],
|
||||||
|
function (angular, _, $) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('kibana.directives')
|
||||||
|
.directive('influxdbFuncEditor', function($compile) {
|
||||||
|
|
||||||
|
var funcSpanTemplate = '<a gf-dropdown="functionMenu" class="dropdown-toggle" ' +
|
||||||
|
'data-toggle="dropdown">{{target.function}}</a><span>(</span>';
|
||||||
|
|
||||||
|
var paramTemplate = '<input type="text" style="display:none"' +
|
||||||
|
' class="input-mini grafana-function-param-input"></input>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function postLink($scope, elem) {
|
||||||
|
var $funcLink = $(funcSpanTemplate);
|
||||||
|
|
||||||
|
$scope.functionMenu = _.map($scope.functions, function(func) {
|
||||||
|
return {
|
||||||
|
text: func,
|
||||||
|
click: "changeFunction('" + func + "');"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function clickFuncParam() {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
|
||||||
|
var $link = $(this);
|
||||||
|
var $input = $link.next();
|
||||||
|
|
||||||
|
$input.val($scope.target.column);
|
||||||
|
$input.css('width', ($link.width() + 16) + 'px');
|
||||||
|
|
||||||
|
$link.hide();
|
||||||
|
$input.show();
|
||||||
|
$input.focus();
|
||||||
|
$input.select();
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
if (typeahead) {
|
||||||
|
$input.val('');
|
||||||
|
typeahead.lookup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputBlur() {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
|
||||||
|
var $input = $(this);
|
||||||
|
var $link = $input.prev();
|
||||||
|
|
||||||
|
if ($input.val() !== '') {
|
||||||
|
$link.text($input.val());
|
||||||
|
|
||||||
|
$scope.target.column = $input.val();
|
||||||
|
$scope.$apply($scope.get_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.hide();
|
||||||
|
$link.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyPress(e) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
|
||||||
|
if(e.which === 13) {
|
||||||
|
inputBlur.call(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyDown() {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
this.style.width = (3 + this.value.length) * 8 + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTypeahead($input) {
|
||||||
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
|
||||||
|
$input.typeahead({
|
||||||
|
source: function () {
|
||||||
|
return $scope.listColumns.apply(null, arguments);
|
||||||
|
},
|
||||||
|
minLength: 0,
|
||||||
|
items: 20,
|
||||||
|
updater: function (value) {
|
||||||
|
setTimeout(function() {
|
||||||
|
inputBlur.call($input[0]);
|
||||||
|
}, 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
typeahead.lookup = function () {
|
||||||
|
var items;
|
||||||
|
this.query = this.$element.val() || '';
|
||||||
|
items = this.source(this.query, $.proxy(this.process, this));
|
||||||
|
return items ? this.process(items) : items;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function addElementsAndCompile() {
|
||||||
|
$funcLink.appendTo(elem);
|
||||||
|
|
||||||
|
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + $scope.target.column + '</a>');
|
||||||
|
var $input = $(paramTemplate);
|
||||||
|
|
||||||
|
$paramLink.appendTo(elem);
|
||||||
|
$input.appendTo(elem);
|
||||||
|
|
||||||
|
$input.blur(_.partial(inputBlur));
|
||||||
|
$input.keyup(inputKeyDown);
|
||||||
|
$input.keypress(_.partial(inputKeyPress));
|
||||||
|
$paramLink.click(_.partial(clickFuncParam));
|
||||||
|
|
||||||
|
addTypeahead($input);
|
||||||
|
|
||||||
|
$('<span>)</span>').appendTo(elem);
|
||||||
|
|
||||||
|
$compile(elem.contents())($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
addElementsAndCompile();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
6
src/app/filters/all.js
Normal file → Executable file
6
src/app/filters/all.js
Normal file → Executable file
@ -114,4 +114,10 @@ define(['angular', 'jquery', 'underscore', 'moment'], function (angular, $, _, m
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.filter('urlDecode', function() {
|
||||||
|
return function(input) {
|
||||||
|
return decodeURIComponent(input);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
6
src/app/panels/filtering/module.html
Normal file → Executable file
6
src/app/panels/filtering/module.html
Normal file → Executable file
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class='filtering-container'>
|
<div class='filtering-container'>
|
||||||
|
|
||||||
<div ng-repeat="filter in filterSrv.list" class="small filter-panel-filter">
|
<div ng-repeat="filter in filter.templateParameters" class="small filter-panel-filter">
|
||||||
<div>
|
<div>
|
||||||
<i class="filter-action pointer icon-remove" bs-tooltip="'Remove'" ng-click="remove(filter)"></i>
|
<i class="filter-action pointer icon-remove" bs-tooltip="'Remove'" ng-click="remove(filter)"></i>
|
||||||
<i class="filter-action pointer icon-edit" ng-hide="filter.editing" bs-tooltip="'Edit'" ng-click="filter.editing = true"></i>
|
<i class="filter-action pointer icon-edit" ng-hide="filter.editing" bs-tooltip="'Edit'" ng-click="filter.editing = true"></i>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li ng-repeat="option in filter.options">
|
<li ng-repeat="option in filter.options">
|
||||||
<a ng-click="filterOptionSelected(filter, option)">{{option.text}}</a>
|
<a ng-click="filterOptionSelected(filter, option)">{{option.text | urlDecode}}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -47,4 +47,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<i class="pointer icon-plus-sign add-filter-action" ng-click="add()" bs-tooltip="'Add metric filter / param'" data-placement="right"></i>
|
<i class="pointer icon-plus-sign add-filter-action" ng-click="add()" bs-tooltip="'Add metric filter / param'" data-placement="right"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ function (angular, app, _) {
|
|||||||
var module = angular.module('kibana.panels.filtering', []);
|
var module = angular.module('kibana.panels.filtering', []);
|
||||||
app.useModule(module);
|
app.useModule(module);
|
||||||
|
|
||||||
module.controller('filtering', function($scope, filterSrv, datasourceSrv, $rootScope, dashboard) {
|
module.controller('filtering', function($scope, datasourceSrv, $rootScope, $timeout, $q) {
|
||||||
|
|
||||||
$scope.panelMeta = {
|
$scope.panelMeta = {
|
||||||
status : "Stable",
|
status : "Stable",
|
||||||
@ -27,54 +27,72 @@ function (angular, app, _) {
|
|||||||
_.defaults($scope.panel,_d);
|
_.defaults($scope.panel,_d);
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.filterSrv = filterSrv;
|
// empty. Don't know if I need the function then.
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.remove = function(filter) {
|
$scope.remove = function(templateParameter) {
|
||||||
filterSrv.remove(filter);
|
$scope.filter.removeTemplateParameter(templateParameter);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.filterOptionSelected = function(filter, option) {
|
$scope.filterOptionSelected = function(templateParameter, option, recursive) {
|
||||||
filterSrv.filterOptionSelected(filter, option);
|
templateParameter.current = option;
|
||||||
$scope.applyFilterToOtherFilters(filter);
|
|
||||||
|
$scope.filter.updateTemplateData();
|
||||||
|
|
||||||
|
return $scope.applyFilterToOtherFilters(templateParameter)
|
||||||
|
.then(function() {
|
||||||
|
// only refresh in the outermost call
|
||||||
|
if (!recursive) {
|
||||||
|
$scope.dashboard.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.applyFilterToOtherFilters = function(updatedFilter) {
|
$scope.applyFilterToOtherFilters = function(updatedTemplatedParam) {
|
||||||
_.each(filterSrv.list, function(filter) {
|
var promises = _.map($scope.filter.templateParameters, function(templateParam) {
|
||||||
if (filter === updatedFilter) {
|
if (templateParam === updatedTemplatedParam) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (filter.query.indexOf(updatedFilter.name) !== -1) {
|
if (templateParam.query.indexOf(updatedTemplatedParam.name) !== -1) {
|
||||||
$scope.applyFilter(filter);
|
return $scope.applyFilter(templateParam);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return $q.all(promises);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.applyFilter = function(filter) {
|
$scope.applyFilter = function(templateParam) {
|
||||||
var query = filterSrv.applyFilterToTarget(filter.query);
|
return datasourceSrv.default.metricFindQuery($scope.filter, templateParam.query)
|
||||||
|
|
||||||
datasourceSrv.default.metricFindQuery(query)
|
|
||||||
.then(function (results) {
|
.then(function (results) {
|
||||||
filter.editing=undefined;
|
templateParam.editing = undefined;
|
||||||
filter.options = _.map(results, function(node) {
|
templateParam.options = _.map(results, function(node) {
|
||||||
return { text: node.text, value: node.text };
|
return { text: node.text, value: node.text };
|
||||||
});
|
});
|
||||||
|
|
||||||
if (filter.includeAll) {
|
if (templateParam.includeAll) {
|
||||||
var allExpr = '{';
|
var allExpr = '{';
|
||||||
_.each(filter.options, function(option) {
|
_.each(templateParam.options, function(option) {
|
||||||
allExpr += option.text + ',';
|
allExpr += option.text + ',';
|
||||||
});
|
});
|
||||||
allExpr = allExpr.substring(0, allExpr.length - 1) + '}';
|
allExpr = allExpr.substring(0, allExpr.length - 1) + '}';
|
||||||
filter.options.unshift({text: 'All', value: allExpr});
|
templateParam.options.unshift({text: 'All', value: allExpr});
|
||||||
}
|
}
|
||||||
|
|
||||||
filterSrv.filterOptionSelected(filter, filter.options[0]);
|
// if parameter has current value
|
||||||
|
// if it exists in options array keep value
|
||||||
|
if (templateParam.current) {
|
||||||
|
var currentExists = _.findWhere(templateParam.options, { value: templateParam.current.value });
|
||||||
|
if (currentExists) {
|
||||||
|
return $scope.filterOptionSelected(templateParam, templateParam.current, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $scope.filterOptionSelected(templateParam, templateParam.options[0], true);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.add = function() {
|
$scope.add = function() {
|
||||||
filterSrv.add({
|
$scope.filter.addTemplateParameter({
|
||||||
type : 'filter',
|
type : 'filter',
|
||||||
name : 'filter name',
|
name : 'filter name',
|
||||||
editing : true,
|
editing : true,
|
||||||
@ -82,13 +100,5 @@ function (angular, app, _) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.refresh = function() {
|
|
||||||
dashboard.refresh();
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.render = function() {
|
|
||||||
$rootScope.$broadcast('render');
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
2
src/app/panels/graphite/legend.html → src/app/panels/graph/legend.html
Normal file → Executable file
2
src/app/panels/graphite/legend.html → src/app/panels/graph/legend.html
Normal file → Executable file
@ -9,7 +9,7 @@
|
|||||||
</i>
|
</i>
|
||||||
<span class='small histogram-legend-item'>
|
<span class='small histogram-legend-item'>
|
||||||
<a ng-click="toggleSeries(series, $event)" data-unique="1" data-placement="{{series.yaxis === 2 ? 'bottomRight' : 'bottomLeft'}}">
|
<a ng-click="toggleSeries(series, $event)" data-unique="1" data-placement="{{series.yaxis === 2 ? 'bottomRight' : 'bottomLeft'}}">
|
||||||
{{series.alias}}
|
{{series.alias | urlDecode}}
|
||||||
</a>
|
</a>
|
||||||
<span ng-if="panel.legend.values">
|
<span ng-if="panel.legend.values">
|
||||||
<span ng-show="panel.legend.current">
|
<span ng-show="panel.legend.current">
|
@ -1,4 +1,4 @@
|
|||||||
<div ng-controller='graphite'
|
<div ng-controller='graph'
|
||||||
ng-init="init()"
|
ng-init="init()"
|
||||||
style="min-height:{{panel.height || row.height}}"
|
style="min-height:{{panel.height || row.height}}"
|
||||||
ng-class="{'panel-fullscreen': fullscreen}">
|
ng-class="{'panel-fullscreen': fullscreen}">
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="panel.legend" class="grafana-legend-container">
|
<div ng-if="panel.legend" class="grafana-legend-container">
|
||||||
<div ng-include="'app/panels/graphite/legend.html'"></div>
|
<div ng-include="'app/panels/graph/legend.html'"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
@ -19,7 +19,6 @@ define([
|
|||||||
'kbn',
|
'kbn',
|
||||||
'moment',
|
'moment',
|
||||||
'./timeSeries',
|
'./timeSeries',
|
||||||
'services/filterSrv',
|
|
||||||
'services/annotationsSrv',
|
'services/annotationsSrv',
|
||||||
'services/datasourceSrv',
|
'services/datasourceSrv',
|
||||||
'jquery.flot',
|
'jquery.flot',
|
||||||
@ -34,10 +33,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var module = angular.module('kibana.panels.graphite', []);
|
var module = angular.module('kibana.panels.graph', []);
|
||||||
app.useModule(module);
|
app.useModule(module);
|
||||||
|
|
||||||
module.controller('graphite', function($scope, $rootScope, filterSrv, datasourceSrv, $timeout, annotationsSrv) {
|
module.controller('graph', function($scope, $rootScope, datasourceSrv, $timeout, annotationsSrv) {
|
||||||
|
|
||||||
$scope.panelMeta = {
|
$scope.panelMeta = {
|
||||||
modals : [],
|
modals : [],
|
||||||
@ -53,11 +52,11 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title:'Axes & Grid',
|
title:'Axes & Grid',
|
||||||
src:'app/panels/graphite/axisEditor.html'
|
src:'app/panels/graph/axisEditor.html'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title:'Display Styles',
|
title:'Display Styles',
|
||||||
src:'app/panels/graphite/styleEditor.html'
|
src:'app/panels/graph/styleEditor.html'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
fullscreenEdit: true,
|
fullscreenEdit: true,
|
||||||
@ -211,6 +210,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
|
|
||||||
$scope.datasources = datasourceSrv.listOptions();
|
$scope.datasources = datasourceSrv.listOptions();
|
||||||
$scope.setDatasource($scope.panel.datasource);
|
$scope.setDatasource($scope.panel.datasource);
|
||||||
|
|
||||||
|
if ($scope.panel.targets.length === 0) {
|
||||||
|
$scope.panel.targets.push({});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.setDatasource = function(datasource) {
|
$scope.setDatasource = function(datasource) {
|
||||||
@ -231,8 +234,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.updateTimeRange = function () {
|
$scope.updateTimeRange = function () {
|
||||||
$scope.range = filterSrv.timeRange();
|
$scope.range = this.filter.timeRange();
|
||||||
$scope.rangeUnparsed = filterSrv.timeRange(false);
|
$scope.rangeUnparsed = this.filter.timeRange(false);
|
||||||
$scope.resolution = Math.ceil($(window).width() * ($scope.panel.span / 12));
|
$scope.resolution = Math.ceil($(window).width() * ($scope.panel.span / 12));
|
||||||
$scope.interval = '10m';
|
$scope.interval = '10m';
|
||||||
|
|
||||||
@ -259,13 +262,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
datasource: $scope.panel.datasource
|
datasource: $scope.panel.datasource
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed);
|
$scope.annotationsPromise = annotationsSrv.getAnnotations($scope.filter, $scope.rangeUnparsed);
|
||||||
|
|
||||||
return $scope.datasource.query(graphiteQuery)
|
return $scope.datasource.query($scope.filter, graphiteQuery)
|
||||||
.then($scope.dataHandler)
|
.then($scope.dataHandler)
|
||||||
.then(null, function(err) {
|
.then(null, function(err) {
|
||||||
$scope.panelMeta.loading = false;
|
$scope.panelMeta.loading = false;
|
||||||
$scope.panel.error = err.message || "Graphite HTTP Request Error";
|
$scope.panel.error = err.message || "Timeseries data request error";
|
||||||
$scope.inspector.error = err;
|
$scope.inspector.error = err;
|
||||||
$scope.render([]);
|
$scope.render([]);
|
||||||
});
|
});
|
||||||
@ -357,7 +360,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
$scope.hiddenSeries[serie.alias] = true;
|
$scope.hiddenSeries[serie.alias] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||||
$scope.toggleSeriesExclusiveMode(serie);
|
$scope.toggleSeriesExclusiveMode(serie);
|
||||||
}
|
}
|
||||||
|
|
@ -60,11 +60,11 @@ function (_, kbn) {
|
|||||||
this.info.current = result[result.length-1][1];
|
this.info.current = result[result.length-1][1];
|
||||||
|
|
||||||
var formater = kbn.getFormatFunction(yFormats[this.yaxis - 1], 2);
|
var formater = kbn.getFormatFunction(yFormats[this.yaxis - 1], 2);
|
||||||
this.info.avg = this.info.avg ? formater(this.info.avg) : null;
|
this.info.avg = this.info.avg != null ? formater(this.info.avg) : null;
|
||||||
this.info.current = this.info.current ? formater(this.info.current) : null;
|
this.info.current = this.info.current != null ? formater(this.info.current) : null;
|
||||||
this.info.min = this.info.min ? formater(this.info.min) : null;
|
this.info.min = this.info.min != null ? formater(this.info.min) : null;
|
||||||
this.info.max = this.info.max ? formater(this.info.max) : null;
|
this.info.max = this.info.max != null ? formater(this.info.max) : null;
|
||||||
this.info.total = this.info.total ? formater(this.info.total) : null;
|
this.info.total = this.info.total != null ? formater(this.info.total) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
@ -1,57 +0,0 @@
|
|||||||
define([
|
|
||||||
'kbn'
|
|
||||||
],
|
|
||||||
function (kbn) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* manages the interval logic
|
|
||||||
* @param {[type]} interval_string An interval string in the format '1m', '1y', etc
|
|
||||||
*/
|
|
||||||
function Interval(interval_string) {
|
|
||||||
this.string = interval_string;
|
|
||||||
|
|
||||||
var info = kbn.describe_interval(interval_string);
|
|
||||||
this.type = info.type;
|
|
||||||
this.ms = info.sec * 1000 * info.count;
|
|
||||||
|
|
||||||
// does the length of the interval change based on the current time?
|
|
||||||
if (this.type === 'y' || this.type === 'M') {
|
|
||||||
// we will just modify this time object rather that create a new one constantly
|
|
||||||
this.get = this.get_complex;
|
|
||||||
this.date = new Date(0);
|
|
||||||
} else {
|
|
||||||
this.get = this.get_simple;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Interval.prototype = {
|
|
||||||
toString: function () {
|
|
||||||
return this.string;
|
|
||||||
},
|
|
||||||
after: function(current_ms) {
|
|
||||||
return this.get(current_ms, 1);
|
|
||||||
},
|
|
||||||
before: function (current_ms) {
|
|
||||||
return this.get(current_ms, -1);
|
|
||||||
},
|
|
||||||
get_complex: function (current, delta) {
|
|
||||||
this.date.setTime(current);
|
|
||||||
switch(this.type) {
|
|
||||||
case 'M':
|
|
||||||
this.date.setUTCMonth(this.date.getUTCMonth() + delta);
|
|
||||||
break;
|
|
||||||
case 'y':
|
|
||||||
this.date.setUTCFullYear(this.date.getUTCFullYear() + delta);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return this.date.getTime();
|
|
||||||
},
|
|
||||||
get_simple: function (current, delta) {
|
|
||||||
return current + (delta * this.ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Interval;
|
|
||||||
|
|
||||||
});
|
|
@ -17,14 +17,14 @@
|
|||||||
|
|
||||||
<a class="dropdown-toggle timepicker-dropdown" data-toggle="dropdown" href="" bs-tooltip="time.from.date ? (time.from.date | date:'yyyy-MM-dd HH:mm:ss.sss') + ' <br>to<br>' +(time.to.date | date:'yyyy-MM-dd HH:mm:ss.sss') : 'Click to set a time filter'" data-placement="bottom" ng-click="dismiss();">
|
<a class="dropdown-toggle timepicker-dropdown" data-toggle="dropdown" href="" bs-tooltip="time.from.date ? (time.from.date | date:'yyyy-MM-dd HH:mm:ss.sss') + ' <br>to<br>' +(time.to.date | date:'yyyy-MM-dd HH:mm:ss.sss') : 'Click to set a time filter'" data-placement="bottom" ng-click="dismiss();">
|
||||||
|
|
||||||
<span ng-show="filterSrv.time">
|
<span ng-show="filter.time">
|
||||||
<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
|
||||||
<span class="pointer" ng-hide="panel.now" >{{time.to.date | date:'MMM d, y HH:mm:ss'}}</span>
|
<span class="pointer" ng-hide="panel.now" >{{time.to.date | date:'MMM d, y HH:mm:ss'}}</span>
|
||||||
<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.time">Time filter</span>
|
<span ng-hide="filter.time">Time filter</span>
|
||||||
<span ng-show="dashboard.current.refresh" class="text-warning">refreshed every {{dashboard.current.refresh}} </span>
|
<span ng-show="dashboard.current.refresh" class="text-warning">refreshed every {{dashboard.current.refresh}} </span>
|
||||||
<i class="icon-caret-down"></i>
|
<i class="icon-caret-down"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -25,7 +25,7 @@ function (angular, app, _, moment, kbn) {
|
|||||||
var module = angular.module('kibana.panels.timepicker', []);
|
var module = angular.module('kibana.panels.timepicker', []);
|
||||||
app.useModule(module);
|
app.useModule(module);
|
||||||
|
|
||||||
module.controller('timepicker', function($scope, $modal, $q, filterSrv) {
|
module.controller('timepicker', function($scope, $modal, $q) {
|
||||||
$scope.panelMeta = {
|
$scope.panelMeta = {
|
||||||
status : "Stable",
|
status : "Stable",
|
||||||
description : "A panel for controlling the time range filters. If you have time based data, "+
|
description : "A panel for controlling the time range filters. If you have time based data, "+
|
||||||
@ -44,8 +44,6 @@ function (angular, app, _, moment, kbn) {
|
|||||||
|
|
||||||
_.defaults($scope.panel,_d);
|
_.defaults($scope.panel,_d);
|
||||||
|
|
||||||
$scope.filterSrv = filterSrv;
|
|
||||||
|
|
||||||
// ng-pattern regexs
|
// ng-pattern regexs
|
||||||
$scope.patterns = {
|
$scope.patterns = {
|
||||||
date: /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/,
|
date: /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/,
|
||||||
@ -55,12 +53,14 @@ function (angular, app, _, moment, kbn) {
|
|||||||
millisecond: /^[0-9]*$/
|
millisecond: /^[0-9]*$/
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.$on('refresh', function(){$scope.init();});
|
$scope.$on('refresh', function() {
|
||||||
|
$scope.init();
|
||||||
|
});
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
var time = filterSrv.timeRange();
|
var time = this.filter.timeRange(true);
|
||||||
if(time) {
|
if(time) {
|
||||||
$scope.panel.now = filterSrv.timeRange(false).to === "now" ? true : false;
|
$scope.panel.now = this.filter.timeRange(false).to === "now" ? true : false;
|
||||||
$scope.time = getScopeTimeObj(time.from,time.to);
|
$scope.time = getScopeTimeObj(time.from,time.to);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -135,7 +135,7 @@ function (angular, app, _, moment, kbn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the filter
|
// Set the filter
|
||||||
$scope.panel.filter_id = filterSrv.setTime(_filter);
|
$scope.panel.filter_id = $scope.filter.setTime(_filter);
|
||||||
|
|
||||||
// Update our representation
|
// Update our representation
|
||||||
$scope.time = getScopeTimeObj(time.from,time.to);
|
$scope.time = getScopeTimeObj(time.from,time.to);
|
||||||
@ -149,7 +149,7 @@ function (angular, app, _, moment, kbn) {
|
|||||||
to: "now"
|
to: "now"
|
||||||
};
|
};
|
||||||
|
|
||||||
filterSrv.setTime(_filter);
|
this.filter.setTime(_filter);
|
||||||
|
|
||||||
$scope.time = getScopeTimeObj(kbn.parseDate(_filter.from),new Date());
|
$scope.time = getScopeTimeObj(kbn.parseDate(_filter.from),new Date());
|
||||||
};
|
};
|
||||||
|
@ -23,26 +23,59 @@
|
|||||||
<i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
|
<i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="row-button bgPrimary" ng-click="toggle_row(row)" ng-show="row.collapsable">
|
<span class="row-button bgPrimary" ng-click="toggle_row(row)" ng-show="row.collapsable">
|
||||||
<i bs-tooltip="'Expand row'" data-placement="right" ng-show="row.editable" class="icon-caret-left pointer" ></i>
|
<i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="row-button row-text" ng-click="toggle_row(row)" ng-class="{'pointer':row.collapsable}">{{row.title || 'Row '+$index}}</span>
|
<span class="row-button row-text" ng-click="toggle_row(row)" ng-class="{'pointer':row.collapsable}">{{row.title || 'Row '+$index}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row-open" ng-show="!row.collapse">
|
||||||
<div style="text-align:center" class="row-open" ng-show="!row.collapse">
|
|
||||||
<div ng-show="row.collapsable" class='row-tab bgPrimary' ng-click="toggle_row(row)">
|
<div ng-show="row.collapsable" class='row-tab bgPrimary' ng-click="toggle_row(row)">
|
||||||
<i bs-tooltip="'Collapse row'" data-placement="right" class="icon-caret-right" ></i>
|
<span class="row-tab-button">
|
||||||
<br>
|
<i class="icon-caret-right" ></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div config-modal="app/partials/roweditor.html" class='row-tab bgWarning' ng-show="row.editable">
|
<div class='row-tab bgSuccess dropdown' ng-show="row.editable">
|
||||||
<i bs-tooltip="'Configure row'" data-placement="right" class="icon-cog pointer"></i>
|
<span class="row-tab-button dropdown-toggle" data-toggle="dropdown">
|
||||||
<br>
|
<i class="icon-th-list"></i>
|
||||||
</div>
|
</span>
|
||||||
<div ng-show="rowSpan(row) > 12" class='row-tab bgDanger'>
|
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="drop1">
|
||||||
<i bs-tooltip="'Total span > 12. This row may format poorly'" data-placement="right" class="icon-warning-sign"></i>
|
<li class="dropdown-submenu">
|
||||||
<br>
|
<a href="#">Add Panel</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a ng-click="add_panel_default('graph')">Graph</li></a>
|
||||||
|
<li><a ng-click="add_panel_default('text')">Text</li></a>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Set height</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a ng-click="set_height('100px')">100 px</li></a>
|
||||||
|
<li><a ng-click="set_height('150px')">150 px</li></a>
|
||||||
|
<li><a ng-click="set_height('200px')">200 px</li></a>
|
||||||
|
<li><a ng-click="set_height('250px')">250 px</li></a>
|
||||||
|
<li><a ng-click="set_height('300px')">300 px</li></a>
|
||||||
|
<li><a ng-click="set_height('350px')">350 px</li></a>
|
||||||
|
<li><a ng-click="set_height('450px')">450 px</li></a>
|
||||||
|
<li><a ng-click="set_height('500px')">500 px</li></a>
|
||||||
|
<li><a ng-click="set_height('600px')">600 px</li></a>
|
||||||
|
<li><a ng-click="set_height('700px')">700 px</li></a>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Move</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a ng-click="move_row(-1)">Up</li></a>
|
||||||
|
<li><a ng-click="move_row(1)">Down</li></a>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a config-modal="app/partials/roweditor.html">Row editor</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a ng-click="delete_row()">Delete row</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="padding-top:0px" ng-if="!row.collapse">
|
<div style="padding-top:0px" ng-if="!row.collapse">
|
||||||
@ -58,10 +91,6 @@
|
|||||||
<div ng-show="rowSpan(row) < 10 && dashboard.panelDragging" class="panel" style="margin:5px;width:30%;background:rgba(100,100,100,0.50)" ng-class="{'dragInProgress':dashboard.panelDragging}" ng-style="{height:row.height}" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:row.panels.length,mutate:false,onDrop:'panelMoveDrop',onOver:'panelMoveOver',onOut:'panelMoveOut'}">
|
<div ng-show="rowSpan(row) < 10 && dashboard.panelDragging" class="panel" style="margin:5px;width:30%;background:rgba(100,100,100,0.50)" ng-class="{'dragInProgress':dashboard.panelDragging}" ng-style="{height:row.height}" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:row.panels.length,mutate:false,onDrop:'panelMoveDrop',onOver:'panelMoveOver',onOut:'panelMoveOut'}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span config-modal="app/partials/roweditor.html" ng-show="!dashboard.panelDragging && !dashboard.current.hideControls">
|
|
||||||
<i ng-hide="rowSpan(row) >= 10" class="pointer icon-plus-sign" ng-click="editor.index = 2" bs-tooltip="'Add a panel to this row'" data-placement="right"></i>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -70,8 +99,8 @@
|
|||||||
|
|
||||||
<div ng-show='dashboard.current.editable && dashboard.current.panel_hints' class="row-fluid add-row-panel-hint">
|
<div ng-show='dashboard.current.editable && dashboard.current.panel_hints' class="row-fluid add-row-panel-hint">
|
||||||
<div class="span12" style="text-align:right;">
|
<div class="span12" style="text-align:right;">
|
||||||
<span style="margin-left: 0px;" class="pointer btn btn-mini" config-modal="app/partials/dasheditor.html">
|
<span style="margin-right: 10px;" ng-click="add_row_default()" class="pointer btn btn-info btn-mini">
|
||||||
<span ng-click="editor.index = 1"><i class="icon-plus-sign"></i> ADD A ROW</span>
|
<span><i class="icon-plus-sign"></i> ADD A ROW</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
<div class="span4">
|
<div class="span4">
|
||||||
<h4>Add Row</h4>
|
<h4>Add Row</h4>
|
||||||
<label class="small">Title</label>
|
<label class="small">Title</label>
|
||||||
<input type="text" class="input-medium" ng-model='row.title' placeholder="New row"></input>
|
<input type="text" class="input-normal" ng-model='row.title' placeholder="New row"></input>
|
||||||
<label class="small">Height</label>
|
<label class="small">Height</label>
|
||||||
<input type="text" class="input-mini" ng-model='row.height'></input>
|
<input type="text" class="input-mini" ng-model='row.height'></input>
|
||||||
</div>
|
</div>
|
||||||
|
0
src/app/partials/graphite/editor.html
Normal file → Executable file
0
src/app/partials/graphite/editor.html
Normal file → Executable file
@ -53,13 +53,9 @@
|
|||||||
ng-show="target.rawQuery">
|
ng-show="target.rawQuery">
|
||||||
|
|
||||||
<ul class="grafana-segment-list" role="menu" ng-hide="target.rawQuery">
|
<ul class="grafana-segment-list" role="menu" ng-hide="target.rawQuery">
|
||||||
<li class="grafana-target-segment">
|
|
||||||
from series
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
class="input-small grafana-target-segment-input"
|
class="input-large grafana-target-segment-input"
|
||||||
ng-model="target.series"
|
ng-model="target.series"
|
||||||
spellcheck='false'
|
spellcheck='false'
|
||||||
bs-typeahead="listSeries"
|
bs-typeahead="listSeries"
|
||||||
@ -72,26 +68,11 @@
|
|||||||
select
|
select
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li class="dropdown">
|
||||||
<input type="text"
|
<span influxdb-func-editor class="grafana-target-segment grafana-target-function">
|
||||||
class="input-small grafana-target-segment-input"
|
</span>
|
||||||
ng-model="target.column"
|
|
||||||
placeholder="value"
|
|
||||||
spellcheck='false'
|
|
||||||
bs-typeahead="listColumns"
|
|
||||||
data-min-length=0
|
|
||||||
ng-blur="get_data()">
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="grafana-target-segment">
|
|
||||||
function
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<select class="input-small grafana-target-segment-input"
|
|
||||||
ng-change="get_data()"
|
|
||||||
ng-model="target.function"
|
|
||||||
ng-options="f for f in functions" ></select>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a class="grafana-target-segment"
|
<a class="grafana-target-segment"
|
||||||
ng-click="target.condition_filter = !target.condition_filter; get_data();"
|
ng-click="target.condition_filter = !target.condition_filter; get_data();"
|
||||||
@ -159,16 +140,16 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="grafana-target-segment">
|
<li class="grafana-target-segment">
|
||||||
alias as
|
as
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
class="input-small grafana-target-segment-input"
|
class="input-medium grafana-target-segment-input"
|
||||||
ng-model="target.alias"
|
ng-model="target.alias"
|
||||||
spellcheck='false'
|
spellcheck='false'
|
||||||
placeholder="alias"
|
placeholder="alias"
|
||||||
ng-blur="seriesBlur()">
|
ng-blur="get_data()">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -61,6 +61,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button ng-show="editor.index == 1" ng-click="editor.index = 2;" class="btn btn-success" ng-disabled="panel.loadingEditor">Add Panel</button>
|
<button ng-show="editor.index == 1" ng-click="editor.index = 2;" class="btn btn-success" ng-disabled="panel.loadingEditor">Add Panel</button>
|
||||||
<button ng-show="panel.type && editor.index == 2" ng-click="add_panel(row,panel); reset_panel(); editor.index = 1;" class="btn btn-success" ng-disabled="panel.loadingEditor">Add Panel</button>
|
<button ng-show="panel.type && editor.index == 2" ng-click="add_panel(panel); reset_panel(); editor.index = 1;" class="btn btn-success" ng-disabled="panel.loadingEditor">Add Panel</button>
|
||||||
<button type="button" class="btn btn-info" ng-click="editor.index=0;dismiss();reset_panel();close_edit()">Close</button>
|
<button type="button" class="btn btn-info" ng-click="editor.index=0;dismiss();reset_panel();close_edit()">Close</button>
|
||||||
</div>
|
</div>
|
@ -28,7 +28,7 @@ define([
|
|||||||
list = [];
|
list = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getAnnotations = function(rangeUnparsed) {
|
this.getAnnotations = function(filterSrv, rangeUnparsed) {
|
||||||
if (!annotationPanel.enable) {
|
if (!annotationPanel.enable) {
|
||||||
return $q.when(null);
|
return $q.when(null);
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ define([
|
|||||||
return promiseCached;
|
return promiseCached;
|
||||||
}
|
}
|
||||||
|
|
||||||
var graphiteMetrics = this.getGraphiteMetrics(rangeUnparsed);
|
var graphiteMetrics = this.getGraphiteMetrics(filterSrv, rangeUnparsed);
|
||||||
var graphiteEvents = this.getGraphiteEvents(rangeUnparsed);
|
var graphiteEvents = this.getGraphiteEvents(rangeUnparsed);
|
||||||
|
|
||||||
promiseCached = $q.all(graphiteMetrics.concat(graphiteEvents))
|
promiseCached = $q.all(graphiteMetrics.concat(graphiteEvents))
|
||||||
@ -81,7 +81,7 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getGraphiteMetrics = function(rangeUnparsed) {
|
this.getGraphiteMetrics = function(filterSrv, rangeUnparsed) {
|
||||||
var annotations = this.getAnnotationsByType('graphite metric');
|
var annotations = this.getAnnotationsByType('graphite metric');
|
||||||
if (annotations.length === 0) {
|
if (annotations.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
@ -97,7 +97,7 @@ define([
|
|||||||
|
|
||||||
var receiveFunc = _.partial(receiveGraphiteMetrics, annotation);
|
var receiveFunc = _.partial(receiveGraphiteMetrics, annotation);
|
||||||
|
|
||||||
return datasourceSrv.default.query(graphiteQuery)
|
return datasourceSrv.default.query(filterSrv, graphiteQuery)
|
||||||
.then(receiveFunc)
|
.then(receiveFunc)
|
||||||
.then(null, errorHandler);
|
.then(null, errorHandler);
|
||||||
});
|
});
|
||||||
@ -154,4 +154,4 @@ define([
|
|||||||
this.init();
|
this.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -54,7 +54,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
|
|
||||||
// Store a reference to this
|
// Store a reference to this
|
||||||
var self = this;
|
var self = this;
|
||||||
var filterSrv;
|
|
||||||
|
|
||||||
this.current = _.clone(_dash);
|
this.current = _.clone(_dash);
|
||||||
this.last = {};
|
this.last = {};
|
||||||
@ -63,7 +62,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
$rootScope.$on('$routeChangeSuccess',function(){
|
$rootScope.$on('$routeChangeSuccess',function(){
|
||||||
// Clear the current dashboard to prevent reloading
|
// Clear the current dashboard to prevent reloading
|
||||||
self.current = {};
|
self.current = {};
|
||||||
self.original = null;
|
|
||||||
self.indices = [];
|
self.indices = [];
|
||||||
route();
|
route();
|
||||||
});
|
});
|
||||||
@ -140,6 +138,14 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_.each(dashboard.rows, function(row) {
|
||||||
|
_.each(row.panels, function(panel) {
|
||||||
|
if (panel.type === 'graphite') {
|
||||||
|
panel.type = 'graph';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return dashboard;
|
return dashboard;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,10 +163,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
|
|
||||||
// Set the current dashboard
|
// Set the current dashboard
|
||||||
self.current = angular.copy(dashboard);
|
self.current = angular.copy(dashboard);
|
||||||
|
|
||||||
filterSrv = $injector.get('filterSrv');
|
|
||||||
filterSrv.init();
|
|
||||||
|
|
||||||
if(dashboard.refresh) {
|
if(dashboard.refresh) {
|
||||||
self.set_interval(dashboard.refresh);
|
self.set_interval(dashboard.refresh);
|
||||||
}
|
}
|
||||||
@ -172,11 +174,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
// Take out any that we're not allowed to add from the gui.
|
// Take out any that we're not allowed to add from the gui.
|
||||||
self.availablePanels = _.difference(self.availablePanels,config.hidden_panels);
|
self.availablePanels = _.difference(self.availablePanels,config.hidden_panels);
|
||||||
|
|
||||||
$rootScope.$emit('dashboard-loaded');
|
$rootScope.$emit('dashboard-loaded', self.current);
|
||||||
|
|
||||||
$timeout(function() {
|
|
||||||
self.original = angular.copy(self.current);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -390,7 +388,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
if(type === 'dashboard') {
|
if(type === 'dashboard') {
|
||||||
$location.path('/dashboard/elasticsearch/'+title);
|
$location.path('/dashboard/elasticsearch/'+title);
|
||||||
}
|
}
|
||||||
self.original = angular.copy(self.current);
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
// Failure
|
// Failure
|
||||||
@ -467,8 +464,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
timer.cancel(self.refresh_timer);
|
timer.cancel(self.refresh_timer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
4
src/app/services/dashboard/all.js
Normal file
4
src/app/services/dashboard/all.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
define([
|
||||||
|
'./dashboardKeyBindings',
|
||||||
|
],
|
||||||
|
function () {});
|
58
src/app/services/dashboard/dashboardKeyBindings.js
Normal file
58
src/app/services/dashboard/dashboardKeyBindings.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'jquery',
|
||||||
|
'services/all'
|
||||||
|
],
|
||||||
|
function(angular, $) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var module = angular.module('kibana.services.dashboard');
|
||||||
|
|
||||||
|
module.service('dashboardKeybindings', function($rootScope, keyboardManager, dashboard) {
|
||||||
|
this.shortcuts = function() {
|
||||||
|
$rootScope.$on('panel-fullscreen-enter', function() {
|
||||||
|
$rootScope.fullscreen = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('panel-fullscreen-exit', function() {
|
||||||
|
$rootScope.fullscreen = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('dashboard-saved', function() {
|
||||||
|
if ($rootScope.fullscreen) {
|
||||||
|
$rootScope.$emit('panel-fullscreen-exit');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
keyboardManager.bind('ctrl+f', function(evt) {
|
||||||
|
$rootScope.$emit('open-search', evt);
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
|
||||||
|
keyboardManager.bind('ctrl+h', function() {
|
||||||
|
var current = dashboard.current.hideControls;
|
||||||
|
dashboard.current.hideControls = !current;
|
||||||
|
dashboard.current.panel_hints = current;
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
|
||||||
|
keyboardManager.bind('ctrl+s', function(evt) {
|
||||||
|
$rootScope.$emit('save-dashboard', evt);
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
|
||||||
|
keyboardManager.bind('ctrl+r', function() {
|
||||||
|
dashboard.refresh();
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
|
||||||
|
keyboardManager.bind('ctrl+z', function(evt) {
|
||||||
|
$rootScope.$emit('zoom-out', evt);
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
|
||||||
|
keyboardManager.bind('esc', function() {
|
||||||
|
var popups = $('.popover.in');
|
||||||
|
if (popups.length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$rootScope.$emit('panel-fullscreen-exit');
|
||||||
|
}, { inputDisabled: true });
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
@ -10,7 +10,7 @@ function (angular, _, config) {
|
|||||||
|
|
||||||
var module = angular.module('kibana.services');
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
module.service('datasourceSrv', function($q, filterSrv, $http, GraphiteDatasource, InfluxDatasource) {
|
module.service('datasourceSrv', function($q, $http, GraphiteDatasource, InfluxDatasource) {
|
||||||
|
|
||||||
this.init = function() {
|
this.init = function() {
|
||||||
var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true } );
|
var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true } );
|
||||||
@ -48,4 +48,4 @@ function (angular, _, config) {
|
|||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,104 +8,66 @@ define([
|
|||||||
|
|
||||||
var module = angular.module('kibana.services');
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
module.service('filterSrv', function(dashboard, $rootScope, $timeout, $routeParams) {
|
module.factory('filterSrv', function(dashboard, $rootScope, $timeout, $routeParams) {
|
||||||
// defaults
|
// defaults
|
||||||
var _d = {
|
var _d = {
|
||||||
list: [],
|
templateParameters: [],
|
||||||
time: {}
|
time: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save a reference to this
|
var result = {
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// Call this whenever we need to reload the important stuff
|
updateTemplateData: function(initial) {
|
||||||
this.init = function() {
|
var _templateData = {};
|
||||||
dashboard.current.services.filter = dashboard.current.services.filter || {};
|
_.each(this.templateParameters, function(templateParameter) {
|
||||||
|
|
||||||
_.defaults(dashboard.current.services.filter, _d);
|
|
||||||
|
|
||||||
self.list = dashboard.current.services.filter.list;
|
|
||||||
self.time = dashboard.current.services.filter.time;
|
|
||||||
|
|
||||||
self.templateSettings = {
|
|
||||||
interpolate : /\[\[([\s\S]+?)\]\]/g,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (self.list.length) {
|
|
||||||
this._updateTemplateData(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this._updateTemplateData = function(initial) {
|
|
||||||
self._filterTemplateData = {};
|
|
||||||
|
|
||||||
_.each(self.list, function(filter) {
|
|
||||||
if (initial) {
|
if (initial) {
|
||||||
var urlValue = $routeParams[filter.name];
|
var urlValue = $routeParams[ templateParameter.name ];
|
||||||
if (urlValue) {
|
if (urlValue) {
|
||||||
filter.current = { text: urlValue, value: urlValue };
|
templateParameter.current = { text: urlValue, value: urlValue };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!filter.current || !filter.current.value) {
|
if (!templateParameter.current || !templateParameter.current.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_templateData[templateParameter.name] = templateParameter.current.value;
|
||||||
self._filterTemplateData[filter.name] = filter.current.value;
|
|
||||||
});
|
});
|
||||||
};
|
this._templateData = _templateData;
|
||||||
|
},
|
||||||
|
|
||||||
this.filterOptionSelected = function(filter, option) {
|
addTemplateParameter: function(templateParameter) {
|
||||||
filter.current = option;
|
this.templateParameters.push(templateParameter);
|
||||||
this._updateTemplateData();
|
this.updateTemplateData();
|
||||||
dashboard.refresh();
|
},
|
||||||
};
|
|
||||||
|
|
||||||
this.add = function(filter) {
|
applyTemplateToTarget: function(target) {
|
||||||
self.list.push(filter);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.applyFilterToTarget = function(target) {
|
|
||||||
if (target.indexOf('[[') === -1) {
|
if (target.indexOf('[[') === -1) {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.template(target, self._filterTemplateData, self.templateSettings);
|
return _.template(target, this._templateData, this.templateSettings);
|
||||||
};
|
},
|
||||||
|
|
||||||
this.remove = function(filter) {
|
setTime: function(time) {
|
||||||
self.list = dashboard.current.services.filter.list = _.without(self.list, filter);
|
_.extend(this.time, time);
|
||||||
|
|
||||||
if(!$rootScope.$$phase) {
|
|
||||||
$rootScope.$apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
$timeout(function(){
|
|
||||||
dashboard.refresh();
|
|
||||||
},0);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setTime = function(time) {
|
|
||||||
_.extend(self.time, time);
|
|
||||||
|
|
||||||
// disable refresh if we have an absolute time
|
// disable refresh if we have an absolute time
|
||||||
if (time.to !== 'now') {
|
if (time.to !== 'now') {
|
||||||
self.old_refresh = dashboard.current.refresh;
|
this.old_refresh = this.dashboard.refresh;
|
||||||
dashboard.set_interval(false);
|
dashboard.set_interval(false);
|
||||||
}
|
}
|
||||||
else if (self.old_refresh && self.old_refresh !== dashboard.current.refresh) {
|
else if (this.old_refresh && this.old_refresh !== this.dashboard.refresh) {
|
||||||
dashboard.set_interval(self.old_refresh);
|
dashboard.set_interval(this.old_refresh);
|
||||||
self.old_refresh = null;
|
this.old_refresh = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
dashboard.refresh();
|
dashboard.refresh();
|
||||||
},0);
|
},0);
|
||||||
};
|
},
|
||||||
|
|
||||||
this.timeRange = function(parse) {
|
timeRange: function(parse) {
|
||||||
var _t = self.time;
|
var _t = this.time;
|
||||||
|
if(_.isUndefined(_t) || _.isUndefined(_t.from)) {
|
||||||
if(_.isUndefined(_t)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(parse === false) {
|
if(parse === false) {
|
||||||
@ -114,19 +76,35 @@ define([
|
|||||||
to: _t.to
|
to: _t.to
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
var
|
var _from = _t.from;
|
||||||
_from = _t.from,
|
var _to = _t.to || new Date();
|
||||||
_to = _t.to || new Date();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
from : kbn.parseDate(_from),
|
from : kbn.parseDate(_from),
|
||||||
to : kbn.parseDate(_to)
|
to : kbn.parseDate(_to)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
// Now init
|
removeTemplateParameter: function(templateParameter) {
|
||||||
self.init();
|
this.templateParameters = _.without(this.templateParameters, templateParameter);
|
||||||
|
this.dashboard.services.filter.list = this.templateParameters;
|
||||||
|
},
|
||||||
|
|
||||||
|
init: function(dashboard) {
|
||||||
|
_.defaults(this, _d);
|
||||||
|
this.dashboard = dashboard;
|
||||||
|
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
|
||||||
|
|
||||||
|
if(dashboard.services && dashboard.services.filter) {
|
||||||
|
this.time = dashboard.services.filter.time;
|
||||||
|
this.templateParameters = dashboard.services.filter.list || [];
|
||||||
|
this.updateTemplateData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -69,6 +69,11 @@ function (_) {
|
|||||||
category: categories.Combine,
|
category: categories.Combine,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'isNonNull',
|
||||||
|
category: categories.Combine,
|
||||||
|
});
|
||||||
|
|
||||||
addFuncDef({
|
addFuncDef({
|
||||||
name: 'rangeOfSeries',
|
name: 'rangeOfSeries',
|
||||||
category: categories.Combine
|
category: categories.Combine
|
||||||
@ -231,6 +236,8 @@ function (_) {
|
|||||||
addFuncDef({
|
addFuncDef({
|
||||||
name: 'keepLastValue',
|
name: 'keepLastValue',
|
||||||
category: categories.Special,
|
category: categories.Special,
|
||||||
|
params: [ { name: "n", type: "int", } ],
|
||||||
|
defaultParams: [100]
|
||||||
});
|
});
|
||||||
|
|
||||||
addFuncDef({
|
addFuncDef({
|
||||||
|
@ -11,7 +11,7 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
|
|
||||||
var module = angular.module('kibana.services');
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
module.factory('GraphiteDatasource', function(dashboard, $q, filterSrv, $http) {
|
module.factory('GraphiteDatasource', function(dashboard, $q, $http) {
|
||||||
|
|
||||||
function GraphiteDatasource(datasource) {
|
function GraphiteDatasource(datasource) {
|
||||||
this.type = 'graphite';
|
this.type = 'graphite';
|
||||||
@ -22,7 +22,7 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
this.render_method = datasource.render_method || 'POST';
|
this.render_method = datasource.render_method || 'POST';
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphiteDatasource.prototype.query = function(options) {
|
GraphiteDatasource.prototype.query = function(filterSrv, options) {
|
||||||
try {
|
try {
|
||||||
var graphOptions = {
|
var graphOptions = {
|
||||||
from: this.translateTime(options.range.from, 'round-down'),
|
from: this.translateTime(options.range.from, 'round-down'),
|
||||||
@ -32,7 +32,7 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
maxDataPoints: options.maxDataPoints,
|
maxDataPoints: options.maxDataPoints,
|
||||||
};
|
};
|
||||||
|
|
||||||
var params = this.buildGraphiteParams(graphOptions);
|
var params = this.buildGraphiteParams(filterSrv, graphOptions);
|
||||||
|
|
||||||
if (options.format === 'png') {
|
if (options.format === 'png') {
|
||||||
return $q.when(this.url + '/render' + '?' + params.join('&'));
|
return $q.when(this.url + '/render' + '?' + params.join('&'));
|
||||||
@ -115,10 +115,10 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
return date.format('HH:mm_YYYYMMDD');
|
return date.format('HH:mm_YYYYMMDD');
|
||||||
};
|
};
|
||||||
|
|
||||||
GraphiteDatasource.prototype.metricFindQuery = function(query) {
|
GraphiteDatasource.prototype.metricFindQuery = function(filterSrv, query) {
|
||||||
var interpolated;
|
var interpolated;
|
||||||
try {
|
try {
|
||||||
interpolated = filterSrv.applyFilterToTarget(query);
|
interpolated = encodeURIComponent(filterSrv.applyTemplateToTarget(query));
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
return $q.reject(err);
|
return $q.reject(err);
|
||||||
@ -158,7 +158,7 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
return $http(options);
|
return $http(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
GraphiteDatasource.prototype.buildGraphiteParams = function(options) {
|
GraphiteDatasource.prototype.buildGraphiteParams = function(filterSrv, options) {
|
||||||
var clean_options = [];
|
var clean_options = [];
|
||||||
var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
|
var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
|
||||||
|
|
||||||
@ -173,8 +173,8 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
|
|
||||||
if (key === "targets") {
|
if (key === "targets") {
|
||||||
_.each(value, function (value) {
|
_.each(value, function (value) {
|
||||||
if (!value.hide) {
|
if (value.target && !value.hide) {
|
||||||
var targetValue = filterSrv.applyFilterToTarget(value.target);
|
var targetValue = filterSrv.applyTemplateToTarget(value.target);
|
||||||
clean_options.push("target=" + encodeURIComponent(targetValue));
|
clean_options.push("target=" + encodeURIComponent(targetValue));
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -124,6 +124,7 @@ define([
|
|||||||
i === 45 || // -
|
i === 45 || // -
|
||||||
i === 42 || // *
|
i === 42 || // *
|
||||||
i === 58 || // :
|
i === 58 || // :
|
||||||
|
i === 37 || // %
|
||||||
i >= 97 && i <= 122; // a-z
|
i >= 97 && i <= 122; // a-z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ function (angular, _, kbn) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
InfluxDatasource.prototype.query = function(options) {
|
InfluxDatasource.prototype.query = function(filterSrv, options) {
|
||||||
|
|
||||||
var promises = _.map(options.targets, function(target) {
|
var promises = _.map(options.targets, function(target) {
|
||||||
var query;
|
var query;
|
||||||
|
var alias = '';
|
||||||
|
|
||||||
if (target.hide || !((target.series && target.column) || target.query)) {
|
if (target.hide || !((target.series && target.column) || target.query)) {
|
||||||
return [];
|
return [];
|
||||||
@ -68,18 +68,13 @@ function (angular, _, kbn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query = queryElements.join(" ");
|
query = queryElements.join(" ");
|
||||||
|
query = filterSrv.applyTemplateToTarget(query);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var template = "select [[group]][[group_comma]] [[func]]([[column]]) as [[column]]_[[func]] from [[series]] " +
|
var template = "select [[group]][[group_comma]] [[func]](\"[[column]]\") as \"[[column]]_[[func]]\" from \"[[series]]\" " +
|
||||||
"where [[timeFilter]] [[condition_add]] [[condition_key]] [[condition_op]] [[condition_value]] " +
|
"where [[timeFilter]] [[condition_add]] [[condition_key]] [[condition_op]] [[condition_value]] " +
|
||||||
"group by time([[interval]])[[group_comma]] [[group]] order asc";
|
"group by time([[interval]])[[group_comma]] [[group]] order asc";
|
||||||
|
|
||||||
if (target.column.indexOf('-') !== -1 || target.column.indexOf('.') !== -1) {
|
|
||||||
template = "select [[group]][[group_comma]] [[func]](\"[[column]]\") as \"[[column]]_[[func]]\" from [[series]] " +
|
|
||||||
"where [[timeFilter]] [[condition_add]] [[condition_key]] [[condition_op]] [[condition_value]] " +
|
|
||||||
"group by time([[interval]])[[group_comma]] [[group]] order asc";
|
|
||||||
}
|
|
||||||
|
|
||||||
var templateData = {
|
var templateData = {
|
||||||
series: target.series,
|
series: target.series,
|
||||||
column: target.column,
|
column: target.column,
|
||||||
@ -98,10 +93,16 @@ function (angular, _, kbn) {
|
|||||||
additionalGroups.push(target.groupby_field);
|
additionalGroups.push(target.groupby_field);
|
||||||
}
|
}
|
||||||
query = _.template(template, templateData, this.templateSettings);
|
query = _.template(template, templateData, this.templateSettings);
|
||||||
|
query = filterSrv.applyTemplateToTarget(query);
|
||||||
|
|
||||||
|
if (target.alias) {
|
||||||
|
alias = filterSrv.applyTemplateToTarget(target.alias);
|
||||||
|
}
|
||||||
|
|
||||||
target.query = query;
|
target.query = query;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.doInfluxRequest(query, target.alias).then(handleInfluxQueryResponse(additionalGroups));
|
return this.doInfluxRequest(query, alias).then(handleInfluxQueryResponse(additionalGroups));
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ function (angular, _, kbn) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
InfluxDatasource.prototype.listColumns = function(seriesName) {
|
InfluxDatasource.prototype.listColumns = function(seriesName) {
|
||||||
return this.doInfluxRequest('select * from ' + seriesName + ' limit 1').then(function(data) {
|
return this.doInfluxRequest('select * from "' + seriesName + '" limit 1').then(function(data) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -129,6 +130,26 @@ function (angular, _, kbn) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
InfluxDatasource.prototype.metricFindQuery = function (filterSrv, query) {
|
||||||
|
var interpolated;
|
||||||
|
try {
|
||||||
|
interpolated = filterSrv.applyTemplateToTarget(query);
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
return $q.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.doInfluxRequest(query, 'filters')
|
||||||
|
.then(function (results) {
|
||||||
|
return _.map(results[0].points, function (metric) {
|
||||||
|
return {
|
||||||
|
text: metric[1],
|
||||||
|
expandable: false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function retry(deferred, callback, delay) {
|
function retry(deferred, callback, delay) {
|
||||||
return callback().then(undefined, function(reason) {
|
return callback().then(undefined, function(reason) {
|
||||||
if (reason.status !== 0 || reason.status >= 300) {
|
if (reason.status !== 0 || reason.status >= 300) {
|
||||||
@ -197,7 +218,7 @@ function (angular, _, kbn) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
datapoints = _.map(_.pairs(datapoints), function(values) {
|
datapoints = _.map(_.pairs(datapoints), function(values) {
|
||||||
return [values[0], _.map(values[1], function (point) { return [point[index], point[timeCol]]; }) ];
|
return [values[0], _.map(values[1], function (point) { return [isNaN(point[index]) ? null : point[index], point[timeCol]]; }) ];
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(datapoints, function(values) {
|
_.each(datapoints, function(values) {
|
||||||
|
@ -16,6 +16,18 @@ function (angular, _, config) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var modalScope = $rootScope.$new();
|
var modalScope = $rootScope.$new();
|
||||||
|
|
||||||
|
$rootScope.$on("dashboard-loaded", function(event, newDashboard ) {
|
||||||
|
self.original = angular.copy(newDashboard);
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on("dashboard-saved", function(event, savedDashboard) {
|
||||||
|
self.original = angular.copy(savedDashboard);
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on("$routeChangeSuccess", function() {
|
||||||
|
self.original = null;
|
||||||
|
});
|
||||||
|
|
||||||
window.onbeforeunload = function () {
|
window.onbeforeunload = function () {
|
||||||
if (self.has_unsaved_changes()) {
|
if (self.has_unsaved_changes()) {
|
||||||
return "There are unsaved changes to this dashboard";
|
return "There are unsaved changes to this dashboard";
|
||||||
@ -47,15 +59,16 @@ function (angular, _, config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.has_unsaved_changes = function () {
|
this.has_unsaved_changes = function () {
|
||||||
if (!dashboard.original) {
|
if (!self.original) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var current = angular.copy(dashboard.current);
|
var current = angular.copy(dashboard.current);
|
||||||
var original = dashboard.original;
|
var original = self.original;
|
||||||
|
|
||||||
// ignore timespan changes
|
// ignore timespan changes
|
||||||
current.services.filter.time = original.services.filter.time = {};
|
current.services.filter.time = original.services.filter.time = {};
|
||||||
|
|
||||||
current.refresh = original.refresh;
|
current.refresh = original.refresh;
|
||||||
|
|
||||||
var currentTimepicker = _.findWhere(current.nav, { type: 'timepicker' });
|
var currentTimepicker = _.findWhere(current.nav, { type: 'timepicker' });
|
||||||
@ -82,7 +95,7 @@ function (angular, _, config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
modalScope.ignore = function() {
|
modalScope.ignore = function() {
|
||||||
dashboard.original = null;
|
self.original = null;
|
||||||
self.goto_next();
|
self.goto_next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,4 +112,4 @@ function (angular, _, config) {
|
|||||||
}).run(function(unsavedChangesSrv) {
|
}).run(function(unsavedChangesSrv) {
|
||||||
unsavedChangesSrv.init();
|
unsavedChangesSrv.init();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -68,9 +68,15 @@ function (Settings) {
|
|||||||
*/
|
*/
|
||||||
unsaved_changes_warning: true,
|
unsaved_changes_warning: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the default timespan for the playlist feature
|
||||||
|
* Example: "1m", "1h"
|
||||||
|
*/
|
||||||
|
playlist_timespan: "1m",
|
||||||
|
|
||||||
panel_names: [
|
panel_names: [
|
||||||
'text',
|
'text',
|
||||||
'graphite'
|
'graph'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
2
src/css/bootstrap.dark.min.css
vendored
2
src/css/bootstrap.dark.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/css/bootstrap.light.min.css
vendored
2
src/css/bootstrap.light.min.css
vendored
File diff suppressed because one or more lines are too long
4222
src/css/default.min.css
vendored
Normal file
4222
src/css/default.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -271,7 +271,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grafana-target-segment {
|
.grafana-target-segment {
|
||||||
padding: 5px 7px;
|
padding: 8px 7px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
border-right: 1px solid @grafanaTargetSegmentBorder;
|
border-right: 1px solid @grafanaTargetSegmentBorder;
|
||||||
@ -337,10 +337,11 @@ input[type=text].grafana-function-param-input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
padding: 5px 7px;
|
padding: 8px 7px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 5px;
|
top: 8px;
|
||||||
color: @grafanaTargetColor;
|
color: @grafanaTargetColor;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
.grafana-target-hidden & {
|
.grafana-target-hidden & {
|
||||||
color: @grafanaTargetColorHide;
|
color: @grafanaTargetColorHide;
|
||||||
@ -353,7 +354,7 @@ input[type=text].grafana-function-param-input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input[type=text].grafana-target-text-input {
|
input[type=text].grafana-target-text-input {
|
||||||
padding: 5px 7px;
|
padding: 8px 7px;
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -367,8 +368,7 @@ input[type=text].grafana-target-segment-input {
|
|||||||
border-right: 1px solid @grafanaTargetSegmentBorder;
|
border-right: 1px solid @grafanaTargetSegmentBorder;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
height: 22px;
|
padding: 8px 4px;
|
||||||
line-height: 22px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select.grafana-target-segment-input {
|
select.grafana-target-segment-input {
|
||||||
@ -376,8 +376,8 @@ select.grafana-target-segment-input {
|
|||||||
border-right: 1px solid @grafanaTargetSegmentBorder;
|
border-right: 1px solid @grafanaTargetSegmentBorder;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
height: 30px;
|
height: 36px;
|
||||||
line-height: 30px;
|
padding: 8px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grafana-target .dropdown {
|
.grafana-target .dropdown {
|
||||||
|
@ -204,12 +204,21 @@ form input.ng-invalid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.row-tab {
|
.row-tab {
|
||||||
|
.dropdown-menu-right {
|
||||||
|
top: 0;
|
||||||
|
left: 33px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-tab-button {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
vertical-align: middle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.row-button {
|
.row-button {
|
||||||
|
@ -7,24 +7,20 @@
|
|||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
|
|
||||||
<title>Grafana</title>
|
<title>Grafana</title>
|
||||||
<link rel="stylesheet" href="css/bootstrap.dark.min.css" title="Light">
|
<link rel="stylesheet" href="css/default.min.css" title="Dark">
|
||||||
<link rel="stylesheet" href="css/timepicker.css">
|
|
||||||
<link rel="stylesheet" href="css/spectrum.css">
|
<!-- build:js app/app.js -->
|
||||||
<link rel="stylesheet" href="css/animate.min.css">
|
|
||||||
<link rel="stylesheet" href="css/normalize.min.css">
|
|
||||||
<!-- load the root require context -->
|
|
||||||
<script src="vendor/require/require.js"></script>
|
<script src="vendor/require/require.js"></script>
|
||||||
<script src="app/components/require.config.js"></script>
|
<script src="app/components/require.config.js"></script>
|
||||||
|
<!-- endbuild -->
|
||||||
|
|
||||||
<script>require(['app'], function () {})</script>
|
<script>require(['app'], function () {})</script>
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body ng-cloak body-class>
|
<body ng-cloak body-class>
|
||||||
|
|
||||||
<!--<link rel="stylesheet" ng-href="css/bootstrap.{{dashboard.current.style||'dark'}}.min.css">-->
|
<link rel="stylesheet" href="css/bootstrap.light.min.css" ng-if="dashboard.current.style === 'light'">
|
||||||
<link rel="stylesheet" ng-href="css/bootstrap.{{dashboard.current.style||'dark'}}.min.css">
|
|
||||||
<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">
|
||||||
|
|
||||||
|
@ -19,25 +19,33 @@ define([
|
|||||||
_filterSrv = filterSrv;
|
_filterSrv = filterSrv;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
_filterSrv.init(_dashboard.current);
|
||||||
|
});
|
||||||
|
|
||||||
describe('init', function() {
|
describe('init', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
_filterSrv.add({ name: 'test', current: { value: 'oogle' } });
|
_filterSrv.addTemplateParameter({ name: 'test', current: { value: 'oogle' } });
|
||||||
_filterSrv.init();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initialize template data', function() {
|
it('should initialize template data', function() {
|
||||||
var target = _filterSrv.applyFilterToTarget('this.[[test]].filters');
|
var target = _filterSrv.applyTemplateToTarget('this.[[test]].filters');
|
||||||
expect(target).to.be('this.oogle.filters');
|
expect(target).to.be('this.oogle.filters');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('filterOptionSelected', function() {
|
describe('updateTemplateData', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
_filterSrv.add({ name: 'test' });
|
_filterSrv.addTemplateParameter({
|
||||||
_filterSrv.filterOptionSelected(_filterSrv.list[0], { value: 'muuuu' });
|
name: 'test',
|
||||||
|
value: 'muuu',
|
||||||
|
current: { value: 'muuuu' }
|
||||||
|
});
|
||||||
|
|
||||||
|
_filterSrv.updateTemplateData();
|
||||||
});
|
});
|
||||||
it('should set current value and update template data', function() {
|
it('should set current value and update template data', function() {
|
||||||
var target = _filterSrv.applyFilterToTarget('this.[[test]].filters');
|
var target = _filterSrv.applyTemplateToTarget('this.[[test]].filters');
|
||||||
expect(target).to.be('this.muuuu.filters');
|
expect(target).to.be('this.muuuu.filters');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
34
src/vendor/chromath.js
vendored
34
src/vendor/chromath.js
vendored
@ -1,34 +0,0 @@
|
|||||||
(function(){function a(d){var c,b,e,f;if("[object String]"===Object.prototype.toString.call(d)||"[object Number]"===Object.prototype.toString.call(d))c=a.parse(d);else{if(m(d))throw Error("Unsure how to parse array `"+d+"`, please pass an object or CSS style or try Chromath.rgb, Chromath.hsl, or Chromath.hsv");d instanceof a?c=k({},d):n(d)&&(c=k({},d))}if(c)isFinite(c.a)||(c.a=1);else throw Error("Could not parse `"+d+"`");if("r"in c)f=[c.r,c.g,c.b],b=a.rgb2hsl(f),e=a.rgb2hsv(f);else if("h"in c)if("l"in
|
|
||||||
c)b=[c.h,c.s,c.l],f=a.hsl2rgb(b),e=a.rgb2hsv(f);else if("v"in c||"b"in c)"b"in c&&(c.v=c.b),e=[c.h,c.s,c.v],f=a.hsv2rgb(e),b=a.rgb2hsl(f);k(this,{r:f[0],g:f[1],b:f[2],h:b[0],sl:b[1],l:b[2],sv:e[1],v:e[2],a:c.a});this.h=(this.h%360+360)%360;1<this.sl&&(this.sl/=100);1<this.sv&&(this.sv/=100);1<this.l&&(this.l/=100);this.r=h(parseInt(this.r,10),0,255);this.g=h(parseInt(this.g,10),0,255);this.b=h(parseInt(this.b,10),0,255);this.a=h(this.a,0,1);return this}function q(d,a,b,e){var f=d;m(f)&&(d=f[0],a=
|
|
||||||
f[1],b=f[2],e=f[3]);n(f)&&(d=f.r,a=f.g,b=f.b,e=f.a);return[d,a,b,e]}function p(d,a,b,e){var f=d;m(f)&&(d=f[0],a=f[1],b=f[2],e=f[3]);n(f)&&(d=f.h,a=f.s,b=f.l||f.v,e=f.a);return[d,a,b,e]}function r(a,c,b){isFinite(c)||(b=q(a,c,b),a=b[0],c=b[1],b=b[2]);1<a&&(a/=255);1<c&&(c/=255);1<b&&(b/=255);return[a,c,b]}function s(a,c,b){isFinite(c)||(b=p(a,c,b),a=b[0],c=b[1],b=b[2]);1<c&&(c/=100);1<b&&(b/=100);return[(a%360+360)%360,c,b]}function k(){for(var a=arguments[0],c=1,b,e;b=arguments[c++];)for(e in b)a[e]=
|
|
||||||
b[e];return a}function m(a){return"[object Array]"===Object.prototype.toString.call(a)}function n(a){return"[object Object]"===Object.prototype.toString.call(a)}function h(a,c,b){return a>b?b:a<c?c:a}function l(a,c,b){return a+(c-a)*b}a.rgb=function(d,c,b,e){e=q(d,c,b,e);d=e[0];c=e[1];b=e[2];e=e[3];return new a({r:d,g:c,b:b,a:e})};a.rgba=a.rgb;a.hsl=function(d,c,b,e){e=p(d,c,b,e);d=e[0];c=e[1];b=e[2];e=e[3];return new a({h:d,s:c,l:b,a:e})};a.hsla=a.hsl;a.hsv=function(d,c,b,e){e=p(d,c,b,e);d=e[0];
|
|
||||||
c=e[1];b=e[2];e=e[3];return new a({h:d,s:c,v:b,a:e})};a.hsva=a.hsv;a.hsb=a.hsv;a.hsba=a.hsva;a.toInteger=function(d){d=(new a(d)).toRGBObject();return d.b|d.g<<8|d.r<<16};a.toName=function(d){var d=+new a(d),c;for(c in a.colors)if(+a[c]==d)return c};a.rgb2hex=function(d,c,b){d=a.toInteger({r:d,g:c,b:b}).toString(16).toUpperCase();c=6;b=0;d=d.toString();c||(c=2);for(b||(b="0");d.length<c;)d=b+d;return"#"+d};a.rgb2hsl=function(a,c,b){var b=r(a,c,b),a=b[0],c=b[1],b=b[2],e=Math.max(a,c,b),f=Math.min(a,
|
|
||||||
c,b),g=e-f,f=0.5*(e+f),h=0===g?0:g/(1-Math.abs(2*f-1)),i;0===g?i=0:e===a?i=(c-b)/g%6:e===c?i=(b-a)/g+2:e===b&&(i=(a-c)/g+4);return[60*i,parseFloat(h),parseFloat(f)]};a.rgb2hsv=function(a,c,b){var b=r(a,c,b),a=b[0],c=b[1],b=b[2],e=Math.max(a,c,b),f=Math.min(a,c,b),f=e-f,g;0===f?g=0:e===a?g=(c-b)/f%6:e===c?g=(b-a)/f+2:e===b&&(g=(a-c)/f+4);return[60*g,parseFloat(0===f?0:f/e),parseFloat(e)]};a.rgb2hsb=a.rgb2hsv;a.hsl2rgb=function(a,c,b){var b=s(a,c,b),a=b[0],c=b[1],b=b[2],c=(1-Math.abs(2*b-1))*c,a=a/
|
|
||||||
60,e=c*(1-Math.abs(a%2-1));switch(Math.floor(a)){case 0:a=[c,e,0];break;case 1:a=[e,c,0];break;case 2:a=[0,c,e];break;case 3:a=[0,e,c];break;case 4:a=[e,0,c];break;case 5:a=[c,0,e];break;default:a=[0,0,0]}b-=c/2;return[255*(a[0]+b),255*(a[1]+b),255*(a[2]+b)]};a.hsv2rgb=function(a,c,b){var b=s(a,c,b),a=b[0],c=b[1],b=b[2],c=b*c,e=a/60,f=c*(1-Math.abs(e%2-1)),g;void 0==a?g=[0,0,0]:0<=e&&1>e?g=[c,f,0]:1<=e&&2>e?g=[f,c,0]:2<=e&&3>e?g=[0,c,f]:3<=e&&4>e?g=[0,f,c]:4<=e&&5>e?g=[f,0,c]:5<=e&&6>e&&(g=[c,0,f]);
|
|
||||||
a=b-c;return[255*(g[0]+a),255*(g[1]+a),255*(g[2]+a)]};a.hsb2rgb=a.hsv2rgb;a.complement=function(d){d=(new a(d)).toHSLObject();d.h=(d.h+180)%360;return new a(d)};a.triad=function(d){d=new a(d);return[d,new a({r:d.b,g:d.r,b:d.g}),new a({r:d.g,g:d.b,b:d.r})]};a.tetrad=function(d){d=new a(d);return[d,new a({r:d.b,g:d.r,b:d.b}),new a({r:d.b,g:d.g,b:d.r}),new a({r:d.r,g:d.b,b:d.r})]};a.analogous=function(d,c,b){isFinite(c)||(c=8);isFinite(b)||(b=30);var e=new a(d),d=e.toHSVObject(),b=360/b,e=[e];for(d.h=
|
|
||||||
(d.h-(b*c>>1)+720)%360;--c;)d.h+=b,d.h%=360,e.push(new a(d));return e};a.monochromatic=function(d,c){c||(c=5);for(var b=(new a(d)).toHSVObject(),e=1/c,f=[],g=0;g++<c;)b.v=g*e,f.push(new a(b));return f};a.splitcomplement=function(d){var c=new a(d),d=c.toHSVObject(),c=[c];d.h*=0.2;d.h%=360;c.push(new a(d));d.h*=0.4;d.h%=360;c.push(new a(d));return c};a.tint=function(d,c){return a.towards(d,"#FFFFFF",c)};a.lighten=a.tint;a.shade=function(d,c){return a.towards(d,"#000000",c)};a.darken=a.shade;a.desaturate=
|
|
||||||
function(d,c){var b=new a(d);switch(c){case 1:b=0.35+13*(b.r+b.g+b.b)/60;break;case 2:b=(13*(b.r+b.g+b.b)+5355)/60;break;default:b=0.3*b.r+0.59*b.g+0.11*b.b}b=h(b,0,255);return new a({r:b,g:b,b:b})};a.greyscale=a.desaturate;a.websafe=function(d){d=new a(d);d.r=51*Math.round(d.r/51);d.g=51*Math.round(d.g/51);d.b=51*Math.round(d.b/51);return new a(d)};a.additive=function(){for(var d=arguments.length-2,c=-1,b,e;c++<d;){b=b||new a(arguments[c]);e=new a(arguments[c+1]);if(255<(b.r+=e.r))b.r=255;if(255<
|
|
||||||
(b.g+=e.g))b.g=255;if(255<(b.b+=e.b))b.b=255;b=new a(b)}return b};a.subtractive=function(){for(var d=arguments.length-2,c=-1,b,e;c++<d;){b=b||new a(arguments[c]);e=new a(arguments[c+1]);if(0>(b.r+=e.r-255))b.r=0;if(0>(b.g+=e.g-255))b.g=0;if(0>(b.b+=e.b-255))b.b=0;b=new a(b)}return b};a.multiply=function(){for(var d=arguments.length-2,c=-1,b,e;c++<d;)b=b||new a(arguments[c]),e=new a(arguments[c+1]),b.r=b.r/255*e.r|0,b.g=b.g/255*e.g|0,b.b=b.b/255*e.b|0,b=new a(b);return b};a.average=function(){for(var d=
|
|
||||||
arguments.length-2,c=-1,b,e;c++<d;)b=b||new a(arguments[c]),e=new a(arguments[c+1]),b.r=b.r+e.r>>1,b.g=b.g+e.g>>1,b.b=b.b+e.b>>1,b=new a(b);return b};a.overlay=function(d,c,b){d=new a(d);c=new a(c);1<b&&(b/=100);b=h(b-1+c.a,0,1);return new a({r:l(d.r,c.r,b),g:l(d.g,c.g,b),b:l(d.b,c.b,b)})};a.towards=function(d,c,b,e){if(!c)return d;if(!isFinite(b))throw Error("TypeError: `by`("+b+") should be between 0 and 1");d instanceof a||(d=new a(d));c instanceof a||(c=new a(c||"#FFFFFF"));e||(e=l);b=parseFloat(b);
|
|
||||||
return new a({r:e(d.r,c.r,b),g:e(d.g,c.g,b),b:e(d.b,c.b,b),a:e(d.a,c.a,b)})};a.gradient=function(d,c,b,e){var f=[],g;b||(b=20);g=b-1;if(isFinite(e))return a.towards(d,c,e/g);for(e=-1;++e<b;)f.push(a.towards(d,c,e/g));return f};a.parse=function(d){var c=a.parsers,b,e,f,g,h;b=0;for(e=c.length;b<e;b++)if(f=c[b],(g=f.regex.exec(d))&&g.length&&(h=f.process.apply(this,g)),h)return h};a.parsers=[{example:["red","burlywood"],regex:/^[a-z]+$/i,process:function(d){if(a.colors[d])return a.colors[d]}},{example:[3554431,
|
|
||||||
16809984],regex:/^\d+$/,process:function(a){return{r:a>>16&255,g:a>>8&255,b:a&255}}},{example:["#fb0","f0f"],regex:/^#?([\dA-F]{1})([\dA-F]{1})([\dA-F]{1})$/i,process:function(a,c,b,e){return{r:parseInt(c+c,16),g:parseInt(b+b,16),b:parseInt(e+e,16)}}},{example:["#00ff00","336699"],regex:/^#?([\dA-F]{2})([\dA-F]{2})([\dA-F]{2})$/i,process:function(a,c,b,e){return{r:parseInt(c,16),g:parseInt(b,16),b:parseInt(e,16)}}},{example:["rgb(123, 234, 45)","rgb(25, 50%, 100%)","rgba(12%, 34, 56%, 0.78)"],regex:/^rgba*\((\d{1,3}\%*),\s*(\d{1,3}\%*),\s*(\d{1,3}\%*)(?:,\s*([0-9.]+))?\)/,
|
|
||||||
process:function(a,c,b,e,f){c=c&&"%"==c.slice(-1)?Math.round(2.55*c.slice(0,-1)):1*c;b=b&&"%"==b.slice(-1)?Math.round(2.55*b.slice(0,-1)):1*b;e=e&&"%"==e.slice(-1)?Math.round(2.55*e.slice(0,-1)):1*e;f=f&&"%"==f.slice(-1)?Math.round(100*f.slice(0,-1)):1*f;return{r:h(c,0,255),g:h(b,0,255),b:h(e,0,255),a:h(f,0,1)||void 0}}},{example:["hsl(123, 34%, 45%)","hsla(25, 50%, 100%, 0.75)","hsv(12, 34%, 56%)"],regex:/^hs([bvl])a*\((\d{1,3}\%*),\s*(\d{1,3}\%*),\s*(\d{1,3}\%*)(?:,\s*([0-9.]+))?\)/,process:function(a,
|
|
||||||
c,b,e,f){b*=1;e=e.slice(0,-1)/100;f=f.slice(0,-1)/100;a={h:h(b,0,360),s:h(e,0,1),a:h(f,0,1)};a[c]=h(f,0,1);return a}}];a.colors={aqua:new a({r:0,g:255,b:255}),black:new a({r:0,g:0,b:0}),blue:new a({r:0,g:0,b:255}),fuchsia:new a({r:255,g:0,b:255}),gray:new a({r:128,g:128,b:128}),green:new a({r:0,g:128,b:0}),lime:new a({r:0,g:255,b:0}),maroon:new a({r:128,g:0,b:0}),navy:new a({r:0,g:0,b:128}),olive:new a({r:128,g:128,b:0}),purple:new a({r:128,g:0,b:128}),red:new a({r:255,g:0,b:0}),silver:new a({r:192,
|
|
||||||
g:192,b:192}),teal:new a({r:0,g:128,b:128}),white:new a({r:255,g:255,b:255}),yellow:new a({r:255,g:255,b:0}),aliceblue:new a({r:240,g:248,b:255}),antiquewhite:new a({r:250,g:235,b:215}),aquamarine:new a({r:127,g:255,b:212}),azure:new a({r:240,g:255,b:255}),beige:new a({r:245,g:245,b:220}),bisque:new a({r:255,g:228,b:196}),blanchedalmond:new a({r:255,g:235,b:205}),blueviolet:new a({r:138,g:43,b:226}),brown:new a({r:165,g:42,b:42}),burlywood:new a({r:222,g:184,b:135}),cadetblue:new a({r:95,g:158,b:160}),
|
|
||||||
chartreuse:new a({r:127,g:255,b:0}),chocolate:new a({r:210,g:105,b:30}),coral:new a({r:255,g:127,b:80}),cornflowerblue:new a({r:100,g:149,b:237}),cornsilk:new a({r:255,g:248,b:220}),crimson:new a({r:220,g:20,b:60}),cyan:new a({r:0,g:255,b:255}),darkblue:new a({r:0,g:0,b:139}),darkcyan:new a({r:0,g:139,b:139}),darkgoldenrod:new a({r:184,g:134,b:11}),darkgray:new a({r:169,g:169,b:169}),darkgreen:new a({r:0,g:100,b:0}),darkgrey:new a({r:169,g:169,b:169}),darkkhaki:new a({r:189,g:183,b:107}),darkmagenta:new a({r:139,
|
|
||||||
g:0,b:139}),darkolivegreen:new a({r:85,g:107,b:47}),darkorange:new a({r:255,g:140,b:0}),darkorchid:new a({r:153,g:50,b:204}),darkred:new a({r:139,g:0,b:0}),darksalmon:new a({r:233,g:150,b:122}),darkseagreen:new a({r:143,g:188,b:143}),darkslateblue:new a({r:72,g:61,b:139}),darkslategray:new a({r:47,g:79,b:79}),darkslategrey:new a({r:47,g:79,b:79}),darkturquoise:new a({r:0,g:206,b:209}),darkviolet:new a({r:148,g:0,b:211}),deeppink:new a({r:255,g:20,b:147}),deepskyblue:new a({r:0,g:191,b:255}),dimgray:new a({r:105,
|
|
||||||
g:105,b:105}),dimgrey:new a({r:105,g:105,b:105}),dodgerblue:new a({r:30,g:144,b:255}),firebrick:new a({r:178,g:34,b:34}),floralwhite:new a({r:255,g:250,b:240}),forestgreen:new a({r:34,g:139,b:34}),gainsboro:new a({r:220,g:220,b:220}),ghostwhite:new a({r:248,g:248,b:255}),gold:new a({r:255,g:215,b:0}),goldenrod:new a({r:218,g:165,b:32}),greenyellow:new a({r:173,g:255,b:47}),grey:new a({r:128,g:128,b:128}),honeydew:new a({r:240,g:255,b:240}),hotpink:new a({r:255,g:105,b:180}),indianred:new a({r:205,
|
|
||||||
g:92,b:92}),indigo:new a({r:75,g:0,b:130}),ivory:new a({r:255,g:255,b:240}),khaki:new a({r:240,g:230,b:140}),lavender:new a({r:230,g:230,b:250}),lavenderblush:new a({r:255,g:240,b:245}),lawngreen:new a({r:124,g:252,b:0}),lemonchiffon:new a({r:255,g:250,b:205}),lightblue:new a({r:173,g:216,b:230}),lightcoral:new a({r:240,g:128,b:128}),lightcyan:new a({r:224,g:255,b:255}),lightgoldenrodyellow:new a({r:250,g:250,b:210}),lightgray:new a({r:211,g:211,b:211}),lightgreen:new a({r:144,g:238,b:144}),lightgrey:new a({r:211,
|
|
||||||
g:211,b:211}),lightpink:new a({r:255,g:182,b:193}),lightsalmon:new a({r:255,g:160,b:122}),lightseagreen:new a({r:32,g:178,b:170}),lightskyblue:new a({r:135,g:206,b:250}),lightslategray:new a({r:119,g:136,b:153}),lightslategrey:new a({r:119,g:136,b:153}),lightsteelblue:new a({r:176,g:196,b:222}),lightyellow:new a({r:255,g:255,b:224}),limegreen:new a({r:50,g:205,b:50}),linen:new a({r:250,g:240,b:230}),magenta:new a({r:255,g:0,b:255}),mediumaquamarine:new a({r:102,g:205,b:170}),mediumblue:new a({r:0,
|
|
||||||
g:0,b:205}),mediumorchid:new a({r:186,g:85,b:211}),mediumpurple:new a({r:147,g:112,b:219}),mediumseagreen:new a({r:60,g:179,b:113}),mediumslateblue:new a({r:123,g:104,b:238}),mediumspringgreen:new a({r:0,g:250,b:154}),mediumturquoise:new a({r:72,g:209,b:204}),mediumvioletred:new a({r:199,g:21,b:133}),midnightblue:new a({r:25,g:25,b:112}),mintcream:new a({r:245,g:255,b:250}),mistyrose:new a({r:255,g:228,b:225}),moccasin:new a({r:255,g:228,b:181}),navajowhite:new a({r:255,g:222,b:173}),oldlace:new a({r:253,
|
|
||||||
g:245,b:230}),olivedrab:new a({r:107,g:142,b:35}),orange:new a({r:255,g:165,b:0}),orangered:new a({r:255,g:69,b:0}),orchid:new a({r:218,g:112,b:214}),palegoldenrod:new a({r:238,g:232,b:170}),palegreen:new a({r:152,g:251,b:152}),paleturquoise:new a({r:175,g:238,b:238}),palevioletred:new a({r:219,g:112,b:147}),papayawhip:new a({r:255,g:239,b:213}),peachpuff:new a({r:255,g:218,b:185}),peru:new a({r:205,g:133,b:63}),pink:new a({r:255,g:192,b:203}),plum:new a({r:221,g:160,b:221}),powderblue:new a({r:176,
|
|
||||||
g:224,b:230}),rosybrown:new a({r:188,g:143,b:143}),royalblue:new a({r:65,g:105,b:225}),saddlebrown:new a({r:139,g:69,b:19}),salmon:new a({r:250,g:128,b:114}),sandybrown:new a({r:244,g:164,b:96}),seagreen:new a({r:46,g:139,b:87}),seashell:new a({r:255,g:245,b:238}),sienna:new a({r:160,g:82,b:45}),skyblue:new a({r:135,g:206,b:235}),slateblue:new a({r:106,g:90,b:205}),slategray:new a({r:112,g:128,b:144}),slategrey:new a({r:112,g:128,b:144}),snow:new a({r:255,g:250,b:250}),springgreen:new a({r:0,g:255,
|
|
||||||
b:127}),steelblue:new a({r:70,g:130,b:180}),tan:new a({r:210,g:180,b:140}),thistle:new a({r:216,g:191,b:216}),tomato:new a({r:255,g:99,b:71}),turquoise:new a({r:64,g:224,b:208}),violet:new a({r:238,g:130,b:238}),wheat:new a({r:245,g:222,b:179}),whitesmoke:new a({r:245,g:245,b:245}),yellowgreen:new a({r:154,g:205,b:50})};a.prototype={toName:function(){return a.toName(this)},toString:function(){return this.toHexString()},valueOf:function(){return a.toInteger(this)},rgb:function(){return this.toRGBArray()},
|
|
||||||
toRGBArray:function(){return this.toRGBAArray().slice(0,3)},toRGBObject:function(){var a=this.toRGBArray();return{r:a[0],g:a[1],b:a[2]}},toRGBString:function(){return"rgb("+this.toRGBArray().join(",")+")"},rgba:function(){return this.toRGBAArray()},toRGBAArray:function(){return[Math.round(this.r),Math.round(this.g),Math.round(this.b),parseFloat(this.a)]},toRGBAObject:function(){var a=this.toRGBAArray();return{r:a[0],g:a[1],b:a[2],a:a[3]}},toRGBAString:function(){return"rgba("+this.toRGBAArray().join(",")+
|
|
||||||
")"},hex:function(){return this.toHexArray()},toHexArray:function(){return this.toHexString().slice(1).match(/([\dA-F]{2})/ig)},toHexObject:function(){var a=this.toHexArray();return{r:a[0],g:a[1],b:a[2]}},toHexString:function(){return a.rgb2hex(this.r,this.g,this.b)},hsl:function(){return this.toHSLArray()},toHSLArray:function(){return this.toHSLAArray().slice(0,3)},toHSLObject:function(){var a=this.toHSLArray();return{h:a[0],s:a[1],l:a[2]}},toHSLString:function(){return"hsl("+this.toHSLArray().join(",")+
|
|
||||||
")"},hsla:function(){return this.toHSLAArray()},toHSLAArray:function(){return[Math.round(this.h),parseFloat(this.sl),parseFloat(this.l),parseFloat(this.a)]},toHSLAObject:function(){var a=this.toHSLArray();return{h:a[0],s:a[1],l:a[2],a:a[3]}},toHSLAString:function(){return"hsla("+this.toHSLAArray().join(",")+")"},hsv:function(){return this.toHSVArray()},toHSVArray:function(){return[Math.round(this.h),parseFloat(this.sv),parseFloat(this.v)]},toHSVObject:function(){return{h:Math.round(this.h),s:parseFloat(this.sv),
|
|
||||||
v:parseFloat(this.v)}},toHSVString:function(){var a=this.toHSVArray();return"hsv("+[a[0],100*a[1]+"%",100*a[2]+"%"]+")"},hsva:function(){return this.toHSVAArray()},toHSVAArray:function(){return[Math.round(this.h),parseFloat(this.sv),parseFloat(this.v),parseFloat(this.a)]},toHSVAObject:function(){var a=this.toHSVAArray();return{h:a[0],s:a[1],l:a[2],a:a[3]}},toHSVAString:function(){var a=this.toHSVAArray();return"hsva("+[a[0],100*a[1]+"%",100*a[2]+"%",a[3]]+")"},hsb:function(){return this.hsv()},toHSBArray:function(){return this.toHSVArray()},
|
|
||||||
toHSBObject:function(){return this.toHSVObject()},toHSBString:function(){return this.toHSVString()},hsba:function(){return this.hsva()},toHSBAArray:function(){return this.toHSVAArray()},toHSBAObject:function(){return this.toHSVAObject()},toHSBAString:function(){return this.toHSVAString()},complement:function(){return a.complement(this)},triad:function(){return a.triad(this)},tetrad:function(){return a.tetrad(this)},analogous:function(d,c){return a.analogous(this,d,c)},monochromatic:function(d){return a.monochromatic(this,
|
|
||||||
d)},splitcomplement:function(){return a.splitcomplement(this)},tint:function(d){return a.tint(this,d)},lighten:function(a){return this.tint(a)},shade:function(d){return a.shade(this,d)},darken:function(a){return this.shade(a)},desaturate:function(d){return a.desaturate(this,d)},greyscale:function(a){return this.desaturate(a)},websafe:function(){return a.websafe(this)},additive:function(){var d=Array.prototype.slice.call(arguments);return a.additive.apply(a,[this].concat(d))},subtractive:function(){var d=
|
|
||||||
Array.prototype.slice.call(arguments);return a.subtractive.apply(a,[this].concat(d))},multiply:function(){var d=Array.prototype.slice.call(arguments);return a.multiply.apply(a,[this].concat(d))},average:function(){var d=Array.prototype.slice.call(arguments);return a.average.apply(a,[this].concat(d))},overlay:function(d,c){return a.overlay(this,d,c)},clone:function(){return new a(this)},towards:function(d,c){return a.towards(this,d,c)},gradient:function(d,c,b){return a.gradient(this,d,c,b)}};k(a,a.colors);
|
|
||||||
var j="Chromath",i=a,t,u;"string"!==typeof j&&(i=j,j=null);t=function(){return this}.call(null);i=i||{};"undefined"!==typeof module&&("undefined"!==typeof exports&&module.exports)&&(u=!0,module.exports=exports=i);"undefined"!==typeof window&&!u&&(j&&i)&&(t[j]=i)})();
|
|
4
src/vendor/license.json
vendored
4
src/vendor/license.json
vendored
@ -47,10 +47,6 @@
|
|||||||
"version":"2.1.8",
|
"version":"2.1.8",
|
||||||
"license":"MIT"
|
"license":"MIT"
|
||||||
},
|
},
|
||||||
"chromath": {
|
|
||||||
"version":"0.0.5",
|
|
||||||
"license":"MIT"
|
|
||||||
},
|
|
||||||
"filesaver": {
|
"filesaver": {
|
||||||
"version":"2013-01-23",
|
"version":"2013-01-23",
|
||||||
"license":"MIT"
|
"license":"MIT"
|
||||||
|
993
src/vendor/timezone.js
vendored
993
src/vendor/timezone.js
vendored
@ -1,993 +0,0 @@
|
|||||||
// -----
|
|
||||||
// The `timezoneJS.Date` object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data.
|
|
||||||
//
|
|
||||||
// The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March).
|
|
||||||
//
|
|
||||||
// The other significant difference from the built-in JavaScript Date is that `timezoneJS.Date` also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer.
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2010 Matthew Eernisse (mde@fleegix.org)
|
|
||||||
* and Open Source Applications Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Credits: Ideas included from incomplete JS implementation of Olson
|
|
||||||
* parser, "XMLDAte" by Philippe Goetz (philippe.goetz@wanadoo.fr)
|
|
||||||
*
|
|
||||||
* Contributions:
|
|
||||||
* Jan Niehusmann
|
|
||||||
* Ricky Romero
|
|
||||||
* Preston Hunt (prestonhunt@gmail.com)
|
|
||||||
* Dov. B Katz (dov.katz@morganstanley.com)
|
|
||||||
* Peter Bergström (pbergstr@mac.com)
|
|
||||||
* Long Ho
|
|
||||||
*/
|
|
||||||
(function () {
|
|
||||||
// Standard initialization stuff to make sure the library is
|
|
||||||
// usable on both client and server (node) side.
|
|
||||||
"use strict";
|
|
||||||
var root = this;
|
|
||||||
|
|
||||||
var timezoneJS;
|
|
||||||
if (typeof exports !== 'undefined') {
|
|
||||||
timezoneJS = exports;
|
|
||||||
} else {
|
|
||||||
timezoneJS = root.timezoneJS = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
timezoneJS.VERSION = '0.4.4';
|
|
||||||
|
|
||||||
// Grab the ajax library from global context.
|
|
||||||
// This can be jQuery, Zepto or fleegix.
|
|
||||||
// You can also specify your own transport mechanism by declaring
|
|
||||||
// `timezoneJS.timezone.transport` to a `function`. More details will follow
|
|
||||||
var $ = root.$ || root.jQuery || root.Zepto
|
|
||||||
, fleegix = root.fleegix
|
|
||||||
, _arrIndexOf
|
|
||||||
// Declare constant list of days and months. Unfortunately this doesn't leave room for i18n due to the Olson data being in English itself
|
|
||||||
, DAYS = timezoneJS.Days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
|
||||||
, MONTHS = timezoneJS.Months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
|
||||||
, SHORT_MONTHS = {}
|
|
||||||
, SHORT_DAYS = {}
|
|
||||||
, EXACT_DATE_TIME = {}
|
|
||||||
, TZ_REGEXP = new RegExp('^[a-zA-Z]+/');
|
|
||||||
|
|
||||||
//`{ "Jan": 0, "Feb": 1, "Mar": 2, "Apr": 3, "May": 4, "Jun": 5, "Jul": 6, "Aug": 7, "Sep": 8, "Oct": 9, "Nov": 10, "Dec": 11 }`
|
|
||||||
for (var i = 0; i < MONTHS.length; i++) {
|
|
||||||
SHORT_MONTHS[MONTHS[i].substr(0, 3)] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
//`{ "Sun": 0, "Mon": 1, "Tue": 2, "Wed": 3, "Thu": 4, "Fri": 5, "Sat": 6 }`
|
|
||||||
for (i = 0; i < DAYS.length; i++) {
|
|
||||||
SHORT_DAYS[DAYS[i].substr(0, 3)] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Handle array indexOf in IE
|
|
||||||
//From https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
|
|
||||||
//Extending Array prototype causes IE to iterate thru extra element
|
|
||||||
_arrIndexOf = Array.prototype.indexOf || function (el) {
|
|
||||||
if (this === null) {
|
|
||||||
throw new TypeError();
|
|
||||||
}
|
|
||||||
var t = Object(this);
|
|
||||||
var len = t.length >>> 0;
|
|
||||||
if (len === 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
var n = 0;
|
|
||||||
if (arguments.length > 1) {
|
|
||||||
n = Number(arguments[1]);
|
|
||||||
if (n != n) { // shortcut for verifying if it's NaN
|
|
||||||
n = 0;
|
|
||||||
} else if (n !== 0 && n !== Infinity && n !== -Infinity) {
|
|
||||||
n = (n > 0 || -1) * Math.floor(Math.abs(n));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n >= len) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
|
|
||||||
for (; k < len; k++) {
|
|
||||||
if (k in t && t[k] === el) {
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Format a number to the length = digits. For ex:
|
|
||||||
//
|
|
||||||
// `_fixWidth(2, 2) = '02'`
|
|
||||||
//
|
|
||||||
// `_fixWidth(1998, 2) = '98'`
|
|
||||||
//
|
|
||||||
// This is used to pad numbers in converting date to string in ISO standard.
|
|
||||||
var _fixWidth = function (number, digits) {
|
|
||||||
if (typeof number !== "number") { throw "not a number: " + number; }
|
|
||||||
var s = number.toString();
|
|
||||||
if (number.length > digits) {
|
|
||||||
return number.substr(number.length - digits, number.length);
|
|
||||||
}
|
|
||||||
while (s.length < digits) {
|
|
||||||
s = '0' + s;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Abstraction layer for different transport layers, including fleegix/jQuery/Zepto
|
|
||||||
//
|
|
||||||
// Object `opts` include
|
|
||||||
//
|
|
||||||
// - `url`: url to ajax query
|
|
||||||
//
|
|
||||||
// - `async`: true for asynchronous, false otherwise. If false, return value will be response from URL. This is true by default
|
|
||||||
//
|
|
||||||
// - `success`: success callback function
|
|
||||||
//
|
|
||||||
// - `error`: error callback function
|
|
||||||
// Returns response from URL if async is false, otherwise the AJAX request object itself
|
|
||||||
var _transport = function (opts) {
|
|
||||||
if ((!fleegix || typeof fleegix.xhr === 'undefined') && (!$ || typeof $.ajax === 'undefined')) {
|
|
||||||
throw new Error('Please use the Fleegix.js XHR module, jQuery ajax, Zepto ajax, or define your own transport mechanism for downloading zone files.');
|
|
||||||
}
|
|
||||||
if (!opts) return;
|
|
||||||
if (!opts.url) throw new Error ('URL must be specified');
|
|
||||||
if (!('async' in opts)) opts.async = true;
|
|
||||||
if (!opts.async) {
|
|
||||||
return fleegix && fleegix.xhr
|
|
||||||
? fleegix.xhr.doReq({ url: opts.url, async: false })
|
|
||||||
: $.ajax({ url : opts.url, async : false }).responseText;
|
|
||||||
}
|
|
||||||
return fleegix && fleegix.xhr
|
|
||||||
? fleegix.xhr.send({
|
|
||||||
url : opts.url,
|
|
||||||
method : 'get',
|
|
||||||
handleSuccess : opts.success,
|
|
||||||
handleErr : opts.error
|
|
||||||
})
|
|
||||||
: $.ajax({
|
|
||||||
url : opts.url,
|
|
||||||
dataType: 'text',
|
|
||||||
method : 'GET',
|
|
||||||
error : opts.error,
|
|
||||||
success : opts.success
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constructor, which is similar to that of the native Date object itself
|
|
||||||
timezoneJS.Date = function () {
|
|
||||||
var args = Array.prototype.slice.apply(arguments)
|
|
||||||
, dt = null
|
|
||||||
, tz = null
|
|
||||||
, arr = [];
|
|
||||||
|
|
||||||
|
|
||||||
//We support several different constructors, including all the ones from `Date` object
|
|
||||||
// with a timezone string at the end.
|
|
||||||
//
|
|
||||||
//- `[tz]`: Returns object with time in `tz` specified.
|
|
||||||
//
|
|
||||||
// - `utcMillis`, `[tz]`: Return object with UTC time = `utcMillis`, in `tz`.
|
|
||||||
//
|
|
||||||
// - `Date`, `[tz]`: Returns object with UTC time = `Date.getTime()`, in `tz`.
|
|
||||||
//
|
|
||||||
// - `year, month, [date,] [hours,] [minutes,] [seconds,] [millis,] [tz]: Same as `Date` object
|
|
||||||
// with tz.
|
|
||||||
//
|
|
||||||
// - `Array`: Can be any combo of the above.
|
|
||||||
//
|
|
||||||
//If 1st argument is an array, we can use it as a list of arguments itself
|
|
||||||
if (Object.prototype.toString.call(args[0]) === '[object Array]') {
|
|
||||||
args = args[0];
|
|
||||||
}
|
|
||||||
if (typeof args[args.length - 1] === 'string' && TZ_REGEXP.test(args[args.length - 1])) {
|
|
||||||
tz = args.pop();
|
|
||||||
}
|
|
||||||
switch (args.length) {
|
|
||||||
case 0:
|
|
||||||
dt = new Date();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
dt = new Date(args[0]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
arr[i] = args[i] || 0;
|
|
||||||
}
|
|
||||||
dt = new Date(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._useCache = false;
|
|
||||||
this._tzInfo = {};
|
|
||||||
this._day = 0;
|
|
||||||
this.year = 0;
|
|
||||||
this.month = 0;
|
|
||||||
this.date = 0;
|
|
||||||
this.hours = 0;
|
|
||||||
this.minutes = 0;
|
|
||||||
this.seconds = 0;
|
|
||||||
this.milliseconds = 0;
|
|
||||||
this.timezone = tz || null;
|
|
||||||
//Tricky part:
|
|
||||||
// For the cases where there are 1/2 arguments: `timezoneJS.Date(millis, [tz])` and `timezoneJS.Date(Date, [tz])`. The
|
|
||||||
// Date `dt` created should be in UTC. Thus the way I detect such cases is to determine if `arr` is not populated & `tz`
|
|
||||||
// is specified. Because if `tz` is not specified, `dt` can be in local time.
|
|
||||||
if (arr.length) {
|
|
||||||
this.setFromDateObjProxy(dt);
|
|
||||||
} else {
|
|
||||||
this.setFromTimeProxy(dt.getTime(), tz);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implements most of the native Date object
|
|
||||||
timezoneJS.Date.prototype = {
|
|
||||||
getDate: function () { return this.date; },
|
|
||||||
getDay: function () { return this._day; },
|
|
||||||
getFullYear: function () { return this.year; },
|
|
||||||
getMonth: function () { return this.month; },
|
|
||||||
getYear: function () { return this.year - 1900; },
|
|
||||||
getHours: function () { return this.hours; },
|
|
||||||
getMilliseconds: function () { return this.milliseconds; },
|
|
||||||
getMinutes: function () { return this.minutes; },
|
|
||||||
getSeconds: function () { return this.seconds; },
|
|
||||||
getUTCDate: function () { return this.getUTCDateProxy().getUTCDate(); },
|
|
||||||
getUTCDay: function () { return this.getUTCDateProxy().getUTCDay(); },
|
|
||||||
getUTCFullYear: function () { return this.getUTCDateProxy().getUTCFullYear(); },
|
|
||||||
getUTCHours: function () { return this.getUTCDateProxy().getUTCHours(); },
|
|
||||||
getUTCMilliseconds: function () { return this.getUTCDateProxy().getUTCMilliseconds(); },
|
|
||||||
getUTCMinutes: function () { return this.getUTCDateProxy().getUTCMinutes(); },
|
|
||||||
getUTCMonth: function () { return this.getUTCDateProxy().getUTCMonth(); },
|
|
||||||
getUTCSeconds: function () { return this.getUTCDateProxy().getUTCSeconds(); },
|
|
||||||
// Time adjusted to user-specified timezone
|
|
||||||
getTime: function () {
|
|
||||||
return this._timeProxy + (this.getTimezoneOffset() * 60 * 1000);
|
|
||||||
},
|
|
||||||
getTimezone: function () { return this.timezone; },
|
|
||||||
getTimezoneOffset: function () { return this.getTimezoneInfo().tzOffset; },
|
|
||||||
getTimezoneAbbreviation: function () { return this.getTimezoneInfo().tzAbbr; },
|
|
||||||
getTimezoneInfo: function () {
|
|
||||||
if (this._useCache) return this._tzInfo;
|
|
||||||
var res;
|
|
||||||
// If timezone is specified, get the correct timezone info based on the Date given
|
|
||||||
if (this.timezone) {
|
|
||||||
res = this.timezone === 'Etc/UTC' || this.timezone === 'Etc/GMT'
|
|
||||||
? { tzOffset: 0, tzAbbr: 'UTC' }
|
|
||||||
: timezoneJS.timezone.getTzInfo(this._timeProxy, this.timezone);
|
|
||||||
}
|
|
||||||
// If no timezone was specified, use the local browser offset
|
|
||||||
else {
|
|
||||||
res = { tzOffset: this.getLocalOffset(), tzAbbr: null };
|
|
||||||
}
|
|
||||||
this._tzInfo = res;
|
|
||||||
this._useCache = true;
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
getUTCDateProxy: function () {
|
|
||||||
var dt = new Date(this._timeProxy);
|
|
||||||
dt.setUTCMinutes(dt.getUTCMinutes() + this.getTimezoneOffset());
|
|
||||||
return dt;
|
|
||||||
},
|
|
||||||
setDate: function (date) {
|
|
||||||
this.setAttribute('date', date);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setFullYear: function (year, month, date) {
|
|
||||||
if (date !== undefined) { this.setAttribute('date', 1); }
|
|
||||||
this.setAttribute('year', year);
|
|
||||||
if (month !== undefined) { this.setAttribute('month', month); }
|
|
||||||
if (date !== undefined) { this.setAttribute('date', date); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setMonth: function (month, date) {
|
|
||||||
this.setAttribute('month', month);
|
|
||||||
if (date !== undefined) { this.setAttribute('date', date); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setYear: function (year) {
|
|
||||||
year = Number(year);
|
|
||||||
if (0 <= year && year <= 99) { year += 1900; }
|
|
||||||
this.setUTCAttribute('year', year);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setHours: function (hours, minutes, seconds, milliseconds) {
|
|
||||||
this.setAttribute('hours', hours);
|
|
||||||
if (minutes !== undefined) { this.setAttribute('minutes', minutes); }
|
|
||||||
if (seconds !== undefined) { this.setAttribute('seconds', seconds); }
|
|
||||||
if (milliseconds !== undefined) { this.setAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setMinutes: function (minutes, seconds, milliseconds) {
|
|
||||||
this.setAttribute('minutes', minutes);
|
|
||||||
if (seconds !== undefined) { this.setAttribute('seconds', seconds); }
|
|
||||||
if (milliseconds !== undefined) { this.setAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setSeconds: function (seconds, milliseconds) {
|
|
||||||
this.setAttribute('seconds', seconds);
|
|
||||||
if (milliseconds !== undefined) { this.setAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setMilliseconds: function (milliseconds) {
|
|
||||||
this.setAttribute('milliseconds', milliseconds);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setTime: function (n) {
|
|
||||||
if (isNaN(n)) { throw new Error('Units must be a number.'); }
|
|
||||||
this.setFromTimeProxy(n, this.timezone);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCFullYear: function (year, month, date) {
|
|
||||||
if (date !== undefined) { this.setUTCAttribute('date', 1); }
|
|
||||||
this.setUTCAttribute('year', year);
|
|
||||||
if (month !== undefined) { this.setUTCAttribute('month', month); }
|
|
||||||
if (date !== undefined) { this.setUTCAttribute('date', date); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCMonth: function (month, date) {
|
|
||||||
this.setUTCAttribute('month', month);
|
|
||||||
if (date !== undefined) { this.setUTCAttribute('date', date); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCDate: function (date) {
|
|
||||||
this.setUTCAttribute('date', date);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCHours: function (hours, minutes, seconds, milliseconds) {
|
|
||||||
this.setUTCAttribute('hours', hours);
|
|
||||||
if (minutes !== undefined) { this.setUTCAttribute('minutes', minutes); }
|
|
||||||
if (seconds !== undefined) { this.setUTCAttribute('seconds', seconds); }
|
|
||||||
if (milliseconds !== undefined) { this.setUTCAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCMinutes: function (minutes, seconds, milliseconds) {
|
|
||||||
this.setUTCAttribute('minutes', minutes);
|
|
||||||
if (seconds !== undefined) { this.setUTCAttribute('seconds', seconds); }
|
|
||||||
if (milliseconds !== undefined) { this.setUTCAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCSeconds: function (seconds, milliseconds) {
|
|
||||||
this.setUTCAttribute('seconds', seconds);
|
|
||||||
if (milliseconds !== undefined) { this.setUTCAttribute('milliseconds', milliseconds); }
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setUTCMilliseconds: function (milliseconds) {
|
|
||||||
this.setUTCAttribute('milliseconds', milliseconds);
|
|
||||||
return this.getTime();
|
|
||||||
},
|
|
||||||
setFromDateObjProxy: function (dt) {
|
|
||||||
this.year = dt.getFullYear();
|
|
||||||
this.month = dt.getMonth();
|
|
||||||
this.date = dt.getDate();
|
|
||||||
this.hours = dt.getHours();
|
|
||||||
this.minutes = dt.getMinutes();
|
|
||||||
this.seconds = dt.getSeconds();
|
|
||||||
this.milliseconds = dt.getMilliseconds();
|
|
||||||
this._day = dt.getDay();
|
|
||||||
this._dateProxy = dt;
|
|
||||||
this._timeProxy = Date.UTC(this.year, this.month, this.date, this.hours, this.minutes, this.seconds, this.milliseconds);
|
|
||||||
this._useCache = false;
|
|
||||||
},
|
|
||||||
setFromTimeProxy: function (utcMillis, tz) {
|
|
||||||
var dt = new Date(utcMillis);
|
|
||||||
var tzOffset;
|
|
||||||
tzOffset = tz ? timezoneJS.timezone.getTzInfo(dt, tz).tzOffset : dt.getTimezoneOffset();
|
|
||||||
dt.setTime(utcMillis + (dt.getTimezoneOffset() - tzOffset) * 60000);
|
|
||||||
this.setFromDateObjProxy(dt);
|
|
||||||
},
|
|
||||||
setAttribute: function (unit, n) {
|
|
||||||
if (isNaN(n)) { throw new Error('Units must be a number.'); }
|
|
||||||
var dt = this._dateProxy;
|
|
||||||
var meth = unit === 'year' ? 'FullYear' : unit.substr(0, 1).toUpperCase() + unit.substr(1);
|
|
||||||
dt['set' + meth](n);
|
|
||||||
this.setFromDateObjProxy(dt);
|
|
||||||
},
|
|
||||||
setUTCAttribute: function (unit, n) {
|
|
||||||
if (isNaN(n)) { throw new Error('Units must be a number.'); }
|
|
||||||
var meth = unit === 'year' ? 'FullYear' : unit.substr(0, 1).toUpperCase() + unit.substr(1);
|
|
||||||
var dt = this.getUTCDateProxy();
|
|
||||||
dt['setUTC' + meth](n);
|
|
||||||
dt.setUTCMinutes(dt.getUTCMinutes() - this.getTimezoneOffset());
|
|
||||||
this.setFromTimeProxy(dt.getTime() + this.getTimezoneOffset() * 60000, this.timezone);
|
|
||||||
},
|
|
||||||
setTimezone: function (tz) {
|
|
||||||
var previousOffset = this.getTimezoneInfo().tzOffset;
|
|
||||||
this.timezone = tz;
|
|
||||||
this._useCache = false;
|
|
||||||
// Set UTC minutes offsets by the delta of the two timezones
|
|
||||||
this.setUTCMinutes(this.getUTCMinutes() - this.getTimezoneInfo().tzOffset + previousOffset);
|
|
||||||
},
|
|
||||||
removeTimezone: function () {
|
|
||||||
this.timezone = null;
|
|
||||||
this._useCache = false;
|
|
||||||
},
|
|
||||||
valueOf: function () { return this.getTime(); },
|
|
||||||
clone: function () {
|
|
||||||
return this.timezone ? new timezoneJS.Date(this.getTime(), this.timezone) : new timezoneJS.Date(this.getTime());
|
|
||||||
},
|
|
||||||
toGMTString: function () { return this.toString('EEE, dd MMM yyyy HH:mm:ss Z', 'Etc/GMT'); },
|
|
||||||
toLocaleString: function () {},
|
|
||||||
toLocaleDateString: function () {},
|
|
||||||
toLocaleTimeString: function () {},
|
|
||||||
toSource: function () {},
|
|
||||||
toISOString: function () { return this.toString('yyyy-MM-ddTHH:mm:ss.SSS', 'Etc/UTC') + 'Z'; },
|
|
||||||
toJSON: function () { return this.toISOString(); },
|
|
||||||
// Allows different format following ISO8601 format:
|
|
||||||
toString: function (format, tz) {
|
|
||||||
// Default format is the same as toISOString
|
|
||||||
if (!format) format = 'yyyy-MM-dd HH:mm:ss';
|
|
||||||
var result = format;
|
|
||||||
var tzInfo = tz ? timezoneJS.timezone.getTzInfo(this.getTime(), tz) : this.getTimezoneInfo();
|
|
||||||
var _this = this;
|
|
||||||
// If timezone is specified, get a clone of the current Date object and modify it
|
|
||||||
if (tz) {
|
|
||||||
_this = this.clone();
|
|
||||||
_this.setTimezone(tz);
|
|
||||||
}
|
|
||||||
var hours = _this.getHours();
|
|
||||||
return result
|
|
||||||
// fix the same characters in Month names
|
|
||||||
.replace(/a+/g, function () { return 'k'; })
|
|
||||||
// `y`: year
|
|
||||||
.replace(/y+/g, function (token) { return _fixWidth(_this.getFullYear(), token.length); })
|
|
||||||
// `d`: date
|
|
||||||
.replace(/d+/g, function (token) { return _fixWidth(_this.getDate(), token.length); })
|
|
||||||
// `m`: minute
|
|
||||||
.replace(/m+/g, function (token) { return _fixWidth(_this.getMinutes(), token.length); })
|
|
||||||
// `s`: second
|
|
||||||
.replace(/s+/g, function (token) { return _fixWidth(_this.getSeconds(), token.length); })
|
|
||||||
// `S`: millisecond
|
|
||||||
.replace(/S+/g, function (token) { return _fixWidth(_this.getMilliseconds(), token.length); })
|
|
||||||
// `M`: month. Note: `MM` will be the numeric representation (e.g February is 02) but `MMM` will be text representation (e.g February is Feb)
|
|
||||||
.replace(/M+/g, function (token) {
|
|
||||||
var _month = _this.getMonth(),
|
|
||||||
_len = token.length;
|
|
||||||
if (_len > 3) {
|
|
||||||
return timezoneJS.Months[_month];
|
|
||||||
} else if (_len > 2) {
|
|
||||||
return timezoneJS.Months[_month].substring(0, _len);
|
|
||||||
}
|
|
||||||
return _fixWidth(_month + 1, _len);
|
|
||||||
})
|
|
||||||
// `k`: AM/PM
|
|
||||||
.replace(/k+/g, function () {
|
|
||||||
if (hours >= 12) {
|
|
||||||
if (hours > 12) {
|
|
||||||
hours -= 12;
|
|
||||||
}
|
|
||||||
return 'PM';
|
|
||||||
}
|
|
||||||
return 'AM';
|
|
||||||
})
|
|
||||||
// `H`: hour
|
|
||||||
.replace(/H+/g, function (token) { return _fixWidth(hours, token.length); })
|
|
||||||
// `E`: day
|
|
||||||
.replace(/E+/g, function (token) { return DAYS[_this.getDay()].substring(0, token.length); })
|
|
||||||
// `Z`: timezone abbreviation
|
|
||||||
.replace(/Z+/gi, function () { return tzInfo.tzAbbr; });
|
|
||||||
},
|
|
||||||
toUTCString: function () { return this.toGMTString(); },
|
|
||||||
civilToJulianDayNumber: function (y, m, d) {
|
|
||||||
var a;
|
|
||||||
// Adjust for zero-based JS-style array
|
|
||||||
m++;
|
|
||||||
if (m > 12) {
|
|
||||||
a = parseInt(m/12, 10);
|
|
||||||
m = m % 12;
|
|
||||||
y += a;
|
|
||||||
}
|
|
||||||
if (m <= 2) {
|
|
||||||
y -= 1;
|
|
||||||
m += 12;
|
|
||||||
}
|
|
||||||
a = Math.floor(y / 100);
|
|
||||||
var b = 2 - a + Math.floor(a / 4)
|
|
||||||
, jDt = Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + d + b - 1524;
|
|
||||||
return jDt;
|
|
||||||
},
|
|
||||||
getLocalOffset: function () {
|
|
||||||
return this._dateProxy.getTimezoneOffset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
timezoneJS.timezone = new function () {
|
|
||||||
var _this = this
|
|
||||||
, regionMap = {'Etc':'etcetera','EST':'northamerica','MST':'northamerica','HST':'northamerica','EST5EDT':'northamerica','CST6CDT':'northamerica','MST7MDT':'northamerica','PST8PDT':'northamerica','America':'northamerica','Pacific':'australasia','Atlantic':'europe','Africa':'africa','Indian':'africa','Antarctica':'antarctica','Asia':'asia','Australia':'australasia','Europe':'europe','WET':'europe','CET':'europe','MET':'europe','EET':'europe'}
|
|
||||||
, regionExceptions = {'Pacific/Honolulu':'northamerica','Atlantic/Bermuda':'northamerica','Atlantic/Cape_Verde':'africa','Atlantic/St_Helena':'africa','Indian/Kerguelen':'antarctica','Indian/Chagos':'asia','Indian/Maldives':'asia','Indian/Christmas':'australasia','Indian/Cocos':'australasia','America/Danmarkshavn':'europe','America/Scoresbysund':'europe','America/Godthab':'europe','America/Thule':'europe','Asia/Yekaterinburg':'europe','Asia/Omsk':'europe','Asia/Novosibirsk':'europe','Asia/Krasnoyarsk':'europe','Asia/Irkutsk':'europe','Asia/Yakutsk':'europe','Asia/Vladivostok':'europe','Asia/Sakhalin':'europe','Asia/Magadan':'europe','Asia/Kamchatka':'europe','Asia/Anadyr':'europe','Africa/Ceuta':'europe','America/Argentina/Buenos_Aires':'southamerica','America/Argentina/Cordoba':'southamerica','America/Argentina/Tucuman':'southamerica','America/Argentina/La_Rioja':'southamerica','America/Argentina/San_Juan':'southamerica','America/Argentina/Jujuy':'southamerica','America/Argentina/Catamarca':'southamerica','America/Argentina/Mendoza':'southamerica','America/Argentina/Rio_Gallegos':'southamerica','America/Argentina/Ushuaia':'southamerica','America/Aruba':'southamerica','America/La_Paz':'southamerica','America/Noronha':'southamerica','America/Belem':'southamerica','America/Fortaleza':'southamerica','America/Recife':'southamerica','America/Araguaina':'southamerica','America/Maceio':'southamerica','America/Bahia':'southamerica','America/Sao_Paulo':'southamerica','America/Campo_Grande':'southamerica','America/Cuiaba':'southamerica','America/Porto_Velho':'southamerica','America/Boa_Vista':'southamerica','America/Manaus':'southamerica','America/Eirunepe':'southamerica','America/Rio_Branco':'southamerica','America/Santiago':'southamerica','Pacific/Easter':'southamerica','America/Bogota':'southamerica','America/Curacao':'southamerica','America/Guayaquil':'southamerica','Pacific/Galapagos':'southamerica','Atlantic/Stanley':'southamerica','America/Cayenne':'southamerica','America/Guyana':'southamerica','America/Asuncion':'southamerica','America/Lima':'southamerica','Atlantic/South_Georgia':'southamerica','America/Paramaribo':'southamerica','America/Port_of_Spain':'southamerica','America/Montevideo':'southamerica','America/Caracas':'southamerica'};
|
|
||||||
function invalidTZError(t) { throw new Error('Timezone "' + t + '" is either incorrect, or not loaded in the timezone registry.'); }
|
|
||||||
function builtInLoadZoneFile(fileName, opts) {
|
|
||||||
var url = _this.zoneFileBasePath + '/' + fileName;
|
|
||||||
return !opts || !opts.async
|
|
||||||
? _this.parseZones(_this.transport({ url : url, async : false }))
|
|
||||||
: _this.transport({
|
|
||||||
async: true,
|
|
||||||
url : url,
|
|
||||||
success : function (str) {
|
|
||||||
if (_this.parseZones(str) && typeof opts.callback === 'function') {
|
|
||||||
opts.callback();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
error : function () {
|
|
||||||
throw new Error('Error retrieving "' + url + '" zoneinfo files');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function getRegionForTimezone(tz) {
|
|
||||||
var exc = regionExceptions[tz]
|
|
||||||
, reg
|
|
||||||
, ret;
|
|
||||||
if (exc) return exc;
|
|
||||||
reg = tz.split('/')[0];
|
|
||||||
ret = regionMap[reg];
|
|
||||||
// If there's nothing listed in the main regions for this TZ, check the 'backward' links
|
|
||||||
if (ret) return ret;
|
|
||||||
var link = _this.zones[tz];
|
|
||||||
if (typeof link === 'string') {
|
|
||||||
return getRegionForTimezone(link);
|
|
||||||
}
|
|
||||||
// Backward-compat file hasn't loaded yet, try looking in there
|
|
||||||
if (!_this.loadedZones.backward) {
|
|
||||||
// This is for obvious legacy zones (e.g., Iceland) that don't even have a prefix like "America/" that look like normal zones
|
|
||||||
_this.loadZoneFile('backward');
|
|
||||||
return getRegionForTimezone(tz);
|
|
||||||
}
|
|
||||||
invalidTZError(tz);
|
|
||||||
}
|
|
||||||
function parseTimeString(str) {
|
|
||||||
var pat = /(\d+)(?::0*(\d*))?(?::0*(\d*))?([wsugz])?$/;
|
|
||||||
var hms = str.match(pat);
|
|
||||||
hms[1] = parseInt(hms[1], 10);
|
|
||||||
hms[2] = hms[2] ? parseInt(hms[2], 10) : 0;
|
|
||||||
hms[3] = hms[3] ? parseInt(hms[3], 10) : 0;
|
|
||||||
|
|
||||||
return hms;
|
|
||||||
}
|
|
||||||
function processZone(z) {
|
|
||||||
if (!z[3]) { return; }
|
|
||||||
var yea = parseInt(z[3], 10);
|
|
||||||
var mon = 11;
|
|
||||||
var dat = 31;
|
|
||||||
if (z[4]) {
|
|
||||||
mon = SHORT_MONTHS[z[4].substr(0, 3)];
|
|
||||||
dat = parseInt(z[5], 10) || 1;
|
|
||||||
}
|
|
||||||
var string = z[6] ? z[6] : '00:00:00'
|
|
||||||
, t = parseTimeString(string);
|
|
||||||
return [yea, mon, dat, t[1], t[2], t[3]];
|
|
||||||
}
|
|
||||||
function getZone(dt, tz) {
|
|
||||||
var utcMillis = typeof dt === 'number' ? dt : new Date(dt).getTime();
|
|
||||||
var t = tz;
|
|
||||||
var zoneList = _this.zones[t];
|
|
||||||
// Follow links to get to an actual zone
|
|
||||||
while (typeof zoneList === "string") {
|
|
||||||
t = zoneList;
|
|
||||||
zoneList = _this.zones[t];
|
|
||||||
}
|
|
||||||
if (!zoneList) {
|
|
||||||
// Backward-compat file hasn't loaded yet, try looking in there
|
|
||||||
if (!_this.loadedZones.backward) {
|
|
||||||
//This is for backward entries like "America/Fort_Wayne" that
|
|
||||||
// getRegionForTimezone *thinks* it has a region file and zone
|
|
||||||
// for (e.g., America => 'northamerica'), but in reality it's a
|
|
||||||
// legacy zone we need the backward file for.
|
|
||||||
_this.loadZoneFile('backward');
|
|
||||||
return getZone(dt, tz);
|
|
||||||
}
|
|
||||||
invalidTZError(t);
|
|
||||||
}
|
|
||||||
if (zoneList.length === 0) {
|
|
||||||
throw new Error('No Zone found for "' + tz + '" on ' + dt);
|
|
||||||
}
|
|
||||||
//Do backwards lookup since most use cases deal with newer dates.
|
|
||||||
for (var i = zoneList.length - 1; i >= 0; i--) {
|
|
||||||
var z = zoneList[i];
|
|
||||||
if (z[3] && utcMillis > z[3]) break;
|
|
||||||
}
|
|
||||||
return zoneList[i+1];
|
|
||||||
}
|
|
||||||
function getBasicOffset(time) {
|
|
||||||
var off = parseTimeString(time)
|
|
||||||
, adj = time.charAt(0) === '-' ? -1 : 1;
|
|
||||||
off = adj * (((off[1] * 60 + off[2]) * 60 + off[3]) * 1000);
|
|
||||||
return off/60/1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if isUTC is true, date is given in UTC, otherwise it's given
|
|
||||||
// in local time (ie. date.getUTC*() returns local time components)
|
|
||||||
function getRule(dt, zone, isUTC) {
|
|
||||||
var date = typeof dt === 'number' ? new Date(dt) : dt;
|
|
||||||
var ruleset = zone[1];
|
|
||||||
var basicOffset = zone[0];
|
|
||||||
|
|
||||||
// If the zone has a DST rule like '1:00', create a rule and return it
|
|
||||||
// instead of looking it up in the parsed rules
|
|
||||||
var staticDstMatch = ruleset.match(/^([0-9]):([0-9][0-9])$/);
|
|
||||||
if (staticDstMatch) {
|
|
||||||
return [-1000000,'max','-','Jan',1,parseTimeString('0:00'),parseInt(staticDstMatch[1]) * 60 + parseInt(staticDstMatch[2]), '-'];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Convert a date to UTC. Depending on the 'type' parameter, the date
|
|
||||||
// parameter may be:
|
|
||||||
//
|
|
||||||
// - `u`, `g`, `z`: already UTC (no adjustment).
|
|
||||||
//
|
|
||||||
// - `s`: standard time (adjust for time zone offset but not for DST)
|
|
||||||
//
|
|
||||||
// - `w`: wall clock time (adjust for both time zone and DST offset).
|
|
||||||
//
|
|
||||||
// DST adjustment is done using the rule given as third argument.
|
|
||||||
var convertDateToUTC = function (date, type, rule) {
|
|
||||||
var offset = 0;
|
|
||||||
|
|
||||||
if (type === 'u' || type === 'g' || type === 'z') { // UTC
|
|
||||||
offset = 0;
|
|
||||||
} else if (type === 's') { // Standard Time
|
|
||||||
offset = basicOffset;
|
|
||||||
} else if (type === 'w' || !type) { // Wall Clock Time
|
|
||||||
offset = getAdjustedOffset(basicOffset, rule);
|
|
||||||
} else {
|
|
||||||
throw("unknown type " + type);
|
|
||||||
}
|
|
||||||
offset *= 60 * 1000; // to millis
|
|
||||||
|
|
||||||
return new Date(date.getTime() + offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Step 1: Find applicable rules for this year.
|
|
||||||
//
|
|
||||||
//Step 2: Sort the rules by effective date.
|
|
||||||
//
|
|
||||||
//Step 3: Check requested date to see if a rule has yet taken effect this year. If not,
|
|
||||||
//
|
|
||||||
//Step 4: Get the rules for the previous year. If there isn't an applicable rule for last year, then
|
|
||||||
// there probably is no current time offset since they seem to explicitly turn off the offset
|
|
||||||
// when someone stops observing DST.
|
|
||||||
//
|
|
||||||
// FIXME if this is not the case and we'll walk all the way back (ugh).
|
|
||||||
//
|
|
||||||
//Step 5: Sort the rules by effective date.
|
|
||||||
//Step 6: Apply the most recent rule before the current time.
|
|
||||||
var convertRuleToExactDateAndTime = function (yearAndRule, prevRule) {
|
|
||||||
var year = yearAndRule[0]
|
|
||||||
, rule = yearAndRule[1];
|
|
||||||
// Assume that the rule applies to the year of the given date.
|
|
||||||
|
|
||||||
var hms = rule[5];
|
|
||||||
var effectiveDate;
|
|
||||||
|
|
||||||
if (!EXACT_DATE_TIME[year])
|
|
||||||
EXACT_DATE_TIME[year] = {};
|
|
||||||
|
|
||||||
// Result for given parameters is already stored
|
|
||||||
if (EXACT_DATE_TIME[year][rule])
|
|
||||||
effectiveDate = EXACT_DATE_TIME[year][rule];
|
|
||||||
else {
|
|
||||||
//If we have a specific date, use that!
|
|
||||||
if (!isNaN(rule[4])) {
|
|
||||||
effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4], hms[1], hms[2], hms[3], 0));
|
|
||||||
}
|
|
||||||
//Let's hunt for the date.
|
|
||||||
else {
|
|
||||||
var targetDay
|
|
||||||
, operator;
|
|
||||||
//Example: `lastThu`
|
|
||||||
if (rule[4].substr(0, 4) === "last") {
|
|
||||||
// Start at the last day of the month and work backward.
|
|
||||||
effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]] + 1, 1, hms[1] - 24, hms[2], hms[3], 0));
|
|
||||||
targetDay = SHORT_DAYS[rule[4].substr(4, 3)];
|
|
||||||
operator = "<=";
|
|
||||||
}
|
|
||||||
//Example: `Sun>=15`
|
|
||||||
else {
|
|
||||||
//Start at the specified date.
|
|
||||||
effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4].substr(5), hms[1], hms[2], hms[3], 0));
|
|
||||||
targetDay = SHORT_DAYS[rule[4].substr(0, 3)];
|
|
||||||
operator = rule[4].substr(3, 2);
|
|
||||||
}
|
|
||||||
var ourDay = effectiveDate.getUTCDay();
|
|
||||||
//Go forwards.
|
|
||||||
if (operator === ">=") {
|
|
||||||
effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay + ((targetDay < ourDay) ? 7 : 0)));
|
|
||||||
}
|
|
||||||
//Go backwards. Looking for the last of a certain day, or operator is "<=" (less likely).
|
|
||||||
else {
|
|
||||||
effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay - ((targetDay > ourDay) ? 7 : 0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXACT_DATE_TIME[year][rule] = effectiveDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//If previous rule is given, correct for the fact that the starting time of the current
|
|
||||||
// rule may be specified in local time.
|
|
||||||
if (prevRule) {
|
|
||||||
effectiveDate = convertDateToUTC(effectiveDate, hms[4], prevRule);
|
|
||||||
}
|
|
||||||
return effectiveDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
var findApplicableRules = function (year, ruleset) {
|
|
||||||
var applicableRules = [];
|
|
||||||
for (var i = 0; ruleset && i < ruleset.length; i++) {
|
|
||||||
//Exclude future rules.
|
|
||||||
if (ruleset[i][0] <= year &&
|
|
||||||
(
|
|
||||||
// Date is in a set range.
|
|
||||||
ruleset[i][1] >= year ||
|
|
||||||
// Date is in an "only" year.
|
|
||||||
(ruleset[i][0] === year && ruleset[i][1] === "only") ||
|
|
||||||
//We're in a range from the start year to infinity.
|
|
||||||
ruleset[i][1] === "max"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
//It's completely okay to have any number of matches here.
|
|
||||||
// Normally we should only see two, but that doesn't preclude other numbers of matches.
|
|
||||||
// These matches are applicable to this year.
|
|
||||||
applicableRules.push([year, ruleset[i]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return applicableRules;
|
|
||||||
};
|
|
||||||
|
|
||||||
var compareDates = function (a, b, prev) {
|
|
||||||
var year, rule;
|
|
||||||
if (a.constructor !== Date) {
|
|
||||||
year = a[0];
|
|
||||||
rule = a[1];
|
|
||||||
a = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule])
|
|
||||||
? EXACT_DATE_TIME[year][rule]
|
|
||||||
: convertRuleToExactDateAndTime(a, prev);
|
|
||||||
} else if (prev) {
|
|
||||||
a = convertDateToUTC(a, isUTC ? 'u' : 'w', prev);
|
|
||||||
}
|
|
||||||
if (b.constructor !== Date) {
|
|
||||||
year = b[0];
|
|
||||||
rule = b[1];
|
|
||||||
b = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule]) ? EXACT_DATE_TIME[year][rule]
|
|
||||||
: convertRuleToExactDateAndTime(b, prev);
|
|
||||||
} else if (prev) {
|
|
||||||
b = convertDateToUTC(b, isUTC ? 'u' : 'w', prev);
|
|
||||||
}
|
|
||||||
a = Number(a);
|
|
||||||
b = Number(b);
|
|
||||||
return a - b;
|
|
||||||
};
|
|
||||||
|
|
||||||
var year = date.getUTCFullYear();
|
|
||||||
var applicableRules;
|
|
||||||
|
|
||||||
applicableRules = findApplicableRules(year, _this.rules[ruleset]);
|
|
||||||
applicableRules.push(date);
|
|
||||||
//While sorting, the time zone in which the rule starting time is specified
|
|
||||||
// is ignored. This is ok as long as the timespan between two DST changes is
|
|
||||||
// larger than the DST offset, which is probably always true.
|
|
||||||
// As the given date may indeed be close to a DST change, it may get sorted
|
|
||||||
// to a wrong position (off by one), which is corrected below.
|
|
||||||
applicableRules.sort(compareDates);
|
|
||||||
|
|
||||||
//If there are not enough past DST rules...
|
|
||||||
if (_arrIndexOf.call(applicableRules, date) < 2) {
|
|
||||||
applicableRules = applicableRules.concat(findApplicableRules(year-1, _this.rules[ruleset]));
|
|
||||||
applicableRules.sort(compareDates);
|
|
||||||
}
|
|
||||||
var pinpoint = _arrIndexOf.call(applicableRules, date);
|
|
||||||
if (pinpoint > 1 && compareDates(date, applicableRules[pinpoint-1], applicableRules[pinpoint-2][1]) < 0) {
|
|
||||||
//The previous rule does not really apply, take the one before that.
|
|
||||||
return applicableRules[pinpoint - 2][1];
|
|
||||||
} else if (pinpoint > 0 && pinpoint < applicableRules.length - 1 && compareDates(date, applicableRules[pinpoint+1], applicableRules[pinpoint-1][1]) > 0) {
|
|
||||||
|
|
||||||
//The next rule does already apply, take that one.
|
|
||||||
return applicableRules[pinpoint + 1][1];
|
|
||||||
} else if (pinpoint === 0) {
|
|
||||||
//No applicable rule found in this and in previous year.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return applicableRules[pinpoint - 1][1];
|
|
||||||
}
|
|
||||||
function getAdjustedOffset(off, rule) {
|
|
||||||
return -Math.ceil(rule[6] - off);
|
|
||||||
}
|
|
||||||
function getAbbreviation(zone, rule) {
|
|
||||||
var res;
|
|
||||||
var base = zone[2];
|
|
||||||
if (base.indexOf('%s') > -1) {
|
|
||||||
var repl;
|
|
||||||
if (rule) {
|
|
||||||
repl = rule[7] === '-' ? '' : rule[7];
|
|
||||||
}
|
|
||||||
//FIXME: Right now just falling back to Standard --
|
|
||||||
// apparently ought to use the last valid rule,
|
|
||||||
// although in practice that always ought to be Standard
|
|
||||||
else {
|
|
||||||
repl = 'S';
|
|
||||||
}
|
|
||||||
res = base.replace('%s', repl);
|
|
||||||
}
|
|
||||||
else if (base.indexOf('/') > -1) {
|
|
||||||
//Chose one of two alternative strings.
|
|
||||||
res = base.split("/", 2)[rule[6] ? 1 : 0];
|
|
||||||
} else {
|
|
||||||
res = base;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.zoneFileBasePath = null;
|
|
||||||
this.zoneFiles = ['africa', 'antarctica', 'asia', 'australasia', 'backward', 'etcetera', 'europe', 'northamerica', 'pacificnew', 'southamerica'];
|
|
||||||
this.loadingSchemes = {
|
|
||||||
PRELOAD_ALL: 'preloadAll',
|
|
||||||
LAZY_LOAD: 'lazyLoad',
|
|
||||||
MANUAL_LOAD: 'manualLoad'
|
|
||||||
};
|
|
||||||
this.loadingScheme = this.loadingSchemes.LAZY_LOAD;
|
|
||||||
this.loadedZones = {};
|
|
||||||
this.zones = {};
|
|
||||||
this.rules = {};
|
|
||||||
|
|
||||||
this.init = function (o) {
|
|
||||||
var opts = { async: true }
|
|
||||||
, def = this.loadingScheme === this.loadingSchemes.PRELOAD_ALL
|
|
||||||
? this.zoneFiles
|
|
||||||
: (this.defaultZoneFile || 'northamerica')
|
|
||||||
, done = 0
|
|
||||||
, callbackFn;
|
|
||||||
//Override default with any passed-in opts
|
|
||||||
for (var p in o) {
|
|
||||||
opts[p] = o[p];
|
|
||||||
}
|
|
||||||
if (typeof def === 'string') {
|
|
||||||
return this.loadZoneFile(def, opts);
|
|
||||||
}
|
|
||||||
//Wraps callback function in another one that makes
|
|
||||||
// sure all files have been loaded.
|
|
||||||
callbackFn = opts.callback;
|
|
||||||
opts.callback = function () {
|
|
||||||
done++;
|
|
||||||
(done === def.length) && typeof callbackFn === 'function' && callbackFn();
|
|
||||||
};
|
|
||||||
for (var i = 0; i < def.length; i++) {
|
|
||||||
this.loadZoneFile(def[i], opts);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Get the zone files via XHR -- if the sync flag
|
|
||||||
// is set to true, it's being called by the lazy-loading
|
|
||||||
// mechanism, so the result needs to be returned inline.
|
|
||||||
this.loadZoneFile = function (fileName, opts) {
|
|
||||||
if (typeof this.zoneFileBasePath === 'undefined') {
|
|
||||||
throw new Error('Please define a base path to your zone file directory -- timezoneJS.timezone.zoneFileBasePath.');
|
|
||||||
}
|
|
||||||
//Ignore already loaded zones.
|
|
||||||
if (this.loadedZones[fileName]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loadedZones[fileName] = true;
|
|
||||||
return builtInLoadZoneFile(fileName, opts);
|
|
||||||
};
|
|
||||||
this.loadZoneJSONData = function (url, sync) {
|
|
||||||
var processData = function (data) {
|
|
||||||
data = eval('('+ data +')');
|
|
||||||
for (var z in data.zones) {
|
|
||||||
_this.zones[z] = data.zones[z];
|
|
||||||
}
|
|
||||||
for (var r in data.rules) {
|
|
||||||
_this.rules[r] = data.rules[r];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return sync
|
|
||||||
? processData(_this.transport({ url : url, async : false }))
|
|
||||||
: _this.transport({ url : url, success : processData });
|
|
||||||
};
|
|
||||||
this.loadZoneDataFromObject = function (data) {
|
|
||||||
if (!data) { return; }
|
|
||||||
for (var z in data.zones) {
|
|
||||||
_this.zones[z] = data.zones[z];
|
|
||||||
}
|
|
||||||
for (var r in data.rules) {
|
|
||||||
_this.rules[r] = data.rules[r];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.getAllZones = function () {
|
|
||||||
var arr = [];
|
|
||||||
for (var z in this.zones) { arr.push(z); }
|
|
||||||
return arr.sort();
|
|
||||||
};
|
|
||||||
this.parseZones = function (str) {
|
|
||||||
var lines = str.split('\n')
|
|
||||||
, arr = []
|
|
||||||
, chunk = ''
|
|
||||||
, l
|
|
||||||
, zone = null
|
|
||||||
, rule = null;
|
|
||||||
for (var i = 0; i < lines.length; i++) {
|
|
||||||
l = lines[i];
|
|
||||||
if (l.match(/^\s/)) {
|
|
||||||
l = "Zone " + zone + l;
|
|
||||||
}
|
|
||||||
l = l.split("#")[0];
|
|
||||||
if (l.length > 3) {
|
|
||||||
arr = l.split(/\s+/);
|
|
||||||
chunk = arr.shift();
|
|
||||||
//Ignore Leap.
|
|
||||||
switch (chunk) {
|
|
||||||
case 'Zone':
|
|
||||||
zone = arr.shift();
|
|
||||||
if (!_this.zones[zone]) {
|
|
||||||
_this.zones[zone] = [];
|
|
||||||
}
|
|
||||||
if (arr.length < 3) break;
|
|
||||||
//Process zone right here and replace 3rd element with the processed array.
|
|
||||||
arr.splice(3, arr.length, processZone(arr));
|
|
||||||
if (arr[3]) arr[3] = Date.UTC.apply(null, arr[3]);
|
|
||||||
arr[0] = -getBasicOffset(arr[0]);
|
|
||||||
_this.zones[zone].push(arr);
|
|
||||||
break;
|
|
||||||
case 'Rule':
|
|
||||||
rule = arr.shift();
|
|
||||||
if (!_this.rules[rule]) {
|
|
||||||
_this.rules[rule] = [];
|
|
||||||
}
|
|
||||||
//Parse int FROM year and TO year
|
|
||||||
arr[0] = parseInt(arr[0], 10);
|
|
||||||
arr[1] = parseInt(arr[1], 10) || arr[1];
|
|
||||||
//Parse time string AT
|
|
||||||
arr[5] = parseTimeString(arr[5]);
|
|
||||||
//Parse offset SAVE
|
|
||||||
arr[6] = getBasicOffset(arr[6]);
|
|
||||||
_this.rules[rule].push(arr);
|
|
||||||
break;
|
|
||||||
case 'Link':
|
|
||||||
//No zones for these should already exist.
|
|
||||||
if (_this.zones[arr[1]]) {
|
|
||||||
throw new Error('Error with Link ' + arr[1] + '. Cannot create link of a preexisted zone.');
|
|
||||||
}
|
|
||||||
//Create the link.
|
|
||||||
_this.zones[arr[1]] = arr[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
//Expose transport mechanism and allow overwrite.
|
|
||||||
this.transport = _transport;
|
|
||||||
this.getTzInfo = function (dt, tz, isUTC) {
|
|
||||||
//Lazy-load any zones not yet loaded.
|
|
||||||
if (this.loadingScheme === this.loadingSchemes.LAZY_LOAD) {
|
|
||||||
//Get the correct region for the zone.
|
|
||||||
var zoneFile = getRegionForTimezone(tz);
|
|
||||||
if (!zoneFile) {
|
|
||||||
throw new Error('Not a valid timezone ID.');
|
|
||||||
}
|
|
||||||
if (!this.loadedZones[zoneFile]) {
|
|
||||||
//Get the file and parse it -- use synchronous XHR.
|
|
||||||
this.loadZoneFile(zoneFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var z = getZone(dt, tz);
|
|
||||||
var off = z[0];
|
|
||||||
//See if the offset needs adjustment.
|
|
||||||
var rule = getRule(dt, z, isUTC);
|
|
||||||
if (rule) {
|
|
||||||
off = getAdjustedOffset(off, rule);
|
|
||||||
}
|
|
||||||
var abbr = getAbbreviation(z, rule);
|
|
||||||
return { tzOffset: off, tzAbbr: abbr };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}).call(this);
|
|
@ -6,11 +6,16 @@ module.exports = function(grunt) {
|
|||||||
'jshint:tests',
|
'jshint:tests',
|
||||||
'clean:on_start',
|
'clean:on_start',
|
||||||
'less:src',
|
'less:src',
|
||||||
|
'concat:css',
|
||||||
'copy:everything_but_less_to_temp',
|
'copy:everything_but_less_to_temp',
|
||||||
'htmlmin:build',
|
'htmlmin:build',
|
||||||
|
'ngtemplates',
|
||||||
'cssmin:build',
|
'cssmin:build',
|
||||||
'ngmin:build',
|
'ngmin:build',
|
||||||
'requirejs:build',
|
'requirejs:build',
|
||||||
|
'concat:js',
|
||||||
|
'filerev',
|
||||||
|
'usemin',
|
||||||
'clean:temp',
|
'clean:temp',
|
||||||
'build:write_revision',
|
'build:write_revision',
|
||||||
'uglify:dest'
|
'uglify:dest'
|
||||||
@ -19,6 +24,7 @@ module.exports = function(grunt) {
|
|||||||
// run a string replacement on the require config, using the latest revision number as the cache buster
|
// run a string replacement on the require config, using the latest revision number as the cache buster
|
||||||
grunt.registerTask('build:write_revision', function() {
|
grunt.registerTask('build:write_revision', function() {
|
||||||
grunt.event.once('git-describe', function (desc) {
|
grunt.event.once('git-describe', function (desc) {
|
||||||
|
|
||||||
grunt.config('string-replace.config', {
|
grunt.config('string-replace.config', {
|
||||||
files: {
|
files: {
|
||||||
'<%= destDir %>/app/components/require.config.js': '<%= destDir %>/app/components/require.config.js',
|
'<%= destDir %>/app/components/require.config.js': '<%= destDir %>/app/components/require.config.js',
|
||||||
@ -41,4 +47,4 @@ module.exports = function(grunt) {
|
|||||||
});
|
});
|
||||||
grunt.task.run('git-describe');
|
grunt.task.run('git-describe');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Lint and build CSS
|
// Lint and build CSS
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
grunt.registerTask('default', ['jshint:source', 'jshint:tests', 'less:src']);
|
grunt.registerTask('default', ['jshint:source', 'jshint:tests', 'less:src', 'concat:css']);
|
||||||
grunt.registerTask('test', ['default', 'karma:test']);
|
grunt.registerTask('test', ['default', 'karma:test']);
|
||||||
};
|
};
|
||||||
|
22
tasks/options/concat.js
Normal file
22
tasks/options/concat.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
css: {
|
||||||
|
src: [
|
||||||
|
'<%= srcDir %>/css/normalize.min.css',
|
||||||
|
'<%= srcDir %>/css/bootstrap.dark.min.css',
|
||||||
|
'<%= srcDir %>/css/timepicker.css',
|
||||||
|
'<%= srcDir %>/css/spectrum.css',
|
||||||
|
'<%= srcDir %>/css/animate.min.css'
|
||||||
|
],
|
||||||
|
dest: '<%= srcDir %>/css/default.min.css'
|
||||||
|
},
|
||||||
|
js: {
|
||||||
|
src: [
|
||||||
|
'<%= destDir %>/vendor/require/require.js',
|
||||||
|
'<%= destDir %>/app/components/require.config.js',
|
||||||
|
'<%= destDir %>/app/app.js',
|
||||||
|
],
|
||||||
|
dest: '<%= destDir %>/app/app.js'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
17
tasks/options/filerev.js
Normal file
17
tasks/options/filerev.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
encoding: 'utf8',
|
||||||
|
algorithm: 'md5',
|
||||||
|
length: 8,
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
src: '<%= destDir %>/css/default.min.css',
|
||||||
|
dest: '<%= destDir %>/css'
|
||||||
|
},
|
||||||
|
js: {
|
||||||
|
src: '<%= destDir %>/app/app.js',
|
||||||
|
dest: '<%= destDir %>/app'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -8,7 +8,7 @@ module.exports = function(config) {
|
|||||||
expand: true,
|
expand: true,
|
||||||
cwd: '<%= tempDir %>',
|
cwd: '<%= tempDir %>',
|
||||||
src: [
|
src: [
|
||||||
'index.html',
|
//'index.html',
|
||||||
'app/panels/**/*.html',
|
'app/panels/**/*.html',
|
||||||
'app/partials/**/*.html'
|
'app/partials/**/*.html'
|
||||||
],
|
],
|
||||||
|
18
tasks/options/ngtemplates.js
Normal file
18
tasks/options/ngtemplates.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
grafana: {
|
||||||
|
cwd: '<%= tempDir %>',
|
||||||
|
src: ['app/**/*.html', '!app/panels/*/module.html'],
|
||||||
|
dest: '<%= tempDir %>/app/components/partials.js',
|
||||||
|
options: {
|
||||||
|
bootstrap: function(module, script) {
|
||||||
|
return "define('components/partials', ['angular'], function(angular) { \n" +
|
||||||
|
"angular.module('kibana').run(['$templateCache', function($templateCache) { \n" +
|
||||||
|
script +
|
||||||
|
'\n}]);' +
|
||||||
|
'\n});';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -60,7 +60,7 @@ module.exports = function(config,grunt) {
|
|||||||
'directives/all',
|
'directives/all',
|
||||||
'jquery.flot.pie',
|
'jquery.flot.pie',
|
||||||
'angular-sanitize',
|
'angular-sanitize',
|
||||||
'angular-dragdrop'
|
'angular-dragdrop',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -70,18 +70,8 @@ module.exports = function(config,grunt) {
|
|||||||
|
|
||||||
// create a module for each directory in src/app/panels/
|
// create a module for each directory in src/app/panels/
|
||||||
fs.readdirSync(panelPath).forEach(function (panelName) {
|
fs.readdirSync(panelPath).forEach(function (panelName) {
|
||||||
if(!grunt.file.exists(panelPath+'/'+panelName+'/module.js')) {
|
requireModules[0].include.push('panels/'+panelName+'/module');
|
||||||
fs.readdirSync(panelPath+"/"+panelName).forEach(function (subName) {
|
requireModules[0].include.push('text!panels/'+panelName+'/module.html');
|
||||||
requireModules.push({
|
|
||||||
name: 'panels/'+panelName+'/'+subName+'/module',
|
|
||||||
exclude: ['app']
|
|
||||||
}); })
|
|
||||||
} else {
|
|
||||||
requireModules.push({
|
|
||||||
name: 'panels/'+panelName+'/module',
|
|
||||||
exclude: ['app']
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// exclude the literal config definition from all modules
|
// exclude the literal config definition from all modules
|
||||||
|
5
tasks/options/usemin.js
Normal file
5
tasks/options/usemin.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
html: '<%= destDir %>/index.html',
|
||||||
|
};
|
||||||
|
};
|
5
tasks/options/useminPrepare.js
Normal file
5
tasks/options/useminPrepare.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
html: 'tmp/index.html',
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user