Skip to content
Snippets Groups Projects
Commit 173c663d authored by Benoit Lavenier's avatar Benoit Lavenier
Browse files

[enh] Allow to change period on blockchain stats charts (24h by default)

[enh] Add network stats charts (endpoints per API)
[enh] Add currency stats charts (memberships and pending memberships)
parent 05532a60
No related branches found
No related tags found
No related merge requests found
Showing
with 757 additions and 196 deletions
...@@ -176,5 +176,5 @@ Peer.prototype.isBma = function() { ...@@ -176,5 +176,5 @@ Peer.prototype.isBma = function() {
}; };
Peer.prototype.hasBma = function() { Peer.prototype.hasBma = function() {
return this.hasEndpoint('(BASIC_MERKLE_API|BMAS|BMATOR)'); return this.hasEndpoint('(BASIC_MERKLED_API|BMAS|BMATOR)');
}; };
...@@ -6,7 +6,7 @@ angular.module('cesium.es.document.controllers', ['cesium.es.services']) ...@@ -6,7 +6,7 @@ angular.module('cesium.es.document.controllers', ['cesium.es.services'])
$stateProvider $stateProvider
.state('app.document_search', { .state('app.document_search', {
url: "/data/search/:index/:type?q", url: "/data/search/:index/:type?q&sort",
views: { views: {
'menuContent': { 'menuContent': {
templateUrl: "plugins/es/templates/document/lookup.html", templateUrl: "plugins/es/templates/document/lookup.html",
...@@ -47,8 +47,10 @@ function ESDocumentLookupController($scope, $ionicPopover, $location, $timeout, ...@@ -47,8 +47,10 @@ function ESDocumentLookupController($scope, $ionicPopover, $location, $timeout,
$scope.helptipPrefix = 'helptip-document'; $scope.helptipPrefix = 'helptip-document';
$scope.compactMode = angular.isDefined($scope.compactMode) ? $scope.compactMode : true; $scope.compactMode = angular.isDefined($scope.compactMode) ? $scope.compactMode : true;
$scope._source = $scope._source || ["issuer", "hash", "time", "creationTime", "title", "message", "recipient", $scope._source = $scope._source || ["issuer", "hash", "time", "creationTime", "title", "message", "recipient",
// Movement field: // Movement fields:
"medianTime", "amount", "currency", "reference" "medianTime", "amount", "currency", "reference",
// Pending fields:
"pubkey", "uid", "blockNumber"
]; ];
$scope.showHeaders = angular.isDefined($scope.showHeaders) ? $scope.showHeaders : true; $scope.showHeaders = angular.isDefined($scope.showHeaders) ? $scope.showHeaders : true;
...@@ -62,6 +64,14 @@ function ESDocumentLookupController($scope, $ionicPopover, $location, $timeout, ...@@ -62,6 +64,14 @@ function ESDocumentLookupController($scope, $ionicPopover, $location, $timeout,
$scope.entered = true; $scope.entered = true;
$scope.search.index = state.stateParams && state.stateParams.index || $scope.search.index; $scope.search.index = state.stateParams && state.stateParams.index || $scope.search.index;
$scope.search.type = state.stateParams && state.stateParams.type || $scope.search.type; $scope.search.type = state.stateParams && state.stateParams.type || $scope.search.type;
$scope.search.text = state.stateParams && state.stateParams.q || $scope.search.text;
$scope.search.sort = state.stateParams && state.stateParams.sort || $scope.search.sort;
$scope.search.last = !$scope.search.text;
$scope.load();
}
// Reload only if params changed (.e.g if comes from a graph click)
else if (state.stateParams && state.stateParams.q && $scope.search.text !== state.stateParams.q) {
$scope.search.text = state.stateParams && state.stateParams.q || $scope.search.text; $scope.search.text = state.stateParams && state.stateParams.q || $scope.search.text;
$scope.search.last = !$scope.search.text; $scope.search.last = !$scope.search.text;
$scope.load(); $scope.load();
......
...@@ -3,7 +3,11 @@ ...@@ -3,7 +3,11 @@
Graph currency popover Graph currency popover
**********/ **********/
.popover-graph-currency { .popover-graph-range {
height: 300px !important; height: 300px !important;
max-width: 250px !important; max-width: 250px !important;
} }
.popover-graph-period {
height: 420px !important;
max-width: 250px !important;
}
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
"HOUR": "Group by <b>hour</b>", "HOUR": "Group by <b>hour</b>",
"DAY": "Group by <b>day</b>", "DAY": "Group by <b>day</b>",
"MONTH": "Group by <b>month</b>" "MONTH": "Group by <b>month</b>"
},
"MAX_AGE": {
"DAY": "For 24h",
"WEEK": "For a week",
"MONTH": "For a month",
"QUARTER": "For 3 months",
"SEMESTER": "For 6 months",
"YEAR": "For a year",
"FOREVER": "Forever"
} }
}, },
"ACCOUNT": { "ACCOUNT": {
...@@ -49,7 +58,11 @@ ...@@ -49,7 +58,11 @@
"MONETARY_MASS_SHARE_LABEL": "Average per member", "MONETARY_MASS_SHARE_LABEL": "Average per member",
"UD_TITLE": "Evolution of the universal dividend", "UD_TITLE": "Evolution of the universal dividend",
"MEMBERS_COUNT_TITLE": "Evolution of the number of members", "MEMBERS_COUNT_TITLE": "Evolution of the number of members",
"MEMBERS_COUNT_LABEL": "Number of members" "MEMBERS_COUNT_LABEL": "Number of members",
"MEMBERS_DELTA_TITLE": "variation in the number of members",
"IS_MEMBER_DELTA_LABEL": "Validated memberships",
"WAS_MEMBER_DELTA_LABEL": "Membership losses",
"PENDING_DELTA_LABEL": "Membership requests"
}, },
"PEER": { "PEER": {
"VIEW": { "VIEW": {
...@@ -86,6 +99,24 @@ ...@@ -86,6 +99,24 @@
"TITLE": "Other documents", "TITLE": "Other documents",
"HISTORY_DELETE": "Deletion of documents" "HISTORY_DELETE": "Deletion of documents"
} }
},
"SYNCHRO": {
"TITLE": "Synchronization statistics",
"COUNT": {
"TITLE": "Synchronized volume",
"INSERTS": "Insertions",
"UPDATES": "Updates",
"DELETES": "Deletions"
},
"PEER": {
"TITLE": "Requested peers",
"ES_USER_API": "Peers with with user data",
"ES_SUBSCRIPTION_API": "Peers with subscription"
},
"PERFORMANCE": {
"TITLE": "Execution performance",
"DURATION": "Execution time (ms)"
}
} }
} }
} }
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
"HOUR": "Group by <b>hour</b>", "HOUR": "Group by <b>hour</b>",
"DAY": "Group by <b>day</b>", "DAY": "Group by <b>day</b>",
"MONTH": "Group by <b>month</b>" "MONTH": "Group by <b>month</b>"
},
"MAX_AGE": {
"DAY": "For 24h",
"WEEK": "For a week",
"MONTH": "For a month",
"QUARTER": "For 3 months",
"SEMESTER": "For 6 months",
"YEAR": "For a year",
"FOREVER": "Forever"
} }
}, },
"ACCOUNT": { "ACCOUNT": {
...@@ -49,7 +58,11 @@ ...@@ -49,7 +58,11 @@
"MONETARY_MASS_SHARE_LABEL": "Average per member", "MONETARY_MASS_SHARE_LABEL": "Average per member",
"UD_TITLE": "Evolution of the universal dividend", "UD_TITLE": "Evolution of the universal dividend",
"MEMBERS_COUNT_TITLE": "Evolution of the number of members", "MEMBERS_COUNT_TITLE": "Evolution of the number of members",
"MEMBERS_COUNT_LABEL": "Number of members" "MEMBERS_COUNT_LABEL": "Number of members",
"MEMBERS_DELTA_TITLE": "variation in the number of members",
"IS_MEMBER_DELTA_LABEL": "Validated memberships",
"WAS_MEMBER_DELTA_LABEL": "Membership losses",
"PENDING_DELTA_LABEL": "Membership requests"
}, },
"PEER": { "PEER": {
"VIEW": { "VIEW": {
...@@ -86,6 +99,24 @@ ...@@ -86,6 +99,24 @@
"TITLE": "Other documents", "TITLE": "Other documents",
"HISTORY_DELETE": "Deletion of documents" "HISTORY_DELETE": "Deletion of documents"
} }
},
"SYNCHRO": {
"TITLE": "Synchronization statistics",
"COUNT": {
"TITLE": "Synchronized volume",
"INSERTS": "Insertions",
"UPDATES": "Updates",
"DELETES": "Deletions"
},
"PEER": {
"TITLE": "Requested peers",
"ES_USER_API": "Peers with with user data",
"ES_SUBSCRIPTION_API": "Peers with subscription"
},
"PERFORMANCE": {
"TITLE": "Execution performance",
"DURATION": "Execution time (ms)"
}
} }
} }
} }
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
"HOUR": "Heure", "HOUR": "Heure",
"DAY": "Jour", "DAY": "Jour",
"MONTH": "Mois" "MONTH": "Mois"
},
"MAX_AGE": {
"DAY": "Depuis 24h",
"WEEK": "Depuis une semaine",
"MONTH": "Depuis un mois",
"QUARTER": "Depuis 3 mois",
"SEMESTER": "Depuis 6 mois",
"YEAR": "Depuis un an",
"FOREVER": "Depuis toujours"
} }
}, },
"ACCOUNT": { "ACCOUNT": {
...@@ -50,7 +59,6 @@ ...@@ -50,7 +59,6 @@
"TX_COUNT_TITLE": "Nombre de transactions écrites", "TX_COUNT_TITLE": "Nombre de transactions écrites",
"TX_COUNT_LABEL": "Nombre de transactions", "TX_COUNT_LABEL": "Nombre de transactions",
"TX_AVG_BY_BLOCK": "Nombre moyen de transactions / bloc" "TX_AVG_BY_BLOCK": "Nombre moyen de transactions / bloc"
}, },
"CURRENCY": { "CURRENCY": {
"MONETARY_MASS_TITLE": "Evolution de la masse monétaire", "MONETARY_MASS_TITLE": "Evolution de la masse monétaire",
...@@ -58,7 +66,11 @@ ...@@ -58,7 +66,11 @@
"MONETARY_MASS_SHARE_LABEL": "Moyenne par membre", "MONETARY_MASS_SHARE_LABEL": "Moyenne par membre",
"UD_TITLE": "Evolution du dividende universel", "UD_TITLE": "Evolution du dividende universel",
"MEMBERS_COUNT_TITLE": "Evolution du nombre de membres", "MEMBERS_COUNT_TITLE": "Evolution du nombre de membres",
"MEMBERS_COUNT_LABEL": "Nombre de membres" "MEMBERS_COUNT_LABEL": "Nombre de membres",
"MEMBERS_DELTA_TITLE": "Variation du nombre de membres",
"IS_MEMBER_DELTA_LABEL": "Prises en compte d'adhésion",
"WAS_MEMBER_DELTA_LABEL": "Pertes d'adhésion",
"PENDING_DELTA_LABEL": "Demandes d'adhésion"
}, },
"PEER": { "PEER": {
"VIEW": { "VIEW": {
...@@ -106,13 +118,18 @@ ...@@ -106,13 +118,18 @@
}, },
"PEER": { "PEER": {
"TITLE": "Noeuds requêtés", "TITLE": "Noeuds requêtés",
"ES_USER_API": "Noeuds données utilisateurs", "ES_USER_API": "Noeuds avec données utilisateurs",
"ES_SUBSCRIPTION_API": "Noeuds services en ligne" "ES_SUBSCRIPTION_API": "Noeuds avec services en ligne"
}, },
"PERFORMANCE": { "PERFORMANCE": {
"TITLE": "Performances d'exécution", "TITLE": "Performances d'exécution",
"DURATION": "Temps d'exécution (ms)" "DURATION": "Temps d'exécution (ms)"
} }
},
"NETWORK": {
"TITLE": "Statistiques réseau",
"ENDPOINT_COUNT_TITLE": "Nombre de points d'accès",
"ENDPOINT_DELTA_TITLE": "Variation du nombre de points d'accès"
} }
} }
} }
...@@ -86,12 +86,11 @@ function GpBlockchainTxCountController($scope, $controller, $q, $state, $filter, ...@@ -86,12 +86,11 @@ function GpBlockchainTxCountController($scope, $controller, $q, $state, $filter,
if (!result || !result.times) return; // no data if (!result || !result.times) return; // no data
$scope.times = result.times; $scope.times = result.times;
var formatInteger = $filter('formatInteger');
var formatAmount = $filter('formatDecimal'); var formatAmount = $filter('formatDecimal');
$scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, $scope.formData.useRelative); $scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, $scope.formData.useRelative);
// Data // Data
if ($scope.formData.rangeDuration != 'hour') { if ($scope.formData.rangeDuration !== 'hour') {
$scope.data = [ $scope.data = [
result.amount, result.amount,
result.count result.count
...@@ -207,13 +206,18 @@ function GpBlockchainIssuersController($scope, $controller, $q, $state, $transla ...@@ -207,13 +206,18 @@ function GpBlockchainIssuersController($scope, $controller, $q, $state, $transla
// Initialize the super class and extend it. // Initialize the super class and extend it.
angular.extend(this, $controller('GpCurrencyAbstractCtrl', {$scope: $scope})); angular.extend(this, $controller('GpCurrencyAbstractCtrl', {$scope: $scope}));
// Change defaults
$scope.formData.maxAge = 'day';
$scope.computeStartTimeByAge();
$scope.load = function() { $scope.load = function() {
return $q.all([ return $q.all([
$translate([ $translate([
'GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_TITLE', 'GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_TITLE',
'GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_LABEL' 'GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_LABEL'
]), ]),
gpData.blockchain.countByIssuer($scope.formData.currency) gpData.blockchain.countByIssuer($scope.formData.currency, {startTime: $scope.formData.startTime})
]) ])
.then(function(result) { .then(function(result) {
var translations = result[0]; var translations = result[0];
......
...@@ -12,13 +12,12 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -12,13 +12,12 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
useRelative: csSettings.data.useRelative, useRelative: csSettings.data.useRelative,
timePct: 100, timePct: 100,
rangeDuration: 'day', rangeDuration: 'day',
maxAge: undefined, // forever
firstBlockTime: 0, firstBlockTime: 0,
scale: 'linear', scale: 'linear',
hide: [], hide: [],
beginAtZero: true beginAtZero: true
}; };
$scope.formData.useRelative = false; /*angular.isDefined($scope.formData.useRelative) ?
$scope.formData.useRelative : csSettings.data.useRelative;*/
$scope.scale = 'linear'; $scope.scale = 'linear';
$scope.height = undefined; $scope.height = undefined;
$scope.width = undefined; $scope.width = undefined;
...@@ -32,6 +31,21 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -32,6 +31,21 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
$scope.enter = function (e, state) { $scope.enter = function (e, state) {
if ($scope.loading) { if ($scope.loading) {
// Make sure there is currency, or load it not
if (!$scope.formData.currency) {
return csCurrency.get()
.then(function (currency) {
$scope.formData.currency = currency ? currency.name : null;
$scope.formData.firstBlockTime = currency ? _truncDate(currency.firstBlockTime) : 0;
if (!$scope.formData.firstBlockTime){
console.warn('[graph] currency.firstBlockTime not loaded ! Should have been loaded by currrency service!');
}
$scope.formData.currencyAge = _truncDate(moment().utc().unix()) - $scope.formData.firstBlockTime;
return $scope.enter(e, state); // Loop
});
}
if (state && state.stateParams) { if (state && state.stateParams) {
// remember state, to be able to refresh location // remember state, to be able to refresh location
$scope.stateName = state && state.stateName; $scope.stateName = state && state.stateName;
...@@ -63,21 +77,6 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -63,21 +77,6 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
// Should be override by subclasses // Should be override by subclasses
$scope.init(e, state); $scope.init(e, state);
// Make sure there is currency, or load it not
if (!$scope.formData.currency) {
return csCurrency.get()
.then(function (currency) {
$scope.formData.currency = currency ? currency.name : null;
$scope.formData.firstBlockTime = currency ? _truncDate(currency.firstBlockTime) : 0;
if (!$scope.formData.firstBlockTime){
console.warn('[graph] currency.firstBlockTime not loaded ! Should have been loaded by currrency service!');
}
$scope.formData.currencyAge = _truncDate(moment().utc().unix()) - $scope.formData.firstBlockTime;
return $scope.enter(e, state);
});
}
$scope.load() // Should be override by subclasses $scope.load() // Should be override by subclasses
.then(function () { .then(function () {
// Update scale // Update scale
...@@ -103,9 +102,9 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -103,9 +102,9 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
$scope.stateParams = $scope.stateParams || {}; $scope.stateParams = $scope.stateParams || {};
$scope.stateParams.t = ($scope.formData.timePct >= 0 && $scope.formData.timePct < 100) ? $scope.formData.timePct : undefined; $scope.stateParams.t = ($scope.formData.timePct >= 0 && $scope.formData.timePct < 100) ? $scope.formData.timePct : undefined;
$scope.stateParams.stepUnit = $scope.formData.rangeDuration != 'day' ? $scope.formData.rangeDuration : undefined; $scope.stateParams.stepUnit = $scope.formData.rangeDuration !== 'day' ? $scope.formData.rangeDuration : undefined;
$scope.stateParams.hide = $scope.formData.hide && $scope.formData.hide.length ? $scope.formData.hide.join(',') : undefined; $scope.stateParams.hide = $scope.formData.hide && $scope.formData.hide.length ? $scope.formData.hide.join(',') : undefined;
$scope.stateParams.scale = $scope.formData.scale != 'linear' ?$scope.formData.scale : undefined; $scope.stateParams.scale = $scope.formData.scale !== 'linear' ?$scope.formData.scale : undefined;
$state.go($scope.stateName, $scope.stateParams, { $state.go($scope.stateName, $scope.stateParams, {
reload: false, reload: false,
...@@ -123,7 +122,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -123,7 +122,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
// When parent view execute a refresh action // When parent view execute a refresh action
$scope.$on('csView.action.refresh', function(event, context) { $scope.$on('csView.action.refresh', function(event, context) {
if (!context || context == 'currency') { if (!context || context === 'currency') {
return $scope.load(); return $scope.load();
} }
}); });
...@@ -152,7 +151,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -152,7 +151,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
_.forEach($scope.options.scales.yAxes, function(yAxe, index) { _.forEach($scope.options.scales.yAxes, function(yAxe, index) {
yAxe.type = scale; yAxe.type = scale;
yAxe.ticks = yAxe.ticks || {}; yAxe.ticks = yAxe.ticks || {};
if (scale == 'linear') { if (scale === 'linear') {
yAxe.ticks.beginAtZero = angular.isDefined($scope.formData.beginAtZero) ? $scope.formData.beginAtZero : true; yAxe.ticks.beginAtZero = angular.isDefined($scope.formData.beginAtZero) ? $scope.formData.beginAtZero : true;
delete yAxe.ticks.min; delete yAxe.ticks.min;
yAxe.ticks.callback = function(value) { yAxe.ticks.callback = function(value) {
...@@ -176,7 +175,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -176,7 +175,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
$scope.setRangeDuration = function(rangeDuration) { $scope.setRangeDuration = function(rangeDuration) {
$scope.hideActionsPopover(); $scope.hideActionsPopover();
if ($scope.formData && rangeDuration == $scope.formData.rangeDuration) return; if ($scope.formData && rangeDuration === $scope.formData.rangeDuration) return;
$scope.formData.rangeDuration = rangeDuration; $scope.formData.rangeDuration = rangeDuration;
...@@ -192,6 +191,55 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -192,6 +191,55 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
$scope.updateLocation(); $scope.updateLocation();
}; };
$scope.setMaxAge = function(maxAge) {
$scope.hideActionsPopover();
if ($scope.formData && maxAge === $scope.formData.maxAge) return;
$scope.formData.maxAge = maxAge;
// Restore default values
delete $scope.formData.startTime;
delete $scope.formData.endTime;
delete $scope.formData.rangeDurationSec;
$scope.computeStartTimeByAge(); // Compute formData.startTime
// Reload data
$scope.load();
// Update location
$scope.updateLocation();
};
$scope.computeStartTimeByAge = function() {
if (!$scope.formData.maxAge) {
delete $scope.formData.startTime; // Forever
}
else {
var ageInSecond = 60 * 60; // one hour
switch ($scope.formData.maxAge) {
case 'day':
ageInSecond *= 24;
break;
case 'week':
ageInSecond *= 24 * 7;
break;
case 'month':
ageInSecond *= 24 * 365.25/12;
break;
case 'quarter':
ageInSecond *= 24 * 365.25/4;
break;
case 'semester':
ageInSecond *= 24 * 365.25/2;
break;
case 'year':
ageInSecond *= 24 * 365.25;
break;
}
$scope.formData.startTime = moment.utc().unix() - ageInSecond;
}
}
$scope.updateHiddenDataset = function(datasetOverride) { $scope.updateHiddenDataset = function(datasetOverride) {
datasetOverride = datasetOverride || $scope.datasetOverride || {}; datasetOverride = datasetOverride || $scope.datasetOverride || {};
...@@ -208,7 +256,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -208,7 +256,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
var yAxisDatasetCount = _.filter(datasetOverride, function(dataset) { var yAxisDatasetCount = _.filter(datasetOverride, function(dataset) {
return dataset.yAxisID === yAxisID; return dataset.yAxisID === yAxisID;
}).length; }).length;
if (yAxisDatasetCount == 1) { if (yAxisDatasetCount === 1) {
yAxe.display = false; yAxe.display = false;
} }
} }
...@@ -314,9 +362,10 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -314,9 +362,10 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
/* -- Popover -- */ /* -- Popover -- */
$scope.showActionsPopover = function(event) { $scope.showActionsPopover = function(event, options) {
var templateUrl = options && options.templateUrl || 'plugins/graph/templates/common/popover_range_actions.html';
UIUtils.popover.show(event, { UIUtils.popover.show(event, {
templateUrl: 'plugins/graph/templates/common/popover_range_actions.html', templateUrl: templateUrl,
scope: $scope, scope: $scope,
autoremove: true, autoremove: true,
afterShow: function(popover) { afterShow: function(popover) {
...@@ -325,6 +374,11 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist ...@@ -325,6 +374,11 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist
}); });
}; };
$scope.showPeriodPopover = function(event) {
return $scope.showActionsPopover(event, {templateUrl: 'plugins/graph/templates/common/popover_period_actions.html'});
};
$scope.hideActionsPopover = function() { $scope.hideActionsPopover = function() {
if ($scope.actionsPopover) { if ($scope.actionsPopover) {
$scope.actionsPopover.hide(); $scope.actionsPopover.hide();
......
...@@ -39,7 +39,7 @@ angular.module('cesium.graph.currency.controllers', ['chart.js', 'cesium.graph.s ...@@ -39,7 +39,7 @@ angular.module('cesium.graph.currency.controllers', ['chart.js', 'cesium.graph.s
} }
}) })
.state('app.currency_stats_lg', { .state('app.currency_stats_lg', {
url: "/currency/stats/lg?hide&scale", url: "/currency/stats/lg?hide&scale&stepUnit&t",
views: { views: {
'menuContent': { 'menuContent': {
templateUrl: "plugins/graph/templates/currency/view_stats_lg.html" templateUrl: "plugins/graph/templates/currency/view_stats_lg.html"
...@@ -86,6 +86,8 @@ angular.module('cesium.graph.currency.controllers', ['chart.js', 'cesium.graph.s ...@@ -86,6 +86,8 @@ angular.module('cesium.graph.currency.controllers', ['chart.js', 'cesium.graph.s
.controller('GpCurrencyDUCtrl', GpCurrencyDUController) .controller('GpCurrencyDUCtrl', GpCurrencyDUController)
.controller('GpCurrencyMembersCountCtrl', GpCurrencyMembersCountController) .controller('GpCurrencyMembersCountCtrl', GpCurrencyMembersCountController)
.controller('GpCurrencyPendingCountCtrl', GpCurrencyPendingCountController)
; ;
function GpCurrencyViewExtendController($scope, PluginService, UIUtils, esSettings) { function GpCurrencyViewExtendController($scope, PluginService, UIUtils, esSettings) {
...@@ -134,7 +136,9 @@ function GpCurrencyMonetaryMassController($scope, $controller, $q, $state, $tran ...@@ -134,7 +136,9 @@ function GpCurrencyMonetaryMassController($scope, $controller, $q, $state, $tran
return $q.all([ return $q.all([
$translate(['GRAPH.CURRENCY.MONETARY_MASS_TITLE', $translate(['GRAPH.CURRENCY.MONETARY_MASS_TITLE',
'GRAPH.CURRENCY.MONETARY_MASS_LABEL', 'GRAPH.CURRENCY.MONETARY_MASS_LABEL',
'GRAPH.CURRENCY.MONETARY_MASS_SHARE_LABEL']), 'GRAPH.CURRENCY.MONETARY_MASS_SHARE_LABEL',
'COMMON.DATE_SHORT_PATTERN',
'COMMON.DATE_MONTH_YEAR_PATTERN']),
gpData.blockchain.withDividend($scope.formData.currency, { gpData.blockchain.withDividend($scope.formData.currency, {
from: from, from: from,
size: size size: size
...@@ -146,56 +150,51 @@ function GpCurrencyMonetaryMassController($scope, $controller, $q, $state, $tran ...@@ -146,56 +150,51 @@ function GpCurrencyMonetaryMassController($scope, $controller, $q, $state, $tran
if (!result || !result.times) return; if (!result || !result.times) return;
$scope.times = result.times; $scope.times = result.times;
// Choose a date formatter, depending on the blocks period // Compute the date pattern, depending on the blocks period
var blocksPeriod = result.times[result.times.length-1] - result.times[0]; var blocksPeriod = result.times[result.times.length-1] - result.times[0];
var formatDate; var datePattern = (blocksPeriod < 31557600/* less than 1 year */) ?
if (blocksPeriod < 31557600/* less than 1 year */) { translations['COMMON.DATE_SHORT_PATTERN'] : translations['COMMON.DATE_MONTH_YEAR_PATTERN'];
formatDate = $filter('medianDateShort');
}
else {
formatDate = $filter('formatDateMonth'); //see #683
}
var formatAmount = $filter('formatDecimal'); var formatAmount = $filter('formatDecimal');
$scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, $scope.formData.useRelative); $scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, $scope.formData.useRelative);
// Data: relative // Data: relative
var data = []; var data = [];
if($scope.formData.useRelative) { if ($scope.formData.useRelative) {
// M/N // M/N
data.push( data.push(
result.blocks.reduce(function(res, block) { _.map(result.blocks, function(block) {
return res.concat(truncAmount(block.monetaryMass / block.dividend / block.membersCount)); return truncAmount(block.monetaryMass / block.dividend / block.membersCount);
}, [])); }));
// Mass // Mass
data.push( data.push(
result.blocks.reduce(function(res, block) { _.map(result.blocks, function(block) {
return res.concat(truncAmount(block.monetaryMass / block.dividend)); return truncAmount(block.monetaryMass / block.dividend);
}, [])); }));
} }
// Data: quantitative // Data: quantitative
else { else {
// M/N // M/N
data.push( data.push(
result.blocks.reduce(function(res, block) { _.map(result.blocks, function(block) {
return res.concat(truncAmount(block.monetaryMass / block.membersCount / 100)); return truncAmount(block.monetaryMass / block.membersCount / 100);
}, [])); }));
// Mass // Mass
data.push( data.push(
result.blocks.reduce(function(res, block) { _.map(result.blocks, function(block) {
return res.concat(block.monetaryMass / 100); return block.monetaryMass / 100;
}, [])); }));
} }
$scope.data = data; $scope.data = data;
// Labels // Labels
$scope.labels = result.times.reduce(function(res, time) { $scope.labels = _.map(result.times, function(time) {
return res.concat(formatDate(time)); return moment.unix(time).local().format(datePattern);
}, []); });
// Colors // Colors
$scope.colors = gpColor.scale.fix(result.times.length); $scope.colors = gpColor.scale.fix(result.times.length);
...@@ -327,7 +326,9 @@ function GpCurrencyDUController($scope, $q, $controller, $translate, gpColor, gp ...@@ -327,7 +326,9 @@ function GpCurrencyDUController($scope, $q, $controller, $translate, gpColor, gp
return $q.all([ return $q.all([
$translate([ $translate([
'GRAPH.CURRENCY.UD_TITLE', 'GRAPH.CURRENCY.UD_TITLE',
'COMMON.UNIVERSAL_DIVIDEND']), 'COMMON.UNIVERSAL_DIVIDEND',
'COMMON.DATE_SHORT_PATTERN',
'COMMON.DATE_MONTH_YEAR_PATTERN']),
gpData.blockchain.withDividend($scope.formData.currency, { gpData.blockchain.withDividend($scope.formData.currency, {
from: from, from: from,
size: size size: size
...@@ -341,28 +342,23 @@ function GpCurrencyDUController($scope, $q, $controller, $translate, gpColor, gp ...@@ -341,28 +342,23 @@ function GpCurrencyDUController($scope, $q, $controller, $translate, gpColor, gp
// Choose a date formatter, depending on the blocks period // Choose a date formatter, depending on the blocks period
var blocksPeriod = result.times[result.times.length-1] - result.times[0]; var blocksPeriod = result.times[result.times.length-1] - result.times[0];
var dateFilter; var datePattern = (blocksPeriod < 31557600/* less than 1 year */) ?
if (blocksPeriod < 31557600/* less than 1 year */) { translations['COMMON.DATE_SHORT_PATTERN'] : translations['COMMON.DATE_MONTH_YEAR_PATTERN'];
dateFilter = $filter('medianDateShort');
}
else {
dateFilter = $filter('formatDateMonth');
}
var formatAmount = $filter('formatDecimal'); var formatAmount = $filter('formatDecimal');
$scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, false); $scope.currencySymbol = $filter('currencySymbolNoHtml')($scope.formData.currency, false);
// Data // Data
$scope.data = [ $scope.data = [
result.blocks.reduce(function(res, block) { _.map(result.blocks, function(block) {
return res.concat(block.dividend / 100); return block.dividend / 100;
}, []) })
]; ];
// Labels // Labels
$scope.labels = result.times.reduce(function(res, time) { $scope.labels = _.map(result.times, function(time) {
return res.concat(dateFilter(time)); return moment.unix(time).local().format(datePattern);
}, []); });
// Colors // Colors
$scope.colors = result.blocks.reduce(function(res) { $scope.colors = result.blocks.reduce(function(res) {
...@@ -453,7 +449,11 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran ...@@ -453,7 +449,11 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran
size = size || 10000; size = size || 10000;
return $q.all([ return $q.all([
$translate(['GRAPH.CURRENCY.MEMBERS_COUNT_TITLE', 'GRAPH.CURRENCY.MEMBERS_COUNT_LABEL']), $translate(['GRAPH.CURRENCY.MEMBERS_COUNT_TITLE',
'GRAPH.CURRENCY.MEMBERS_COUNT_LABEL',
'COMMON.DATE_SHORT_PATTERN',
'COMMON.DATE_MONTH_YEAR_PATTERN'
]),
gpData.blockchain.withDividend($scope.formData.currency, { gpData.blockchain.withDividend($scope.formData.currency, {
from: from, from: from,
size: size, size: size,
...@@ -469,18 +469,18 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran ...@@ -469,18 +469,18 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran
// Choose a date formatter, depending on the blocks period // Choose a date formatter, depending on the blocks period
var blocksPeriod = result.times[result.blocks.length-1] - result.times[0]; var blocksPeriod = result.times[result.blocks.length-1] - result.times[0];
var dateFilter; var datePattern = (blocksPeriod < 31557600/* less than 1 year */) ?
if (blocksPeriod < 31557600/* less than 1 year*/) { translations['COMMON.DATE_SHORT_PATTERN'] : translations['COMMON.DATE_MONTH_YEAR_PATTERN'];
dateFilter = $filter('medianDateShort');
}
else {
dateFilter = $filter('formatDateMonth');
}
// Format time // Data
$scope.labels = result.times.reduce(function(res, time) { $scope.data = [
return res.concat(dateFilter(time)); _.pluck(result.blocks, 'membersCount')
}, []); ];
// Labels
$scope.labels = _.map(result.times, function(time) {
return moment.unix(time).local().format(datePattern);
});
// Members count graph: ------------------------- // Members count graph: -------------------------
$scope.options = { $scope.options = {
...@@ -512,12 +512,6 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran ...@@ -512,12 +512,6 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran
pointHoverRadius: 3 pointHoverRadius: 3
}]; }];
// Data
$scope.data = [
result.blocks.reduce(function(res, block) {
return res.concat(block.membersCount);
}, [])
];
// Colors // Colors
$scope.colors = gpColor.scale.fix(result.blocks.length); $scope.colors = gpColor.scale.fix(result.blocks.length);
...@@ -539,3 +533,123 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran ...@@ -539,3 +533,123 @@ function GpCurrencyMembersCountController($scope, $controller, $q, $state, $tran
} }
function GpCurrencyPendingCountController($scope, $controller, $q, $state, $translate, gpColor, esHttp) {
'ngInject';
// Initialize the super class and extend it.
angular.extend(this, $controller('GpDocStatsCtrl', {$scope: $scope}));
$scope.chartIdPrefix = 'currency-chart-pending-';
$scope.init = function(e, state) {
var currency = $scope.formData.currency;
if (!currency) throw Error('Missing formData.currency!');
$scope.formData.index = currency;
$scope.formData.types = ['member', 'pending'];
$scope.charts = [
// Pending delta
{
id: currency + '_member_delta',
title: 'GRAPH.CURRENCY.MEMBERS_DELTA_TITLE',
series: [
{
key: currency + '_is_member_delta',
label: 'GRAPH.CURRENCY.IS_MEMBER_DELTA_LABEL',
type: 'bar',
yAxisID: 'y-axis-delta',
color: gpColor.rgba.calm(),
pointHoverBackgroundColor: gpColor.rgba.calm(),
},
{
key: currency + '_was_member_delta',
label: 'GRAPH.CURRENCY.WAS_MEMBER_DELTA_LABEL',
type: 'bar',
yAxisID: 'y-axis-delta',
color: gpColor.rgba.assertive(0.7),
pointHoverBackgroundColor: gpColor.rgba.assertive(),
},
{
key: currency + '_pending_delta',
label: 'GRAPH.CURRENCY.PENDING_DELTA_LABEL',
type: 'line',
yAxisID: 'y-axis-delta',
color: gpColor.rgba.gray(0.5),
pointHoverBackgroundColor: gpColor.rgba.gray()
}
]
}];
$scope.formData.queryNames = $scope.charts.reduce(function(res, chart){
return chart.series.reduce(function(res, serie) {
var queryName = serie.key.replace(/_delta$/, '');
return res.concat(queryName);
}, res);
}, []);
};
var inheritedLoad = $scope.load;
$scope.load = function() {
// Call inherited load
return inheritedLoad()
.then(function() {
var chart = $scope.charts[0];
// Compute wasMember serie, using the is_member
if (chart.data[1]) {
chart.data[1] = _.map(chart.data[0], function(value) {
return value < 0 ? value : undefined;
});
}
chart.data[0] = _.map(chart.data[0], function(value) {
return value >= 0 ? value : undefined;
});
$scope.chart = chart;
});
};
$scope.onChartClick = function(data, e, item) {
if (!item) return;
var from = $scope.times[item._index];
var to = moment.unix(from).utc().add(1, $scope.formData.rangeDuration).unix();
var blockRequest = esHttp.get('/{0}/block/_search?pretty'.format($scope.formData.currency));
// Get block min/max
return $q.all([
// Get first (min) block
blockRequest({
q: 'time:>={0} AND time:<={1}'.format(from, to),
sort: 'number:asc',
size: 1,
_source: ['number']
}),
// Get last (max) block
blockRequest({
q: 'time:>={0} AND time:<={1}'.format(from, to),
sort: 'number:desc',
size: 1,
_source: ['number']
})
])
.then(function(res) {
var minBlockHit = res[0] && res[0].hits && res[0].hits.hits && res[0].hits.hits[0];
var maxBlockHit = res[1] && res[1].hits && res[1].hits.hits && res[1].hits.hits[0];
var minBlockNumber = minBlockHit ? minBlockHit._source.number : undefined;
var maxBlockNumber = maxBlockHit ? maxBlockHit._source.number : undefined;
return $state.go('app.document_search', {
index: $scope.formData.currency,
type: 'pending',
q: 'blockNumber:>={0} AND blockNumber:<{1}'.format(minBlockNumber, maxBlockNumber)
});
})
};
}
...@@ -262,6 +262,9 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol ...@@ -262,6 +262,9 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
}; };
$scope.load = function(updateTimePct) { $scope.load = function(updateTimePct) {
updateTimePct = angular.isDefined(updateTimePct) ? updateTimePct : true;
console.debug("[graph] Loading docstats data...");
return $q.all([ return $q.all([
// Get i18n keys (chart title, series labels, date patterns) // Get i18n keys (chart title, series labels, date patterns)
......
...@@ -54,12 +54,25 @@ angular.module('cesium.graph.network.controllers', ['chart.js', 'cesium.graph.se ...@@ -54,12 +54,25 @@ angular.module('cesium.graph.network.controllers', ['chart.js', 'cesium.graph.se
controller: 'GpBlockchainTxCountCtrl' controller: 'GpBlockchainTxCountCtrl'
} }
} }
})
.state('app.network_stats', {
url: "/network/stats?stepUnit&t&hide&scale",
views: {
'menuContent': {
templateUrl: "plugins/graph/templates/network/view_stats.html",
controller: 'GpNetworkStatsCtrl'
}
}
}); });
} }
}) })
.controller('GpPeerViewExtendCtrl', GpPeerViewExtendController) .controller('GpPeerViewExtendCtrl', GpPeerViewExtendController)
.controller('GpNetworkStatsCtrl', GpNetworkStatsController)
; ;
function GpPeerViewExtendController($scope, $timeout, PluginService, esSettings, csCurrency, gpData) { function GpPeerViewExtendController($scope, $timeout, PluginService, esSettings, csCurrency, gpData) {
...@@ -117,3 +130,133 @@ function GpPeerViewExtendController($scope, $timeout, PluginService, esSettings, ...@@ -117,3 +130,133 @@ function GpPeerViewExtendController($scope, $timeout, PluginService, esSettings,
}); });
}; };
} }
function GpNetworkStatsController($scope, $controller, $q, $state, $translate, gpColor, esHttp) {
'ngInject';
// Initialize the super class and extend it.
angular.extend(this, $controller('GpDocStatsCtrl', {$scope: $scope}));
$scope.chartIdPrefix = 'network-chart-stats-';
$scope.apis = [
{
name: 'BASIC_MERKLED_API',
color: gpColor.rgba.calm()
},
{
name: 'BMAS',
color: gpColor.rgba.calm()
},
{
name: 'BMATOR',
color: gpColor.rgba.calm()
},
{
name: 'WS2P',
color: gpColor.rgba.balanced()
},
{
name: 'GVA',
color: gpColor.rgba.energized()
},
{
name: 'GVASUB',
color: gpColor.rgba.energized()
}
];
var inheritedInit = $scope.init;
$scope.init = function(e, state) {
var currency = $scope.formData.currency;
if (!currency) throw Error('Missing formData.currency!');
inheritedInit(e, state);
if (state && state.stateParams) {
}
$scope.formData.index = currency;
$scope.formData.types = ['peer'];
$scope.charts = [
// Count by api
{
id: currency + '_peer',
title: 'GRAPH.NETWORK.ENDPOINT_COUNT_TITLE',
series: _.map($scope.apis, function (api) {
return {
key: currency + '_peer_' + api.name.toLowerCase(),
label: api.name,
color: api.color,
pointHoverBackgroundColor: api.color,
};
})
},
// Delta by api
{
id: currency + '_peer_delta',
title: 'GRAPH.NETWORK.ENDPOINT_DELTA_TITLE',
series: _.map($scope.apis, function (api) {
return {
key: currency + '_peer_' + api.name.toLowerCase() + '_delta',
label: api.name,
type: 'line',
yAxisID: 'y-axis-delta',
color: api.color,
pointHoverBackgroundColor: api.color,
};
})
}
];
$scope.formData.queryNames = $scope.charts.reduce(function(res, chart){
return chart.series.reduce(function(res, serie) {
var queryName = serie.key.replace(/_delta$/, '');
return res.concat(queryName);
}, res);
}, []);
};
$scope.onChartClick = function(data, e, item) {
if (!item) return;
var from = $scope.times[item._index];
var to = moment.unix(from).utc().add(1, $scope.formData.rangeDuration).unix();
var blockRequest = esHttp.get('/{0}/block/_search?pretty'.format($scope.formData.currency));
// Get block min/max
return $q.all([
// Get first (min) block
blockRequest({
q: 'time:>={0} AND time:<={1}'.format(from, to),
sort: 'number:asc',
size: 1,
_source: ['number']
}),
// Get last (max) block
blockRequest({
q: 'time:>={0} AND time:<={1}'.format(from, to),
sort: 'number:desc',
size: 1,
_source: ['number']
})
])
.then(function(res) {
var minBlockHit = res[0] && res[0].hits && res[0].hits.hits && res[0].hits.hits[0];
var maxBlockHit = res[1] && res[1].hits && res[1].hits.hits && res[1].hits.hits[0];
var minBlockNumber = minBlockHit ? minBlockHit._source.number : undefined;
var maxBlockNumber = maxBlockHit ? maxBlockHit._source.number : undefined;
return $state.go('app.document_search', {
index: $scope.formData.currency,
type: 'peer',
q: 'blockNumber:>={0} AND blockNumber:<{1}'.format(minBlockNumber, maxBlockNumber)
});
})
};
}
...@@ -58,13 +58,13 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. ...@@ -58,13 +58,13 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es.
} }
function _initRangeOptions(options) { function _initRangeOptions(options) {
options = options || {}; options = angular.copy(options);
options.maxRangeSize = options.maxRangeSize || 30; options.maxRangeSize = options.maxRangeSize || 30;
options.defaultTotalRangeCount = options.defaultTotalRangeCount || options.maxRangeSize*2; options.defaultTotalRangeCount = options.defaultTotalRangeCount || options.maxRangeSize*2;
options.rangeDuration = options.rangeDuration || 'day'; options.rangeDuration = options.rangeDuration || 'day';
options.endTime = options.endTime || moment().utc().add(1, options.rangeDuration).unix(); options.endTime = angular.isDefined(options.endTime) ? options.endTime : moment().utc().add(1, options.rangeDuration).unix();
options.startTime = options.startTime || options.startTime = angular.isDefined(options.startTime) ? options.startTime :
moment.unix(options.endTime).utc().subtract(options.defaultTotalRangeCount, options.rangeDuration).unix(); moment.unix(options.endTime).utc().subtract(options.defaultTotalRangeCount, options.rangeDuration).unix();
// Make to sure startTime is never before the currency starts - fix #483 // Make to sure startTime is never before the currency starts - fix #483
if (options.firstBlockTime && options.startTime < options.firstBlockTime) { if (options.firstBlockTime && options.startTime < options.firstBlockTime) {
...@@ -73,12 +73,48 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. ...@@ -73,12 +73,48 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es.
return options; return options;
} }
function _getManyRanges(options) {
var from = moment.unix(options.startTime).utc().startOf(options.rangeDuration);
var to = moment.unix(options.endTime).utc().startOf(options.rangeDuration);
var result = [];
var ranges = [];
while (from.isBefore(to)) {
ranges.push({
from: from.unix(),
to: from.add(1, options.rangeDuration).unix()
});
// Flush if max range count, or just before loop condition end (fix #483)
var flush = (ranges.length === options.maxRangeSize) || !from.isBefore(to);
if (flush) {
result.push(ranges);
ranges = [];
}
}
if (ranges.length) {
result.push(ranges);
}
return result;
}
/** /**
* Graph: "blocks count by issuer" * Graph: "blocks count by issuer"
* @param currency * @param currency
* @returns {*} * @returns {*}
*/ */
exports.blockchain.countByIssuer = function(currency) { exports.blockchain.countByIssuer = function(currency, options) {
options = options || {};
var filters = [];
if (options.startTime > 0) {
// Round to hour, to be able to use cache
var startTime = Math.floor(options.startTime / 60 / 60 ) * 60 * 60;
filters.push({range: {time: {gte: startTime}}});
}
var request = { var request = {
size: 0, size: 0,
...@@ -92,7 +128,17 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. ...@@ -92,7 +128,17 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es.
} }
}; };
return exports.raw.block.search(request, {currency: currency}) if (filters.length) {
request.query = {bool: {}};
request.query.bool.filter = filters;
}
var params = {
currency: currency,
request_cache: angular.isDefined(options.cache) ? options.cache : true // enable by default
};
return exports.raw.block.search(request, params)
.then(function(res) { .then(function(res) {
var aggs = res.aggregations; var aggs = res.aggregations;
if (!aggs.blocksByIssuer || !aggs.blocksByIssuer.buckets || !aggs.blocksByIssuer.buckets.length) return; if (!aggs.blocksByIssuer || !aggs.blocksByIssuer.buckets || !aggs.blocksByIssuer.buckets.length) return;
...@@ -695,7 +741,6 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. ...@@ -695,7 +741,6 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es.
options = _initRangeOptions(options); options = _initRangeOptions(options);
var searchRequest = exports.raw.docstat.search;
if (options.server) { if (options.server) {
var serverParts = options.server.split(':'); var serverParts = options.server.split(':');
var host = serverParts[0]; var host = serverParts[0];
...@@ -703,96 +748,123 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. ...@@ -703,96 +748,123 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es.
searchRequest = rawLightInstance(host, port, options.useSsl).docstat.search; searchRequest = rawLightInstance(host, port, options.useSsl).docstat.search;
} }
var jobs = []; var filters = [];
if (options.index) {
var from = moment.unix(options.startTime).utc().startOf(options.rangeDuration); console.debug('[graph] filter on index:', options.index);
var to = moment.unix(options.endTime).utc().startOf(options.rangeDuration); filters.push({term : { index: options.index}});
var ranges = []; }
if (options.types) {
var processSearchResult = function (res) { console.debug('[graph] filter on types:', options.types);
var aggs = res.aggregations; filters.push({terms : { type: options.types}});
return (aggs.range && aggs.range.buckets || []).reduce(function (res, agg) { }
var item = { var request = {
from: agg.from, size: 0,
to: agg.to aggs: {
}; range: {
_.forEach(agg.index && agg.index.buckets || [], function (agg) { range: {
var index = agg.key; field: "time",
_.forEach(agg.type && agg.type.buckets || [], function (agg) { ranges: [] // Will be replace
var key = (index + '_' + agg.key); }
item[key] = agg.max.value; }
if (!indices[key]) indices[key] = true; }
});
});
return res.concat(item);
}, []);
}; };
while(from.isBefore(to)) {
ranges.push({ if (options.queryNames) {
from: from.unix(), console.debug('[graph] filter on queryNames:', options.queryNames);
to: from.add(1, options.rangeDuration).unix() filters.push({terms : { queryName: options.queryNames }});
}); request.aggs.range.aggs = {
queryName: {
// Flush if max range count, or just before loop condition end (fix #483) terms: {
var flush = (ranges.length === options.maxRangeSize) || !from.isBefore(to); field: "queryName",
if (flush) { size: 0
var request = { },
size: 0,
aggs: { aggs: {
range: { max: {
range: { max: {
field: "time", field: "count"
ranges: ranges }
}
}
}
};
}
else {
request.aggs.range.aggs = {
index: {
terms: {
field: "index",
size: 0
},
aggs: {
type: {
terms: {
field: "type",
size: 0
}, },
aggs: { aggs: {
index : { max: {
terms: { max: {
field: "index", field: "count"
size: 0
},
aggs: {
type: {
terms: {
field: "type",
size: 0
},
aggs: {
max: {
max: {
field : "count"
}
}
}
}
} }
} }
} }
} }
} }
}
};
}
}; // Add filter on request
if (filters.length > 0) {
request.query = request.query || {};
request.query.bool = request.query.bool || {};
request.query.bool.filter = filters;
}
// prepare next loop var params = {
ranges = []; request_cache: angular.isDefined(options.cache) ? options.cache : true // enable by default
var indices = {}; };
var params = {
request_cache: angular.isDefined(options.cache) ? options.cache : true // enable by default
};
if (jobs.length === 10) { var indices = {};
console.error('Too many parallel jobs!'); var processSearchResult = function (res) {
from = moment.unix(options.endTime).utc(); // stop while var aggs = res.aggregations;
return _.map(aggs.range && aggs.range.buckets || [], function (agg) {
var item = { from: agg.from, to: agg.to };
if (agg.queryName) {
_.forEach(agg.queryName && agg.queryName.buckets || [], function (agg) {
var key = agg.key;
item[key] = agg.max.value;
if (!indices[key]) indices[key] = true;
});
} }
else { else{
jobs.push( _.forEach(agg.index && agg.index.buckets || [], function (agg) {
searchRequest(request, params) var key = agg.key;
.then(processSearchResult) if (agg.max) {
); item[key] = agg.max.value;
if (!indices[key]) indices[key] = true;
} else {
_.forEach(agg.type && agg.type.buckets || [], function (agg) {
var typeKey = key + '_' + agg.key;
item[typeKey] = agg.max.value;
if (!indices[typeKey]) indices[typeKey] = true;
});
}
});
} }
} return item;
} // loop });
};
var jobs = _.map(_getManyRanges(options), function(ranges) {
var req = angular.copy(request);
req.aggs.range.range.ranges = ranges;
// Execute request
return exports.raw.docstat.search(req, params)
.then(processSearchResult);
});
return $q.all(jobs) return $q.all(jobs)
.then(function(res) { .then(function(res) {
......
...@@ -3,6 +3,16 @@ ...@@ -3,6 +3,16 @@
<!-- bar --> <!-- bar -->
<div class="col col-75"> <div class="col col-75">
<!-- graphs button bar -->
<div class="button-bar-inline "
style="top: 33px; margin-top:-33px; position: relative;">
<button
class="button button-stable button-clear no-padding-xs no-padding-sm pull-right"
ng-click="showPeriodPopover($event)">
<i class="icon ion-navicon-round"></i>
</button>
</div>
<canvas id="bar" class="chart-bar" <canvas id="bar" class="chart-bar"
height="{{height}}" width="{{width}}" height="{{height}}" width="{{width}}"
chart-data="data" chart-data="data"
......
...@@ -35,7 +35,10 @@ ...@@ -35,7 +35,10 @@
<!-- Blocks issuer --> <!-- Blocks issuer -->
<ng-controller ng-controller="GpBlockchainIssuersCtrl"> <ng-controller ng-controller="GpBlockchainIssuersCtrl">
<div class="item item-divider" ng-if="!loading" translate>GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_DIVIDER</div> <div class="item item-divider" ng-if="!loading">
<span translate>GRAPH.BLOCKCHAIN.BLOCKS_ISSUERS_DIVIDER</span>
<span ng-if="formData.maxAge">({{'GRAPH.COMMON.MAX_AGE.' + formData.maxAge | uppercase | translate | lowercase }})</span>
</div>
<div class="item no-padding-xs no-padding-sm" <div class="item no-padding-xs no-padding-sm"
ng-if="!loading" ng-if="!loading"
......
<ion-popover-view class="has-header popover-graph-period">
<ion-header-bar>
<h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1>
</ion-header-bar>
<ion-content scroll="false">
<div class="list item-text-wrap">
<!-- each durations -->
<a class="item item-icon-left ink"
ng-click="setMaxAge('day')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='day'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.DAY</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge('week')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='week'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.WEEK</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge('month')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='month'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.MONTH</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge('quarter')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='quarter'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.QUARTER</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge('semester')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='semester'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.SEMESTER</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge('year')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.maxAge==='year'"></i>
<span translate>GRAPH.COMMON.MAX_AGE.YEAR</span>
</a>
<a class="item item-icon-left ink"
ng-click="setMaxAge()">
<i class="icon ion-ios-checkmark-empty" ng-show="!formData.maxAge"></i>
<span translate>GRAPH.COMMON.MAX_AGE.FOREVER</span>
</a>
</div>
</ion-content>
</ion-popover-view>
<ion-popover-view class="has-header popover-graph-currency"> <ion-popover-view class="has-header popover-graph-range">
<ion-header-bar> <ion-header-bar>
<h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1> <h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1>
</ion-header-bar> </ion-header-bar>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<!-- scale --> <!-- scale -->
<a class="item item-icon-left ink" <a class="item item-icon-left ink"
ng-click="toggleScale()"> ng-click="toggleScale()">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.scale=='logarithmic'"></i> <i class="icon ion-ios-checkmark-empty" ng-show="formData.scale==='logarithmic'"></i>
<span ng-bind-html="'GRAPH.COMMON.LOGARITHMIC_SCALE' | translate"></span> <span ng-bind-html="'GRAPH.COMMON.LOGARITHMIC_SCALE' | translate"></span>
</a> </a>
...@@ -20,21 +20,21 @@ ...@@ -20,21 +20,21 @@
<!-- duration: hour --> <!-- duration: hour -->
<a class="item item-icon-left ink" <a class="item item-icon-left ink"
ng-click="setRangeDuration('hour')"> ng-click="setRangeDuration('hour')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration=='hour'"></i> <i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration==='hour'"></i>
<span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.HOUR' | translate"></span> <span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.HOUR' | translate"></span>
</a> </a>
<!-- duration: day --> <!-- duration: day -->
<a class="item item-icon-left ink" <a class="item item-icon-left ink"
ng-click="setRangeDuration('day')"> ng-click="setRangeDuration('day')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration=='day'"></i> <i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration==='day'"></i>
<span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.DAY' | translate"></span> <span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.DAY' | translate"></span>
</a> </a>
<!-- duration: month --> <!-- duration: month -->
<a class="item item-icon-left ink" <a class="item item-icon-left ink"
ng-click="setRangeDuration('month')"> ng-click="setRangeDuration('month')">
<i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration=='month'"></i> <i class="icon ion-ios-checkmark-empty" ng-show="formData.rangeDuration==='month'"></i>
<span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.MONTH' | translate"></span> <span ng-bind-html="'GRAPH.COMMON.RANGE_DURATION.MONTH' | translate"></span>
</a> </a>
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<div class="list"> <div class="list">
<div class="item" <div class="item"
ng-include="::'plugins/graph/templates/blockchain/graph_block_issuers.html'" ng-controller="GpBlockchainIssuersCtrl"
ng-controller="GpBlockchainIssuersCtrl" ng-include="::'plugins/graph/templates/blockchain/graph_block_issuers.html'"
ng-init="setSize(500,700,true)"> ng-init="setSize(500,700,true)">
</div> </div>
</div> </div>
......
...@@ -5,10 +5,19 @@ ...@@ -5,10 +5,19 @@
</div> </div>
<div class="list no-padding"> <div class="list no-padding">
<div class="item no-padding-top" <ng-controller ng-controller="GpCurrencyMembersCountCtrl" >
ng-include="::'plugins/graph/templates/currency/graph_members_count.html'" <div class="item no-padding-top"
ng-init="setSize(600,700,false)"> ng-include="::'plugins/graph/templates/currency/graph_members_count.html'"
</div> ng-init="setSize(600,700,false)">
</div>
</ng-controller>
<ng-controller ng-controller="GpCurrencyPendingCountCtrl" >
<div class="item"
ng-include="::'plugins/graph/templates/docstats/graph.html'"
ng-init="setSize(600,700,false)">
</div>
</ng-controller>
</div> </div>
</ion-content> </ion-content>
</ion-view> </ion-view>
<!-- section actual parameters --> <!-- section parameters -->
<ng-if ng-if=":state:enable && extensionPoint === 'parameters-actual'" > <ng-if ng-if=":state:enable && extensionPoint === 'parameters-actual'" >
<ng-if ng-if="!smallscreen"> <ng-if ng-if="!smallscreen">
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</div> </div>
</ng-if> </ng-if>
<!-- section Wot --> <!-- section Network -->
<ng-if ng-if=":state:enable && extensionPoint === 'network-actual'" > <ng-if ng-if=":state:enable && extensionPoint === 'network-actual'" >
<div class="item padding-left padding-right no-padding-xs no-padding-sm" <div class="item padding-left padding-right no-padding-xs no-padding-sm"
......
...@@ -45,12 +45,21 @@ ...@@ -45,12 +45,21 @@
<!-- Member count --> <!-- Member count -->
<ng-controller ng-controller="GpCurrencyMembersCountCtrl" > <ng-controller ng-controller="GpCurrencyMembersCountCtrl" >
<div class="item no-padding-xs" <div class="item no-padding-xs"
ng-if="!loading" ng-if="!loading"
ng-include="::'plugins/graph/templates/currency/graph_members_count.html'" ng-include="::'plugins/graph/templates/currency/graph_members_count.html'"
ng-init="setSize(250, 1000)"> ng-init="setSize(250, 1000)">
</div> </div>
</ng-controller>
<!-- Pending count -->
<ng-controller ng-controller="GpCurrencyPendingCountCtrl" >
<div class="item no-padding-xs"
ng-if="chart"
ng-include="::'plugins/graph/templates/docstats/graph.html'"
ng-init="setSize(250, 1000)">
</div>
</ng-controller>
</div> </div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment