From c2922b2e1b3f13dae31d6524621cd03b74ff8372 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Mon, 30 Sep 2024 11:42:04 +0300 Subject: [PATCH] Refactor Enrollment Attributes Add/Edit view --- .../resources/locales/en_US/core_enroller.po | 14 +- .../Model/Table/EnrollmentAttributesTable.php | 2 +- .../EnrollmentAttributes/columns.inc | 71 +- .../templates/EnrollmentAttributes/fields.inc | 694 +++++------------- app/src/Lib/Traits/TabTrait.php | 9 +- app/src/View/Helper/FieldHelper.php | 20 +- app/templates/EnrollmentFlows/start.php | 2 +- app/templates/Standard/index.php | 24 +- app/templates/element/form/fieldDiv.php | 6 + app/templates/element/form/nameDiv.php | 1 + 10 files changed, 296 insertions(+), 547 deletions(-) diff --git a/app/plugins/CoreEnroller/resources/locales/en_US/core_enroller.po b/app/plugins/CoreEnroller/resources/locales/en_US/core_enroller.po index b7df19fd3..9fd6389a2 100644 --- a/app/plugins/CoreEnroller/resources/locales/en_US/core_enroller.po +++ b/app/plugins/CoreEnroller/resources/locales/en_US/core_enroller.po @@ -32,9 +32,6 @@ msgstr "{0,plural,=1{Enrollment Attribute} other{Enrollment Attributes}}" msgid "enumeration.DefaultValueValidityType.after" msgstr "Days After Finalization" -msgid "enumeration.DefaultValueValidityType.on" -msgstr "On This Date" - msgid "field.EnrollmentAttributes.address_required_fields" msgstr "Required Address Fields" @@ -57,19 +54,22 @@ msgid "field.EnrollmentAttributes.default_value" msgstr "Default Value" msgid "field.EnrollmentAttributes.default_value_affiliation_type_id" -msgstr "Default Value" +msgstr "Default Affiliation Type" msgid "field.EnrollmentAttributes.default_value_cou_id" -msgstr "Default Value" +msgstr "Default Cou" msgid "field.EnrollmentAttributes.default_value_datetime" -msgstr "Default Value" +msgstr "Default Datetime" + +msgid "field.EnrollmentAttributes.default_value_datetime.desc" +msgstr "On This Date" msgid "field.EnrollmentAttributes.default_value_env_name" msgstr "Environmental Variable for Default Value" msgid "field.EnrollmentAttributes.default_value_group_id" -msgstr "Default Value" +msgstr "Default Group" msgid "field.EnrollmentAttributes.default_value_validity_type" msgstr "Default Validity Date Type" diff --git a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php index 64538be5d..a9b6bc9e4 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php @@ -299,7 +299,7 @@ public function supportedAttributes(string $format='full'): array { $attrs['name'] = [ 'label' => __d('controller', 'Names', [1]), - 'mveaModel' => 'Namen', + 'mveaModel' => 'Names', 'mveaParents' => ['Person'] ]; diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc index b1d8006e1..01bf7b8a2 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc @@ -25,6 +25,10 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ +declare(strict_types = 1); + +use \Cake\Utility\Inflector; + $indexColumns = [ 'label' => [ 'type' => 'link', @@ -46,4 +50,69 @@ $indexColumns = [ 'type' => 'boolean', 'class' => 'YesBooleanEnum' ] -]; \ No newline at end of file +]; + + +if(empty($attributes)) { + return; +} + +// Map attributes to icons +$attributeToIcons = + [ + 'adHocAttribute' => 'grass', + 'address' => 'home', + 'affiliation_type_id' => 'person_search', + 'cou_id' => 'supervised_user_circle', + 'date_of_birth' => 'event', + 'department' => 'domain', + 'emailAddress' => 'email', + 'group_id' => 'groups', + 'identifier' => 'badge', + 'manager_person_id' => 'supervisor_account', + 'name' => 'face', + 'organization' => 'corporate_fare', + 'pronoun' => 'transgender', + 'sponsor_person_id' => 'person', + 'telephoneNumber' => 'call', + 'petition_textarea' => 'text_fields', + 'petition_text' => 'text_fields', + 'title' => 'title', + 'url' => 'link', + 'valid_from' => 'calendar_month', + 'valid_through' => 'calendar_month' + ]; + +// Build the Add menu +$action_args = array(); +// This is an add action as a result we do not have an obect id +// and we will use the username instead. +$action_args['vv_attr_id'] = $vv_user['username']; +$action_args['vv_actions_type'] = 'mvea-add-menu'; +$action_args['vv_actions_title'] = __d('operation', 'add'); +$action_args['vv_actions_icon'] = 'add_circle'; +$action_args['vv_actions_class'] = 'mvea-add-menu'; +$actionOrderDefault = $this->Menu->getMenuOrder('Default'); +foreach ($attributes as $attr => $hr_name) { + $actionLabel = $hr_name; + $actionClass = 'cm-modal-link nospin'; + $actionOrder = $actionOrderDefault++; + $actionIcon = $attributeToIcons[$attr] ?? $this->Menu->getMenuIcon('Default'); + $dataAttrs = ['data-cm-modal-title', __d('file-connector', 'EnrollmentAttributes', 1)]; + $actionUrl = [ + 'pluing' => $this->getPlugin(), + 'controller' => $vv_controller, + 'action' => 'add', + '?' => array_merge($linkFilter, ['attribute_type' => $attr]) + ]; + + $action_args['vv_actions'][] = [ + 'order' => $actionOrder, + 'icon' => $actionIcon, + 'iconClass' => '', + 'url' => $actionUrl, + 'class' => $actionClass, + 'label' => $actionLabel, + 'dataAttrs' => [] + ]; +} diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc index 8791062f7..511bada1d 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc @@ -24,582 +24,240 @@ * @since COmanage Registry v5.0.0 * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ -?> - - -element('form/listItem', [ - 'arguments' => [ - 'fieldName' => $field - ]]); - } +/* + * MVEAS which are allowed to attach to a Person or PersonRole + */ +if ( + !empty($vv_supported_attributes[$attribute_type]['mveaParents']) + && count($vv_supported_attributes[$attribute_type]['mveaParents']) > 0 +) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => 'attribute', + 'fieldName' => 'attribute_mvea_parent', 'fieldOptions' => [ - 'onChange' => 'updateGadgets()' - ] + 'empty' => false + ], + 'fieldType' => 'select', + 'fieldSelectOptions' => array_combine( + $vv_supported_attributes[$attribute_type]['mveaParents'], + $vv_supported_attributes[$attribute_type]['mveaParents'] + ) ] ]); - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => 'attribute_mvea_parent', - ] - ]); // This field is called attribute_type and not attribute_type_id because we want this // to behave as a hidden value populated by the appropriate select, and we don't want // Cake to implement foreign key automagic. - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => 'attribute_type' - ]]); - - // These are the actual selects that will render for the appropriate Attribute - foreach (['address_type_id', - 'email_address_type_id', - 'identifier_type_id', - 'name_type_id', - 'pronoun_type_id', - 'telephone_number_type_id', - 'url_type_id', - ] as $field) { + $mveaAutoPopulatedVariable = $attribute_type . 'Types'; + // Check if this mvea model supports types, if it does then render the attribute type + // dropdown list + if ($this->get($mveaAutoPopulatedVariable) !== null) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => $field, + 'fieldName' => 'attribute_type', + 'fieldLabel' => $attributes[$attribute_type] . ' Type', 'fieldOptions' => [ - 'onChange' => "document.getElementById('attribute-type').value = document.getElementById('" . $field . "').value" - ] + 'empty' => false + ], + 'fieldType' => 'select', + 'fieldSelectOptions' => $this->get($mveaAutoPopulatedVariable) ] ]); } +} - foreach ( ['attribute_language', - 'attribute_tag', - 'status', - 'ordr', - ] as $field) { +/* + * Default Values field + * Supported for attributes: group_id, cou_id, affiliation_type_id + */ +if(str_ends_with($attribute_type, '_id')) { + $suffix = substr($attribute_type, 0, -3); + $suffix = Inflector::pluralize(Inflector::camelize($suffix)) ; + $defaultValuesPopulated = 'defaultValue' . $suffix; + if ($this->get($defaultValuesPopulated) !== null) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => $field - ]]); - } - - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => 'default_value_validity_type', - 'fieldOptions' => [ - 'on' => __d('core_enroller', 'enumeration.DefaultValueValidityType.on'), - 'after' => __d('core_enroller', 'enumeration.DefaultValueValidityType.after'), - 'onChange' => 'updateValidityGadgets()' + 'fieldName' => 'default_value', + 'fieldOptions' => [ + 'empty' => true + ], + 'fieldType' => 'select', + 'fieldSelectOptions' => $this->get($defaultValuesPopulated) ] - ]]); + ]); + } +} - // The default value is always stored in default_value, however for select based fields - // (such as cou_id or affiliation) the value is copied into default_value and the - // field specific attribute is used for display purposes only +/* + * Attribute Tag field + * + * Supported for attributes: adHocAttribute + */ +if (\in_array($attribute_type, ['adHocAttribute'], true)) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => 'default_value' + 'fieldName' => 'attribute_tag', ]]); +} - foreach (['default_value_affiliation_type_id', - 'default_value_cou_id', - 'default_value_group_id' - ] as $field) { +/* + * Attribute Required field + * Attribute Language field + * + * Supported for attributes: name, address + */ +if(\in_array($attribute_type, ['name', 'address', 'pronoun'], true)) { + $requiredFieldsPopulated = $attribute_type . 'RequiredFields'; + // Pronouns have no required fields at the moment, as a result we will not render any. + if ($this->get($requiredFieldsPopulated) !== null) { + $label = __d('core_enroller', 'field.EnrollmentAttributes.' . $attribute_type . '_required_fields'); print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => $field, - 'fieldOptions' => [ - 'onChange' => "document.getElementById('default-value').value = document.getElementById('" . $field . "').value" - ] + 'fieldLabel' => $label, + 'fieldName' => 'attribute_required_fields', + 'fieldOptions' => [ + 'empty' => true + ], + 'fieldType' => 'select', + 'fieldSelectOptions' => $this->get($requiredFieldsPopulated) ] ]); } - foreach ( ['default_value_datetime', - 'default_value_env_name', - ] as $field) { - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => $field - ]]); - } print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => 'required', - 'fieldOptions' => [ - 'default' => true - ] + 'fieldName' => 'attribute_language', ]]); +} - // Like attribute_type, this is a "behind the scenes" field that is not directly edited + +/* + * Default Environmental Variable Name field + */ +$defaultValueEnvNameSupported = [ + 'address', 'adHocAttribute', 'emailAddress', 'identifier', 'name' ,'pronoun', 'telephoneNumber', 'url' +]; +$personRoleExclude = [ + 'affiliation_type_id', 'cou_id', 'valid_from', 'valid_through' +]; +if ( + \in_array($attribute_type, $defaultValueEnvNameSupported, true) + || ( + isset($vv_supported_attributes[$attribute_type]['model']) + && $vv_supported_attributes[$attribute_type]['model'] !== 'PersonRole' + && !\in_array($attribute_type, $personRoleExclude, true) + ) +) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => 'attribute_required_fields' + 'fieldName' => 'default_value_env_name', ]]); +} - foreach ([ - 'address_required_fields', - 'name_required_fields', +/* + * The valid from attribute is a dateTime field + * + */ +if($attribute_type === 'valid_from') { + print $this->element('form/listItem', [ + 'arguments' => [ + 'fieldName' => 'default_value_datetime', + 'fieldType' => 'datetime' + ]]); +} - ] as $field) { - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => $field, - 'fieldOptions' => [ - 'onChange' => "document.getElementById('attribute-required-fields').value = document.getElementById('" . $field . "').value" - ] +/* + * The valid through attribute is a textbox/number field + */ +if($attribute_type === 'valid_through') { + print $this->element('form/listItem', [ + 'arguments' => [ + 'fieldName' => 'default_value', + 'fieldDescription' => __d('core_enroller', 'enumeration.DefaultValueValidityType.after'), + 'fieldOptions' => [ + 'type' => 'number' ] - ]); - } + ]]); +} +/* + * Fields modifiable, hidden + * Supported for Models: PersonRole, Person, Group + */ +if ( + isset($vv_supported_attributes[$attribute_type]['model']) + && \in_array($vv_supported_attributes[$attribute_type]['model'], ['PersonRole', 'Person', 'Group'], true) +) { print $this->element('form/listItem', [ 'arguments' => [ - 'fieldName' => 'modifiable', + 'fieldName' => 'modifiable', 'fieldOptions' => [ 'default' => true ] - ]]); + ] + ]); print $this->element('form/listItem', [ 'arguments' => [ diff --git a/app/src/Lib/Traits/TabTrait.php b/app/src/Lib/Traits/TabTrait.php index 0144c11e3..331224cd2 100644 --- a/app/src/Lib/Traits/TabTrait.php +++ b/app/src/Lib/Traits/TabTrait.php @@ -35,12 +35,14 @@ trait TabTrait * Tabs configuration * * @var array - */ + * @since COmanage Registry v5.0.0 + */ private array $tabsConfig = []; /** * @return array - */ + * @since COmanage Registry v5.0.0 + */ public function getTabsConfig(): array { return $this->tabsConfig; @@ -50,7 +52,8 @@ public function getTabsConfig(): array * @param array $tabsConfig * * @return void - */ + * @since COmanage Registry v5.0.0 + */ public function setTabsConfig(array $tabsConfig): void { $this->tabsConfig = $tabsConfig; diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 818fd307d..396621c23 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -307,11 +307,13 @@ public function dateField(string $fieldName, /** * Create the actual Form element * - * @param string $fieldName Form field - * @param array|null $fieldOptions The second parameter of the Form->control helper. List of element options - * @param string|null $fieldLabel Custom label thext - * @param string $fieldPrefix If the field has a specil prefix provide the value - * @param string|null $fieldType Field type to override the one calculated from the schema + * @param string $fieldName Form field + * @param array|null $fieldOptions The second parameter of the Form->control helper. List of element options + * @param string|null $fieldLabel Custom label thext + * @param string $fieldPrefix If the field has a specil prefix provide the value + * @param string|null $fieldType Field type to override the one calculated from the schema + * @param array|null $fieldSelectOptions Options array to override the one calculated options from the AutoPopulate property + * fieldType has to be 'select' * * @return string HTML element * @since COmanage Registry v5.0.0 @@ -320,7 +322,8 @@ public function formField(string $fieldName, array $fieldOptions = null, string $fieldLabel = null, string $fieldPrefix = '', - string $fieldType = null): string + string $fieldType = null, + array $fieldSelectOptions = null): string { $fieldArgs = $fieldOptions ?? []; $fieldArgs['label'] = $fieldOptions['label'] ?? false; @@ -347,8 +350,8 @@ public function formField(string $fieldName, // Check if the empty option comes with a value if($fieldArgs['empty'] - && !empty($fieldOptions['empty']) - && \is_string($fieldOptions['empty'])) { + && isset($fieldOptions['empty']) + && \is_bool($fieldOptions['empty'])) { $fieldArgs['empty'] = $fieldOptions['empty']; } @@ -380,6 +383,7 @@ public function formField(string $fieldName, 'label' => $fieldLabel, 'class' => 'form-check-input', ]), + 'select' => $this->Form->select($fieldName, $fieldSelectOptions, $fieldArgs), 'date' => $this->dateField($fieldName, DateTypeEnum::DateOnly), 'datetime', 'timestamp' => $this->dateField($fieldName), diff --git a/app/templates/EnrollmentFlows/start.php b/app/templates/EnrollmentFlows/start.php index ecf30a486..2887d05f2 100644 --- a/app/templates/EnrollmentFlows/start.php +++ b/app/templates/EnrollmentFlows/start.php @@ -31,7 +31,7 @@
-

+

diff --git a/app/templates/Standard/index.php b/app/templates/Standard/index.php index 114141198..7a1e6b532 100644 --- a/app/templates/Standard/index.php +++ b/app/templates/Standard/index.php @@ -58,10 +58,6 @@ if(!is_readable($incFile)) { throw new \InvalidArgumentException("$incFile is not readable"); } -include($incFile); -if(isset($indexColumns)) { - $this->set('vv_indexColumns', $indexColumns); -} // $linkFilter is used for models that belong to a specific parent model (eg: co_id) $linkFilter = []; @@ -79,6 +75,13 @@ $flashArgs['vv_banners'] = $banners; } +// First, complete all the initial calculations and then start including +// this way we have more ViewVars available +include($incFile); +if(isset($indexColumns)) { + $this->set('vv_indexColumns', $indexColumns); +} + // Subnavigation if(file_exists(ROOT . DS . 'templates' . DS . 'Standard/subnavigation.inc')) { include(ROOT . DS . 'templates' . DS . 'Standard/subnavigation.inc'); @@ -98,7 +101,13 @@ // Action list for top menu dropdown / button listing // Index view top link action item can be atomized using the user's identifier // since there will not always be an object id available. Like the case of add action - if($vv_permissions['add']) { + if( + // Action menu is only supported for index views and add actions + $vv_permissions['add'] + // A plugin might provide its own set of action_args, in this scenario + // we will bypass the default behavior + && empty($action_args) + ) { $action_args = []; $action_args['vv_attr_id'] = $vv_user['username']; $action_args['vv_actions'] = []; @@ -132,8 +141,7 @@ $action_args['vv_actions'][] = $action_configuration; } - - + if(!empty($peoplePicker)) { // There is a page-level autocomplete people picker. $action_args['vv_people_picker'] = $peoplePicker; @@ -208,7 +216,7 @@ $indexTableClasses .= ' with-actions'; } ?> - +
element('form/nameDiv'); + // This configuration isn't necessary anymore. + if(isset($vv_field_arguments['fieldDescription'])) { + unset($vv_field_arguments['fieldDescription']); + $this->set('vv_field_arguments', $vv_field_arguments); + } + // Info Div if(isset($vv_field_arguments['fieldPrefix'])) { print $this->element('form/infoDiv/withPrefix'); diff --git a/app/templates/element/form/nameDiv.php b/app/templates/element/form/nameDiv.php index dfd74c93c..db9774612 100644 --- a/app/templates/element/form/nameDiv.php +++ b/app/templates/element/form/nameDiv.php @@ -57,6 +57,7 @@ [$label, $desc] = $this->Field->calculateLabelAndDescription($fn); $label = $vv_field_arguments['fieldLabel'] ?? $label; +$desc = $vv_field_arguments['fieldDescription'] ?? $desc; // We determine if a field is rquired by first getting the "expected" value // from FieldHelper, then overriding that value if an argument was passed in.