'type' => 'search',
'title' => ts('Notes'),
'description' => '',
- 'contact_summary' => 'tab',
+ 'placement' => ['contact_summary_tab'],
'summary_weight' => 100,
'icon' => 'fa-sticky-note-o',
'summary_contact_type' => NULL,
'permission' => [
'access CiviCRM',
],
- 'contact_summary' => 'tab',
+ 'placement' => ['contact_summary_tab'],
'icon' => 'fa-handshake-o',
'summary_weight' => 80,
'permission_operator' => 'AND',
* @return array
*/
public static function getAdminSettings() {
+ $afformPlacement = \CRM_Utils_Array::formatForSelect2((array) \Civi\Api4\OptionValue::get(FALSE)
+ ->addSelect('value', 'label', 'icon', 'description')
+ ->addWhere('is_active', '=', TRUE)
+ ->addWhere('option_group_id:name', '=', 'afform_placement')
+ ->addOrderBy('weight')
+ ->execute(), 'label', 'value');
$afformTypes = (array) \Civi\Api4\OptionValue::get(FALSE)
->addSelect('name', 'label', 'icon')
->addWhere('is_active', '=', TRUE)
}
return [
'afform_type' => $afformTypes,
+ 'afform_placement' => $afformPlacement,
'search_operators' => \Civi\Afform\Utils::getSearchOperators(),
];
}
// 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', 'is_dashlet', 'contact_summary: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']
});
}
}
this.afforms = _.transform(afforms, function(afforms, afform) {
afform.type = afform.type || 'system';
- // Aggregate a couple fields for the "Placement" column
- afform.placement = [];
- if (afform.is_dashlet) {
- afform.placement.push(ts('Dashboard'));
- }
- if (afform['contact_summary:label']) {
- afform.placement.push(afform['contact_summary:label']);
- }
+ afform.placement = afform['placement:label'];
if (afform.submission_date) {
afform.submission_date = CRM.utils.formatDate(afform.submission_date);
}
});
},
- meta: CRM.afGuiEditor,
+ meta: _.extend(CRM.afGuiEditor, CRM.afAdmin),
getEntity: function(entityName) {
return CRM.afGuiEditor.entities[entityName];
delete editor.afform.name;
delete editor.afform.server_route;
delete editor.afform.navigation;
- editor.afform.is_dashlet = false;
editor.afform.title += ' ' + ts('(copy)');
}
editor.afform.icon = editor.afform.icon || 'fa-list-alt';
+ editor.afform.placement = editor.afform.placement || [];
$scope.canvasTab = 'layout';
$scope.layoutHtml = '';
$scope.entities = {};
return filter ? _.filter($scope.entities, filter) : _.toArray($scope.entities);
};
- this.toggleContactSummary = function() {
- if (editor.afform.contact_summary) {
- editor.afform.contact_summary = null;
+ this.isContactSummary = function() {
+ return editor.afform.placement.includes('contact_summary_block') || editor.afform.placement.includes('contact_summary_tab');
+ };
+
+ this.onChangePlacement = function() {
+ if (!editor.isContactSummary()) {
_.each(editor.searchDisplays, function(searchDisplay) {
delete searchDisplay.element.filters;
});
} else {
- editor.afform.contact_summary = 'block';
_.each(editor.searchDisplays, function(searchDisplay) {
var filterOptions = getSearchFilterOptions(searchDisplay.settings);
if (filterOptions.length) {
<label for="af_config_form_server_route">
{{:: ts('Page Route') }}
</label>
- <input ng-model="editor.afform.server_route" name="server_route" class="form-control" id="af_config_form_server_route" pattern="^civicrm\/[-0-9a-zA-Z\/_]+$" onfocus="this.value = this.value || 'civicrm/'" onblur="if (this.value === 'civicrm/') this.value = ''" title="{{:: ts('Path must begin with "civicrm/"') }}" ng-model-options="editor.debounceMode">
+ <input ng-model="editor.afform.server_route" name="server_route" class="form-control" id="af_config_form_server_route" pattern="^civicrm\/[-0-9a-zA-Z\/_]+$" onfocus="this.value = this.value || 'civicrm/'" onblur="if (this.value === 'civicrm/') this.value = ''" title="{{:: ts('Path must begin with "civicrm/"') }}" placeholder="{{:: ts('None') }}" ng-model-options="editor.debounceMode">
<p class="help-block">{{:: ts('Expose the form as a standalone webpage. (Example: "civicrm/my-form")') }}</p>
</div>
</label>
</div>
- <div class="form-group" ng-if="!!editor.afform.server_route">
- <label>
- <input type="checkbox" ng-model="editor.afform.is_token">
- {{:: ts('Provide Email Token') }}
- </label>
- <p class="help-block">{{:: ts('Allows CiviMail authors to easily link to this page') }}</p>
- </div>
-
<div class="form-group">
<div class="form-inline">
<label ng-class="{disabled: !editor.afform.server_route}">
</div>
<div class="form-group">
+ <label for="afform_placement">
+ {{:: ts('Expose To') }}
+ </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">{{:: ts('Additional contexts in which the form can be embedded') }}</p>
+ </div>
+
+ <div class="form-group" ng-if="editor.afform.placement.includes('contact_summary_block') || editor.afform.placement.includes('contact_summary_tab')">
<div class="form-inline">
- <label>
- <input type="checkbox" ng-checked="editor.afform.contact_summary" ng-click="editor.toggleContactSummary()">
- {{:: ts('Add to Contact Summary Page') }}
- </label>
- <select class="form-control" ng-model="editor.afform.contact_summary" ng-if="editor.afform.contact_summary">
- <option value="block">{{:: ts('As Block') }}</option>
- <option value="tab">{{:: ts('As Tab') }}</option>
- </select>
+ <label for="afform_summary_contact_type">{{:: ts('For') }}</label>
+ <input class="form-control" crm-autocomplete="'ContactType'" id="afform_summary_contact_type" ng-model="editor.afform.summary_contact_type" auto-open="true" multi="true" crm-autocomplete-params="{key: 'name'}" placeholder="{{:: ts('Any contact type') }}">
</div>
- <div class="form-inline" ng-if="editor.afform.contact_summary">
+ <div class="form-inline">
<label for="afform_summary_weight">{{:: ts('Position') }}</label>
<input class="form-control" type="number" id="afform_summary_weight" ng-model="editor.afform.summary_weight" placeholder="{{:: ts('Auto') }}">
- <label for="afform_summary_contact_type">{{:: ts('For') }}</label>
- <input class="form-control" crm-autocomplete="'ContactType'" id="afform_summary_contact_type" ng-model="editor.afform.summary_contact_type" auto-open="true" multi="true" crm-autocomplete-params="{key: 'name'}" placeholder="{{:: ts('Any contact type') }}">
</div>
- <p class="help-block" ng-show="editor.afform.contact_summary">
- {{:: ts('Placement can be configured using the Contact Layout Editor.') }}
- </p>
- </div>
-
- <div class="form-group">
- <label>
- <input type="checkbox" ng-model="editor.afform.is_dashlet">
- {{:: ts('Add to Dashboard') }}
- </label>
- <p class="help-block">{{:: ts('Allow CiviCRM users to add the form to their home dashboard.') }}</p>
</div>
</fieldset>
'requires' => [],
'title' => '',
'description' => '',
- 'is_dashlet' => FALSE,
'is_public' => FALSE,
- 'is_token' => FALSE,
'permission' => ['access CiviCRM'],
'type' => 'system',
];
*/
public static function getTokenForms() {
if (!isset(\Civi::$statics[__CLASS__]['tokenForms'])) {
- $tokenForms = (array) \Civi\Api4\Afform::get(0)
- ->addWhere('is_token', '=', TRUE)
+ $tokenForms = (array) \Civi\Api4\Afform::get(FALSE)
+ ->addWhere('placement', 'CONTAINS', 'msg_token')
->addSelect('name', 'title', 'server_route', 'is_public')
->execute()
->indexBy('name');
];
}
+ public static function shouldReconcileManaged(array $updatedAfform, array $originalAfform = []): bool {
+ $isChanged = function($field) use ($updatedAfform, $originalAfform) {
+ return ($updatedAfform[$field] ?? NULL) !== ($originalAfform[$field] ?? NULL);
+ };
+
+ return $isChanged('placement') ||
+ $isChanged('navigation') ||
+ (!empty($updatedAfform['placement']) && $isChanged('title')) ||
+ (!empty($updatedAfform['navigation']) && ($isChanged('title') || $isChanged('permission') || $isChanged('icon') || $isChanged('server_route')));
+ }
+
+ public static function shouldClearMenuCache(array $updatedAfform, array $originalAfform = []): bool {
+ $isChanged = function($field) use ($updatedAfform, $originalAfform) {
+ return ($updatedAfform[$field] ?? NULL) !== ($originalAfform[$field] ?? NULL);
+ };
+
+ return $isChanged('server_route') ||
+ (!empty($updatedAfform['server_route']) && $isChanged('title'));
+ }
+
}
if ($getSearchDisplays) {
$afforms[$name]['search_displays'] = $this->getSearchDisplays($afforms[$name]['layout']);
}
+ if (!isset($afforms[$name]['placement']) && $this->_isFieldSelected('placement')) {
+ self::convertLegacyPlacement($afforms[$name]);
+ }
}
if ($getLayout && $this->layoutFormat !== 'html') {
'requires' => [],
'title' => E::ts('%1 block', [1 => $custom['title']]),
'description' => '',
- 'is_dashlet' => FALSE,
'is_public' => FALSE,
- 'is_token' => FALSE,
'permission' => ['access CiviCRM'],
'join_entity' => 'Custom_' . $custom['name'],
'entity_type' => $custom['extends'],
return $searchDisplays;
}
+ private static function convertLegacyPlacement(array &$afform): void {
+ $afform['placement'] = [];
+ if (!empty($afform['is_dashlet'])) {
+ $afform['placement'][] = 'dashboard_dashlet';
+ }
+ if (!empty($afform['is_token'])) {
+ $afform['placement'][] = 'msg_token';
+ }
+ if (!empty($afform['contact_summary'])) {
+ $afform['placement'][] = 'contact_summary_' . $afform['contact_summary'];
+ }
+ unset($afform['is_dashlet'], $afform['is_token'], $afform['contact_summary']);
+ }
+
}
namespace Civi\Api4\Action\Afform;
+use Civi\Afform\Utils;
use Civi\Api4\Generic\Result;
use CRM_Afform_ExtensionUtil as E;
$original = (array) $scanner->getMeta($item['name']);
// If the dashlet setting changed, managed entities must be reconciled
- if (
- (empty($item['is_dashlet']) !== empty($original['is_dashlet'])) ||
- ($item['is_dashlet'] && ($item['title'] ?? '') !== ($original['title'] ?? ''))
- ) {
+ if (Utils::shouldReconcileManaged($item, $original)) {
$this->flushManaged = TRUE;
}
// If the server_route changed, reset menu cache
- if (($item['server_route'] ?? '') !== ($original['server_route'] ?? '')) {
+ if (Utils::shouldClearMenuCache($item, $original)) {
$this->flushMenu = TRUE;
}
* @return string[]
*/
protected function getSelect() {
- return ['name', 'title', 'is_dashlet', 'server_route'];
+ return ['name', 'title', 'placement', 'server_route'];
}
}
'title' => E::ts('Description'),
],
[
- 'name' => 'is_dashlet',
- 'title' => E::ts('Dashboard Dashlet'),
- 'data_type' => 'Boolean',
- ],
- [
- 'name' => 'is_public',
- 'title' => E::ts('Is Public'),
- 'data_type' => 'Boolean',
- ],
- [
- 'name' => 'is_token',
- 'title' => E::ts('Generate Tokens'),
- 'data_type' => 'Boolean',
- ],
- [
- 'name' => 'contact_summary',
- 'title' => E::ts('Contact Summary'),
- 'data_type' => 'String',
- 'options' => [
- 'block' => E::ts('Contact Summary Block'),
- 'tab' => E::ts('Contact Summary Tab'),
- ],
+ 'name' => 'placement',
+ 'title' => E::ts('Placement'),
+ 'pseudoconstant' => ['optionGroupName' => 'afform_placement'],
+ 'data_type' => 'Array',
],
[
'name' => 'summary_contact_type',
'name' => 'server_route',
'title' => E::ts('Page Route'),
],
+ [
+ 'name' => 'is_public',
+ 'title' => E::ts('Is Public'),
+ 'data_type' => 'Boolean',
+ ],
[
'name' => 'permission',
'title' => E::ts('Permission'),
namespace Civi\Api4\Utils;
+use Civi\Afform\Utils;
use CRM_Afform_ExtensionUtil as E;
/**
// We may have changed list of files covered by the cache.
_afform_clear();
- $isChanged = function($field) use ($item, $orig) {
- return ($item[$field] ?? NULL) !== ($orig[$field] ?? NULL);
- };
-
// If the dashlet or navigation setting changed, managed entities must be reconciled
- // TODO: If this list of conditions gets any longer, then
- // maybe we should unconditionally reconcile and accept the small performance drag.
- if (
- $isChanged('is_dashlet') ||
- $isChanged('navigation') ||
- (!empty($meta['is_dashlet']) && $isChanged('title')) ||
- (!empty($meta['navigation']) && ($isChanged('title') || $isChanged('permission') || $isChanged('icon') || $isChanged('server_route')))
- ) {
+ if (Utils::shouldReconcileManaged($item, $orig ?? [])) {
\CRM_Core_ManagedEntities::singleton()->reconcile(E::LONG_NAME);
}
- // Right now, permission-checks are completely on-demand.
- if ($isChanged('server_route') /* || $isChanged('permission') */) {
+ if (Utils::shouldClearMenuCache($item, $orig ?? [])) {
\CRM_Core_Menu::store();
}
if (empty($afform['name'])) {
continue;
}
+ // Backward-compat with legacy `is_dashlet`
if (!empty($afform['is_dashlet'])) {
+ $afform['placement'][] = 'dashboard_dashlet';
+ }
+ if (in_array('dashboard_dashlet', $afform['placement'] ?? [], TRUE)) {
$entities[] = [
'module' => E::LONG_NAME,
'name' => 'afform_dashlet_' . $afform['name'],
'weight' => $afform['navigation']['weight'] ?? 0,
'url' => $afform['server_route'],
'is_active' => 1,
- 'icon' => 'crm-i ' . $afform['icon'],
+ 'icon' => !empty($afform['icon']) ? 'crm-i ' . $afform['icon'] : '',
'domain_id' => $domain['id'],
],
'match' => ['domain_id', 'name'],
$contactTypes = array_merge((array) ($context['contact_type'] ?? []), $context['contact_sub_type'] ?? []);
$afforms = Civi\Api4\Afform::get(FALSE)
->addSelect('name', 'title', 'icon', 'module_name', 'directive_name', 'summary_contact_type', 'summary_weight')
- ->addWhere('contact_summary', '=', 'tab')
+ ->addWhere('placement', 'CONTAINS', 'contact_summary_tab')
->addOrderBy('title')
->execute();
$weight = 111;
}
$afforms = Civi\Api4\Afform::get(FALSE)
->addSelect('name', 'title', 'icon', 'module_name', 'directive_name', 'summary_contact_type')
- ->addWhere('contact_summary', '=', 'block')
+ ->addWhere('placement', 'CONTAINS', 'contact_summary_block')
->addOrderBy('summary_weight')
->addOrderBy('title')
->execute();
function afform_civicrm_contactSummaryBlocks(&$blocks) {
$afforms = \Civi\Api4\Afform::get(FALSE)
->setSelect(['name', 'title', 'directive_name', 'module_name', 'type', 'type:icon', 'type:label', 'summary_contact_type'])
- ->addWhere('contact_summary', '=', 'block')
+ ->addWhere('placement', 'CONTAINS', 'contact_summary_block')
->addOrderBy('title')
->execute();
foreach ($afforms as $index => $afform) {
'title' => 'Type',
'type' => CRM_Utils_Type::T_STRING,
];
- $fields['is_dashlet'] = [
- 'title' => 'Dashlet',
- 'type' => CRM_Utils_Type::T_BOOLEAN,
+ $fields['placement'] = [
+ 'title' => 'Placement',
];
$fields['is_public'] = [
'title' => 'Public',
--- /dev/null
+<?php
+
+use CRM_Afform_ExtensionUtil as E;
+
+// Option group for Afform.placement field
+return [
+ [
+ 'name' => 'AfformPlacement',
+ 'entity' => 'OptionGroup',
+ 'update' => 'always',
+ 'cleanup' => 'always',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'afform_placement',
+ 'title' => E::ts('Afform Placement'),
+ 'is_reserved' => TRUE,
+ 'is_active' => TRUE,
+ 'option_value_fields' => [
+ 'name',
+ 'label',
+ 'icon',
+ 'description',
+ ],
+ ],
+ 'match' => ['name'],
+ ],
+ ],
+ [
+ 'name' => 'AfformPlacement:dashboard_dashlet',
+ 'entity' => 'OptionValue',
+ 'cleanup' => 'always',
+ 'update' => 'always',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'option_group_id.name' => 'afform_placement',
+ 'name' => 'dashboard_dashlet',
+ 'value' => 'dashboard_dashlet',
+ 'label' => E::ts('Dashboard Dashlet'),
+ 'is_reserved' => TRUE,
+ 'is_active' => TRUE,
+ 'icon' => 'fa-tachometer',
+ 'description' => E::ts('Allow CiviCRM users to add the form to their home dashboard.'),
+ ],
+ 'match' => ['option_group_id', 'name'],
+ ],
+ ],
+ [
+ 'name' => 'AfformPlacement:contact_summary_tab',
+ 'entity' => 'OptionValue',
+ 'cleanup' => 'always',
+ 'update' => 'always',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'option_group_id.name' => 'afform_placement',
+ 'name' => 'contact_summary_tab',
+ 'value' => 'contact_summary_tab',
+ 'label' => E::ts('Contact Summary Tab'),
+ 'is_reserved' => TRUE,
+ 'is_active' => TRUE,
+ 'icon' => 'fa-address-card-o',
+ 'description' => E::ts('Add tab to contact summary page.'),
+ ],
+ 'match' => ['option_group_id', 'name'],
+ ],
+ ],
+ [
+ 'name' => 'AfformPlacement:contact_summary_block',
+ 'entity' => 'OptionValue',
+ 'cleanup' => 'always',
+ 'update' => 'always',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'option_group_id.name' => 'afform_placement',
+ 'name' => 'contact_summary_block',
+ 'value' => 'contact_summary_block',
+ 'label' => E::ts('Contact Summary Block'),
+ 'is_reserved' => TRUE,
+ 'is_active' => TRUE,
+ 'icon' => 'fa-columns',
+ 'description' => E::ts('Add block to main contact summary tab.'),
+ ],
+ 'match' => ['option_group_id', 'name'],
+ ],
+ ],
+ [
+ 'name' => 'AfformPlacement:msg_token',
+ 'entity' => 'OptionValue',
+ 'cleanup' => 'always',
+ 'update' => 'always',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'option_group_id.name' => 'afform_placement',
+ 'name' => 'msg_token',
+ 'value' => 'msg_token',
+ 'label' => E::ts('Message Tokens'),
+ 'is_reserved' => TRUE,
+ 'is_active' => TRUE,
+ 'icon' => 'fa-code',
+ 'description' => E::ts('Allows CiviMail authors to easily link to this page'),
+ ],
+ 'match' => ['option_group_id', 'name'],
+ ],
+ ],
+];
Afform::create()
->addValue('name', $this->formNames[0])
->addValue('title', 'Test B')
- ->addValue('contact_summary', 'tab')
+ ->addValue('placement', ['contact_summary_tab'])
->addValue('summary_contact_type', ['Organization'])
->execute();
Afform::create()
->addValue('name', $this->formNames[1])
->addValue('title', 'Test C')
- ->addValue('contact_summary', 'tab')
+ ->addValue('placement', ['contact_summary_tab'])
->addValue('summary_contact_type', ['FooBar'])
->addValue('icon', 'smiley-face')
->execute();
Afform::create()
->addValue('name', $this->formNames[2])
->addValue('title', 'Test A')
- ->addValue('contact_summary', 'tab')
+ ->addValue('placement', ['contact_summary_tab'])
->execute();
Afform::create()
->addValue('name', $this->formNames[3])
->addValue('title', 'Test D')
- ->addValue('contact_summary', 'tab')
+ ->addValue('placement', ['contact_summary_tab'])
->addValue('summary_contact_type', ['Individual'])
->addValue('summary_weight', 99)
->execute();
->addValue('name', $this->formNames[0])
->addValue('title', 'Test B')
->addValue('type', 'search')
- ->addValue('contact_summary', 'block')
+ ->addValue('placement', ['contact_summary_block'])
->addValue('summary_contact_type', ['Individual', 'Household'])
->execute();
Afform::create()
->addValue('name', $this->formNames[1])
->addValue('title', 'Test C')
->addValue('type', 'form')
- ->addValue('contact_summary', 'block')
+ ->addValue('placement', ['contact_summary_block'])
->addValue('summary_contact_type', ['Farm'])
->addValue('icon', 'smiley-face')
->execute();
->addValue('name', $this->formNames[2])
->addValue('type', 'form')
->addValue('title', 'Test A')
- ->addValue('contact_summary', 'block')
+ ->addValue('placement', ['contact_summary_block'])
->execute();
Afform::create()
->addValue('name', $this->formNames[3])
->addValue('type', 'form')
->addValue('title', 'A Weight Test')
- ->addValue('contact_summary', 'block')
+ ->addValue('placement', ['contact_summary_block'])
->addValue('summary_weight', 99)
->execute();
$this->assertEquals(['name', 'label', 'icon', 'description'], $fields['type']['suffixes']);
$this->assertTrue($fields['base_module']['options']);
- $this->assertTrue($fields['contact_summary']['options']);
+ $this->assertTrue($fields['placement']['options']);
}
public function testGetEntityFields():void {
public function getBasicDirectives() {
return [
- ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => ['access Foobar'], 'is_dashlet' => TRUE, 'submit_enabled' => TRUE]],
- ['mockBareFile', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM'], 'is_dashlet' => FALSE, 'submit_enabled' => TRUE]],
+ ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => ['access Foobar'], 'placement' => ['dashboard_dashlet'], 'submit_enabled' => TRUE]],
+ ['mockBareFile', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM'], 'placement' => [], 'submit_enabled' => TRUE]],
['mockFoo', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM']], 'submit_enabled' => TRUE],
['mock-weird-name', ['title' => 'Weird Name', 'description' => '', 'permission' => ['access CiviCRM']], 'submit_enabled' => TRUE],
];
$dashlet = Dashboard::get(FALSE)
->addWhere('name', '=', $formName)
->execute();
- if (!empty($afform['is_dashlet'])) {
+ if (in_array('dashboard_dashlet', $afform['placement'] ?? [], TRUE)) {
$this->assertCount(1, $dashlet);
}
else {
$this->assertEquals($get($originalMetadata, 'title'), $get($result[0], 'title'), $message);
$this->assertEquals($get($originalMetadata, 'description'), $get($result[0], 'description'), $message);
$this->assertEquals($get($originalMetadata, 'server_route'), $get($result[0], 'server_route'), $message);
- $this->assertEquals($get($originalMetadata, 'is_dashlet'), $get($result[0], 'is_dashlet'), $message);
+ $this->assertEquals($get($originalMetadata, 'placement') ?? [], $get($result[0], 'placement'), $message);
$this->assertEquals($get($originalMetadata, 'permission'), $get($result[0], 'permission'), $message);
$this->assertTrue(is_array($result[0]['layout']), $message);
$this->assertEquals(TRUE, $get($result[0], 'has_base'), $message);
->addWhere('name', '=', $formName)
->addValue('description', 'The temporary description')
->addValue('permission', ['access foo', 'access bar'])
- ->addValue('is_dashlet', empty($originalMetadata['is_dashlet']))
+ ->addValue('placement', empty($originalMetadata['placement']) ? ['dashboard_dashlet'] : [])
->execute();
$this->assertEquals($formName, $result[0]['name'], $message);
$this->assertEquals('The temporary description', $result[0]['description'], $message);
$this->assertEquals($formName, $result[0]['name'], $message);
$this->assertEquals($get($originalMetadata, 'title'), $get($result[0], 'title'), $message);
$this->assertEquals('The temporary description', $get($result[0], 'description'), $message);
- $this->assertEquals(empty($originalMetadata['is_dashlet']), $get($result[0], 'is_dashlet'), $message);
+ $this->assertNotEquals($get($originalMetadata, 'placement'), $get($result[0], 'placement'), $message);
$this->assertEquals($get($originalMetadata, 'server_route'), $get($result[0], 'server_route'), $message);
$this->assertEquals(['access foo', 'access bar'], $get($result[0], 'permission'), $message);
$this->assertTrue(is_array($result[0]['layout']), $message);
$this->assertEquals($get($originalMetadata, 'description'), $get($result[0], 'description'), $message);
$this->assertEquals($get($originalMetadata, 'server_route'), $get($result[0], 'server_route'), $message);
$this->assertEquals($get($originalMetadata, 'permission'), $get($result[0], 'permission'), $message);
- $this->assertEquals($get($originalMetadata, 'is_dashlet'), $get($result[0], 'is_dashlet'), $message);
+ $this->assertEquals($get($originalMetadata, 'placement') ?? [], $get($result[0], 'placement'), $message);
$this->assertTrue(is_array($result[0]['layout']), $message);
$this->assertEquals(TRUE, $get($result[0], 'has_base'), $message);
$this->assertEquals(FALSE, $get($result[0], 'has_local'), $message);
return [
'type' => 'search',
'title' => E::ts('Grants'),
- 'contact_summary' => 'tab',
+ 'placement' => ['contact_summary_tab'],
'summary_weight' => 60,
'icon' => 'fa-money',
'server_route' => '',