From b8fef4f79062a22b78fdb4190b9202e2b47852a6 Mon Sep 17 00:00:00 2001
From: blavenie <benoit.lavenier@e-is.pro>
Date: Thu, 5 Oct 2017 14:55:16 +0200
Subject: [PATCH] [fix] Need to update the field "time", in JSON document store
 in ES node - fix #572 [enh] Wot: Add search on page+group

---
 www/js/controllers/wot-controllers.js         |  22 +--
 www/js/services/wot-services.js               |   2 +-
 www/plugins/es/i18n/locale-fr-FR.json         |   5 +
 .../es/js/controllers/registry-controllers.js |  12 +-
 www/plugins/es/js/entities/notification.js    |   8 +-
 .../es/js/services/profile-services.js        | 151 +++++++++++++-----
 .../es/js/services/settings-services.js       |  15 +-
 .../es/templates/group/lookup_item.html       |  18 +++
 .../es/templates/group/view_record.html       |   2 +-
 www/plugins/es/templates/registry/lookup.html |   2 +-
 .../es/templates/registry/lookup_item.html    |  27 ++++
 .../es/templates/registry/lookup_lg.html      |  32 +---
 www/plugins/es/templates/wot/lookup_item.html |  21 +++
 .../es/templates/wot/lookup_item_group.html   |  32 ++++
 .../es/templates/wot/lookup_item_page.html    |  24 +++
 www/templates/wot/lookup_form.html            |  22 ++-
 16 files changed, 293 insertions(+), 102 deletions(-)
 create mode 100644 www/plugins/es/templates/group/lookup_item.html
 create mode 100644 www/plugins/es/templates/registry/lookup_item.html
 create mode 100644 www/plugins/es/templates/wot/lookup_item.html
 create mode 100644 www/plugins/es/templates/wot/lookup_item_group.html
 create mode 100644 www/plugins/es/templates/wot/lookup_item_page.html

diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js
index 95bcbb420..1969c3e5e 100644
--- a/www/js/controllers/wot-controllers.js
+++ b/www/js/controllers/wot-controllers.js
@@ -345,17 +345,19 @@ function WotLookupController($scope, $state, $timeout, $focus, $ionicPopover, $l
       });
   };
 
-  $scope.select = function(identity) {
-    // identity = self -> open the user wallet
-    if (csWallet.isUserPubkey(identity.pubkey)) {
-      $state.go('app.view_wallet');
+  $scope.select = function(item) {
+    var state = item.state;
+
+    //  Identity
+    if (!state && item.pubkey) {
+      // identity = self -> open the user wallet
+      state = csWallet.isUserPubkey(item.pubkey)
+        ? 'app.view_wallet'
+        : 'app.wot_identity';
     }
-    // Open identity view
-    else {
-      $state.go('app.wot_identity', {
-        pubkey: identity.pubkey,
-        uid: identity.uid
-      });
+
+    if (state) {
+      $state.go(state, item.stateParams||item);
     }
   };
 
diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js
index fec37e7b5..e1f8be17e 100644
--- a/www/js/services/wot-services.js
+++ b/www/js/services/wot-services.js
@@ -15,7 +15,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
       _addUniqueIds = function(idties) {
         var idtyKeys = {};
         return idties.reduce(function(res, idty) {
-          idty.id = idty.uid + '-' + idty.pubkey;
+          idty.id = idty.id || idty.uid + '-' + idty.pubkey;
           if (!idtyKeys[idty.id]) {
             idtyKeys[idty.id] = true;
             return res.concat(idty);
diff --git a/www/plugins/es/i18n/locale-fr-FR.json b/www/plugins/es/i18n/locale-fr-FR.json
index b45b197c0..f3760e57c 100644
--- a/www/plugins/es/i18n/locale-fr-FR.json
+++ b/www/plugins/es/i18n/locale-fr-FR.json
@@ -50,6 +50,11 @@
       "TITLE": "Demander des certifications",
       "HELP": "Sélectionner les destinataires"
     },
+    "SEARCH": {
+      "DIVIDER_PROFILE": "Comptes",
+      "DIVIDER_PAGE": "Pages",
+      "DIVIDER_GROUP": "Groupes"
+    },
     "CONFIRM": {
       "SUGGEST_CERTIFICATIONS": "Etes-vous sûr de vouloir <b>envoyer ces suggestions de certification</b> ?",
       "ASK_CERTIFICATION": "Etes-vous sûr de vouloir <b>envoyer une demande de certification</b> ?",
diff --git a/www/plugins/es/js/controllers/registry-controllers.js b/www/plugins/es/js/controllers/registry-controllers.js
index 55257a9ad..5f9e87abf 100644
--- a/www/plugins/es/js/controllers/registry-controllers.js
+++ b/www/plugins/es/js/controllers/registry-controllers.js
@@ -28,8 +28,8 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium.
       }
     })
 
-    .state('app.registry_view_record', {
-      url: "/registry/view/:id/:title?refresh",
+    .state('app.view_page', {
+      url: "/page/:id/:title?refresh",
       views: {
         'menuContent': {
           templateUrl: "plugins/es/templates/registry/view_record.html",
@@ -38,8 +38,8 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium.
       }
     })
 
-    .state('app.registry_view_record_anchor', {
-      url: "/registry/view/:id/:title/:anchor",
+    .state('app.view_page_anchor', {
+      url: "/page/:id/:title/:anchor",
       views: {
         'menuContent': {
           templateUrl: "plugins/es/templates/registry/view_record.html",
@@ -532,7 +532,7 @@ function ESRegistryRecordViewController($scope, $state, $q, $timeout, $ionicPopo
     $scope.hideActionsPopover();
     var title = $scope.formData.title;
     // Use shareBasePath (fix #530) or rootPath (fix #390)
-    var url = (csConfig.shareBaseUrl || $rootScope.rootPath) + $state.href('app.registry_view_record', {title: title, id: $scope.id});
+    var url = (csConfig.shareBaseUrl || $rootScope.rootPath) + $state.href('app.view_page', {title: title, id: $scope.id});
     // Override default position, is small screen - fix #545
     if (UIUtils.screen.isSmall()) {
       event = angular.element(document.querySelector('#registry-share-anchor-'+$scope.id)) || event;
@@ -668,7 +668,7 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q,
         $scope.saving = false;
         $ionicHistory.clearCache($ionicHistory.currentView().stateId); // clear current view
         $ionicHistory.nextViewOptions({historyRoot: true});
-        return $state.go('app.registry_view_record', {id: $scope.id, refresh: true});
+        return $state.go('app.view_page', {id: $scope.id, refresh: true});
       })
 
       .catch(function(err) {
diff --git a/www/plugins/es/js/entities/notification.js b/www/plugins/es/js/entities/notification.js
index 90f7c13c6..cd564c88c 100644
--- a/www/plugins/es/js/entities/notification.js
+++ b/www/plugins/es/js/entities/notification.js
@@ -78,12 +78,12 @@ function Notification(json, markAsReadCallback) {
     that.id = json.reference.id; // Do not care about notification ID, because notification screen use message _id
   }
 
-  // registry record
-  else if (json.reference && json.reference.index == 'registry') {
+  // page record
+  else if (json.reference && json.reference.index == 'page') {
     that.avatarIcon = 'ion-ios-book';
     if (json.reference.anchor) {
       that.icon = 'ion-ios-chatbubble-outline dark';
-      that.state = 'app.registry_view_record_anchor';
+      that.state = 'app.view_page_anchor';
       that.stateParams = {
         id: json.reference.id,
         title: json.params[1],
@@ -92,7 +92,7 @@ function Notification(json, markAsReadCallback) {
     }
     else {
       that.icon = 'ion-ios-book dark';
-      that.state = 'app.registry_view_record';
+      that.state = 'app.view_page';
       that.stateParams = {
         id: json.reference.id,
         title: json.params[1]};
diff --git a/www/plugins/es/js/services/profile-services.js b/www/plugins/es/js/services/profile-services.js
index bfbef908d..cc70f0761 100644
--- a/www/plugins/es/js/services/profile-services.js
+++ b/www/plugins/es/js/services/profile-services.js
@@ -10,7 +10,7 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http
 
   })
 
-.factory('esProfile', function($rootScope, $q, esHttp, SocialUtils, csWot, csWallet, csPlatform) {
+.factory('esProfile', function($rootScope, $q, esHttp, SocialUtils, csWot, csWallet, csPlatform, esSettings) {
   'ngInject';
 
   var
@@ -21,7 +21,8 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http
     getFields: esHttp.get('/user/profile/:id?&_source_exclude=avatar._content&_source=:fields'),
     get: esHttp.get('/user/profile/:id?&_source_exclude=avatar._content'),
     getAll: esHttp.get('/user/profile/:id'),
-    search: esHttp.post('/user/profile/_search')
+    search: esHttp.post('/user/profile/_search'),
+    mixedSearch: esHttp.post('/user,page,group/profile,record/_search')
   };
 
   function getAvatarAndName(pubkey) {
@@ -101,6 +102,29 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http
     return onWotSearch(null, datas, pubkeyAtributeName);
   }
 
+  function _fillSearchResultFromHit(data, hit, avatarFieldName) {
+    data.avatar = data.avatar || esHttp.image.fromHit(hit, avatarFieldName||'avatar');
+    // name (basic or highlighted)
+    data.name = hit._source.title;
+    // Avoid too long name (workaround for #308)
+    if (data.name && data.name.length > 30) {
+      data.name = data.name.substr(0, 27) + '...';
+    }
+    data.description = hit._source.description;
+    data.city = hit._source.city;
+
+    if (hit.highlight) {
+      if (hit.highlight.title) {
+        data.name = hit.highlight.title[0];
+      }
+      if (hit.highlight.tags) {
+        data.tags = hit.highlight.tags.reduce(function(res, tag){
+          return res.concat(tag.replace('<em>', '').replace('</em>', ''));
+        },[]);
+      }
+    }
+  }
+
   function onWotSearch(text, datas, pubkeyAtributeName, deferred) {
     deferred = deferred || $q.defer();
     if (!text && (!datas || !datas.length)) {
@@ -120,6 +144,11 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http
       _source: ["title", "avatar._content_type"]
     };
 
+    var mixedSearch = esSettings.wot.isMixedSearchEnable();
+    if (mixedSearch) {
+      request._source = request._source.concat(["description", "thumbnail._content_type", "city", "creationTime", "membersCount"]);
+    }
+
     if (datas.length > 0) {
       // collect pubkeys and fill values map
       dataByPubkey = {};
@@ -185,52 +214,90 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http
       return deferred.promise;
     }
 
+    if (text && mixedSearch) {
+      request.indices_boost = {
+        "user" : 100,
+        "page" : 1,
+        "group" : 0.01
+      };
+    }
+
     var hits;
-    that.raw.search(request)
-    .then(function(res) {
-      hits = res.hits;
-      if (hits.total > 0) {
-        _.forEach(hits.hits, function(hit) {
-          var values = dataByPubkey && dataByPubkey[hit._id];
-          if (!values) {
-            var value = {};
-            value[pubkeyAtributeName] = hit._id;
-            values=[value];
-            datas.push(value);
-          }
-          var avatar = esHttp.image.fromHit(hit, 'avatar');
-          _.forEach(values, function(data) {
-            // name (basic or highlighted)
-            data.name = hit._source.title;
-            // Avoid too long name (workaround for #308)
-            if (data.name && data.name.length > 30) {
-              data.name = data.name.substr(0, 27) + '...';
-            }
-            if (hit.highlight) {
-              if (hit.highlight.title) {
-                  data.name = hit.highlight.title[0];
+
+    var search = mixedSearch ? that.raw.mixedSearch : that.raw.search;
+    search(request)
+      .then(function(res) {
+        hits = res.hits;
+        if (hits.total > 0) {
+          var indices = {};
+          var values;
+          _.forEach(hits.hits, function(hit) {
+
+            var avatarFieldName = 'avatar';
+            // User profile
+            if (hit._index == "user") {
+              values = dataByPubkey && dataByPubkey[hit._id];
+              if (!values) {
+                var value = {};
+                value[pubkeyAtributeName] = hit._id;
+                values=[value];
+                datas.push(value);
               }
-              if (hit.highlight.tags) {
-                data.tags = hit.highlight.tags.reduce(function(res, tag){
-                  return res.concat(tag.replace('<em>', '').replace('</em>', ''));
-                },[]);
+
+              avatar = esHttp.image.fromHit(hit, 'avatar');
+            }
+
+            // Page or group
+            else if (hit._index != "user") {
+              if (!indices[hit._index]) {
+                indices[hit._index] = true;
+                // add a separator
+                datas.push({
+                  id: 'divider-' + hit._index,
+                  divider: true,
+                  index: hit._index
+                });
               }
+              var item = {
+                id: hit._index + '-' + hit._id, // unique id in list
+                index: hit._index,
+                templateUrl: 'plugins/es/templates/wot/lookup_item_{0}.html'.format(hit._index),
+                state: 'app.view_{0}'.format(hit._index),
+                stateParams: {id: hit._id, title: hit._source.title},
+                creationTime: hit._source.creationTime,
+                memberCount: hit._source.memberCount
+              };
+              values=[item];
+              datas.push(item);
+              avatarFieldName = 'thumbnail';
             }
-            // avatar
-            data.avatar=avatar;
+
+            avatar = esHttp.image.fromHit(hit, avatarFieldName);
+            _.forEach(values, function(data) {
+              data.avatar= avatar;
+              _fillSearchResultFromHit(data, hit);
+            });
           });
-        });
-      }
-      deferred.resolve(datas);
-    })
-    .catch(function(err){
-      if (err && err.ucode && err.ucode == 404) {
+
+          // Add divider on top
+          if (_.keys(indices).length) {
+            datas.splice(0,0, {
+              id: 'divider-identities',
+              divider: true,
+              index: 'profile'
+            });
+          }
+        }
         deferred.resolve(datas);
-      }
-      else {
-        deferred.reject(err);
-      }
-    });
+      })
+      .catch(function(err){
+        if (err && err.ucode && err.ucode == 404) {
+          deferred.resolve(datas);
+        }
+        else {
+          deferred.reject(err);
+        }
+      });
 
     return deferred.promise;
   }
diff --git a/www/plugins/es/js/services/settings-services.js b/www/plugins/es/js/services/settings-services.js
index b791fbc09..703720db6 100644
--- a/www/plugins/es/js/services/settings-services.js
+++ b/www/plugins/es/js/services/settings-services.js
@@ -43,7 +43,10 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt
             },
             defaultCountry: undefined,
             enableGoogleApi: false,
-            googleApiKey: undefined
+            googleApiKey: undefined,
+            wot: {
+              enableMixedSearch: true
+            }
           }
         }
     }, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}),
@@ -66,6 +69,16 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt
       !!csSettings.data.plugins.es.host;
   };
 
+  that.wot = {};
+  that.wot.isMixedSearchEnable = function() {
+    return csSettings.data.plugins &&
+      csSettings.data.plugins.es &&
+      csSettings.data.plugins.es.enable &&
+      (angular.isDefined(csSettings.data.plugins.es.wot && csSettings.data.plugins.es.wot.enableMixedSearch)
+        ? csSettings.data.plugins.es.wot.enableMixedSearch
+        : true);
+  };
+
   function copyUsingSpec(data, copySpec) {
     var result = {};
 
diff --git a/www/plugins/es/templates/group/lookup_item.html b/www/plugins/es/templates/group/lookup_item.html
new file mode 100644
index 000000000..3efb68bf7
--- /dev/null
+++ b/www/plugins/es/templates/group/lookup_item.html
@@ -0,0 +1,18 @@
+
+  <i class="item-image avatar" style="background-image: url({{::item.avatar.src}})" ng-if="item.avatar"></i>
+  <i class="item-image icon ion-android-people" ng-if="!item.avatar"></i>
+  <i class="item-image icon-secondary ion-android-lock" ng-if="!item.avatar" style="left: 20px; top: 17px; font-size: 19px; color: #d9d9d9;"></i>
+
+  <h2 ng-bind-html=":rebind:item.title"></h2>
+
+  <!-- creation time-->
+  <h4 class="gray pull-right">
+    <i class="ion-clock"></i>
+    {{:rebind:'GROUP.CREATED_TIME'|translate: item }}
+  </h4>
+
+  <!-- membersCount -->
+  <h4 class="dark pull-left" ng-if=":rebind:item.membersCount">
+    <i class="dark ion-person"></i>
+    <span class="dark">+{{:rebind:item.membersCount}}</span>
+  </h4>
diff --git a/www/plugins/es/templates/group/view_record.html b/www/plugins/es/templates/group/view_record.html
index c48b694e6..55942cb3b 100644
--- a/www/plugins/es/templates/group/view_record.html
+++ b/www/plugins/es/templates/group/view_record.html
@@ -92,7 +92,7 @@
 
         <ion-item>
             <h2>
-              <span class="text-keep-lines" ng-bind-html="formData.description"></span>
+              <span trust-as-html="formData.description"></span>
             </h2>
         </ion-item>
 
diff --git a/www/plugins/es/templates/registry/lookup.html b/www/plugins/es/templates/registry/lookup.html
index 0c0f58934..e445676ac 100644
--- a/www/plugins/es/templates/registry/lookup.html
+++ b/www/plugins/es/templates/registry/lookup.html
@@ -46,7 +46,7 @@
 
         <a ng-repeat="rec in search.results"
            class="item item-record ink padding-xs item-icon-right"
-           ui-sref="app.registry_view_record({id: rec.id, title: rec.urlTitle})">
+           ui-sref="app.view_page({id: rec.id, title: rec.urlTitle})">
 
           <div class="item-text-wrap item-thumbnail-left-padding"
                ng-class="{'item-thumbnail-left': rec.thumbnail || rec.type}">
diff --git a/www/plugins/es/templates/registry/lookup_item.html b/www/plugins/es/templates/registry/lookup_item.html
new file mode 100644
index 000000000..c0044b566
--- /dev/null
+++ b/www/plugins/es/templates/registry/lookup_item.html
@@ -0,0 +1,27 @@
+<div class="row row-record ">
+  <div class="col item-text-wrap item-thumbnail-left-padding"
+       ng-class="{'item-thumbnail-left': item.thumbnail || item.type}">
+    <i class="item-image icon cion-page-{{::item.type}}" ng-if="!item.thumbnail"></i>
+    <i class="item-image avatar" style="background-image: url({{::item.thumbnail.src}})" ng-if="item.thumbnail"></i>
+    <h2 ng-bind-html="item.title"></h2>
+    <h4 class="gray">
+      <i class="icon ion-location" ng-if="item.city"></i>
+      <span ng-bind-html="item.city"></span>
+    </h4>
+    <h4 class="gray" ng-if="item.time">
+      <i class="icon ion-clock" ></i>
+      {{::item.time | formatFromNow}}
+    </h4>
+    <span  ng-if="item.picturesCount > 1"
+           class="badge badge-balanced badge-picture-count">{{::item.picturesCount}}&nbsp;<i class="icon ion-camera"></i></span>
+  </div>
+  <div class="col col-20 hidden-xs">
+    <h3 class="gray">
+      <ng-if ng-if="item.category">{{::item.category.name}}</ng-if>
+      <!--ng-if ng-if="!item.category">{{'REGISTRY.TYPE.ENUM.'+item.type|translate}}</ng-if-->
+    </h3>
+  </div>
+  <div class="col">
+    <h3 class="gray text-wrap" ng-bind-html="item.description" ng-if="item.description"></h3>
+  </div>
+</div>
diff --git a/www/plugins/es/templates/registry/lookup_lg.html b/www/plugins/es/templates/registry/lookup_lg.html
index b700ec85a..0d1e8f757 100644
--- a/www/plugins/es/templates/registry/lookup_lg.html
+++ b/www/plugins/es/templates/registry/lookup_lg.html
@@ -65,37 +65,11 @@
     <div class="list {{::motion.ionListClass}}"
          ng-if="!search.loading && search.results && search.results.length > 0">
 
-      <a ng-repeat="rec in search.results"
+      <a ng-repeat="item in search.results"
          class="item ink padding-xs"
-         ui-sref="app.registry_view_record({id: rec.id, title: rec.urlTitle})">
+         ui-sref="app.view_page({id: item.id, title: item.urlTitle})">
 
-        <div class="row row-record ">
-          <div class="col item-text-wrap item-thumbnail-left-padding"
-               ng-class="{'item-thumbnail-left': rec.thumbnail || rec.type}">
-            <i class="item-image icon cion-page-{{::rec.type}}" ng-if="!rec.thumbnail"></i>
-            <i class="item-image avatar" style="background-image: url({{::rec.thumbnail.src}})" ng-if="rec.thumbnail"></i>
-            <h2 ng-bind-html="rec.title"></h2>
-            <h4 class="gray">
-              <i class="icon ion-location" ng-if="rec.city"></i>
-              <span ng-bind-html="rec.city"></span>
-            </h4>
-            <h4 class="gray" ng-if="rec.time">
-              <i class="icon ion-clock" ></i>
-              {{::rec.time | formatFromNow}}
-            </h4>
-            <span  ng-if="rec.picturesCount > 1"
-                   class="badge badge-balanced badge-picture-count">{{::rec.picturesCount}}&nbsp;<i class="icon ion-camera"></i></span>
-          </div>
-          <div class="col col-20 hidden-xs">
-            <h3 class="gray">
-              <ng-if ng-if="rec.category">{{::rec.category.name}}</ng-if>
-              <!--ng-if ng-if="!rec.category">{{'REGISTRY.TYPE.ENUM.'+rec.type|translate}}</ng-if-->
-            </h3>
-          </div>
-          <div class="col">
-            <h3 class="gray text-wrap" ng-bind-html="rec.description" ng-if="rec.description"></h3>
-          </div>
-        </div>
+        <ng-include src="'plugins/es/templates/registry/lookup_item.html'"></ng-include>
       </a>
     </div>
 
diff --git a/www/plugins/es/templates/wot/lookup_item.html b/www/plugins/es/templates/wot/lookup_item.html
new file mode 100644
index 000000000..90693a566
--- /dev/null
+++ b/www/plugins/es/templates/wot/lookup_item.html
@@ -0,0 +1,21 @@
+<i ng-if="::!identity.avatar" class="item-image icon ion-person"></i>
+<i ng-if="::identity.avatar" class="item-image avatar" style="background-image: url({{::identity.avatar.src}})"></i>
+
+<h2>
+  <ng-if ng-if="::identity.name||identity.uid" ng-bind-html="::identity.name||identity.uid"></ng-if>
+
+</h2>
+
+<h4 class="gray">
+  <span class="positive" ng-if="::identity.description">
+    <i class="ion-quote"></i>
+    {{::identity.description|truncText}}
+  </span>
+</h4>
+<h4 ng-if="::identity.tags">
+  <span ng-if="::identity.tags" class="dark">
+   <ng-repeat ng-repeat="tag in ::identity.tags">
+     #<ng-bind-html ng-bind-html="::tag"></ng-bind-html>
+   </ng-repeat>
+  </span>
+</h4>
diff --git a/www/plugins/es/templates/wot/lookup_item_group.html b/www/plugins/es/templates/wot/lookup_item_group.html
new file mode 100644
index 000000000..3c37adfd4
--- /dev/null
+++ b/www/plugins/es/templates/wot/lookup_item_group.html
@@ -0,0 +1,32 @@
+
+<i ng-if="::!item.avatar" class="item-image icon ion-android-people"></i>
+<i ng-if="::!item.avatar" class="item-image icon-secondary ion-android-lock" style="left: 20px; top: 17px; font-size: 19px; color: #d9d9d9;"></i>
+<i ng-if="::item.avatar" class="item-image avatar" style="background-image: url({{::item.avatar.src}})"></i>
+
+<h2 ng-bind-html=":rebind:item.name"></h2>
+
+<!-- creation time-->
+<h4 class="gray">
+  <i class="ion-clock"></i>
+  {{:rebind:'GROUP.CREATED_TIME'|translate: item }}
+</h4>
+
+<!-- membersCount -->
+<h4 class="dark pull-left" ng-if=":rebind:item.membersCount">
+  <i class="dark ion-person"></i>
+  <span class="dark">+{{:rebind:item.membersCount}}</span>
+</h4>
+
+<h4 class="dark">
+  <span class="dark" ng-if="::item.description">
+    <i class="ion-quote"></i>
+    {{::item.description|truncText}}
+  </span>
+</h4>
+<h4 ng-if="::item.tags">
+  <span ng-if="::item.tags" class="dark">
+   <ng-repeat ng-repeat="tag in ::item.tags">
+     #<ng-bind-html ng-bind-html="::tag"></ng-bind-html>
+   </ng-repeat>
+  </span>
+</h4>
diff --git a/www/plugins/es/templates/wot/lookup_item_page.html b/www/plugins/es/templates/wot/lookup_item_page.html
new file mode 100644
index 000000000..d4a30ebaf
--- /dev/null
+++ b/www/plugins/es/templates/wot/lookup_item_page.html
@@ -0,0 +1,24 @@
+<i ng-if="::!item.avatar" class="item-image icon ion-person"></i>
+<i ng-if="::item.avatar" class="item-image avatar" style="background-image: url({{::item.avatar.src}})"></i>
+
+<h2 ng-bind-html=":rebind:item.name"></h2>
+
+<h4 class="gray">
+  <span class="gray" ng-if="::item.city">
+    <i class="ion-location"></i>
+    {{::item.city|truncText}}
+  </span>
+</h4>
+<h4 class="dark">
+  <span class="dark" ng-if="::item.description">
+    <i class="ion-quote"></i>
+    {{::item.description|truncText}}
+  </span>
+</h4>
+<h4 ng-if="::item.tags">
+  <span ng-if="::item.tags" class="dark">
+   <ng-repeat ng-repeat="tag in ::item.tags">
+     #<ng-bind-html ng-bind-html="::tag"></ng-bind-html>
+   </ng-repeat>
+  </span>
+</h4>
diff --git a/www/templates/wot/lookup_form.html b/www/templates/wot/lookup_form.html
index 40329d6b1..cde0230d1 100644
--- a/www/templates/wot/lookup_form.html
+++ b/www/templates/wot/lookup_form.html
@@ -103,19 +103,23 @@
     <!-- simple selection + device -->
     <!--removeIf(no-device)-->
     <ion-list
-      ng-if="!allowMultiple && $root.device.enable"
+      ng-if="::!allowMultiple && $root.device.enable"
       class="{{::motion.ionListClass}}"
       can-swipe="true">
 
       <ion-item
         ng-repeat="identity in search.results track by identity.id"
         id="helptip-wot-search-result-{{$index}}"
-        class="item item-border-large item-avatar item-icon-right ink" ng-click="::select(identity)">
+        ng-class="::{'item-avatar item-icon-right ink': !identity.divider, 'item-divider': identity.divider}"
+        class="item item-border-large " ng-click="::select(identity)">
 
-        <ng-include src="'templates/wot/identity.html'"></ng-include>
+        <ng-include ng-if="identity.divider || identity.type" src="'templates/wot/lookup_item.html'"></ng-include>
+        <ng-include ng-if="!identity.divider && !identity.type" src="'templates/wot/identity.html'"></ng-include>
 
         <i class="icon ion-ios-arrow-right "></i>
-        <ion-option-button class="button-positive" ng-click="showTransferModal({pubkey: identity.pubkey, uid: identity.name ||identity.uid})" translate>COMMON.BTN_SEND_MONEY_SHORT</ion-option-button>
+        <ion-option-button
+          ng-if="identity.pubkey"
+          class="button-positive" ng-click="showTransferModal({pubkey: identity.pubkey, uid: identity.name ||identity.uid})" translate>COMMON.BTN_SEND_MONEY_SHORT</ion-option-button>
       </ion-item>
 
     </ion-list>
@@ -130,11 +134,15 @@
       <div
         ng-repeat="identity in search.results track by identity.id"
         id="helptip-wot-search-result-{{$index}}"
-        class="item item-border-large item-avatar item-icon-right ink" ng-click="::select(identity)">
+        ng-class="::{'item-avatar item-icon-right ink': !identity.divider, 'item-divider ': identity.divider}"
+        class="item item-border-large {{::identity.ionItemClass}}" ng-click="::select(identity)">
 
-        <ng-include src="'templates/wot/identity.html'"></ng-include>
+        <!-- divider -->
+        <span ng-if="identity.divider">{{::('WOT.SEARCH.DIVIDER_' + identity.index)|upper|translate}}</span>
+        <ng-include ng-if="identity.templateUrl" src="identity.templateUrl" ng-init="item=identity"></ng-include>
+        <ng-include ng-if="!identity.templateUrl && !identity.divider" src="'templates/wot/identity.html'"></ng-include>
 
-        <i class="icon ion-ios-arrow-right "></i>
+        <i ng-if="!identity.divider" class="icon ion-ios-arrow-right "></i>
       </div>
     </div>
     <!--endRemoveIf(device)-->
-- 
GitLab