Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SearchKit - Support conditional links #22557

Merged
merged 1 commit into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ private function formatLinksColumn($column, $data): array {
$out['text'] = $this->replaceTokens($column['text'], $data, 'view');
}
foreach ($column['links'] as $item) {
if (!$this->checkLinkCondition($item, $data)) {
continue;
}
$path = $this->replaceTokens($this->getLinkPath($item, $data), $data, 'url');
if ($path) {
$link = [
Expand All @@ -390,6 +393,30 @@ private function formatLinksColumn($column, $data): array {
return $out;
}

/**
colemanw marked this conversation as resolved.
Show resolved Hide resolved
* Check if a link should be shown based on its conditions.
*
* Given a link, check if it is set to be displayed conditionally.
* If so, evaluate the condition, else return TRUE.
*
* @param array $item
* @param array $data
* @return bool
*/
private function checkLinkCondition(array $item, array $data): bool {
if (empty($item['condition'][0]) || empty($item['condition'][1])) {
return TRUE;
}
$op = $item['condition'][1];
if ($item['condition'][0] === 'check user permission') {
if (!empty($item['condition'][2]) && !\CRM_Core_Permission::check($item['condition'][2])) {
return $op !== '=';
}
return TRUE;
}
return ArrayQueryActionTrait::filterCompare($data, $item['condition']);
}

/**
* @param array $link
* @param array $data
Expand Down
16 changes: 15 additions & 1 deletion ext/search_kit/Civi/Search/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ class Admin {
public static function getAdminSettings():array {
$schema = self::getSchema();
$extensions = \CRM_Extension_System::singleton()->getMapper();
return [
$data = [
'schema' => self::addImplicitFKFields($schema),
'joins' => self::getJoins($schema),
'pseudoFields' => AbstractRunAction::getPseudoFields(),
'operators' => \CRM_Utils_Array::makeNonAssociative(self::getOperators()),
'permissions' => [],
'functions' => self::getSqlFunctions(),
'displayTypes' => Display::getDisplayTypes(['id', 'name', 'label', 'description', 'icon']),
'styles' => \CRM_Utils_Array::makeNonAssociative(self::getStyles()),
Expand All @@ -49,6 +50,19 @@ public static function getAdminSettings():array {
->addWhere('used_for', 'CONTAINS', 'civicrm_saved_search')
->execute(),
];
$perms = \Civi\Api4\Permission::get()
->addWhere('group', 'IN', ['civicrm', 'cms'])
->addWhere('is_active', '=', 1)
->setOrderBy(['title' => 'ASC'])
->execute();
foreach ($perms as $perm) {
$data['permissions'][] = [
'id' => $perm['name'],
'text' => $perm['title'],
'description' => $perm['description'] ?? NULL,
];
}
return $data;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,53 @@
apiParams: '<',
links: '<'
},
require: {
crmSearchAdmin: '^crmSearchAdmin'
},
templateUrl: '~/crmSearchAdmin/crmSearchAdminLinkGroup.html',
controller: function ($scope, $element, $timeout, searchMeta) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = this,
linkProps = ['path', 'entity', 'action', 'join', 'target', 'icon', 'text', 'style'];
linkProps = ['path', 'entity', 'action', 'join', 'target', 'icon', 'text', 'style', 'condition'];

var permissionOperators = [
{key: '=', value: ts('Has')},
{key: '!=', value: ts('Lacks')}
];

this.getOperators = function(clause) {
if (clause[0] === 'check user permission') {
return permissionOperators;
}
return CRM.crmSearchAdmin.operators;
};

this.styles = CRM.crmSearchAdmin.styles;

this.getStyle = function(item) {
return _.findWhere(this.styles, {key: item.style});
};

this.getField = searchMeta.getField;

this.fields = function() {
var selectFields = ctrl.crmSearchAdmin.getSelectFields();
var permissionField = [{
text: ts('Current User Permission'),
id: 'check user permission',
description: ts('Check permission of logged-in user')
}];
return {results: permissionField.concat(selectFields)};
};

this.onChangeCondition = function(item) {
if (item.condition[0]) {
item.condition[1] = '=';
} else {
item.condition = [];
}
};

this.sortableOptions = {
containment: 'tbody',
direction: 'vertical',
Expand All @@ -32,23 +67,31 @@
}
};

this.permissions = CRM.crmSearchAdmin.permissions;

$scope.pickIcon = function(index) {
searchMeta.pickIcon().then(function(icon) {
ctrl.group[index].icon = icon;
});
};

function setDefaults(item, newValue) {
_.each(linkProps, function(prop) {
item[prop] = newValue[prop] || (prop === 'condition' ? [] : '');
});
}

this.addItem = function(item) {
ctrl.group.push(_.pick(item, linkProps));
var newItem = _.pick(item, linkProps);
setDefaults(newItem, newItem);
ctrl.group.push(newItem);
};

this.onChangeLink = function(item, newValue) {
if (newValue.path === 'civicrm/') {
newValue = JSON.parse(this.default);
}
_.each(linkProps, function(prop) {
item[prop] = newValue[prop] || '';
});
setDefaults(item, newValue);
};

this.serialize = JSON.stringify;
Expand All @@ -58,11 +101,15 @@
style: 'default',
text: ts('Link'),
icon: 'fa-external-link',
condition: [],
path: 'civicrm/'
});
var defaultLinks = _.filter(ctrl.links, function(link) {
return !link.join;
});
_.each(ctrl.group, function(item) {
setDefaults(item, item);
});
if (!ctrl.group.length) {
if (defaultLinks.length) {
_.each(defaultLinks, ctrl.addItem);
Expand Down
12 changes: 12 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearchAdminLinkGroup.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<th>{{:: ts('Open') }}</th>
<th>{{:: ts('Text') }}</th>
<th>{{:: ts('Link') }}</th>
<th>{{:: ts('Show if') }}</th>
<th>{{:: ts('Style') }}</th>
<th class="crm-search-admin-icon-col"></th>
</tr>
Expand Down Expand Up @@ -34,6 +35,17 @@
<td class="form-inline">
<crm-search-admin-link-select api-entity="$ctrl.apiEntity" api-params="$ctrl.apiParams" link="item" links="$ctrl.links" on-change="$ctrl.onChangeLink(item, newLink)"></crm-search-admin-link-select>
</td>
<td class="form-inline">
<input ng-model="item.condition[0]" crm-ui-select="{placeholder: item.action ? ts('Allowed') : ts('Always'), data: $ctrl.fields}" ng-change="$ctrl.onChangeCondition(item)">
<select ng-if="item.condition[0]" class="form-control api4-operator" ng-model="item.condition[1]" ng-options="o.key as o.value for o in $ctrl.getOperators(item.condition)">
</select>
<div class="form-group" ng-if="item.condition[0] === 'check user permission'">
<input class="form-control" crm-ui-select="{data: $ctrl.permissions}" ng-model="item.condition[2]">
</div>
<div class="form-group" ng-if="item.condition[0] && item.condition[0] !== 'check user permission' && item.condition[1].indexOf('IS ') !== 0">
<crm-search-input ng-model="item.condition[2]" field="$ctrl.getField(item.condition[0])" option-key="'name'" op="item.condition[1]" class="form-group"></crm-search-input>
</div>
</td>
<td>
<div class="btn-group">
<button type="button" style="min-width: 85px" class="btn btn-{{ item.style }} dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,8 @@

this.getTokens = function() {
var allFields = ctrl.admin.getAllFields(ctrl.suffix || '', ['Field', 'Custom', 'Extra', 'Pseudo']);
_.eachRight(ctrl.admin.savedSearch.api_params.select, function(fieldName) {
allFields.unshift({
id: _.last(fieldName.split(' AS ')),
text: searchMeta.getDefaultLabel(fieldName)
});
});
return {
results: allFields
results: ctrl.admin.getSelectFields().concat(allFields)
};
};

Expand Down