You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by tb...@apache.org on 2018/11/06 15:21:15 UTC
[3/9] brooklyn-ui git commit: sort search results by relevance
sort search results by relevance
and display sort fields dropdown in order used
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/commit/6ae7338f
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/tree/6ae7338f
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/diff/6ae7338f
Branch: refs/heads/master
Commit: 6ae7338f72a25cc7862ad0db37860a108dabce3d
Parents: a0cddab
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Oct 31 12:56:20 2018 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Nov 1 12:15:22 2018 +0000
----------------------------------------------------------------------
.../catalog-selector.directive.js | 65 +++++++++++++++-----
.../catalog-selector.template.html | 5 +-
2 files changed, 52 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/6ae7338f/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js
----------------------------------------------------------------------
diff --git a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js
index 60f7beb..9f0bd14 100644
--- a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js
+++ b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js
@@ -25,10 +25,11 @@ import { distanceInWordsToNow } from 'date-fns';
const MIN_ROWS_PER_PAGE = 4;
const PALETTE_VIEW_ORDERS = {
- name: { label: "Name", field: "displayName" },
- lastUsed: { label: "Recent", field: "-lastUsed" },
- bundle: { label: "Bundle", field: "containingBundle" },
- id: { label: "ID", field: "symbolicName" },
+ relevance: { id: "relevance", label: "Relevance", field: "relevance" },
+ name: { id: "name", label: "Name", field: "displayName" },
+ lastUsed: { id: "lastUsed", label: "Recent", field: "-lastUsed" },
+ bundle: { id: "bundle", label: "Bundle", field: "containingBundle" },
+ id: { id: "id", label: "ID", field: "symbolicName" },
};
const PALETTE_VIEW_MODES = {
@@ -39,7 +40,7 @@ const PALETTE_VIEW_MODES = {
};
// fields in either bundle or type record:
-const FIELDS_TO_SEARCH = ['name', 'displayName', 'symbolicName', 'version', 'type', 'supertypes', 'containingBundle', 'description', 'displayTags', 'tags'];
+const FIELDS_TO_SEARCH = ['displayName', 'name', 'symbolicName', 'version', 'type', 'supertypes', 'containingBundle', 'description', 'displayTags', 'tags'];
export function catalogSelectorDirective() {
return {
@@ -88,23 +89,42 @@ export function catalogSelectorSearchFilter() {
return function (items, search) {
if (search) {
return items.filter(function (item) {
- return search.toLowerCase().split(' ').reduce( (found, part) =>
- found &&
- FIELDS_TO_SEARCH
- .filter(field => item.hasOwnProperty(field) && item[field])
- .reduce((match, field) => {
+ item.relevance = 0;
+ let wordNum = 0;
+ return search.toLowerCase().split(' ').reduce( (found, part) => {
+ wordNum++;
+ let fieldNum = 0;
+ return found &&
+ FIELDS_TO_SEARCH.reduce((match, field) => {
if (match) return true;
+ fieldNum++;
+ if (!item.hasOwnProperty(field) || !item[field]) return false;
let text = item[field];
if (!text.toLowerCase) {
text = JSON.stringify(text).toLowerCase();
} else {
text = text.toLowerCase();
}
- return match || text.indexOf(part) > -1;
+ let index = text.indexOf(part);
+ if (index == -1) return false;
+ // found, set relevance -- uses an ad hoc heuristic preferring first fields and short text length,
+ // earlier occurrences and earlier words weighted more highly (smaller number is better)
+ let score = fieldNum * (2 / (1 + wordNum)) * Math.log(1 + text.length * index);
+ /* to debug the scoring function:
+ if (item.symbolicName.indexOf("EIP") >= 0 || item.symbolicName.indexOf("OpsWorks") >= 0) {
+ console.log(item.symbolicName, ": match", part, "in", field,
+ "#", fieldNum, wordNum,
+ "pos", index, "/", text.length,
+ ":", item.relevance, "+=", score);
+ }
+ */
+ item.relevance += score;
+ return true;
}, false)
- , true);
+ }, true);
});
} else {
+ items.forEach( item => item.relevance = 0 );
return items;
}
}
@@ -150,7 +170,6 @@ function controller($scope, $element, $timeout, $q, $uibModal, $log, $templateCa
if (!$scope.state) $scope.state = {};
if (!$scope.state.viewMode) $scope.state.viewMode = PALETTE_VIEW_MODES.normal;
- if (!$scope.state.currentOrder) $scope.state.currentOrder = [ PALETTE_VIEW_ORDERS.name.field, '-version' ];
$scope.pagination = {
page: 1,
@@ -247,11 +266,23 @@ function controller($scope, $element, $timeout, $q, $uibModal, $log, $templateCa
paletteDragAndDropService.dragEnd();
tryMarkUsed(item);
};
+
$scope.sortBy = function (order) {
- let newOrder = [].concat($scope.state.currentOrder);
- newOrder = newOrder.filter( (o) => o !== order.field );
- $scope.state.currentOrder = [order.field].concat(newOrder);
+ let newFirst = {};
+ if (order) {
+ newFirst[order.id] = order;
+ }
+ $scope.state.currentOrder = Object.assign(newFirst, $scope.state.currentOrder, newFirst);
+ $scope.state.currentOrderFields = [];
+ $scope.state.currentOrderValues = [];
+ Object.values($scope.state.currentOrder).forEach( it => {
+ $scope.state.currentOrderValues.push(it);
+ $scope.state.currentOrderFields.push(it.field);
+ });
};
+ if (!$scope.state.currentOrder) $scope.state.currentOrder = Object.assign({}, PALETTE_VIEW_ORDERS);
+ $scope.sortBy();
+
$scope.allowFreeForm = function () {
return [
EntityFamily.LOCATION
@@ -295,6 +326,8 @@ function controller($scope, $element, $timeout, $q, $uibModal, $log, $templateCa
if (l < 100000) return 'Preselected for inclusion in "Recent" filter.';
return 'Last used: ' + distanceInWordsToNow(l, { includeSeconds: true, addSuffix: true });
};
+ $scope.roundTwoDecimals = (num) => Math.round(num*100)/100.0;
+
$scope.showPaletteControls = false;
$scope.onFiltersShown = () => {
$timeout( () => {
http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/6ae7338f/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
----------------------------------------------------------------------
diff --git a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
index 870600c..bd996e9 100644
--- a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
+++ b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
@@ -74,7 +74,7 @@
<i class="fa fa-sort"></i></div>
</a>
<ul class="dropdown-menu right-align-icon" role="menu" uib-dropdown-menu aria-labelledby="palette-sort">
- <li role="menuitem" ng-repeat="order in viewOrders track by $index" ng-class="{'active': state.currentOrder[0] === order.field}" class="layer">
+ <li role="menuitem" ng-repeat="order in state.currentOrderValues track by $index" class="layer">
<a ng-click="sortBy(order)"><i class="fa fa-fw fa-circle"></i> {{ order.label }}</a>
</li>
</ul>
@@ -100,7 +100,7 @@
<!-- here and below, col-xs-3 or -4 or -2 all work giving different densities;
this could be configurable ("compressed"=xs-2 w no labels, "normal"=xs-3, "big"=xs-4) -->
<div class="catalog-palette-item" ng-class="state.viewMode.classes"
- ng-repeat="item in searchedItems = (items | catalogSelectorSearch:search | catalogSelectorFilters:this) | orderBy:state.currentOrder | limitTo:pagination.itemsPerPage:(pagination.page-1)*pagination.itemsPerPage track by (item.containingBundle + ':' + item.symbolicName + ':' + item.version)"
+ ng-repeat="item in searchedItems = (items | catalogSelectorSearch:search | catalogSelectorFilters:this) | orderBy:state.currentOrderFields | limitTo:pagination.itemsPerPage:(pagination.page-1)*pagination.itemsPerPage track by (item.containingBundle + ':' + item.symbolicName + ':' + item.version)"
ng-click="onSelectItem(item)">
<div class="item" draggable="true" ng-dragstart="onDragItem(item, $event)" ng-dragend="onDragEnd(item, $event)">
<div class="item-logo">
@@ -157,6 +157,7 @@
<span ng-repeat-start="tag in item.displayTags" class="label label-primary palette-item-tag">{{ tag }}</span>
<span ng-repeat-end> </span> </p>
<p><i class="mini-icon fa fa-fw fa-file-zip-o"></i> {{item.containingBundle}}</p>
+ <p ng-if="item.relevance"><i class="mini-icon fa fa-sort-numeric-asc"></i> Relevance score: {{ roundTwoDecimals(item.relevance) }}</p>
</div>
</div>
</script>