From 119c46980d5f2f3795e7bdf7faaad51a20748ce6 Mon Sep 17 00:00:00 2001
From: ArnaudCerisier <arnaud.cerisier@gmail.com>
Date: Tue, 30 May 2017 18:33:54 +0200
Subject: [PATCH] [fix] Evolution of the search in the network tab

---
 www/plugins/es/i18n/locale-en-GB.json         | 10 ++-
 www/plugins/es/i18n/locale-en.json            | 10 ++-
 www/plugins/es/i18n/locale-es-ES.json         | 10 ++-
 www/plugins/es/i18n/locale-fr-FR.json         | 10 ++-
 www/plugins/es/i18n/locale-nl-NL.json         |  4 ++
 .../js/controllers/blockchain-controllers.js  | 38 ++++++++++-
 .../es/js/services/blockchain-services.js     | 39 ++++++++++++
 .../es/templates/blockchain/lookup_form.html  | 63 ++++++++++++++-----
 8 files changed, 160 insertions(+), 24 deletions(-)

diff --git a/www/plugins/es/i18n/locale-en-GB.json b/www/plugins/es/i18n/locale-en-GB.json
index 9f0e6c25..72e4f937 100644
--- a/www/plugins/es/i18n/locale-en-GB.json
+++ b/www/plugins/es/i18n/locale-en-GB.json
@@ -185,7 +185,15 @@
       "HEADER_MEDIAN_TIME": "Date / Time",
       "HEADER_BLOCK": "Block #",
       "HEADER_ISSUER": "Peer owner",
-      "BTN_LAST": "Last blocks"
+      "BTN_LAST": "Last blocks",
+      "DISPLAY_QUERY": "View query",
+      "HIDE_QUERY": "Hide query",
+      "TX_SEARCH_FILTER": {
+        "MEMBER_FLOWS": "Members inputs/outputs",
+        "EXISTING_TRANSACTION": "With transactions",
+        "PERIOD": "Calculated between the {{params[2]|formatDate}} and the {{params[4]|formatDate}}",
+        "PUBKEY": "Calculated by {{params[1]|formatPubkey}}"
+      }
     },
     "ERROR": {
       "SEARCH_BLOCKS_FAILED": "Error while searching blocks."
diff --git a/www/plugins/es/i18n/locale-en.json b/www/plugins/es/i18n/locale-en.json
index 9f0e6c25..9978a43a 100644
--- a/www/plugins/es/i18n/locale-en.json
+++ b/www/plugins/es/i18n/locale-en.json
@@ -185,7 +185,15 @@
       "HEADER_MEDIAN_TIME": "Date / Time",
       "HEADER_BLOCK": "Block #",
       "HEADER_ISSUER": "Peer owner",
-      "BTN_LAST": "Last blocks"
+      "BTN_LAST": "Last blocks",
+      "DISPLAY_QUERY": "View query",
+      "HIDE_QUERY": "Hide query",
+      "TX_SEARCH_FILTER": {
+        "MEMBER_FLOWS": "Members Input/Output",
+        "EXISTING_TRANSACTION": "Existing transactions",
+        "PERIOD": "Calculated between the {{params[2]|formatDate}} and the {{params[4]|formatDate}}",
+        "PUBKEY": "Calculated by {{params[1]|formatPubkey}}"
+      }
     },
     "ERROR": {
       "SEARCH_BLOCKS_FAILED": "Error while searching blocks."
diff --git a/www/plugins/es/i18n/locale-es-ES.json b/www/plugins/es/i18n/locale-es-ES.json
index 95a8345f..c0034111 100644
--- a/www/plugins/es/i18n/locale-es-ES.json
+++ b/www/plugins/es/i18n/locale-es-ES.json
@@ -185,7 +185,15 @@
       "HEADER_MEDIAN_TIME": "Fecha / Hora",
       "HEADER_BLOCK": "Bloque #",
       "HEADER_ISSUER": "Nodo emisor",
-      "BTN_LAST": "últimos bloques"
+      "BTN_LAST": "últimos bloques",
+      "DISPLAY_QUERY": "Mostrar la consulta",
+      "HIDE_QUERY": "Ocultar la consulta",
+      "TX_SEARCH_FILTER": {
+        "MEMBER_FLOWS": "Entradas/salidas de miembros",
+        "EXISTING_TRANSACTION": "Con transacciones",
+        "PERIOD": "Calculado entre el {{params[2]|formatDate}} y el {{params[4]|formatDate}}",
+        "PUBKEY": "Calculado por {{params[1]|formatPubkey}}"
+      }
     },
     "ERROR": {
       "SEARCH_BLOCKS_FAILED": "Fracaso en la búsqueda de los bloques."
diff --git a/www/plugins/es/i18n/locale-fr-FR.json b/www/plugins/es/i18n/locale-fr-FR.json
index 8db45044..0cfa3e37 100644
--- a/www/plugins/es/i18n/locale-fr-FR.json
+++ b/www/plugins/es/i18n/locale-fr-FR.json
@@ -185,7 +185,15 @@
       "HEADER_MEDIAN_TIME": "Date / Heure",
       "HEADER_BLOCK": "Bloc #",
       "HEADER_ISSUER": "Noeud émetteur",
-      "BTN_LAST": "Derniers blocs"
+      "BTN_LAST": "Derniers blocs",
+      "DISPLAY_QUERY": "Afficher la requête",
+      "HIDE_QUERY": "Masquer la requête",
+      "TX_SEARCH_FILTER": {
+        "MEMBER_FLOWS": "Entrées/sorties de membres",
+        "EXISTING_TRANSACTION": "Avec transactions",
+        "PERIOD": "Calculés entre le {{params[2]|formatDate}} et le {{params[4]|formatDate}}",
+        "PUBKEY": "Calculé par {{params[1]|formatPubkey}}"
+      }
     },
     "ERROR": {
       "SEARCH_BLOCKS_FAILED": "Erreur de la recherche des blocs."
diff --git a/www/plugins/es/i18n/locale-nl-NL.json b/www/plugins/es/i18n/locale-nl-NL.json
index 009ee496..39e922a9 100644
--- a/www/plugins/es/i18n/locale-nl-NL.json
+++ b/www/plugins/es/i18n/locale-nl-NL.json
@@ -174,6 +174,10 @@
       "RECORD_REMOVED" : "Advertentie succesvol verwijderd"
     }
   },
+  "TX_SEARCH": {
+    "PERIOD": "Transacties tussen de {{date.startDate|formatDate}} en {{date.endDate|formatDate}}",
+    "PUBKEY": "Public key : {{pubkey|formatPubkey}}"
+  },
   "REGISTRY": {
     "CATEGORY": "Hoofdactiviteit",
     "GENERAL_DIVIDER": "Basisinformatie",
diff --git a/www/plugins/es/js/controllers/blockchain-controllers.js b/www/plugins/es/js/controllers/blockchain-controllers.js
index eca785a9..5d483ae8 100644
--- a/www/plugins/es/js/controllers/blockchain-controllers.js
+++ b/www/plugins/es/js/controllers/blockchain-controllers.js
@@ -47,11 +47,13 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
   $scope.enableFilter = true;
 
   $scope.doSearchText = function() {
-    if (!$scope.search.text || $scope.search.text.trim().length === 0) {
+    if ((!$scope.search.text || !$scope.search.text.trim().length) &&
+      (!$scope.search.filters || !$scope.search.filters.length) ) {
       return $scope.doSearchLast();
     }
 
     $scope.search.type = 'text';
+
     $scope.doSearch();
 
     $ionicHistory.nextViewOptions({
@@ -59,7 +61,7 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
       disableBack: true,
       historyRoot: true
     });
-    $state.go('app.blockchain_search', {q: $scope.search.text}, {
+    $state.go('app.blockchain_search', {q: $scope.search.query}, {
       reload: false,
       inherit: true,
       notify: false});
@@ -83,6 +85,7 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
       notify: false});
   };
 
+
   // This method override the base class method
   $scope.doSearch = function(from) {
     from = angular.isDefined(from) ? from : 0;
@@ -107,12 +110,26 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
         };
       }
       request.excludeCurrent = (from === 0);
+
       promise = esBlockchain.block.search($scope.currency, request);
     }
 
     // Full text search
     else if ($scope.search.type == 'text') {
 
+      // Parse text search into filters array
+      var res = esBlockchain.block.parseSearchText($scope.search.text, $scope.search.filters);
+      $scope.search.filters = res.filters;
+      var query = $scope.search.filters.reduce(function(query, filter){
+        return query + ' AND ' + filter.text;
+      }, '');
+      if (res.text.length) {
+        query += ' AND ' + res.text;
+      }
+
+      $scope.search.query = query.substr(5);
+      $scope.search.text = res.text;
+
       request.from = from;
 
       // add sort
@@ -123,7 +140,8 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
         request.sort = "number:desc";
       }
       request.excludeCurrent = true;
-      promise = esBlockchain.block.searchText($scope.currency, $scope.search.text, request);
+
+      promise = esBlockchain.block.searchText($scope.currency, $scope.search.query, request);
     }
 
     var time = new Date().getTime();
@@ -191,5 +209,19 @@ function ESBlockLookupController($scope, $state, $controller, $ionicPopover, UIU
       $scope.actionsPopover.hide();
     }
   };
+
+  /* -- manage click -- */
+
+
+  // Cancel search filter
+  $scope.itemRemove = function(index) {
+    $scope.search.filters.splice(index, 1);
+    $scope.doSearchText();
+  };
+
+  //Show the query
+  $scope.toggleShowQuery = function() {
+    $scope.showQuery = !$scope.showQuery;
+  };
 }
 
diff --git a/www/plugins/es/js/services/blockchain-services.js b/www/plugins/es/js/services/blockchain-services.js
index 26ef53bb..81dcb238 100644
--- a/www/plugins/es/js/services/blockchain-services.js
+++ b/www/plugins/es/js/services/blockchain-services.js
@@ -10,6 +10,15 @@ angular.module('cesium.es.blockchain.services', ['cesium.services', 'cesium.es.h
         DEFAULT_SEARCH_SIZE: 40,
         ES_CORE_API_ENDPOINT: 'ES_CORE_API( ([a-z_][a-z0-9-_.]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))'
       },
+      REGEXPS = {
+        SEARCH_FILTER: {
+          MEMBER_FLOWS: /\(_exists_:joiners OR _exists_:leavers OR _exists_:revoked OR _exists_:excluded\)([ ]+AND)?/,
+          EXISTING_TRANSACTION: /_exists_:transactions([ ]+AND)?/,
+          PERIOD: /medianTime:>(=)?([0-9]+)[ ]+AND[ ]+medianTime:<(=)?([0-9]+)([ ]+AND)?/,
+          PUBKEY: /issuer:([a-zA-Z0-9]+)([ ]+AND)?/
+        },
+        LAST_AND: /[ ]+AND$/
+      },
       FIELDS = {
         MINIMAL: ['number', 'hash', 'medianTime', 'issuer'],
         COMMONS: ['number', 'hash', 'medianTime', 'issuer', 'currency', 'version', 'powMin', 'dividend', 'membersCount', 'identities', 'joiners', 'actives', 'leavers', 'revoked', 'excluded', 'certifications', 'transactions']
@@ -116,9 +125,39 @@ angular.module('cesium.es.blockchain.services', ['cesium.services', 'cesium.es.h
         });
     };
 
+    exports.block.parseSearchText = function(text, filters) {
+
+      var unparsedText = text;
+      filters = _.keys(REGEXPS.SEARCH_FILTER).reduce(function(res, filterType){
+        var matches = REGEXPS.SEARCH_FILTER[filterType].exec(unparsedText);
+        if (matches) {
+          var filterText = matches[0];
+
+          // update rest
+          unparsedText = unparsedText.replace(filterText, '');
+
+          filterText = filterText.replace(REGEXPS.LAST_AND, '');
+
+          var filter = {
+            type: filterType,
+            text: filterText,
+            params: matches
+          };
+          return res.concat(filter);
+        }
+        return res;
+      }, filters||[]);
+
+      return {
+        filters: filters,
+        text: unparsedText.trim()
+      };
+    };
+
     return exports;
   }
 
+
   return EsBlockchain();
 })
 ;
diff --git a/www/plugins/es/templates/blockchain/lookup_form.html b/www/plugins/es/templates/blockchain/lookup_form.html
index 835b9828..03ee2fe5 100644
--- a/www/plugins/es/templates/blockchain/lookup_form.html
+++ b/www/plugins/es/templates/blockchain/lookup_form.html
@@ -1,24 +1,35 @@
 <div class="lookupForm">
 
-  <!-- search text-->
-  <label class="item item-input">
-    <i class="icon ion-search placeholder-icon"></i>
-    <input type="text"
-           class="visible-xs visible-sm"
-           placeholder="{{'BLOCKCHAIN.LOOKUP.SEARCH_HELP'|translate}}"
-           ng-model="search.text"
-           ng-model-options="{ debounce: 650 }"
-           ng-change="doSearchText()">
-    <input type="text"
-           class="hidden-xs hidden-sm"
-           id="{{searchTextId}}" placeholder="{{'BLOCKCHAIN.LOOKUP.SEARCH_HELP'|translate}}"
-           ng-model="search.text"
-           on-return="doSearchText()">
-    <div class="helptip-anchor-center">
-      <a id="helptip-blockchain-search-text"></a>
+
+  <div class="item no-padding">
+
+    <div class="button button-small button-text button-stable button-icon-event padding no-padding-right ink"
+         ng-repeat="filter in search.filters" ng-if="filter">
+      <span>{{'BLOCKCHAIN.LOOKUP.TX_SEARCH_FILTER.'+filter.type|translate:filter}}</span>
+      <i class="icon ion-close" ng-click="itemRemove($index)"></i>
+
     </div>
 
-  </label>
+    <label class="item-input">
+      <i class="icon ion-search placeholder-icon"></i>
+      <input type="text"
+             class="visible-xs visible-sm"
+             placeholder="{{'BLOCKCHAIN.LOOKUP.SEARCH_HELP'|translate}}"
+             ng-model="search.text"
+             ng-model-options="{ debounce: 650 }"
+             ng-change="doSearchText()">
+      <input type="text"
+             class="hidden-xs hidden-sm"
+             id="{{searchTextId}}" placeholder="{{'BLOCKCHAIN.LOOKUP.SEARCH_HELP'|translate}}"
+             ng-model="search.text"
+             on-return="doSearchText()">
+      <div class="helptip-anchor-center">
+        <a id="helptip-blockchain-search-text"></a>
+      </div>
+
+    </label>
+  </div>
+
 
   <div class="padding-top padding-xs" style="display: block; height: 60px;">
     <div class="pull-left">
@@ -34,6 +45,18 @@
         <small class="gray" ng-if=":rebind:search.took && expertMode">
           - {{:rebind:'COMMON.EXECUTION_TIME'|translate: {duration: search.took} }}
         </small>
+        <small class="gray" ng-if=":rebind:expertMode && search.filters && search.filters.length">
+          - <a ng-click="toggleShowQuery()"
+            ng-if="!showQuery" >
+            Voir la requête
+            <i class="icon ion-arrow-down-b gray"></i>
+          </a>
+          <a ng-click="toggleShowQuery()"
+             ng-if="showQuery" >
+             Masquer la requête
+             <i class="icon ion-arrow-up-b gray"></i>
+          </a>
+        </small>
       </h5>
       <h5 class="gray" ng-if="search.loading" >
         <ion-spinner class="icon ion-spinner-small" icon="android"></ion-spinner>
@@ -61,6 +84,12 @@
     </div>
   </div>
 
+  <div class="item no-border no-padding" ng-if=":rebind:search.filters && search.filters.length && expertMode">
+    <small class="no-padding no-margin" ng-if="showQuery">
+      <span class="gray text-wrap dark">{{:rebind:search.query}}</span>
+    </small>
+  </div>
+
   <ion-list class="list list-blocks" ng-class="::motion.ionListClass">
 
     <ng-include src="'plugins/es/templates/blockchain/items_blocks.html'"></ng-include>
-- 
GitLab