-
Notifications
You must be signed in to change notification settings - Fork 3
Improve Relink UI and add People Picker (CFM-125) #316
base: develop
Are you sure you want to change the base?
Conversation
@@ -471,6 +471,9 @@ msgstr "Redirect on Duplicate" | |||
msgid "EnrollmentFlows.redirect_on_finalize" | |||
msgstr "Redirect on Finalize" | |||
|
|||
msgid "ExternalIdentitySources.target_person_id" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be ExternalIdentities
instead of ExternalIdentitySources
?> | ||
<ul id="edit_ei-relink" class="fields form-list"> | ||
<?php | ||
$this->Form->unlockField('target_person_id'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the field does not have to be unlocked. The reason why this is needed is because the backend does not know this field name. We can use the person_id
field name which is known to the backend. If we do that we need to parse the id of the user friendly people picker string either before we load the RegistryAuth
module - in the AppController.php file - or in the module itself.
$personId = StringUtilities::extractPeoplePickerPersonId($reqData['person_id'])
If we do not mind having the unlocked field then it works well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow the comment about the backend not knowing the field name, what do you mean by "the backend"?
This is a custom form that is generated by the relink view to pass a variable that is parsed by ExternalIdentitiesController::relink()
and then passed to PipelinesTable::relink()
as a parameter (and is validated there). The name target_person_id
is arbitrary and only used for this passing. Since this worked prior to the introduction of the PeoplePicker, I would assume the PeoplePicker code is doing something that causes Cake's form tampering to complain on the submit. (Give this specific use case, we could unlock the field, though I'd still like to understand what exactly is happening to require it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow the comment about the backend not knowing the field name, what do you mean by "the backend"?
What I meant is this: person_id
is a standard field in the model's schema, whereas target_person_id
is not part of the schema by default.
Currently, we’re including a Vue input element in the form, which gets submitted alongside the form data. However, since this input field isn’t rendered using the Form Helper, CakePHP detects a "form tampered" error when the field is submitted.
After some research, I discovered that one way to prevent an input field from being submitted is to remove its name
attribute. I wasn’t aware of this previously, but after testing, I found it works as expected. If we remove the name
from the Vue input and add a corresponding hidden field with the correct name, only the hidden field will be submitted. The important thing is to ensure the hidden field’s value updates whenever the Vue input changes.
[!important] The hidden field should be visually hidden and not type hidden or display none. For the type hidden use case CAKEPHP will throw a tampered form error. For the display none the field will not be submitted. The visually hidden fields take DOM space, which do not make them the best solution.
$vv_autocomplete_arguments = [
'fieldName' => target_person_id',
'fieldLabel' => __d('field', 'ExternalIdentitySources.target_person_id'),
'autocomplete' => [
'configuration' => [
'action' => 'GET',
'for' => 'co'
]
]
];
then inside the peopleAutocomplete.php
print $this->Form->control($fieldName, [
'id' => $fieldName,
'value' => '',
'type' => 'text',
'class' => 'visually-hidden',
'label' => false,
]
);
autocompleteOptions: {
inputProps: {
//name: '<?php //= $fieldName ?>//',
// This is not translated to data-personid but to datapersonid.
dataPersonid: '<?= $inputValue ?>'
},
...
}
and then inside the people picker element
setPerson() {
...
document.getElementById(this.options.hiddenFieldId).setAttribute('value', this.person.value);
...
}
hide the field:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
border: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; /* Prevent text wrapping */
}
in FieldHelper.php
public function constructSPAField(string $element, string $vueElementName): string {
...
'htmlId' => $matchesId[0][1] . '_picker',
...
}
* @return int extracted Person ID (converted to int from the extracted string) | ||
*/ | ||
|
||
public static function extractPeoplePickerPersonId(string $s): int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will the function do if the string does not match?
Arlen's original comments (from Slack):
|
No description provided.