support display bandwidth usage in chart
This commit is contained in:
parent
c451b396b0
commit
5851469cc0
|
@ -205,14 +205,17 @@
|
||||||
<span> </span>
|
<span> </span>
|
||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<span class="realtime-speed">
|
<a class="global-status" ng-pop-chart ng-data="globalStatusContext.data" ng-container="body"
|
||||||
<i class="icon-download fa fa-arrow-down"></i>
|
ng-placement="top" ng-trigger="click hover" ng-popover-class="global-status-chart">
|
||||||
<span ng-bind="(globalStat.downloadSpeed | readableVolumn) + '/s'"></span>
|
<span class="realtime-speed">
|
||||||
</span>
|
<i class="icon-download fa fa-arrow-down"></i>
|
||||||
<span class="realtime-speed">
|
<span ng-bind="(globalStat.downloadSpeed | readableVolumn) + '/s'"></span>
|
||||||
<i class="icon-upload fa fa-arrow-up"></i>
|
</span>
|
||||||
<span ng-bind="(globalStat.uploadSpeed | readableVolumn) + '/s'"></span>
|
<span class="realtime-speed">
|
||||||
</span>
|
<i class="icon-upload fa fa-arrow-up"></i>
|
||||||
|
<span ng-bind="(globalStat.uploadSpeed | readableVolumn) + '/s'"></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,8 +241,8 @@
|
||||||
<script src="../bower_components/moment/locale/zh-tw.js"></script>
|
<script src="../bower_components/moment/locale/zh-tw.js"></script>
|
||||||
<script src="../bower_components/moment-timezone/builds/moment-timezone-with-data-2010-2020.min.js"></script>
|
<script src="../bower_components/moment-timezone/builds/moment-timezone-with-data-2010-2020.min.js"></script>
|
||||||
<!-- endbuild -->
|
<!-- endbuild -->
|
||||||
<!-- build:js js/echarts.simple-3.1.10.min.js -->
|
<!-- build:js js/echarts-3.1.10.min.js -->
|
||||||
<script src="../bower_components/echarts/dist/echarts.simple.min.js"></script>
|
<script src="../bower_components/echarts/dist/echarts.min.js"></script>
|
||||||
<!-- endbuild -->
|
<!-- endbuild -->
|
||||||
<!-- build:js js/plugins.min.js -->
|
<!-- build:js js/plugins.min.js -->
|
||||||
<script src="../bower_components/AdminLTE/dist/js/app.min.js"></script>
|
<script src="../bower_components/AdminLTE/dist/js/app.min.js"></script>
|
||||||
|
@ -277,6 +280,7 @@
|
||||||
<script src="scripts/controllers/settings-ariang.js"></script>
|
<script src="scripts/controllers/settings-ariang.js"></script>
|
||||||
<script src="scripts/controllers/settings-aria2.js"></script>
|
<script src="scripts/controllers/settings-aria2.js"></script>
|
||||||
<script src="scripts/controllers/status.js"></script>
|
<script src="scripts/controllers/status.js"></script>
|
||||||
|
<script src="scripts/directives/chart.js"></script>
|
||||||
<script src="scripts/directives/placeholder.js"></script>
|
<script src="scripts/directives/placeholder.js"></script>
|
||||||
<script src="scripts/directives/setting.js"></script>
|
<script src="scripts/directives/setting.js"></script>
|
||||||
<script src="scripts/filters/dateDuration.js"></script>
|
<script src="scripts/filters/dateDuration.js"></script>
|
||||||
|
@ -287,6 +291,7 @@
|
||||||
<script src="scripts/filters/volumn.js"></script>
|
<script src="scripts/filters/volumn.js"></script>
|
||||||
<script src="scripts/services/ariaNgCommonService.js"></script>
|
<script src="scripts/services/ariaNgCommonService.js"></script>
|
||||||
<script src="scripts/services/ariaNgSettingService.js"></script>
|
<script src="scripts/services/ariaNgSettingService.js"></script>
|
||||||
|
<script src="scripts/services/ariaNgMonitorService.js"></script>
|
||||||
<script src="scripts/services/aria2TaskService.js"></script>
|
<script src="scripts/services/aria2TaskService.js"></script>
|
||||||
<script src="scripts/services/aria2SettingService.js"></script>
|
<script src="scripts/services/aria2SettingService.js"></script>
|
||||||
<script src="scripts/services/aria2RpcService.js"></script>
|
<script src="scripts/services/aria2RpcService.js"></script>
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
"Status": "状态",
|
"Status": "状态",
|
||||||
"Percent": "完成度",
|
"Percent": "完成度",
|
||||||
"Download / Upload Speed": "下载 / 上传速度",
|
"Download / Upload Speed": "下载 / 上传速度",
|
||||||
|
"No Data": "无数据",
|
||||||
"No connected peers": "没有连接到其他节点",
|
"No connected peers": "没有连接到其他节点",
|
||||||
"Failed to change some tasks state.": "修改一些任务状态时失败.",
|
"Failed to change some tasks state.": "修改一些任务状态时失败.",
|
||||||
"Confirm Remove": "确认删除",
|
"Confirm Remove": "确认删除",
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
title: 'Aria Ng',
|
title: 'Aria Ng',
|
||||||
appPrefix: 'AriaNg',
|
appPrefix: 'AriaNg',
|
||||||
optionStorageKey: 'Options',
|
optionStorageKey: 'Options',
|
||||||
|
globalStatStorageCapacity: 120,
|
||||||
|
taskStatStorageCapacity: 300,
|
||||||
lazySaveTimeout: 500
|
lazySaveTimeout: 500
|
||||||
}).constant('ariaNgDefaultOptions', {
|
}).constant('ariaNgDefaultOptions', {
|
||||||
language: 'en',
|
language: 'en',
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
'Status': 'Status',
|
'Status': 'Status',
|
||||||
'Percent': 'Percent',
|
'Percent': 'Percent',
|
||||||
'Download / Upload Speed': 'Download / Upload Speed',
|
'Download / Upload Speed': 'Download / Upload Speed',
|
||||||
|
'No Data': 'No Data',
|
||||||
'No connected peers': 'No connected peers',
|
'No connected peers': 'No connected peers',
|
||||||
'Failed to change some tasks state.': 'Failed to change some tasks state.',
|
'Failed to change some tasks state.': 'Failed to change some tasks state.',
|
||||||
'Confirm Remove': 'Confirm Remove',
|
'Confirm Remove': 'Confirm Remove',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ariaNg').controller('MainController', ['$rootScope', '$scope', '$route', '$location', '$interval', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $route, $location, $interval, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, aria2TaskService, aria2SettingService) {
|
angular.module('ariaNg').controller('MainController', ['$rootScope', '$scope', '$route', '$location', '$interval', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgMonitorService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $route, $location, $interval, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, ariaNgMonitorService, aria2TaskService, aria2SettingService) {
|
||||||
var globalStatRefreshPromise = null;
|
var globalStatRefreshPromise = null;
|
||||||
|
|
||||||
var refreshGlobalStat = function (silent) {
|
var refreshGlobalStat = function (silent) {
|
||||||
|
@ -13,10 +13,15 @@
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
$scope.globalStat = response.data;
|
$scope.globalStat = response.data;
|
||||||
|
ariaNgMonitorService.recordGlobalStat(response.data);
|
||||||
}
|
}
|
||||||
}, silent);
|
}, silent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.globalStatusContext = {
|
||||||
|
data: ariaNgMonitorService.getGlobalStatsData()
|
||||||
|
};
|
||||||
|
|
||||||
$scope.isTaskSelected = function () {
|
$scope.isTaskSelected = function () {
|
||||||
return $rootScope.taskContext.getSelectedTaskIds().length > 0;
|
return $rootScope.taskContext.getSelectedTaskIds().length > 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ariaNg').controller('TaskDetailController', ['$rootScope', '$scope', '$routeParams', '$interval', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $interval, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, aria2TaskService, aria2SettingService) {
|
angular.module('ariaNg').controller('TaskDetailController', ['$rootScope', '$scope', '$routeParams', '$interval', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgMonitorService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $interval, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, ariaNgMonitorService, aria2TaskService, aria2SettingService) {
|
||||||
var tabOrders = ['overview', 'blocks', 'filelist', 'btpeers'];
|
var tabOrders = ['overview', 'blocks', 'filelist', 'btpeers'];
|
||||||
var downloadTaskRefreshPromise = null;
|
var downloadTaskRefreshPromise = null;
|
||||||
var pauseDownloadTaskRefresh = false;
|
var pauseDownloadTaskRefresh = false;
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
$scope.peers = peers;
|
$scope.peers = peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.healthPercent = aria2TaskService.estimateHealthPercentFromPeers(task, $scope.peers);
|
$scope.context.healthPercent = aria2TaskService.estimateHealthPercentFromPeers(task, $scope.peers);
|
||||||
}, silent);
|
}, silent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,9 +53,7 @@
|
||||||
var task = response.data;
|
var task = response.data;
|
||||||
|
|
||||||
if (task.status == 'active' && task.bittorrent) {
|
if (task.status == 'active' && task.bittorrent) {
|
||||||
if ($scope.context.currentTab == 'btpeers') {
|
refreshBtPeers(task, true);
|
||||||
refreshBtPeers(task, true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (tabOrders.indexOf('btpeers') >= 0) {
|
if (tabOrders.indexOf('btpeers') >= 0) {
|
||||||
tabOrders.splice(tabOrders.indexOf('btpeers'), 1);
|
tabOrders.splice(tabOrders.indexOf('btpeers'), 1);
|
||||||
|
@ -63,7 +61,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$scope.task || $scope.task.status != task.status) {
|
if (!$scope.task || $scope.task.status != task.status) {
|
||||||
$scope.availableOptions = getAvailableOptions(task.status, !!task.bittorrent);
|
$scope.context.availableOptions = getAvailableOptions(task.status, !!task.bittorrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.task = ariaNgCommonService.copyObjectTo(task, $scope.task);
|
$scope.task = ariaNgCommonService.copyObjectTo(task, $scope.task);
|
||||||
|
@ -71,16 +69,18 @@
|
||||||
$rootScope.taskContext.list = [$scope.task];
|
$rootScope.taskContext.list = [$scope.task];
|
||||||
$rootScope.taskContext.selected = {};
|
$rootScope.taskContext.selected = {};
|
||||||
$rootScope.taskContext.selected[$scope.task.gid] = true;
|
$rootScope.taskContext.selected[$scope.task.gid] = true;
|
||||||
|
|
||||||
|
ariaNgMonitorService.recordStat(task.gid, task);
|
||||||
}, silent);
|
}, silent);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.context = {
|
$scope.context = {
|
||||||
currentTab: 'overview'
|
currentTab: 'overview',
|
||||||
|
healthPercent: 0,
|
||||||
|
statusData: ariaNgMonitorService.getEmptyStatsData($routeParams.gid),
|
||||||
|
availableOptions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.healthPercent = 0;
|
|
||||||
$scope.availableOptions = [];
|
|
||||||
|
|
||||||
$rootScope.swipeActions.extentLeftSwipe = function () {
|
$rootScope.swipeActions.extentLeftSwipe = function () {
|
||||||
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
|
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
|
||||||
|
|
||||||
|
@ -152,10 +152,6 @@
|
||||||
}, true);
|
}, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.loadBtPeers = function (task) {
|
|
||||||
$rootScope.loadPromise = refreshBtPeers(task, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.loadTaskOption = function (task) {
|
$scope.loadTaskOption = function (task) {
|
||||||
$rootScope.loadPromise = aria2TaskService.getTaskOptions(task.gid, function (response) {
|
$rootScope.loadPromise = aria2TaskService.getTaskOptions(task.gid, function (response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
|
198
app/scripts/directives/chart.js
Normal file
198
app/scripts/directives/chart.js
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('ariaNg').directive('ngChart', ['$window', 'chartTheme', function ($window, chartTheme) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
template: '<div></div>',
|
||||||
|
scope: {
|
||||||
|
options: '=ngData'
|
||||||
|
},
|
||||||
|
link: function (scope, element, attrs) {
|
||||||
|
var options = {
|
||||||
|
ngTheme: 'default'
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.extend(options, attrs);
|
||||||
|
|
||||||
|
var wrapper = element.find('div');
|
||||||
|
var wrapperParent = element.parent();
|
||||||
|
var parentHeight = wrapperParent.height();
|
||||||
|
|
||||||
|
var height = parseInt(attrs.height) || parentHeight || 200;
|
||||||
|
wrapper.css('height', height + 'px');
|
||||||
|
|
||||||
|
var chart = echarts.init(wrapper[0], chartTheme.get(options.ngTheme));
|
||||||
|
|
||||||
|
var setOptions = function (value) {
|
||||||
|
chart.setOption(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.element($window).on('resize', function () {
|
||||||
|
chart.resize();
|
||||||
|
scope.$apply();
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.$watch(function () {
|
||||||
|
return scope.options;
|
||||||
|
}, function (value) {
|
||||||
|
if (value) {
|
||||||
|
setOptions(value);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]).directive('ngPopChart', ['$window', 'chartTheme', function ($window, chartTheme) {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
scope: {
|
||||||
|
options: '=ngData'
|
||||||
|
},
|
||||||
|
link: function (scope, element, attrs) {
|
||||||
|
var options = {
|
||||||
|
ngTheme: 'default',
|
||||||
|
ngPopoverClass: '',
|
||||||
|
ngContainer: 'body',
|
||||||
|
ngTrigger: 'click',
|
||||||
|
ngPlacement: 'top'
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.extend(options, attrs);
|
||||||
|
|
||||||
|
var chart = null;
|
||||||
|
var loadingIcon = '<div class="loading"><i class="fa fa-spinner fa-spin fa-2x"></i></div>';
|
||||||
|
|
||||||
|
element.popover({
|
||||||
|
container: options.ngContainer,
|
||||||
|
content: '<div class="chart-pop-wrapper"><div class="chart-pop ' + options.ngPopoverClass + '">' + loadingIcon +'</div></div>',
|
||||||
|
html: true,
|
||||||
|
placement: options.ngPlacement,
|
||||||
|
template: '<div class="popover chart-popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
|
||||||
|
trigger: options.ngTrigger
|
||||||
|
}).on('shown.bs.popover', function () {
|
||||||
|
var wrapper = angular.element('.chart-pop');
|
||||||
|
var wrapperParent = wrapper.parent();
|
||||||
|
var parentHeight = wrapperParent.height();
|
||||||
|
|
||||||
|
wrapper.empty();
|
||||||
|
|
||||||
|
var height = parseInt(attrs.height) || parentHeight || 200;
|
||||||
|
wrapper.css('height', height + 'px');
|
||||||
|
|
||||||
|
chart = echarts.init(wrapper[0], chartTheme.get(options.ngTheme));
|
||||||
|
}).on('hide.bs.popover', function () {
|
||||||
|
if (chart && chart.isDisposed()) {
|
||||||
|
chart.dispose();
|
||||||
|
}
|
||||||
|
}).on('hidden.bs.popover', function () {
|
||||||
|
angular.element('.chart-pop').empty().append(loadingIcon);
|
||||||
|
});
|
||||||
|
|
||||||
|
var setOptions = function (value) {
|
||||||
|
if (chart && !chart.isDisposed()) {
|
||||||
|
chart.setOption(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.$watch(function () {
|
||||||
|
return scope.options;
|
||||||
|
}, function (value) {
|
||||||
|
if (value) {
|
||||||
|
setOptions(value);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]).factory('chartTheme', ['chartDefaultTheme', function (chartDefaultTheme) {
|
||||||
|
var themes = {
|
||||||
|
defaultTheme: chartDefaultTheme
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
get: function (name) {
|
||||||
|
return themes[name + 'Theme'] ? themes[name + 'Theme'] : {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]).factory('chartDefaultTheme', function () {
|
||||||
|
return {
|
||||||
|
color: ['#74a329', '#3a89e9'],
|
||||||
|
legend: {
|
||||||
|
top: 'bottom'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
lineStyle: {
|
||||||
|
color: '#233333',
|
||||||
|
type: 'dashed',
|
||||||
|
width: 1
|
||||||
|
},
|
||||||
|
crossStyle: {
|
||||||
|
color: '#008acd',
|
||||||
|
width: 1
|
||||||
|
},
|
||||||
|
shadowStyle: {
|
||||||
|
color: 'rgba(200,200,200,0.2)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
x: 40,
|
||||||
|
y: 20,
|
||||||
|
x2: 30,
|
||||||
|
y2: 50
|
||||||
|
},
|
||||||
|
categoryAxis: {
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f3f3f3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueAxis: {
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f3f3f3'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitArea: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
lineStyle: {
|
||||||
|
width: 2,
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smooth: true,
|
||||||
|
symbolSize: 6
|
||||||
|
},
|
||||||
|
textStyle: {
|
||||||
|
fontFamily: 'Hiragino Sans GB, Microsoft YaHei, STHeiti, Helvetica Neue, Helvetica, Arial, sans-serif'
|
||||||
|
},
|
||||||
|
animationDuration: 500
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})();
|
|
@ -3,25 +3,30 @@
|
||||||
|
|
||||||
angular.module("ariaNg").filter('readableVolumn', ['numberFilter', function (numberFilter) {
|
angular.module("ariaNg").filter('readableVolumn', ['numberFilter', function (numberFilter) {
|
||||||
var units = [ 'B', 'KB', 'MB', 'GB' ];
|
var units = [ 'B', 'KB', 'MB', 'GB' ];
|
||||||
|
var defaultFractionSize = 2;
|
||||||
|
|
||||||
return function (value) {
|
return function (value, fractionSize) {
|
||||||
var unit = units[0];
|
var unit = units[0];
|
||||||
|
|
||||||
if (!value) {
|
if (angular.isUndefined(fractionSize)) {
|
||||||
value = 0;
|
fractionSize = defaultFractionSize;
|
||||||
} else {
|
|
||||||
for (var i = 1; i < units.length; i++) {
|
|
||||||
if (value >= 1024) {
|
|
||||||
value = value / 1024;
|
|
||||||
unit = units[i];
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = numberFilter(value, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!angular.isNumber(value)) {
|
||||||
|
value = parseInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 1; i < units.length; i++) {
|
||||||
|
if (value >= 1024) {
|
||||||
|
value = value / 1024;
|
||||||
|
unit = units[i];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = numberFilter(value, fractionSize);
|
||||||
|
|
||||||
return value + ' ' + unit;
|
return value + ' ' + unit;
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
159
app/scripts/services/ariaNgMonitorService.js
Normal file
159
app/scripts/services/ariaNgMonitorService.js
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('ariaNg').factory('ariaNgMonitorService', ['$translate', 'moment', 'ariaNgConstants', 'readableVolumnFilter', function ($translate, moment, ariaNgConstants, readableVolumnFilter) {
|
||||||
|
var storagesInMemory = {};
|
||||||
|
var globalStorageKey = 'global';
|
||||||
|
|
||||||
|
var getStorageCapacity = function (key) {
|
||||||
|
if (key == globalStorageKey) {
|
||||||
|
return ariaNgConstants.globalStatStorageCapacity;
|
||||||
|
} else {
|
||||||
|
return ariaNgConstants.taskStatStorageCapacity;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var initStorage = function (key) {
|
||||||
|
var data = {
|
||||||
|
legend: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
x: 50,
|
||||||
|
y: 10,
|
||||||
|
x2: 10,
|
||||||
|
y2: 10
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
formatter: function (params) {
|
||||||
|
if (params[0].name == '') {
|
||||||
|
return '<div>' + $translate.instant('No Data') + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = moment(params[0].name, 'X').format('HH:mm:ss');
|
||||||
|
var uploadSpeed = readableVolumnFilter(params[0].value) + '/s';
|
||||||
|
var downloadSpeed = readableVolumnFilter(params[1].value) + '/s';
|
||||||
|
|
||||||
|
return '<div>' + time + '</div>'
|
||||||
|
+ '<div><i class="icon-download fa fa-arrow-down"></i> ' + downloadSpeed +'</div>'
|
||||||
|
+ '<div><i class="icon-upload fa fa-arrow-up"></i> ' + uploadSpeed + '</div>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
data: [],
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLabel: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: function (value) {
|
||||||
|
return readableVolumnFilter(value, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {
|
||||||
|
normal: {
|
||||||
|
opacity: 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smooth: true,
|
||||||
|
symbolSize: 6,
|
||||||
|
showAllSymbol: false,
|
||||||
|
data: []
|
||||||
|
}, {
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {
|
||||||
|
normal: {
|
||||||
|
opacity: 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smooth: true,
|
||||||
|
symbolSize: 6,
|
||||||
|
showAllSymbol: false,
|
||||||
|
data: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
var timeData = data.xAxis.data;
|
||||||
|
var uploadData = data.series[0].data;
|
||||||
|
var downloadData = data.series[1].data;
|
||||||
|
|
||||||
|
for (var i = 0; i < getStorageCapacity(key); i++) {
|
||||||
|
timeData.push('');
|
||||||
|
uploadData.push('');
|
||||||
|
downloadData.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
storagesInMemory[key] = data;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
var isStorageExist = function (key) {
|
||||||
|
return !angular.isUndefined(storagesInMemory[key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
var pushToStorage = function (key, stat) {
|
||||||
|
var storage = storagesInMemory[key];
|
||||||
|
var timeData = storage.xAxis.data;
|
||||||
|
var uploadData = storage.series[0].data;
|
||||||
|
var downloadData = storage.series[1].data;
|
||||||
|
|
||||||
|
if (timeData.length >= getStorageCapacity(key)) {
|
||||||
|
timeData.shift();
|
||||||
|
uploadData.shift();
|
||||||
|
downloadData.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
timeData.push(stat.time);
|
||||||
|
uploadData.push(stat.uploadSpeed);
|
||||||
|
downloadData.push(stat.downloadSpeed);
|
||||||
|
};
|
||||||
|
|
||||||
|
var getStorage = function (key) {
|
||||||
|
return storagesInMemory[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
var removeStorage = function (key) {
|
||||||
|
delete storagesInMemory[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
recordStat: function (key, stat) {
|
||||||
|
if (!isStorageExist(key)) {
|
||||||
|
initStorage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
stat.time = moment().format('X');
|
||||||
|
pushToStorage(key, stat);
|
||||||
|
},
|
||||||
|
getStatsData: function (key) {
|
||||||
|
if (!isStorageExist(key)) {
|
||||||
|
initStorage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getStorage(key);
|
||||||
|
},
|
||||||
|
getEmptyStatsData: function (key) {
|
||||||
|
if (isStorageExist(key)) {
|
||||||
|
removeStorage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getStatsData(key);
|
||||||
|
},
|
||||||
|
recordGlobalStat: function (stat) {
|
||||||
|
return this.recordStat(globalStorageKey, stat);
|
||||||
|
},
|
||||||
|
getGlobalStatsData: function () {
|
||||||
|
return this.getStatsData(globalStorageKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
})();
|
|
@ -309,6 +309,17 @@ td {
|
||||||
content: "\f0c9";
|
content: "\f0c9";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skin-aria-ng .global-status {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skin-aria-ng .global-status:hover {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin-right: 9px;
|
||||||
|
margin-top: -1px
|
||||||
|
}
|
||||||
|
|
||||||
.skin-aria-ng .progress-bar-primary {
|
.skin-aria-ng .progress-bar-primary {
|
||||||
background-color: #208fe5;
|
background-color: #208fe5;
|
||||||
}
|
}
|
||||||
|
@ -555,6 +566,63 @@ td {
|
||||||
cursor: -webkit-grabbing;
|
cursor: -webkit-grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* global-status */
|
||||||
|
.global-status {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-status > .realtime-speed {
|
||||||
|
padding: 0 15px 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-status > .realtime-speed:first-child {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-status > .realtime-speed:last-child {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-status span.realtime-speed > i {
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chart */
|
||||||
|
.chart-popover {
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-popover .popover-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-pop-wrapper {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-pop {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-pop .loading {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: table-cell;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-status-chart {
|
||||||
|
width: 312px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status-chart-wrapper {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* task-table */
|
/* task-table */
|
||||||
.task-table {
|
.task-table {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
|
@ -689,6 +757,14 @@ td {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skin-aria-ng .settings-table > div.row.no-background {
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skin-aria-ng .settings-table > div.row.no-hover:hover {
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-table .input-group-addon {
|
.settings-table .input-group-addon {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
@ -755,11 +831,3 @@ td {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* miscellaneous */
|
|
||||||
span.realtime-speed {
|
|
||||||
padding: 0 15px 0 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.realtime-speed > i {
|
|
||||||
padding-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<a class="pointer-cursor" ng-click="context.currentTab = 'filelist'" translate>Files</a>
|
<a class="pointer-cursor" ng-click="context.currentTab = 'filelist'" translate>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-class="{'active': context.currentTab == 'btpeers'}" ng-if="task && task.status == 'active' && task.bittorrent">
|
<li ng-class="{'active': context.currentTab == 'btpeers'}" ng-if="task && task.status == 'active' && task.bittorrent">
|
||||||
<a class="pointer-cursor" ng-click="context.currentTab = 'btpeers';loadBtPeers(task);" translate>Peers</a>
|
<a class="pointer-cursor" ng-click="context.currentTab = 'btpeers';" translate>Peers</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-class="{'active': context.currentTab == 'settings'}" ng-if="task && (task.status == 'active' || task.status == 'waiting' || task.status == 'paused')" class="slim">
|
<li ng-class="{'active': context.currentTab == 'settings'}" ng-if="task && (task.status == 'active' || task.status == 'waiting' || task.status == 'paused')" class="slim">
|
||||||
<a class="pointer-cursor" ng-click="context.currentTab = 'settings';loadTaskOption(task);">
|
<a class="pointer-cursor" ng-click="context.currentTab = 'settings';loadTaskOption(task);">
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
<span ng-bind="('Completed Percent' | translate) + (task.status == 'active' && task.bittorrent ? ' (' + ('Health Percent' | translate) + ')' : '')"></span>
|
<span ng-bind="('Completed Percent' | translate) + (task.status == 'active' && task.bittorrent ? ' (' + ('Health Percent' | translate) + ')' : '')"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value col-sm-8">
|
<div class="setting-value col-sm-8">
|
||||||
<span ng-bind="(task.completePercent | percent: 2) + '%' + (task.status == 'active' && task.bittorrent ? ' (' + (healthPercent | percent: 2) + '%' + ')' : '')"></span>
|
<span ng-bind="(task.completePercent | percent: 2) + '%' + (task.status == 'active' && task.bittorrent ? ' (' + (context.healthPercent | percent: 2) + '%' + ')' : '')"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" ng-if="task">
|
<div class="row" ng-if="task">
|
||||||
|
@ -120,6 +120,13 @@
|
||||||
<span ng-bind="task.dir"></span>
|
<span ng-bind="task.dir"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row no-hover no-background" ng-if="task && task.status == 'active'">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="task-status-chart-wrapper">
|
||||||
|
<ng-chart ng-data="context.statusData" height="200"></ng-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" ng-class="{'active': context.currentTab == 'blocks'}">
|
<div class="tab-pane" ng-class="{'active': context.currentTab == 'blocks'}">
|
||||||
|
@ -217,7 +224,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" ng-class="{'active': context.currentTab == 'settings'}" ng-if="task && (task.status == 'active' || task.status == 'waiting' || task.status == 'paused')">
|
<div class="tab-pane" ng-class="{'active': context.currentTab == 'settings'}" ng-if="task && (task.status == 'active' || task.status == 'waiting' || task.status == 'paused')">
|
||||||
<div class="settings-table settings-table-firstrow-noborder">
|
<div class="settings-table settings-table-firstrow-noborder">
|
||||||
<ng-setting ng-repeat="option in availableOptions" option="option"
|
<ng-setting ng-repeat="option in context.availableOptions" option="option"
|
||||||
ng-model="options[option.key]" on-change-value="setOption(key, value, optionStatus)"></ng-setting>
|
ng-model="options[option.key]" on-change-value="setOption(key, value, optionStatus)"></ng-setting>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue