Repository navigation
Conversation
akabiru
force-pushed
the
implementation/comms-1067-journal-admin-label-deletion
branch
3 times, most recently
from
October 21, 2026 12:39
eba7da9 to
0a2ff71
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
The label row is gone when the journals are written, so the cause carries the name alongside the id. See COMMS-1067.
Writes one journal per affected work package, authored by the admin, with the label name snapshotted into the cause since the label row is gone. The journals are written directly, so no notifications go out for them. See COMMS-1067.
The delete service collects the labeled work packages before the label goes and hands them to the journaling job once the deletion is committed. See COMMS-1067.
The XSS example only asserted the HTML variant; raw text must keep the name verbatim.
The guard subquery was re-run for every batch and could only scan the whole journals table; one indexed lookup over the given work packages replaces it.
The epic defines the dialog text without a note about journaling.
A cause may now declare that it extends the predecessor's cause; the aggregated journal then carries the merged cause. Deleting several labels in a row leaves one entry per work package listing all of them. See COMMS-1067.
Lists every label of an aggregated deletion and pluralises the verb. See COMMS-1067.
Keeps the journal service free of duck-typing checks.
The cause line already names the removed labels. See COMMS-1067.
Use the store accessor for the cause type and extract the predecessor cause aggregation into a named method.
akabiru
force-pushed
the
implementation/comms-1067-journal-admin-label-deletion
branch
from
October 21, 2026 14:10
93a4f70 to
f88a01a
Compare
Base automatically changed from
implementation/comms-1022-labels-journaling
to
dev
October 21, 2026 15:05
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket
https://community.openproject.org/wp/COMMS-1067
What are you trying to accomplish?
Deleting a label in Administration > Labels removed it from every work package without a trace. Each affected work package now gets an activity entry authored by the deleting admin, "Label removed: 'Frontend' was deleted", or "Label removed: 'Frontend', 'Backend' were deleted" when the same admin deletes several labels within the journal aggregation window. The entry carries no "Labels changed" line of its own; the removed labels are named in the cause.
Screenshots
Activity entry on an affected work package
What approach did you choose and why?
sequenceDiagram participant A as Admin in the labels administration participant C as Admin::LabelsController (destroy) participant S as Labels::DeleteService participant J as Labels::JournalizeDeletionJob participant CS as Journals::CreateService participant T as Activity tab A->>C: DELETE /admin/labels/:id C->>S: call S->>S: pluck labeled work package ids S->>S: destroy label (labelings cascade) S->>J: perform_later(work_package_ids, label_id, label_name, user_id) S-->>C: success C-->>A: redirect, flash "Successful deletion." J->>J: skip work packages whose journals already carry this label id loop each remaining work package, under its mutex J->>CS: call(cause: CausedByLabelDeletion(label_ids, label_names)) alt same admin deleted another label within the aggregation window CS->>CS: aggregate into the previous entry, merge the label lists else CS->>CS: new journal with the cause and the current label snapshot end end A->>T: open an affected work package T->>T: render "Label removed: 'A', 'B' were deleted" Note over T: the "Labels changed" detail is hidden on this entryThe deletion itself stays synchronous and cheap; the journals are written afterwards by a job, since a label can sit on thousands of work packages. The cause carries the label ids and names because the rows are gone by then (the sprint migration cause snapshots a version name the same way). Writing through
Journals::CreateServicedirectly means no notifications go out for these entries, and the job is idempotent: one indexed lookup finds the work packages whose cause already contains the label id.Merging consecutive deletions needed a small generic hook: a cause may declare that it extends the predecessor's cause (
aggregatable_with?/aggregate_with, no-op defaults onCauseOfChange::Base), and the journal service then stores the merged cause on the aggregated journal. The labels detail is hidden only in the activities tab; the API still returns it. A manual label edit by the same admin inside the same window merges into the entry and is hidden with it, which is acceptable for an admin action.AI involvement
Collaborative – AI generated a substantial part of the code; I reviewed and understand every line.
Merge checklist