Workflow Center: per-item execution results, and enrich _bulkfire to support them
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
Show the outcome of a bulk workflow action per item — succeeded, failed with a reason, skipped — and let the user retry the failures. Doing that needs the SSE endpoint to carry information it currently drops, so this issue covers both the backend change and the view built on it.
Part 1 — Enrich POST /api/v1/workflow/contentlet/actions/_bulkfire
Progress is already emitted per contentlet. WorkflowAPIImpl.fireBulkActionTask calls the callbacks once per item:
successConsumer.accept(1L); // no inode — just "+1"
failConsumer.accept(contentlet.getInode(), e); // inode AND the exception
Three things are lost between there and the wire:
- The failure reason.
WorkflowResourcereceives the exception and discards it:eventBuilder.data(Map.class, Map.of("failure", inode)). The message is already in hand —ActionFail.newInstance(user, inode, e)shows how the synchronous path localises it. - Which item succeeded. The
successevent carries only{"success": 1}, so a running total is possible but attributing success to a specific row is not. Fixing this means theConsumer<Long>success callback carrying the inode as well. - Skipped items.
distributeWorkAndProcessNoReturn— the SSE path — never callscomputeSkippedContentletsCount, so skipped is structurally absent from the stream. The synchronous path computes it up front and returnsskippedCountplus askipReason.
Part 2 — Results view
With those three in place, the view can show per-row state during the run and a final summary. Until then a client has to choose between live counters with no reasons (_bulkfire) or reasons only at the end (PUT .../bulk/fire, which returns fails[] with errorMessage, capped by workflow.action.bulk.maxexceptions, default 1000). It cannot have both from one run, because firing twice would run the action twice.
Evidence this is a real gap, not a preference. The legacy dialog appears to offer failure details but does not. In view_bulk_actions_inc.jsp the SSE path initialises var entity = {skippedCount: 0, successCount: 0, fails: 0} — fails is a number — and the SSE listeners only increment a local counter and write it to the DOM. entity.fails stays 0, so toggleFailDetails() always renders "No failed actions" even when failures occurred, and the skipped row is permanently 0. The counters are live; the drill-down behind them is dead.
Acceptance Criteria
Backend
- The
failureSSE event carries the failure reason alongside the inode, localised the same way the synchronousfails[]entries are - The
successSSE event identifies which contentlet succeeded, not only that one more did - The SSE path computes and emits skipped items with the reason, matching what the synchronous endpoint reports
- The synchronous endpoint's response shape is unchanged — this is additive
- Integration tests cover a run with successes, failures and skips, asserting the stream contents
Results view
- Each row shows in-flight, succeeded, failed or skipped state as the run progresses
- A failed row shows its reason inline
- A failed row can be retried on its own, and all failed rows can be retried together
- A final summary reports successful, failed and skipped totals
- Totals in the summary reconcile with the per-row states — no row is unaccounted for
- Retry-all is disabled while a run is in flight
- The view degrades honestly if the stream ends early or drops: no row is left showing in-flight forever
- Unit tests cover the stream-to-row-state mapping, including a failure arriving for an unknown inode
Priority
Medium
Additional Context
Consuming SSE from the frontend needs a shim: native EventSource cannot POST a body, which is why the legacy JSP bundles sse.js. Wiring that is part of this work.
Relevant code:
| What | Where |
|---|---|
| Per-item callbacks | WorkflowAPIImpl.fireBulkActionTask |
| SSE event construction (drops the exception) | WorkflowResource — POST /contentlet/actions/_bulkfire |
| SSE path, no skip computation | WorkflowAPIImpl.distributeWorkAndProcessNoReturn |
| Synchronous path, computes skips + fail messages | WorkflowAPIImpl.distributeWorkAndProcess, ActionFail |
| Legacy consumer (counters live, details dead) | view_bulk_actions_inc.jsp |
Depends on #36819 for the preview the results view is entered from. Sibling issues: #36817, #36818, #36844, #36845.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with WorkflowAPIImpl.fireBulkActionTask and distributeWorkAndProcessNoReturn, then trace SSE construction in WorkflowResource and compare it with ActionFail and the synchronous path. Review view_bulk_actions_inc.jsp and the referenced integration and unit-test areas before mapping events to row states. Done means the stream includes success, failure reasons, and skips, while the view supports per-row results, retries, reconciled totals, and tests for unknown inodes and dropped streams.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, javascript
- Domain
- api, backend, frontend, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100