From 7d9ef74a77fb4fa0cf0a4d0075f6b2c95ef8dd67 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Tue, 18 Aug 2026 18:38:45 -0400 Subject: [PATCH 1/4] Delete Person splash page UI updates (CFM-124) --- app/resources/locales/en_US/information.po | 25 ++- app/resources/locales/en_US/operation.po | 9 + app/src/Controller/PeopleController.php | 6 +- app/templates/People/confirm_delete.php | 239 ++++++++++++++------- app/webroot/css/co-base.css | 36 ++++ app/webroot/css/co-variables.css | 1 + 6 files changed, 230 insertions(+), 86 deletions(-) diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po index 95efe2696..b99a8386a 100644 --- a/app/resources/locales/en_US/information.po +++ b/app/resources/locales/en_US/information.po @@ -142,16 +142,16 @@ msgid "People.delete.cluster" msgstr "Account on {0}" msgid "People.delete.hard" -msgstr "Performing a hard delete will physically remove all records from the database, including all Changelog Entries. This operation cannot be undone, except by restoring from a backup." +msgstr "Performing a hard delete will physically remove all records from the database, including all Changelog Entries. This operation cannot be undone except by restoring from a backup." msgid "People.delete.history.actor" -msgstr "{0} History Records(s) for which this Person is an Actor will be updated to have no Actor" +msgstr "{0} History Records(s) for which this Person is an Actor will be updated to have no Actor." msgid "People.delete.history.job" -msgstr "{0} Job History Records(s) related to this Person will be updated to remove the link" +msgstr "{0} Job History Records(s) related to this Person will be updated to remove the link." msgid "People.delete.person" -msgstr "Deleting this record will delete the complete Person record for {1} (Person ID {2}), including history" +msgstr "Deleting this record will delete the complete Person record for {1} (Person ID {2}), including history." msgid "People.delete.ei" msgstr "External Identity {0} from {1} (Source Key: {2})" @@ -160,28 +160,31 @@ msgid "People.delete.ei.legacy" msgstr "Legacy External Identity {0}" msgid "People.delete.notifications.actor" -msgstr "{0} Notification(s) for which this Person is an Actor will be updated to have no Actor" +msgstr "{0} Notification(s) for which this Person is an Actor will be updated to have no Actor." msgid "People.delete.notifications.recipient" -msgstr "{0} Notification(s) for which this Person is a Recipient will be updated" +msgstr "{0} Notification(s) for which this Person is a Recipient will be updated." msgid "People.delete.notifications.resolver" -msgstr "{0} Notification(s) for which this Person is the Resolver will be updated to have no Resolver" +msgstr "{0} Notification(s) for which this Person is the Resolver will be updated to have no Resolver." msgid "People.delete.petitions.history.actor" -msgstr "{0} Petition History Records(s) for which this Person is an Actor will be updated to have no Actor" +msgstr "{0} Petition History Records(s) for which this Person is an Actor will be updated to have no Actor." msgid "People.delete.petitions.petitioner" -msgstr "{0} Petitions(s) for which this Person is the Petitioner will be updated to have no Petitioner" +msgstr "{0} Petitions(s) for which this Person is the Petitioner will be updated to have no Petitioner." msgid "People.delete.role" msgstr "Person Role {0}: (COU: {1}, Affiliation: {2}, Title: {3})" msgid "People.delete.roles.manager" -msgstr "{0} Person Role(s) for which this Person is a Manager will be updated to have no Manager" +msgstr "{0} Person Role(s) for which this Person is a Manager will be updated to have no Manager." msgid "People.delete.roles.sponsor" -msgstr "{0} Person Role(s) for which this Person is a Sponsor will be updated to have no Sponsor" +msgstr "{0} Person Role(s) for which this Person is a Sponsor will be updated to have no Sponsor." + +msgid "People.delete.soft" +msgstr "A soft delete will mark the Person record as "deleted" and hide it from the user interface." msgid "petition.history" msgstr "Petition History" diff --git a/app/resources/locales/en_US/operation.po b/app/resources/locales/en_US/operation.po index 6e545cf5f..3b6f003ff 100644 --- a/app/resources/locales/en_US/operation.po +++ b/app/resources/locales/en_US/operation.po @@ -192,6 +192,9 @@ msgstr "Decline" msgid "delete" msgstr "Delete" +msgid "delete.a" +msgstr "Delete {0}?" + msgid "delete.confirm" msgstr "Are you sure you want to delete this record ({0})?" @@ -199,6 +202,9 @@ msgid "delete.confirm.title" msgstr "Confirm Deletion" msgid "delete.hard" +msgstr "Hard Delete" + +msgid "delete.hard.perform" msgstr "Perform Hard Delete" msgid "delete.queue" @@ -207,6 +213,9 @@ msgstr "Queue for Deletion" msgid "delete.queue.confirm" msgstr "Are you sure you want to schedule this record ({0}) for deletion?" +msgid "delete.soft" +msgstr "Soft Delete" + msgid "duplicate" msgstr "Duplicate" diff --git a/app/src/Controller/PeopleController.php b/app/src/Controller/PeopleController.php index 97152d9ec..160f73766 100644 --- a/app/src/Controller/PeopleController.php +++ b/app/src/Controller/PeopleController.php @@ -146,10 +146,12 @@ public function confirmDelete(string $id) { 'PetitionerPetitions', 'PetitionHistoryRecords' ]; + + $person = $this->People->get((int)$id, contain: $contain); - $this->set('vv_person', $this->People->get((int)$id, contain: $contain)); + $this->set('vv_person', $person); - $this->set('vv_title', __d('operation', 'delete.confirm.title')); + $this->set('vv_title', __d('operation', 'delete.a',[$person->primary_name->full_name])); // We pull cluster information separately because it can't be contain'd $this->set('vv_person_cluster_status', $this->People->Cos->Clusters->status((int)$id)); diff --git a/app/templates/People/confirm_delete.php b/app/templates/People/confirm_delete.php index 7829262e6..d372cd21c 100644 --- a/app/templates/People/confirm_delete.php +++ b/app/templates/People/confirm_delete.php @@ -32,19 +32,21 @@
-

+

element('flash') // Flash messages ?> element('notify/alert', [ - 'message' => __d('operation', 'delete.confirm', [$vv_person->primary_name->full_name]), - 'type' => 'information' + 'message' => __d('operation', 'delete.confirm', [$vv_person->id]), + 'type' => 'warning' ]) ?> - -Form->create($vv_person, [ +Form->create($vv_person, [ 'id' => 'person-confirm-delete', 'type' => 'post', 'url' => ['action' => 'delete', $vv_person->id] ]); +?> - print $this->element('notify/alert', [ +
+ element('notify/alert', [ + 'message' => __d('information', 'People.delete.soft'), + 'type' => 'information' + ]); ?> +
+ -// XXX is this going to be a standard supported by StandardController? -// if so update developer documentation - print $this->Form->checkbox('hard-delete') . "\n"; - print $this->Form->label('hard-delete', __d('operation', 'delete.hard')) . "\n"; +
+ Form->button(__d('operation', 'delete.soft'),[ + 'type' => 'button', + 'id' => 'person-delete-button', + 'class' => 'btn btn-primary', + 'data-bs-toggle' => 'modal', + 'data-bs-target' => '#dialog' + ]) . "\n"; ?> - print $this->Form->submit(__d('operation', 'delete'), ['class' => 'btn-sm']) . "\n"; + Form->control('hard-delete', [ + 'type' => 'checkbox', + 'label' => __d('operation', 'delete.hard.perform'), + 'class' => 'form-check-input', + 'id' => 'hard-delete' + ]) . "\n"; ?> - print $this->Form->end() . "\n"; -?> + Form->submit(__d('operation', 'delete'), [ + 'id' => 'delete-confirmed', + 'class' => 'invisible' + ]) . "\n"; ?> +
+ +Form->end() . "\n"; ?> + + diff --git a/app/webroot/css/co-base.css b/app/webroot/css/co-base.css index 696489899..9b2db84e5 100644 --- a/app/webroot/css/co-base.css +++ b/app/webroot/css/co-base.css @@ -477,6 +477,7 @@ body.cos.select #top-bar { margin-right: 0.25em; } .co-alert a { + color: var(--cmg-color-link-darker); text-decoration: underline; } /* Alerts in the add-edit form: */ @@ -1485,6 +1486,36 @@ a.cm-row-button:focus { border: 1px solid var(--cmg-color-btn-bg-001); color: var(--cmg-color-txt-inverse) !important; } +#person-confirm-delete { + margin-left: 1em; +} +#person-confirm-delete .alert { + display: inline-block; +} +ul.delete-info-list { + margin: 0 1rem 1.5rem; + padding: 0; +} +ul.delete-info-list li { + margin-top: 1rem; + line-height: 1.75rem; + list-style: none; + font-family: var(--cmg-font-semibold); +} +ul.delete-info-list li:first-child { + margin-top: 0; +} +ul.delete-info-list li li { + margin-top: 0; + font-weight: 400; + list-style: circle; + font-family: var(--cmg-font-regular); +} +#content ul.delete-info-list .material-symbols-outlined { + font-size: 1.5rem; + margin-top: -4px; + vertical-align: middle; +} /* DATA LISTS */ ul.data-list { padding-left: 0; @@ -1588,6 +1619,11 @@ ul.form-list li.fields-submit { ul.form-list li.fields-submit .field:hover { background-color: var(--cmg-color-body-bg); } +.submit-with-flags { + display: flex; + align-items: center; + gap: 0.75rem; +} ul.form-list .field-name { display: block; } diff --git a/app/webroot/css/co-variables.css b/app/webroot/css/co-variables.css index 363206936..f749cf7e0 100644 --- a/app/webroot/css/co-variables.css +++ b/app/webroot/css/co-variables.css @@ -46,6 +46,7 @@ /* Links (primary) */ --cmg-color-link: #06c; /* primary hyperlink color (blue); accessible on backgrounds down to #e7e7e7 */ --cmg-color-link-hover: #115791; /* primary hyperlink hover color (blue); accessible on backgrounds down to #c9c9c9 */ + --cmg-color-link-darker: #005EBD; /* slightly darker hyperlink color for use on alert backgrounds */ /* Buttons */ --cmg-color-btn-bg-001: #115791; /* primary button background color (blue), submit buttons, .btn-primary, pagination */ From bf0c063f202d3acf480d853bf9b74b307a81ce5b Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 19 Aug 2026 07:33:27 -0400 Subject: [PATCH 2/4] Small updates to the Delete Person alert box information texts (CFM-124) --- app/resources/locales/en_US/information.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po index b99a8386a..935509cfe 100644 --- a/app/resources/locales/en_US/information.po +++ b/app/resources/locales/en_US/information.po @@ -142,7 +142,7 @@ msgid "People.delete.cluster" msgstr "Account on {0}" msgid "People.delete.hard" -msgstr "Performing a hard delete will physically remove all records from the database, including all Changelog Entries. This operation cannot be undone except by restoring from a backup." +msgstr "Performing a hard delete will physically remove the Person and all related records from the database, including all Changelog Entries. This operation cannot be undone except by restoring from a backup." msgid "People.delete.history.actor" msgstr "{0} History Records(s) for which this Person is an Actor will be updated to have no Actor." @@ -184,7 +184,7 @@ msgid "People.delete.roles.sponsor" msgstr "{0} Person Role(s) for which this Person is a Sponsor will be updated to have no Sponsor." msgid "People.delete.soft" -msgstr "A soft delete will mark the Person record as "deleted" and hide it from the user interface." +msgstr "Performing a soft delete will mark the Person and associated records as "deleted" and hide them from the user interface." msgid "petition.history" msgstr "Petition History" From 006392fce3a9f6760df2663eb3fb6654deee8983 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 19 Aug 2026 07:37:23 -0400 Subject: [PATCH 3/4] One more small update to the Delete Person alert box information texts (CFM-124) --- app/resources/locales/en_US/information.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po index 935509cfe..1f1938ee1 100644 --- a/app/resources/locales/en_US/information.po +++ b/app/resources/locales/en_US/information.po @@ -142,7 +142,7 @@ msgid "People.delete.cluster" msgstr "Account on {0}" msgid "People.delete.hard" -msgstr "Performing a hard delete will physically remove the Person and all related records from the database, including all Changelog Entries. This operation cannot be undone except by restoring from a backup." +msgstr "Performing a hard delete will physically remove the Person and associated records from the database, including all Changelog Entries. This operation cannot be undone except by restoring from a backup." msgid "People.delete.history.actor" msgstr "{0} History Records(s) for which this Person is an Actor will be updated to have no Actor." From c17263341f4ea94667e2f480320dcfb8552b75a5 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Thu, 20 Aug 2026 08:39:50 +0300 Subject: [PATCH 4/4] Fix missing Person context in breadcrumbs on Confirm Deletion page.Fix BreadcrumbComponent primary key resolution and prevent duplicate foreign keys in standard view links. --- .../Component/BreadcrumbComponent.php | 6 +++--- app/src/Controller/PeopleController.php | 10 ++++++++-- app/templates/People/fields.inc | 2 +- app/templates/Standard/add-edit-view.php | 18 ++++++++++++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/app/src/Controller/Component/BreadcrumbComponent.php b/app/src/Controller/Component/BreadcrumbComponent.php index f09080c69..cee093773 100644 --- a/app/src/Controller/Component/BreadcrumbComponent.php +++ b/app/src/Controller/Component/BreadcrumbComponent.php @@ -295,10 +295,10 @@ public function injectPrimaryLink( $linkTable = \Cake\ORM\TableRegistry::getTableLocator()->get($linkModelFqn); $contain = $this->resolveContainList($linkTable, $mappedAction); - // Normalize attr (people_id → id when the attr matches the model’s own foreign key) + // Use the table alias for query building (avoid plugin-qualified names in SQL) $modelAlias = $linkTable->getAlias(); - $foreignKey = StringUtilities::classNameToForeignKey($modelAlias); - $linkAttr = ($link->attr === $foreignKey) ? 'id' : $link->attr; + + $linkAttr = (string)$linkTable->getPrimaryKey(); // Fetch the linked entity; if not found, handle gracefully $linkedEntity = $linkTable diff --git a/app/src/Controller/PeopleController.php b/app/src/Controller/PeopleController.php index 160f73766..3b71d4d03 100644 --- a/app/src/Controller/PeopleController.php +++ b/app/src/Controller/PeopleController.php @@ -146,10 +146,16 @@ public function confirmDelete(string $id) { 'PetitionerPetitions', 'PetitionHistoryRecords' ]; - - $person = $this->People->get((int)$id, contain: $contain); + $person = $this->People->get((int)$id, contain: $contain); $this->set('vv_person', $person); + + $this->Breadcrumb->injectTitleLink( + table: $this->People, + entity: $person, + action: 'edit', + label: $this->People->generateDisplayField($person) + ); $this->set('vv_title', __d('operation', 'delete.a',[$person->primary_name->full_name])); diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc index ed7997ea5..3fc77a299 100644 --- a/app/templates/People/fields.inc +++ b/app/templates/People/fields.inc @@ -54,7 +54,7 @@ if($vv_action == 'add') { // The initial name must be primary 'names.0.primary_name' => true ]; -} elseif($vv_action == 'edit') { +} else { $a = $vv_obj->extract(['person_role_id', 'person_id']); $useDeleteSplashPage = true; diff --git a/app/templates/Standard/add-edit-view.php b/app/templates/Standard/add-edit-view.php index 53b0e90eb..0f197e01c 100644 --- a/app/templates/Standard/add-edit-view.php +++ b/app/templates/Standard/add-edit-view.php @@ -153,8 +153,22 @@ $perm = $vv_permissions[$linkModel][$t['link']['action']]; } - // Inject a link to the current object ID - $t['link']['?'][\App\Lib\Util\StringUtilities::entityToForeignKey($vv_obj)] = $vv_obj->id; + // This fixes the link in the gear icon in the Person Canvas view. + // Inject a link to the current object ID, unless an equivalent specific foreign key + // (like subject_person_id) is already provided in the query arguments. + $fk = \App\Lib\Util\StringUtilities::entityToForeignKey($vv_obj); + $hasFk = false; + if(!empty($t['link']['?'])) { + foreach($t['link']['?'] as $k => $v) { + if($v === $vv_obj->id && (str_ends_with($k, '_' . $fk) || $k === $fk)) { + $hasFk = true; + break; + } + } + } + if(!$hasFk) { + $t['link']['?'][$fk] = $vv_obj->id; + } } else { $perm = $vv_permissions[$t['link']['action']];