fix(dashboard): derive real open/closed ticket counts for the Work card #175

Merged
haydar merged 1 commit from fix/dashboard-work-counters into develop 2026-10-28 21:06:01 +00:00
Member

The project dashboard Work card reported 0 open / 0 closed while the
same page listed live tickets. Two causes:

  • OpenProjectClient::workPackageStatusGroups() parsed
    _embedded.groups and _links.valueLink.href, but the real API v3
    WorkPackageCollection renders groups as a TOP-LEVEL local property
    (next to total) and each group's valueLink is a LINK LIST. Every
    live call therefore produced an empty group list → 0/0 while
    listWorkPackages (_embedded.elements) worked.

  • workSection() treated empty groups as real zeros instead of
    falling back to a source that had already answered.

Client: read the top-level groups property (with an _embedded
fallback), accept valueLink as link list or single object, and
resolve a group's status through the catalog by id and, failing
that, by its display value — is_closed still drives every bucket.

Service: one listWorkPackages read now feeds both the recent slice
and the count fallback. The grouped collection is preferred for
exact totals; when it yields no groups the already-fetched list is
classified through listStatuses() is_closed metadata. When no
source can classify, the payload carries total/open/closed = null
with counts_unavailable (the card renders a note, never fake
zeros); counts_capped marks a lower bound when the scan saturates
its page. Sprint lookup failures degrade to 'no sprint shown'
instead of blanking the card.

Also: the work section cache key is now per user — the payload
embeds a native authorization decision and a project-wide key could
have served one authorized viewer's snapshot to the next user.

The project dashboard Work card reported 0 open / 0 closed while the same page listed live tickets. Two causes: - OpenProjectClient::workPackageStatusGroups() parsed _embedded.groups and _links.valueLink.href, but the real API v3 WorkPackageCollection renders groups as a TOP-LEVEL local property (next to total) and each group's valueLink is a LINK LIST. Every live call therefore produced an empty group list → 0/0 while listWorkPackages (_embedded.elements) worked. - workSection() treated empty groups as real zeros instead of falling back to a source that had already answered. Client: read the top-level groups property (with an _embedded fallback), accept valueLink as link list or single object, and resolve a group's status through the catalog by id and, failing that, by its display value — is_closed still drives every bucket. Service: one listWorkPackages read now feeds both the recent slice and the count fallback. The grouped collection is preferred for exact totals; when it yields no groups the already-fetched list is classified through listStatuses() is_closed metadata. When no source can classify, the payload carries total/open/closed = null with counts_unavailable (the card renders a note, never fake zeros); counts_capped marks a lower bound when the scan saturates its page. Sprint lookup failures degrade to 'no sprint shown' instead of blanking the card. Also: the work section cache key is now per user — the payload embeds a native authorization decision and a project-wide key could have served one authorized viewer's snapshot to the next user.
fix(dashboard): derive real open/closed ticket counts for the Work card
All checks were successful
ci / commit-trailers (pull_request) Successful in 12s
ci / secret-scan (pull_request) Successful in 17s
ci / integrations-js (pull_request) Successful in 39s
ci / portal-frontend (pull_request) Successful in 50s
ci / openproject-spec (pull_request) Successful in 32s
ci / release-tests (pull_request) Successful in 1m50s
ci / portal-php (pull_request) Successful in 5m55s
ci / openproject-rspec (pull_request) Successful in 5m13s
d861bc96dd
The project dashboard Work card reported 0 open / 0 closed while the
same page listed live tickets. Two causes:

- OpenProjectClient::workPackageStatusGroups() parsed
  _embedded.groups and _links.valueLink.href, but the real API v3
  WorkPackageCollection renders groups as a TOP-LEVEL local property
  (next to total) and each group's valueLink is a LINK LIST. Every
  live call therefore produced an empty group list → 0/0 while
  listWorkPackages (_embedded.elements) worked.

- workSection() treated empty groups as real zeros instead of
  falling back to a source that had already answered.

Client: read the top-level groups property (with an _embedded
fallback), accept valueLink as link list or single object, and
resolve a group's status through the catalog by id and, failing
that, by its display value — is_closed still drives every bucket.

Service: one listWorkPackages read now feeds both the recent slice
and the count fallback. The grouped collection is preferred for
exact totals; when it yields no groups the already-fetched list is
classified through listStatuses() is_closed metadata. When no
source can classify, the payload carries total/open/closed = null
with counts_unavailable (the card renders a note, never fake
zeros); counts_capped marks a lower bound when the scan saturates
its page. Sprint lookup failures degrade to 'no sprint shown'
instead of blanking the card.

Also: the work section cache key is now per user — the payload
embeds a native authorization decision and a project-wide key could
have served one authorized viewer's snapshot to the next user.
haydar scheduled this pull request to auto merge when all checks succeed 2026-10-28 20:59:25 +00:00
haydar merged commit ec7188b0b6 into develop 2026-10-28 21:06:01 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
developing4all/devworkbase!175
No description provided.