Skip to content

Commit

Permalink
Merge pull request #22114 from colemanw/searchKitRevertButton
Browse files Browse the repository at this point in the history
SearchKit - Improve search listing UI
  • Loading branch information
seamuslee001 authored Nov 26, 2021
2 parents 426a220 + 2b02bf9 commit f746d78
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 89 deletions.
7 changes: 5 additions & 2 deletions ext/afform/admin/ang/afAdmin/afAdminList.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,13 @@
$scope.$bindToRoute({
expr: '$ctrl.tab',
param: 'tab',
format: 'raw',
default: ctrl.tabs[0].name
format: 'raw'
});

if (!ctrl.tab) {
ctrl.tab = ctrl.tabs[0].name;
}

this.createLinks = function() {
ctrl.searchCreateLinks = '';
if ($scope.types[ctrl.tab].options) {
Expand Down
37 changes: 33 additions & 4 deletions ext/search_kit/ang/crmSearchAdmin.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@

.config(function($routeProvider) {
$routeProvider.when('/list', {
controller: function() {
searchEntity = 'SavedSearch';
},
template: '<crm-search-admin-search-listing></crm-search-admin-search-listing>',
controller: 'searchList',
reloadOnSearch: false,
templateUrl: '~/crmSearchAdmin/searchListing/crmSearchAdminSearchListing.html',
});
$routeProvider.when('/create/:entity', {
controller: 'searchCreate',
Expand Down Expand Up @@ -45,6 +44,36 @@
});
})

// Controller for tabbed view of SavedSearches
.controller('searchList', function($scope, searchMeta, formatForSelect2) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = $scope.$ctrl = this;
searchEntity = 'SavedSearch';

// Metadata needed for filters
this.entitySelect = searchMeta.getPrimaryAndSecondaryEntitySelect();
this.modules = _.sortBy(_.transform((CRM.crmSearchAdmin.modules), function(modules, label, key) {
modules.push({text: label, id: key});
}, []), 'text');
this.getTags = function() {
return {results: formatForSelect2(CRM.crmSearchAdmin.tags, 'id', 'name', ['color', 'description'])};
};

// Tabs include a rowCount which will be updated by the search controller
this.tabs = [
{name: 'custom', title: ts('Custom Searches'), icon: 'fa-search-plus', rowCount: null, filters: {has_base: false}},
{name: 'packaged', title: ts('Packaged Searches'), icon: 'fa-gift', rowCount: null, filters: {has_base: true}}
];
$scope.$bindToRoute({
expr: '$ctrl.tab',
param: 'tab',
format: 'raw'
});
if (!this.tab) {
this.tab = this.tabs[0].name;
}
})

// Controller for creating a new search
.controller('searchCreate', function($scope, $routeParams, $location) {
searchEntity = $routeParams.entity;
Expand Down
31 changes: 13 additions & 18 deletions ext/search_kit/ang/crmSearchAdmin/crmSearchAdmin.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,30 @@
this.groupExists = !!this.savedSearch.groups.length;

if (!this.savedSearch.id) {
var defaults = {
version: 4,
select: getDefaultSelect(),
orderBy: {},
where: [],
};
_.each(['groupBy', 'join', 'having'], function(param) {
if (ctrl.paramExists(param)) {
defaults[param] = [];
}
});

$scope.$bindToRoute({
param: 'params',
expr: '$ctrl.savedSearch.api_params',
deep: true,
default: {
version: 4,
select: getDefaultSelect(),
orderBy: {},
where: [],
}
default: defaults
});
}

$scope.mainEntitySelect = searchMeta.getPrimaryAndSecondaryEntitySelect();

$scope.$watchCollection('$ctrl.savedSearch.api_params.select', onChangeSelect);

if (this.paramExists('groupBy')) {
this.savedSearch.api_params.groupBy = this.savedSearch.api_params.groupBy || [];
}

if (this.paramExists('join')) {
this.savedSearch.api_params.join = this.savedSearch.api_params.join || [];
}

if (this.paramExists('having')) {
this.savedSearch.api_params.having = this.savedSearch.api_params.having || [];
}

$scope.$watch('$ctrl.savedSearch', onChangeAnything, true);

// After watcher runs for the first time and messes up the status, set it correctly
Expand Down
4 changes: 2 additions & 2 deletions ext/search_kit/ang/crmSearchAdmin/searchListing/buttons.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<a class="btn btn-xs btn-default" title="{{:: ts('View search results table') }}" ng-href="{{:: $ctrl.searchDisplayPath + '#/display/' + row.data.name }}" target="_blank">
{{:: ts('View') }}
</a>
<a class="btn btn-xs btn-primary" href="#/edit/{{:: row.data.id }}" ng-if="row.permissionToEdit">
<a class="btn btn-xs btn-primary" href="#/edit/{{:: row.data.id }}" ng-style="{visibility: row.permissionToEdit ? 'visible' : 'hidden'}">
{{:: ts('Edit') }}
</a>
<a class="btn btn-xs btn-secondary" href="#/create/{{:: row.data.api_entity + '?params=' + $ctrl.encode(row.data.api_params) }}">
{{:: ts('Clone') }}
</a>
<a href class="btn btn-xs btn-{{ row.data['base_module:label'] ? 'warning' : 'danger' }}" ng-click="$ctrl.deleteOrRevert(row)">
<a href ng-style="{visibility: row.data['base_module:label'] && !row.data['local_modified_date'] ? 'hidden' : 'visible'}" class="btn btn-xs btn-{{ row.data['base_module:label'] ? 'warning' : 'danger' }}" ng-click="$ctrl.deleteOrRevert(row)">
{{ row.data['base_module:label'] ? ts('Revert') : ts('Delete') }}
</a>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@

// Specialized searchDisplay, only used by Admins
angular.module('crmSearchAdmin').component('crmSearchAdminSearchListing', {
templateUrl: '~/crmSearchAdmin/searchListing/crmSearchAdminSearchListing.html',
controller: function($scope, $q, crmApi4, crmStatus, searchMeta, searchDisplayBaseTrait, searchDisplaySortableTrait, formatForSelect2) {
bindings: {
filters: '<',
tabCount: '='
},
templateUrl: '~/crmSearchDisplayTable/crmSearchDisplayTable.html',
controller: function($scope, $q, crmApi4, crmStatus, searchMeta, searchDisplayBaseTrait, searchDisplaySortableTrait) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
// Mix in traits to this controller
ctrl = angular.extend(this, searchDisplayBaseTrait, searchDisplaySortableTrait),
Expand All @@ -14,13 +18,6 @@
this.afformPath = CRM.url('civicrm/admin/afform');
this.afformEnabled = CRM.crmSearchAdmin.afformEnabled;
this.afformAdminEnabled = CRM.crmSearchAdmin.afformAdminEnabled;
this.entitySelect = searchMeta.getPrimaryAndSecondaryEntitySelect();
this.modules = _.sortBy(_.transform((CRM.crmSearchAdmin.modules), function(modules, label, key) {
modules.push({text: label, id: key});
}, []), 'text');

this.filters = {has_base: false};
this.totals = {};

this.apiEntity = 'SavedSearch';
this.search = {
Expand All @@ -41,6 +38,7 @@
'modified_date',
'has_base',
'base_module:label',
'local_modified_date',
'DATE(created_date) AS date_created',
'DATE(modified_date) AS date_modified',
'GROUP_CONCAT(display.name ORDER BY display.id) AS display_name',
Expand All @@ -66,25 +64,10 @@
this.initializeDisplay($scope, $());
// Keep tab counts up-to-date - put rowCount in current tab if there are no other filters
$scope.$watch('$ctrl.rowCount', function(val) {
if (typeof val === 'number' && angular.equals({has_base: true}, ctrl.filters)) {
ctrl.totals.has_base = val;
}
else if (typeof val === 'number' && angular.equals({has_base: false}, ctrl.filters)) {
ctrl.totals.no_base = val;
if (typeof val === 'number' && angular.equals(['has_base'], _.keys(ctrl.filters))) {
ctrl.tabCount = val;
}
});
// Initialize count for inactive tab
var params = ctrl.getApiParams('row_count');
params.filters.has_base = true;
crmApi4('SearchDisplay', 'run', params).then(function(result) {
ctrl.totals.has_base = result.count;
});
};

// Change tabs and clear other filters
this.setHasBaseFilter = function(val) {
ctrl.filters = {has_base: val};
buildDisplaySettings();
};

this.onPostRun.push(function(result) {
Expand Down Expand Up @@ -179,10 +162,6 @@
);
};

this.getTags = function() {
return {results: formatForSelect2(CRM.crmSearchAdmin.tags, 'id', 'name', ['color', 'description'])};
};

function buildDisplaySettings() {
ctrl.display = {
type: 'table',
Expand Down Expand Up @@ -237,6 +216,19 @@
]
})
);
ctrl.display.settings.columns.push(
// Using 'local_modified_date' as the column + an empty_value will only show the rewritten value
// if the record has been modified from its packaged state.
searchMeta.fieldToColumn('local_modified_date', {
label: ts('Modified'),
empty_value: ts('No'),
title: ts('Whether and when a search was modified from its packaged settings'),
rewrite: ts('%1 by %2', {1: '[date_modified]', 2: '[modified_id.display_name]'}),
cssRules: [
['font-italic', 'local_modified_date', 'IS EMPTY']
]
})
);
} else {
ctrl.display.settings.columns.push(
searchMeta.fieldToColumn('created_date', {
Expand All @@ -245,14 +237,14 @@
rewrite: ts('%1 by %2', {1: '[date_created]', 2: '[created_id.display_name]'})
})
);
ctrl.display.settings.columns.push(
searchMeta.fieldToColumn('modified_date', {
label: ts('Modified'),
title: '[modified_date]',
rewrite: ts('%1 by %2', {1: '[date_modified]', 2: '[modified_id.display_name]'})
})
);
}
ctrl.display.settings.columns.push(
searchMeta.fieldToColumn('modified_date', {
label: ts('Last Modified'),
title: '[modified_date]',
rewrite: ts('%1 by %2', {1: '[date_modified]', 2: '[modified_id.display_name]'})
})
);
ctrl.display.settings.columns.push({
type: 'include',
alignment: 'text-right',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,30 @@ <h1 crm-page-title>{{:: ts('Saved Searches') }}</h1>

<!-- Tabs based on the has_base filter -->
<ul class="nav nav-tabs">
<li role="presentation" ng-class="{active: !$ctrl.filters.has_base}">
<a href ng-click="$ctrl.setHasBaseFilter(false)"><i class="crm-i fa-search-plus"></i>
{{:: ts('Custom Searches') }}
<span class="badge">{{ $ctrl.totals.no_base }}</span>
</a>
</li>
<li role="presentation" ng-class="{active: $ctrl.filters.has_base}">
<a href ng-click="$ctrl.setHasBaseFilter(true)"><i class="crm-i fa-gift"></i>
{{:: ts('Packaged Searches') }}
<span class="badge">{{ $ctrl.totals.has_base }}</span>
<li ng-repeat="tab in $ctrl.tabs" role="presentation" ng-class="{active: $ctrl.tab === tab.name}">
<a href ng-click="$ctrl.tab = tab.name"><i class="crm-i {{:: tab.icon }}"></i>
{{:: tab.title }}
<span class="badge">{{ tab.rowCount }}</span>
</a>
</li>
</ul>

<!-- Other filters -->
<div class="form-inline">
<input class="form-control" type="search" ng-model="$ctrl.filters.label" placeholder="{{:: ts('Filter by label...') }}">
<input class="form-control" type="search" ng-show="!$ctrl.filters.has_base" ng-model="$ctrl.filters['created_id.display_name,modified_id.display_name']" placeholder="{{:: ts('Filter by author...') }}">
<span ng-if="$ctrl.filters.has_base">
<input class="form-control" ng-model="$ctrl.filters.base_module" ng-list crm-ui-select="{multiple: true, data: $ctrl.modules, placeholder: ts('Filter by package...')}">
</span>
<input class="form-control collapsible-optgroups" ng-model="$ctrl.filters.api_entity" ng-list crm-ui-select="{multiple: true, data: $ctrl.entitySelect, placeholder: ts('Filter by entity...')}">
<span ng-if="$ctrl.getTags().results.length">
<input class="form-control" ng-model="$ctrl.filters.tags" ng-list crm-ui-select="{multiple: true, data: $ctrl.getTags, placeholder: ts('Filter by tags...')}">
</span>
<a class="btn btn-primary pull-right" href="#/create/Contact/">
<i class="crm-i fa-plus"></i>
{{:: ts('New Search') }}
</a>
<div ng-repeat="tab in $ctrl.tabs" ng-show="$ctrl.tab === tab.name">
<div class="form-inline">
<input class="form-control" type="search" ng-model="tab.filters.label" placeholder="{{:: ts('Filter by label...') }}">
<input class="form-control" type="search" ng-if="tab.name === 'custom'" ng-model="tab.filters['created_id.display_name,modified_id.display_name']" placeholder="{{:: ts('Filter by author...') }}">
<span ng-if="tab.name === 'packaged'">
<input class="form-control" ng-model="tab.filters.base_module" ng-list crm-ui-select="{multiple: true, data: $ctrl.modules, placeholder: ts('Filter by package...')}">
</span>
<input class="form-control collapsible-optgroups" ng-model="tab.filters.api_entity" ng-list crm-ui-select="{multiple: true, data: $ctrl.entitySelect, placeholder: ts('Filter by entity...')}">
<span ng-if="$ctrl.getTags().results.length">
<input class="form-control" ng-model="tab.filters.tags" ng-list crm-ui-select="{multiple: true, data: $ctrl.getTags, placeholder: ts('Filter by tags...')}">
</span>
<a class="btn btn-primary pull-right" ng-if="tab.name === 'custom'" href="#/create/Contact/">
<i class="crm-i fa-plus"></i>
{{:: ts('New Search') }}
</a>
</div>
<crm-search-admin-search-listing filters="tab.filters" tab-count="tab.rowCount"></crm-search-admin-search-listing>
</div>
<div ng-include="'~/crmSearchDisplayTable/crmSearchDisplayTable.html'"></div>
</div>

0 comments on commit f746d78

Please sign in to comment.