From 855f8a034cc3c397e1c6b7a2254d9d07fba65f67 Mon Sep 17 00:00:00 2001 From: blavenie <benoit.lavenier@e-is.pro> Date: Tue, 3 Oct 2017 16:56:13 +0200 Subject: [PATCH] [enh] Add synchro execution stats --- www/index.html | 1 + www/plugins/graph/i18n/locale-fr-FR.json | 8 + .../js/controllers/common-controllers.js | 1 + .../js/controllers/docstats-controllers.js | 6 +- .../js/controllers/synchro-controllers.js | 187 ++++++++++++++++++ www/plugins/graph/js/plugin.js | 1 + .../graph/js/services/data-services.js | 114 +++++++++++ .../{graph_doc_stats.html => graph.html} | 0 .../templates/docstats/view_doc_stats_lg.html | 33 ---- .../graph/templates/docstats/view_stats.html | 26 +++ .../graph/templates/synchro/graph.html | 22 +++ .../graph/templates/synchro/view_stats.html | 25 +++ 12 files changed, 388 insertions(+), 36 deletions(-) create mode 100644 www/plugins/graph/js/controllers/synchro-controllers.js rename www/plugins/graph/templates/docstats/{graph_doc_stats.html => graph.html} (100%) delete mode 100644 www/plugins/graph/templates/docstats/view_doc_stats_lg.html create mode 100644 www/plugins/graph/templates/docstats/view_stats.html create mode 100644 www/plugins/graph/templates/synchro/graph.html create mode 100644 www/plugins/graph/templates/synchro/view_stats.html diff --git a/www/index.html b/www/index.html index 6d86e543e..f8d64a11f 100644 --- a/www/index.html +++ b/www/index.html @@ -200,6 +200,7 @@ <script src="dist/dist_js/plugins/graph/js/controllers/currency-controllers.js"></script> <script src="dist/dist_js/plugins/graph/js/controllers/account-controllers.js"></script> <script src="dist/dist_js/plugins/graph/js/controllers/docstats-controllers.js"></script> +<script src="dist/dist_js/plugins/graph/js/controllers/synchro-controllers.js"></script> <!--endRemoveIf(ubuntu)--> <!-- Map plugin --> diff --git a/www/plugins/graph/i18n/locale-fr-FR.json b/www/plugins/graph/i18n/locale-fr-FR.json index af9f18184..1501f1268 100644 --- a/www/plugins/graph/i18n/locale-fr-FR.json +++ b/www/plugins/graph/i18n/locale-fr-FR.json @@ -89,6 +89,14 @@ "TITLE": "Autres documents", "HISTORY_DELETE": "Suppressions de documents", } + }, + "SYNCHRO": { + "EXECUTION": { + "TITLE": "Synchronisation", + "INSERTS": "Insertions", + "UPDATES": "Mises à jour", + "DELETES": "Suppressions" + } } } } diff --git a/www/plugins/graph/js/controllers/common-controllers.js b/www/plugins/graph/js/controllers/common-controllers.js index 95fb03db8..1f7988182 100644 --- a/www/plugins/graph/js/controllers/common-controllers.js +++ b/www/plugins/graph/js/controllers/common-controllers.js @@ -72,6 +72,7 @@ function GpCurrencyAbstractController($scope, $filter, $ionicPopover, $ionicHist console.warn('[graph] currency.firstBlockTime not loaded ! Should have been loaded by currrency service!'); } $scope.formData.currencyAge = _truncDate(esHttp.date.now()) - $scope.formData.firstBlockTime; + return $scope.enter(e, state); }); } diff --git a/www/plugins/graph/js/controllers/docstats-controllers.js b/www/plugins/graph/js/controllers/docstats-controllers.js index f864345ab..d868d1101 100644 --- a/www/plugins/graph/js/controllers/docstats-controllers.js +++ b/www/plugins/graph/js/controllers/docstats-controllers.js @@ -9,7 +9,8 @@ angular.module('cesium.graph.docstats.controllers', ['chart.js', 'cesium.graph.s url: "/data/stats?stepUnit&t&hide&scale", views: { 'menuContent': { - templateUrl: "plugins/graph/templates/docstats/view_doc_stats_lg.html" + templateUrl: "plugins/graph/templates/docstats/view_stats.html", + controller: 'GpDocStatsCtrl' } } }); @@ -43,7 +44,7 @@ function GpDocStatsController($scope, $controller, $q, $translate, gpColor, gpDa key: 'user_profile', label: 'GRAPH.DOC_STATS.USER.USER_PROFILE', color: gpColor.rgba.royal(1), - pointHoverBackgroundColor: gpColor.rgba.gray(1) + pointHoverBackgroundColor: gpColor.rgba.royal(1) }, { key: 'user_settings', @@ -161,7 +162,6 @@ function GpDocStatsController($scope, $controller, $q, $translate, gpColor, gpDa $scope.load = function(updateTimePct) { - return $q.all([ // Get i18n keys (chart title, series labels, date patterns) $translate($scope.charts.reduce(function(res, chart) { diff --git a/www/plugins/graph/js/controllers/synchro-controllers.js b/www/plugins/graph/js/controllers/synchro-controllers.js new file mode 100644 index 000000000..580ce9d93 --- /dev/null +++ b/www/plugins/graph/js/controllers/synchro-controllers.js @@ -0,0 +1,187 @@ + +angular.module('cesium.graph.synchro.controllers', ['chart.js', 'cesium.graph.services', 'cesium.graph.common.controllers']) + + .config(function($stateProvider, PluginServiceProvider, csConfig) { + 'ngInject'; + + $stateProvider + .state('app.doc_synchro_lg', { + url: "/data/synchro?stepUnit&t&hide&scale", + views: { + 'menuContent': { + templateUrl: "plugins/graph/templates/synchro/view_stats.html", + controller: "GpSynchroCtrl" + } + } + }); + + var enable = csConfig.plugins && csConfig.plugins.es; + if (enable) { + // TODO: add buttons to link with doc stats + } + }) + + + .controller('GpSynchroCtrl', GpSynchroController) +; + +function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpData, $filter) { + 'ngInject'; + + // Initialize the super class and extend it. + angular.extend(this, $controller('GpCurrencyAbstractCtrl', {$scope: $scope})); + + $scope.hiddenDatasets = []; + + $scope.charts = [ + + // User count + { + id: 'user', + title: 'GRAPH.SYNCHRO.EXECUTION.TITLE', + series: [ + { + key: 'inserts', + label: 'GRAPH.SYNCHRO.EXECUTION.INSERTS', + color: gpColor.rgba.royal(1), + pointHoverBackgroundColor: gpColor.rgba.royal(1) + }, + { + key: 'updates', + label: 'GRAPH.SYNCHRO.EXECUTION.UPDATES', + color: gpColor.rgba.calm(1), + pointHoverBackgroundColor: gpColor.rgba.calm(1) + }, + { + key: 'deletes', + label: 'GRAPH.SYNCHRO.EXECUTION.DELETES', + color: gpColor.rgba.assertive(0.5), + pointHoverBackgroundColor: gpColor.rgba.assertive(1) + } + ] + } + ]; + + var formatInteger = $filter('formatInteger'); + + $scope.defaultChartOptions = { + responsive: true, + maintainAspectRatio: $scope.maintainAspectRatio, + title: { + display: true + }, + legend: { + display: true, + onClick: $scope.onLegendClick + }, + scales: { + yAxes: [ + { + stacked: true, + id: 'y-axis' + } + ] + }, + tooltips: { + enabled: true, + mode: 'index', + callbacks: { + label: function(tooltipItems, data) { + return data.datasets[tooltipItems.datasetIndex].label + + ': ' + formatInteger(tooltipItems.yLabel); + } + } + } + }; + + $scope.init = function(e, state) { + if (state && state.stateParams) { + // Manage URL parameters + } + }; + + $scope.load = function(updateTimePct) { + + return $q.all([ + // Get i18n keys (chart title, series labels, date patterns) + $translate($scope.charts.reduce(function(res, chart) { + return res.concat(chart.series.reduce(function(res, serie) { + return res.concat(serie.label); + }, [chart.title])); + }, [ + 'COMMON.DATE_PATTERN', + 'COMMON.DATE_SHORT_PATTERN', + 'COMMON.DATE_MONTH_YEAR_PATTERN' + ])), + + // get Data + gpData.synchro.execution.get($scope.formData) + ]) + .then(function(result) { + var translations = result[0]; + var datePatterns = { + hour: translations['COMMON.DATE_PATTERN'], + day: translations['COMMON.DATE_SHORT_PATTERN'], + month: translations['COMMON.DATE_MONTH_YEAR_PATTERN'] + }; + + result = result[1]; + console.log("TODO", result); + if (!result || !result.times) return; // no data + $scope.times = result.times; + + // Labels + var labelPattern = datePatterns[$scope.formData.rangeDuration]; + $scope.labels = result.times.reduce(function(res, time) { + return res.concat(moment.unix(time).local().format(labelPattern)); + }, []); + + // Update range options with received values + $scope.updateRange(result.times[0], result.times[result.times.length-1], updateTimePct); + + $scope.setScale($scope.scale); + + // For each chart + _.forEach($scope.charts, function(chart){ + + // Data + chart.data = []; + _.forEach(chart.series, function(serie){ + chart.data.push(result[serie.key]||[]); + }); + + // Options (with title) + chart.options = angular.copy($scope.defaultChartOptions); + chart.options.title.text = translations[chart.title]; + + // Series datasets + chart.datasetOverride = chart.series.reduce(function(res, serie) { + return res.concat({ + yAxisID: 'y-axis', + type: 'bar', + label: translations[serie.label], + fill: true, + borderColor: serie.color, + borderWidth: 2, + backgroundColor: serie.color, + pointBackgroundColor: serie.color, + pointBorderColor: gpColor.rgba.white(), + pointHoverBackgroundColor: serie.pointHoverBackgroundColor||serie.color, + pointHoverBorderColor: gpColor.rgba.translucent(), + pointRadius: 3 + }); + }, []); + }); + }); + + }; + + $scope.onChartClick = function(data, e, item) { + if (!item) return; + console.log('Click on item index='+ item._index); + var from = $scope.times[item._index]; + var to = moment.unix(from).utc().add(1, $scope.formData.rangeDuration).unix(); + }; + + +} diff --git a/www/plugins/graph/js/plugin.js b/www/plugins/graph/js/plugin.js index d91d14b06..afb599035 100644 --- a/www/plugins/graph/js/plugin.js +++ b/www/plugins/graph/js/plugin.js @@ -9,5 +9,6 @@ angular.module('cesium.graph.plugin', [ 'cesium.graph.currency.controllers', 'cesium.graph.account.controllers', 'cesium.graph.docstats.controllers', + 'cesium.graph.synchro.controllers' ]) ; diff --git a/www/plugins/graph/js/services/data-services.js b/www/plugins/graph/js/services/data-services.js index c7f92796f..b9bfdfdfb 100644 --- a/www/plugins/graph/js/services/data-services.js +++ b/www/plugins/graph/js/services/data-services.js @@ -10,6 +10,9 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. wot: {}, blockchain: {}, docstat: {}, + synchro: { + execution: {} + }, raw: { block: { search: esHttp.post('/:currency/block/_search') @@ -25,6 +28,9 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. }, docstat: { search: esHttp.post('/docstat/record/_search') + }, + synchro: { + search: esHttp.post('/:currency/synchro/_search') } }, regex: { @@ -775,6 +781,114 @@ angular.module('cesium.graph.data.services', ['cesium.wot.services', 'cesium.es. }); }; + + /** + * Graph: "statictics on ES documents" + * @param currency + * @returns {*} + */ + exports.synchro.execution.get = function(options) { + + options = _initRangeOptions(options); + + var jobs = []; + + var from = moment.unix(options.startTime).utc().startOf(options.rangeDuration); + var to = moment.unix(options.endTime).utc().startOf(options.rangeDuration); + 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) { + var request = { + size: 0, + aggs: { + range: { + range: { + field: "time", + ranges: ranges + }, + aggs: { + result: { + nested: { + path: "result" + }, + aggs: { + inserts : { + sum: { + field : "result.inserts" + } + }, + updates : { + sum: { + field : "result.updates" + } + }, + deletes : { + sum: { + field : "result.deletes" + } + } + } + } + } + } + } + + }; + + // prepare next loop + ranges = []; + + if (jobs.length == 10) { + console.error('Too many parallel jobs!'); + from = moment.unix(options.endTime).utc(); // stop while + } + else { + jobs.push( + exports.raw.synchro.search(request, {currency: options.currency}) + .then(function (res) { + var aggs = res.aggregations; + + return (aggs.range && aggs.range.buckets || []).reduce(function (res, agg) { + return res.concat({ + from: agg.from, + to: agg.to, + inserts: agg.result.inserts.value, + updates: agg.result.inserts.value, + deletes: agg.result.deletes.value + }); + }, []); + }) + ); + } + } + } // loop + + return $q.all(jobs) + .then(function(res) { + res = res.reduce(function(res, hits){ + if (!hits || !hits.length) return res; + return res.concat(hits); + }, []); + + res = _.sortBy(res, 'from'); + + return { + times: _.pluck(res, 'from'), + inserts: _.pluck(res, 'inserts'), + updates: _.pluck(res, 'updates'), + deletes: _.pluck(res, 'deletes') + }; + }); + }; + return exports; }) diff --git a/www/plugins/graph/templates/docstats/graph_doc_stats.html b/www/plugins/graph/templates/docstats/graph.html similarity index 100% rename from www/plugins/graph/templates/docstats/graph_doc_stats.html rename to www/plugins/graph/templates/docstats/graph.html diff --git a/www/plugins/graph/templates/docstats/view_doc_stats_lg.html b/www/plugins/graph/templates/docstats/view_doc_stats_lg.html deleted file mode 100644 index e18218d7a..000000000 --- a/www/plugins/graph/templates/docstats/view_doc_stats_lg.html +++ /dev/null @@ -1,33 +0,0 @@ -<ion-view left-buttons="leftButtons" - cache-view="false"> - <ion-nav-title> - {{'GRAPH.DOC_STATS.TITLE' | translate}} - </ion-nav-title> - - <ion-content scroll="true" class="padding" > - - - - <div class="list" > - - <!-- Doc stat --> - <ng-controller ng-controller="GpDocStatsCtrl" > - - <div class="center padding" ng-if="loading"> - <ion-spinner icon="android"></ion-spinner> - </div> - - <div class="item no-padding-xs" ng-if="!loading" - ng-repeat="chart in charts" - ng-include="'plugins/graph/templates/docstats/graph_doc_stats.html'" - ng-init="setSize(250, 1000)"> - </div> - </ng-controller> - - - - </div> - - </ion-content> - -</ion-view> diff --git a/www/plugins/graph/templates/docstats/view_stats.html b/www/plugins/graph/templates/docstats/view_stats.html new file mode 100644 index 000000000..dfea0e947 --- /dev/null +++ b/www/plugins/graph/templates/docstats/view_stats.html @@ -0,0 +1,26 @@ +<ion-view left-buttons="leftButtons" + cache-view="false"> + <ion-nav-title> + {{'GRAPH.DOC_STATS.TITLE' | translate}} + </ion-nav-title> + + <ion-content scroll="true" class="padding" > + + <div class="list" > + + <!-- Doc stat --> + <div class="center padding" ng-if="loading"> + <ion-spinner icon="android"></ion-spinner> + </div> + + <div class="item no-padding-xs" ng-if="!loading" + ng-repeat="chart in charts" + ng-include="'plugins/graph/templates/docstats/graph.html'" + ng-init="setSize(250, 1000)"> + </div> + + </div> + + </ion-content> + +</ion-view> diff --git a/www/plugins/graph/templates/synchro/graph.html b/www/plugins/graph/templates/synchro/graph.html new file mode 100644 index 000000000..19ac3b723 --- /dev/null +++ b/www/plugins/graph/templates/synchro/graph.html @@ -0,0 +1,22 @@ + + <!-- 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 pull-right" + ng-click="showActionsPopover($event)"> + <i class="icon ion-navicon-round"></i> + </button> + </div> + + <canvas id="synchro-chart-{{chart.id}}" + class="chart-bar" + height="{{height}}" + width="{{width}}" + chart-data="chart.data" + chart-labels="labels" + chart-dataset-override="chart.datasetOverride" + chart-options="chart.options"> + </canvas> + + <ng-include src="'plugins/graph/templates/common/graph_range_bar.html'"></ng-include> diff --git a/www/plugins/graph/templates/synchro/view_stats.html b/www/plugins/graph/templates/synchro/view_stats.html new file mode 100644 index 000000000..ec7f0ad31 --- /dev/null +++ b/www/plugins/graph/templates/synchro/view_stats.html @@ -0,0 +1,25 @@ +<ion-view left-buttons="leftButtons" + cache-view="false"> + <ion-nav-title> + {{'GRAPH.DOC_STATS.TITLE' | translate}} + </ion-nav-title> + + <ion-content scroll="true" class="padding" > + + <div class="list" > + + <div class="center padding" ng-if="loading"> + <ion-spinner icon="android"></ion-spinner> + </div> + + <div class="item no-padding-xs" ng-if="!loading" + ng-repeat="chart in charts" + ng-include="'plugins/graph/templates/synchro/graph.html'" + ng-init="setSize(250, 1000)"> + </div> + + </div> + + </ion-content> + +</ion-view> -- GitLab