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

dev/core#5654 add support for tagging Afforms using Tag entity #31890

Merged
merged 9 commits into from
Feb 6, 2025
2 changes: 2 additions & 0 deletions ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public static function getAdminSettings() {
->addWhere('option_group_id:name', '=', 'afform_placement')
->addOrderBy('weight')
->execute(), 'label', 'value');
$afformTags = \CRM_Utils_Array::formatForSelect2((array) \Civi\Api4\Utils\AfformTags::getTagOptions());
$afformTypes = (array) \Civi\Api4\OptionValue::get(FALSE)
->addSelect('name', 'label', 'icon')
->addWhere('is_active', '=', TRUE)
Expand All @@ -38,6 +39,7 @@ public static function getAdminSettings() {
return [
'afform_type' => $afformTypes,
'afform_placement' => $afformPlacement,
'afform_tags' => $afformTags,
'search_operators' => \Civi\Afform\Utils::getSearchOperators(),
];
}
Expand Down
2 changes: 1 addition & 1 deletion ext/afform/admin/ang/afAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Load data for lists
afforms: function(crmApi4) {
return crmApi4('Afform', 'get', {
select: ['name', 'title', 'type', 'server_route', 'is_public', 'submission_count', 'submission_date', 'submit_limit', 'submit_enabled', 'submit_currently_open', 'has_local', 'has_base', 'base_module', 'base_module:label', 'placement:label']
select: ['name', 'title', 'type', 'server_route', 'is_public', 'submission_count', 'submission_date', 'submit_limit', 'submit_enabled', 'submit_currently_open', 'has_local', 'has_base', 'base_module', 'base_module:label', 'placement:label', 'tags:label']
});
}
}
Expand Down
1 change: 1 addition & 0 deletions ext/afform/admin/ang/afAdmin/afAdminList.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
this.afforms = _.transform(afforms, function(afforms, afform) {
afform.type = afform.type || 'system';
afform.placement = afform['placement:label'];
afform.tags = afform['tags:label'];
if (afform.submission_date) {
afform.submission_date = CRM.utils.formatDate(afform.submission_date);
}
Expand Down
14 changes: 12 additions & 2 deletions ext/afform/admin/ang/afAdmin/afAdminList.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ <h1 crm-page-title>{{:: ts('FormBuilder') }}</h1>
<i class="crm-i fa-sort-{{ $ctrl.sortDir ? 'asc' : 'desc' }}" ng-if="$ctrl.sortField === 'base_module'"></i>
{{:: ts('Package') }}
</th>
<th></th>
<th title="{{:: ts('Click to sort') }}" ng-click="$ctrl.sortBy('tags')">
<i class="crm-i fa-sort disabled" ng-if="$ctrl.sortField !== 'tags'"></i>
<i class="crm-i fa-sort-{{ $ctrl.sortDir ? 'asc' : 'desc' }}" ng-if="$ctrl.sortField === 'tags'"></i>
{{:: ts('Tags') }}
</th>
<th>{{:: ts('Actions') }}</th>
</tr>
</thead>
<tbody>
Expand All @@ -90,7 +95,9 @@ <h1 crm-page-title>{{:: ts('FormBuilder') }}</h1>
{{:: afform.server_route }}
</a>
</td>
<td>{{:: afform.placement.join(', ') }}</td>
<td>
{{:: afform.placement.join(', ') }}
</td>
<td ng-if="$ctrl.tab === 'form'">
{{:: afform.submit_currently_open ? ts('Open') : ts('Closed') }}
<span ng-if="afform.submit_limit && afform.submit_enabled">
Expand All @@ -108,6 +115,9 @@ <h1 crm-page-title>{{:: ts('FormBuilder') }}</h1>
<td>
{{:: afform['base_module:label'] }}
</td>
<td>
{{:: afform.tags.join(', ') }}
</td>
<td class="text-right">
<a ng-if="afform.type !== 'system'" ng-href="#/edit/{{:: afform.name }}" class="btn btn-xs btn-primary">{{:: ts('Edit') }}</a>
<a ng-if="afform.type !== 'system'" ng-href="#/clone/{{:: afform.name }}" class="btn btn-xs btn-secondary">{{:: ts('Clone') }}</a>
Expand Down
10 changes: 9 additions & 1 deletion ext/afform/admin/ang/afGuiEditor/config-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,21 @@
</label>
<input ng-list crm-ui-select="{multiple: true, data: editor.meta.afform_placement, placeholder: ts('None')}" class="form-control" id="afform_placement" ng-model="editor.afform.placement" ng-change="editor.onChangePlacement()">
<p class="help-block" ng-if="editor.afform.server_route || !editor.placementRequiresServerRoute()">
{{:: ts('Additional contexts in which the form can be embedded') }}
{{:: ts('Additional contexts in which the form can be embedded.') }}
</p>
<p class="text-warning" ng-if="!editor.afform.server_route && editor.placementRequiresServerRoute()">
<i class="crm-i fa-exclamation-triangle"></i>{{ ts('%1 placement requires a page route.', {1: editor.placementRequiresServerRoute()}) }}
</p>
</div>

<div class="form-group">
<label for="afform_tags">
{{:: ts('Tags') }}
</label>
<input ng-list crm-ui-select="{multiple: true, data: editor.meta.afform_tags, placeholder: ts('None')}" class="form-control" id="afform_tags" ng-model="editor.afform.tags">
<p class="help-block">{{:: ts('Tags can be used to keep track of your forms if Used For is set to include Afform.') }} <a target="_blank" href="/civicrm/tag?reset=1">{{:: ts('Manage Tags') }}</a></p>
</div>

<div class="form-group" ng-if="editor.isContactSummary()">
<div class="form-inline">
<label for="afform_summary_contact_type">{{:: ts('For') }}</label>
Expand Down
9 changes: 9 additions & 0 deletions ext/afform/core/Civi/Api4/Afform.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ public static function getFields($checkPermissions = TRUE) {
'pseudoconstant' => ['optionGroupName' => 'afform_placement'],
'data_type' => 'Array',
],
[
'name' => 'tags',
'title' => E::ts('Tags'),
'pseudoconstant' => [
'callback' => [Utils\AfformTags::class, 'getTagOptions'],
],
'data_type' => 'Array',
'input_type' => 'Select',
],
[
'name' => 'summary_contact_type',
'title' => E::ts('Summary Contact Type'),
Expand Down
34 changes: 34 additions & 0 deletions ext/afform/core/Civi/Api4/Utils/AfformTags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
namespace Civi\Api4\Utils;

/**
* Class AfformTags
* @package Civi\Api4\Utils
*
* Utils for managing the tags field on Afforms
*
*/
class AfformTags {

/**
* @return array
*/
public static function getTagOptions(): array {
$tagRecords = (array) \Civi\Api4\Tag::get(FALSE)
->addSelect('name', 'label', 'description', 'color')
->addWhere('used_for', 'CONTAINS', 'Afform')
->addWhere('is_selectable', '=', TRUE)
->execute();

$tagOptions = [];

// prefer tag names to keys for portability
foreach ($tagRecords as $record) {
$record['id'] = $record['name'];
$tagOptions[] = $record;
}

return $tagOptions;
}

}
31 changes: 31 additions & 0 deletions ext/afform/core/managed/AfformTags.mgd.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use CRM_Afform_ExtensionUtil as E;

// This file:
// - adds option value to `tag_used_for`, allowing Afforms to be tagged
// NOTE: this is unusual in that afform is not a db entity
// (normally the value normally corresponds to a physical table name in the
// database - here it is just the entity name)
return [
[
'name' => 'AfformTags:tag_used_for',
'entity' => 'OptionValue',
'cleanup' => 'always',
'update' => 'always',
'params' => [
'version' => 4,
'values' => [
'option_group_id.name' => 'tag_used_for',
'value' => 'Afform',
'name' => 'Afform',
'label' => E::ts('Afforms'),
'is_reserved' => TRUE,
'is_active' => TRUE,
// this excludes it from being selected in EntityTag entity_table
'filter' => 1,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is filter normally used for ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not much of anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it have a more semantic value? Like filter = 'tableless' and then the condition != tableless?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh the table column is an int.. so no

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment for the significance

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And removed the example tag

],
'match' => ['option_group_id', 'name'],
],
],
];
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<af-field name="title" />
<af-field name="description" />
<af-field name="base_module" defn="{input_attrs: {multiple: true}}" />
<af-field name="tags" defn="{search_operator: 'CONTAINS', input_attrs: {}, label: 'Tag'}" />
</div>
<crm-search-display-table search-name="SearchKit_Reports" display-name="SearchKit_Reports_Table"></crm-search-display-table>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
'description',
'placement:label',
'server_route',
'tags:label',
],
'orderBy' => [],
'where' => [
Expand Down Expand Up @@ -68,14 +69,21 @@
'label' => E::ts('Description'),
'sortable' => TRUE,
],
[
'type' => 'field',
'key' => 'tags:label',
'dataType' => 'Array',
'label' => E::ts('Tags'),
'sortable' => TRUE,
],
[
'size' => 'btn-xs',
'links' => [
[
'path' => '[server_route]',
'icon' => 'fa-external-link',
'text' => E::ts('Open'),
'style' => 'info',
'path' => 'civicrm/admin/afform#/edit/[name]',
'icon' => 'fa-pen-to-square',
'text' => E::ts('Edit'),
'style' => 'warning',
'condition' => [],
'task' => '',
'entity' => '',
Expand All @@ -84,10 +92,10 @@
'target' => '',
],
[
'path' => 'civicrm/admin/afform#/edit/[name]',
'icon' => 'fa-pen-to-square',
'text' => E::ts('Edit'),
'style' => 'warning',
'path' => '[server_route]',
'icon' => 'fa-external-link',
'text' => E::ts('Open'),
'style' => 'info',
'condition' => [],
'task' => '',
'entity' => '',
Expand Down
2 changes: 2 additions & 0 deletions schema/Core/EntityTag.entityType.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
'add' => '3.2',
'pseudoconstant' => [
'option_group_name' => 'tag_used_for',
// exclude taggable entities without tables (that therefore dont use EntityTable)
'condition' => 'filter = 0',
],
],
'entity_id' => [
Expand Down
2 changes: 1 addition & 1 deletion tests/phpunit/api/v3/EntityTagACLTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function setUp(): void {
* @return array
*/
public function getTagOptions() {
$options = $this->callAPISuccess('Tag', 'getoptions', ['field' => 'used_for']);
$options = $this->callAPISuccess('EntityTag', 'getoptions', ['field' => 'entity_table']);
return $options['values'];
}

Expand Down