support display bandwidth usage in chart
This commit is contained in:
parent
c451b396b0
commit
5851469cc0
|
@ -205,14 +205,17 @@
|
|||
<span> </span>
|
||||
|
||||
<div class="pull-right">
|
||||
<span class="realtime-speed">
|
||||
<i class="icon-download fa fa-arrow-down"></i>
|
||||
<span ng-bind="(globalStat.downloadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
<span class="realtime-speed">
|
||||
<i class="icon-upload fa fa-arrow-up"></i>
|
||||
<span ng-bind="(globalStat.uploadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
<a class="global-status" ng-pop-chart ng-data="globalStatusContext.data" ng-container="body"
|
||||
ng-placement="top" ng-trigger="click hover" ng-popover-class="global-status-chart">
|
||||
<span class="realtime-speed">
|
||||
<i class="icon-download fa fa-arrow-down"></i>
|
||||
<span ng-bind="(globalStat.downloadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
<span class="realtime-speed">
|
||||
<i class="icon-upload fa fa-arrow-up"></i>
|
||||
<span ng-bind="(globalStat.uploadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -238,8 +241,8 @@
|
|||
<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>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/echarts.simple-3.1.10.min.js -->
|
||||
<script src="../bower_components/echarts/dist/echarts.simple.min.js"></script>
|
||||
<!-- build:js js/echarts-3.1.10.min.js -->
|
||||
<script src="../bower_components/echarts/dist/echarts.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/plugins.min.js -->
|
||||
<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-aria2.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/setting.js"></script>
|
||||
<script src="scripts/filters/dateDuration.js"></script>
|
||||
|
@ -287,6 +291,7 @@
|
|||
<script src="scripts/filters/volumn.js"></script>
|
||||
<script src="scripts/services/ariaNgCommonService.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/aria2SettingService.js"></script>
|
||||
<script src="scripts/services/aria2RpcService.js"></script>
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"Status": "状态",
|
||||
"Percent": "完成度",
|
||||
"Download / Upload Speed": "下载 / 上传速度",
|
||||
"No Data": "无数据",
|
||||
"No connected peers": "没有连接到其他节点",
|
||||
"Failed to change some tasks state.": "修改一些任务状态时失败.",
|
||||
"Confirm Remove": "确认删除",
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
title: 'Aria Ng',
|
||||
appPrefix: 'AriaNg',
|
||||
optionStorageKey: 'Options',
|
||||
globalStatStorageCapacity: 120,
|
||||
taskStatStorageCapacity: 300,
|
||||
lazySaveTimeout: 500
|
||||
}).constant('ariaNgDefaultOptions', {
|
||||
language: 'en',
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
'Status': 'Status',
|
||||
'Percent': 'Percent',
|
||||
'Download / Upload Speed': 'Download / Upload Speed',
|
||||
'No Data': 'No Data',
|
||||
'No connected peers': 'No connected peers',
|
||||
'Failed to change some tasks state.': 'Failed to change some tasks state.',
|
||||
'Confirm Remove': 'Confirm Remove',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
(function () {
|
||||
'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 refreshGlobalStat = function (silent) {
|
||||
|
@ -13,10 +13,15 @@
|
|||
|
||||
if (response.success) {
|
||||
$scope.globalStat = response.data;
|
||||
ariaNgMonitorService.recordGlobalStat(response.data);
|
||||
}
|
||||
}, silent);
|
||||
};
|
||||
|
||||
$scope.globalStatusContext = {
|
||||
data: ariaNgMonitorService.getGlobalStatsData()
|
||||
};
|
||||
|
||||
$scope.isTaskSelected = function () {
|
||||
return $rootScope.taskContext.getSelectedTaskIds().length > 0;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
(function () {
|
||||
'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 downloadTaskRefreshPromise = null;
|
||||
var pauseDownloadTaskRefresh = false;
|
||||
|
@ -32,7 +32,7 @@
|
|||
$scope.peers = peers;
|
||||
}
|
||||
|
||||
$scope.healthPercent = aria2TaskService.estimateHealthPercentFromPeers(task, $scope.peers);
|
||||
$scope.context.healthPercent = aria2TaskService.estimateHealthPercentFromPeers(task, $scope.peers);
|
||||
}, silent);
|
||||
};
|
||||
|
||||
|
@ -53,9 +53,7 @@
|
|||
var task = response.data;
|
||||
|
||||
if (task.status == 'active' && task.bittorrent) {
|
||||
if ($scope.context.currentTab == 'btpeers') {
|
||||
refreshBtPeers(task, true);
|
||||
}
|
||||
refreshBtPeers(task, true);
|
||||
} else {
|
||||
if (tabOrders.indexOf('btpeers') >= 0) {
|
||||
tabOrders.splice(tabOrders.indexOf('btpeers'), 1);
|
||||
|
@ -63,7 +61,7 @@
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -71,16 +69,18 @@
|
|||
$rootScope.taskContext.list = [$scope.task];
|
||||
$rootScope.taskContext.selected = {};
|
||||
$rootScope.taskContext.selected[$scope.task.gid] = true;
|
||||
|
||||
ariaNgMonitorService.recordStat(task.gid, task);
|
||||
}, silent);
|
||||
};
|
||||
|
||||
$scope.context = {
|
||||
currentTab: 'overview'
|
||||
currentTab: 'overview',
|
||||
healthPercent: 0,
|
||||
statusData: ariaNgMonitorService.getEmptyStatsData($routeParams.gid),
|
||||
availableOptions: []
|
||||
};
|
||||
|
||||
$scope.healthPercent = 0;
|
||||
$scope.availableOptions = [];
|
||||
|
||||
$rootScope.swipeActions.extentLeftSwipe = function () {
|
||||
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
|
||||
|
||||
|
@ -152,10 +152,6 @@
|
|||
}, true);
|
||||
};
|
||||
|
||||
$scope.loadBtPeers = function (task) {
|
||||
$rootScope.loadPromise = refreshBtPeers(task, false);
|
||||
};
|
||||
|
||||
$scope.loadTaskOption = function (task) {
|
||||
$rootScope.loadPromise = aria2TaskService.getTaskOptions(task.gid, function (response) {
|
||||
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) {
|
||||
var units = [ 'B', 'KB', 'MB', 'GB' ];
|
||||
var defaultFractionSize = 2;
|
||||
|
||||
return function (value) {
|
||||
return function (value, fractionSize) {
|
||||
var unit = units[0];
|
||||
|
||||
if (!value) {
|
||||
value = 0;
|
||||
} 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.isUndefined(fractionSize)) {
|
||||
fractionSize = defaultFractionSize;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}]);
|
||||
|
|
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";
|
||||
}
|
||||
|
||||
.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 {
|
||||
background-color: #208fe5;
|
||||
}
|
||||
|
@ -555,6 +566,63 @@ td {
|
|||
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 {
|
||||
margin-left: 15px;
|
||||
|
@ -689,6 +757,14 @@ td {
|
|||
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 {
|
||||
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>
|
||||
</li>
|
||||
<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 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);">
|
||||
|
@ -61,7 +61,7 @@
|
|||
<span ng-bind="('Completed Percent' | translate) + (task.status == 'active' && task.bittorrent ? ' (' + ('Health Percent' | translate) + ')' : '')"></span>
|
||||
</div>
|
||||
<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 class="row" ng-if="task">
|
||||
|
@ -120,6 +120,13 @@
|
|||
<span ng-bind="task.dir"></span>
|
||||
</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 class="tab-pane" ng-class="{'active': context.currentTab == 'blocks'}">
|
||||
|
@ -217,7 +224,7 @@
|
|||
</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="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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Reference in a new issue