Skip to content

Paginate the user references tab against the new object-dependencies endpoint - #4008

Merged
jcPimcore merged 18 commits into
2025.4from
fix/308-paginated-user-object-dependencies
Aug 27, 2026
Merged

jcPimcore merged 18 commits into
2025.4from
fix/308-paginated-user-object-dependencies

Conversation

@jcPimcore

@jcPimcore jcPimcore commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Changes in this pull request

Resolves: pimcore/platform-version#308 Studio UI
Resolves: pimcore/admin-ui-classic-bundle#1106 Studio UI

The user detail screen's "References" tab rendered the entire user.objectDependencies.dependencies array embedded in the GET /users/{id} response, reproducing the same unbounded-hydration OOM risk as pimcore/admin-ui-classic-bundle#1106 on the frontend.

  • Regenerate the OpenAPI client (docs.jsonopenapi.json + user-api-slice.gen.ts) against the new paginated GET /user/{id}/object-dependencies endpoint added in pimcore/studio-backend-bundle.
  • Rework references-container.tsx to page through the new endpoint with local page/pageSize state and a new components/pagination/pagination.tsx, following the same pattern already used by the generic element Dependencies tab's required-by-panel. Uses useTranslation() (not a direct i18next import) so translated text updates on language change, and a shared DEFAULT_PAGE_SIZE constant instead of a duplicated magic number.
  • Add a dedicated USER_OBJECT_DEPENDENCIES cache tag in user-api-slice-enhanced.ts (instead of reusing USER_DETAIL), so editing/deleting a user doesn't force an unnecessary refetch of their object-dependencies pagination, mirroring the existing ELEMENT_DEPENDENCIES tag pattern.
  • No breaking change: objectDependencies on the generated User type keeps its original dependencies/hasHidden fields exactly as they were; it only gains an additive totalItems field. Nothing in this repo's UI reads that field at all (the References tab always calls the new paginated endpoint directly), so this is purely a type-sync change with zero runtime UI impact.

Additional info

Full project tsc --noEmit and eslint both pass clean. The build was re-run locally multiple times after backend changes and verified byte-for-byte (checked for zero-byte/corrupted chunks, not just a clean exit code) to actually contain the current endpoint path/hook, not just the source.

All 6 Copilot review comments on this PR were addressed with real code/doc changes (translation-key description clarified on the backend side for the one that originated there).

Depends on pimcore/studio-backend-bundle's fix/308-paginated-user-object-dependencies.

🤖 Generated with Claude Code

jcPimcore and others added 4 commits August 20, 2026 10:14
…endpoint

The user detail screen's "References" tab rendered the entire
user.objectDependencies.dependencies array embedded in the GET /users/{id}
response, reproducing the same unbounded-hydration OOM risk as
admin-ui-classic-bundle#1106 on the frontend.

Regenerate the OpenAPI client (docs.jsonopenapi.json + user-api-slice.gen.ts)
against the new paginated GET /user/{id}/object-dependencies endpoint added
in studio-backend-bundle, add a userGetObjectDependencies cache-tag wrapper,
and rework references-container.tsx to page through it with local page/
pageSize state and the shared Pagination control, following the same
pattern as the generic element Dependencies tab's required-by-panel.

Refs: pimcore/platform-version#308
studio-backend-bundle's GET /users/{id} now returns objectDependencies
again as a bounded 20-item preview (ObjectDependenciesPreview) instead
of the previously removed field. Regenerate docs.jsonopenapi.json and
user-api-slice.gen.ts so the User type matches; nothing in the UI reads
this field yet, so no other frontend changes are needed.

Refs: pimcore/platform-version#308
Copilot AI balanced review requested due to automatic review settings August 20, 2026 13:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a paginated “object dependencies” data source to the User References tab and wires it to a new RTK Query endpoint.

Changes:

  • Introduces userGetObjectDependencies RTK Query endpoint + types.
  • Updates References tab to fetch dependencies server-side and render pagination controls.
  • Adds a dedicated Pagination component for the References tab.

Reviewed changes

Copilot reviewed 4 out of 6 changed files in this pull request and generated 6 comments.

File Description
assets/js/src/core/modules/user/user-api-slice-enhanced.ts Adds cache tags for the new userGetObjectDependencies endpoint.
assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx Switches from draft-based dependencies to paginated API query + pagination UI.
assets/js/src/core/modules/user/management/detail/tabs/references/components/pagination/pagination.tsx New pagination UI wrapper with loading/empty states.
assets/js/src/core/modules/auth/user/user-api-slice.gen.ts Adds generated endpoint + response/arg types; updates user dependency preview typing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread assets/js/src/core/modules/auth/user/user-api-slice.gen.ts Outdated
Comment thread assets/js/src/core/modules/user/user-api-slice-enhanced.ts Outdated
@jcPimcore jcPimcore self-assigned this Aug 20, 2026
@jcPimcore jcPimcore added this to the 2025.4.13 milestone Aug 20, 2026
jcPimcore and others added 2 commits August 20, 2026 13:31
- Use useTranslation() instead of importing t from i18next so the
  pagination component re-renders on language change
- Extract the default page size into a shared constant to avoid
  divergence between the container's query state and the pagination
  default
- Give userGetObjectDependencies its own USER_OBJECT_DEPENDENCIES
  cache tag instead of USER_DETAIL, avoiding unnecessary refetches
  when unrelated user detail fields change

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jcPimcore added a commit to pimcore/studio-backend-bundle that referenced this pull request Aug 20, 2026
The success-response description for GET /user/{id}/object-dependencies
copied this bundle's standard "with total count as header param"
phrasing, but PaginatedResponseTrait::getPaginatedCollection() also
serializes totalItems in the JSON body via the Collection DTO - true for
every endpoint using that trait, not just this one. Only fixing the one
description this PR introduced; the same incomplete phrasing predates
this change on ~15 other endpoints across the bundle and is out of scope
here.

Refs: pimcore/platform-version#308, review feedback on
pimcore/studio-ui-bundle#4008
jcPimcore and others added 4 commits August 20, 2026 13:41
studio-backend-bundle's OpenAPI description for GET /user/{id}/object-
dependencies now states the total count is in both the response header
and the totalItems body field, resolving the remaining open Copilot
review comment on this PR (the others were already fixed in a prior
commit). Also picks up the MAX_PAGE_SIZE=100 schema constraint from that
same backend PR's earlier review-fix commit, which hadn't been synced
to this repo's generated client yet.

Refs: pimcore/platform-version#308
…ange

studio-backend-bundle restored the original ObjectDependencies name and
its dependencies/hasHidden fields, adding totalItems alongside them
instead of replacing the shape. Regenerate the client so the User type
matches (UserObjectDependenciesPreview -> UserObjectDependencies, with
hasHidden back and totalItems added). Nothing in the UI reads this
field, so no other frontend changes are needed.

Refs: pimcore/platform-version#308

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (2)

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:51

  • After the first response, RTK Query keeps isLoading false during page and page-size requests and reports those through isFetching. The grid therefore continues to present the previous page as settled while the next page is loading. Capture isFetching from the hook and use it for the table's loading state (the pagination can keep the initial-load flag if it must preserve its internal page-size state).
          isLoading={ isLoading }

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:50

  • A failed dependencies request also produces data === undefined, so this fallback presents the failure as an empty references list and the API error is never reported. Capture error from the query and pass it to trackError(new ApiError(error)), following the user-management error-handling pattern.
          data={ data?.items ?? [] }

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (2)

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:28

  • The new RTK Query request does not handle failures. A 403/404/network error is therefore presented as an empty references table (and a zero-item pager) without being reported through the application's error handler. Capture isError/error and call trackError(new ApiError(error)), as other user-management requests do.
  const { id } = useUserManagementContext()
  const [page, setPage] = useState<number>(1)
  const [pageSize, setPageSize] = useState<number>(DEFAULT_PAGE_SIZE)

  const { data, isLoading } = useUserGetObjectDependenciesQuery({ id, page, pageSize })

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:51

  • After the first successful request, RTK Query keeps isLoading false while a new page is fetched and exposes the previous data until that request completes. The pager therefore advances immediately while this table still displays rows from the old page with no loading state. Read isFetching from the query and pass it to the table (while keeping the pagination's initial-load handling unchanged) so stale rows are visibly pending.
        <Table
          data={ data?.items ?? [] }
          isLoading={ isLoading }

- Track query errors via trackError(new ApiError(error)) on isError,
  matching the established pattern used elsewhere (use-user-management-
  draft.tsx, use-zip-download.tsx, custom-metadata-container.tsx, etc.)
  - previously a 403/404/network error just showed an empty table with
  no indication anything went wrong.
- Pass isFetching (not isLoading) to the Table so page/pageSize changes
  show a pending state instead of silently displaying stale rows from
  the previous page while the new one loads. Pagination keeps isLoading
  for its own initial-load skeleton, unchanged.

Note: the sibling required-by-panel.tsx (generic element Dependencies
tab) this was modeled on has the same isLoading-only gap and no error
handling either - left untouched since it's a separate, pre-existing
component out of scope for this PR.

Refs: pimcore/platform-version#308
@jcPimcore

Copy link
Copy Markdown
Contributor Author

Addressed both suppressed Copilot comments in f999c57 (rebased to 7cea893 after the auto-build bot):

  • Query errors now go through trackError(new ApiError(error)) on isError, matching the established pattern elsewhere (use-user-management-draft.tsx, use-zip-download.tsx, custom-metadata-container.tsx) - previously a 403/404/network failure just showed an empty table silently.
  • The table now uses isFetching instead of isLoading, so page/pageSize changes show a pending state instead of displaying stale rows from the previous page while the next one loads. Pagination keeps isLoading for its own initial-load skeleton.

Note: required-by-panel.tsx (the generic element Dependencies tab this was modeled on) has the same isLoading-only gap and no error handling either - left untouched as a separate, pre-existing component out of scope here.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:59

  • RTK Query keeps data from the last fulfilled argument while a newly selected page is pending or rejected. If page 1 loaded and the page 2 request fails, page remains 2 and isFetching becomes false, but this table renders page 1's rows as though they belonged to page 2. Use the hook's currentData for the rows (while retaining data separately if the pagination total should remain visible) so a failed page cannot display stale results.
        <Table
          data={ data?.items ?? [] }
          isLoading={ isFetching }
        />

RTK Query's data retains the last fulfilled result across arg changes;
currentData is only populated for the current query args. If page 1
loaded and switching to page 2 fails, data still held page 1's items
while isFetching settled back to false - the table would render page
1's rows as if they belonged to page 2, with no visual indication.

Use currentData for the table's rows (undefined during a pending or
failed fetch, so the isFetching-driven loading state covers it
correctly) while keeping data for the Pagination spread, so the last
known totalItems stays visible instead of resetting during a
transient failure. Verified against the actual installed RTK Query
type definitions, not just Copilot's description of the behavior.

Refs: pimcore/platform-version#308
@jcPimcore

Copy link
Copy Markdown
Contributor Author

Confirmed and fixed in b97d50f (rebased to f90e04c after the auto-build bot). Verified the claim directly against the installed RTK Query type definitions rather than taking it on faith: currentData is documented there as "only populated for the current query arguments," while data retains the last fulfilled result across arg changes - exactly the stale-page-on-failure scenario described.

The table now reads currentData?.items (empty/undefined during a pending or failed fetch for the current args, correctly covered by the isFetching loading state) while Pagination keeps data so the last-known totalItems doesn't reset during a transient failure - the compromise you suggested.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.

Comment thread assets/js/src/core/modules/auth/user/user-api-slice.gen.ts Outdated
studio-backend-bundle dropped totalItems from ObjectDependencies'
OpenAPI required list specifically to avoid a TypeScript source break
for SDK consumers: UserObjectDependencies is re-exported through this
package's public SDK entry point (sdk/api/user/index.ts), and this
package is actively published to npm, so any existing consumer code
constructing or mocking a value of that type without totalItems would
otherwise fail to compile against the new type. Verified the actual
generated output, not just the OpenAPI spec: totalItems?: number.

Refs: pimcore/platform-version#308

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

assets/js/src/core/modules/user/management/detail/tabs/references/references-container.tsx:29

  • The dependent endpoint counts all matching objects before applying each object's list permission, then filters unauthorized objects out of the selected page. As a result, this tab can show short or completely empty pages while the paginator reports a larger total (and can expose the exact count of hidden references). The backend should paginate and count the authorized result set, or return separate visible/hidden pagination metadata that this UI can represent accurately.
  const { data, currentData, isLoading, isFetching, isError, error } = useUserGetObjectDependenciesQuery({ id, page, pageSize })

@jcPimcore

Copy link
Copy Markdown
Contributor Author

Per discussion, documented (not code-fixed) in pimcore/studio-backend-bundle@34d21edc: totalItems is a raw match count that never subtracts permission-denied objects, since accurately excluding them would require hydrating and checking every matching object across the whole dataset - exactly the unbounded cost this endpoint exists to avoid. That tradeoff is now stated plainly in the schema description, the totalItems property description, the endpoint's operation description, and the upgrade note: a page (or the embedded preview) can legitimately come back shorter than requested, or empty, while totalItems stays the same.

No frontend changes needed - this is purely a documentation-text change on the backend side.

🤖 Generated with Claude Code

@ValeriaMaltseva ValeriaMaltseva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcPimcore
LGTM :)

As soon as pimcore/studio-backend-bundle#2011 is
merged, we can merge this one.

P.S. Please double-check that composer.json and docs.jsonopenapi.json are
updated properly.

jcPimcore added a commit to pimcore/studio-backend-bundle that referenced this pull request Aug 25, 2026
* Add paginated object-dependencies endpoint for users, drop embedded array

ObjectDependenciesService::getDependenciesForUser() and the resolver it
called (DataObject\Service::getObjectsReferencingUser()) unconditionally
hydrate every DataObject referencing a user via a User-type field, and
the result was embedded in every GET /users/{id} response. This has the
same unbounded-hydration OOM risk as admin-ui-classic-bundle#1106, just
not yet reported for Studio.

Add ObjectDependenciesRepository, which reproduces the same class/field
discovery but counts matches per class first and only ever hydrates the
slice of objects that falls inside the requested page's offset/limit
window, regardless of total match count. Expose it via a new paginated
GET /user/{id}/object-dependencies endpoint (GetObjectDependenciesController),
modeled on the generic element Dependencies tab's CollectionController.
Drop the objectDependencies field from the main user payload/schema and
UserHydrator, since it's no longer embedded.

Refs: pimcore/platform-version#308

* Document the object-dependencies breaking change in upgrade notes

Note the removal of the embedded objectDependencies field from GET
/users/{id} and point at the new paginated GET /user/{id}/object-
dependencies endpoint, following the existing per-version bullet
convention in this file.

Refs: pimcore/platform-version#308

* Restore a bounded objectDependencies preview on GET /users/{id}

Avoid the BC break of dropping objectDependencies entirely: keep it on
the User schema, but as a small, deliberately-capped 20-item preview
(ObjectDependenciesPreview: totalItems + dependencies) built by calling
the same paginated ObjectDependenciesService added earlier with
page=1/pageSize=20, instead of the old unbounded hydration. Consumers
that need more than the preview use GET /user/{id}/object-dependencies.

Update the upgrade note accordingly: this is a schema shape change
(hasHidden removed, totalItems added, capped at 20), not a removal.

Refs: pimcore/platform-version#308

* Address Copilot review feedback on the object-dependencies pagination

- ObjectDependenciesRepository: join multi-field User conditions with OR,
  not AND - an object referencing the user via any one of several
  User-type fields was previously excluded from both the page and
  totalItems unless every field matched. Also add a deterministic
  ORDER BY id, since OFFSET/LIMIT paging without one isn't guaranteed
  stable across requests (verified against real data: two adjacent
  pages now have zero overlap and no gap).
- Extract the cross-class windowing math into a pure resolveClassWindow()
  method and add a focused unit test for it (class-boundary pages, deep
  offsets, exhausted budget, exact boundaries) - the surrounding
  class-discovery/listing code still has no unit fixtures in this
  bundle's suite, but the arithmetic that determines pagination
  correctness now does.
- GetObjectDependenciesController: enforce a MAX_PAGE_SIZE of 100
  (matching the largest selectable page size in the Studio UI) before
  offset/limit are calculated, since CollectionParameters has no upper
  bound and an unbounded pageSize would reintroduce the OOM this
  endpoint exists to prevent. Also resolve and authorize the target
  user (NotFoundException / admin-only-viewable-by-admins, mirroring
  UserService::getUserById()) before querying dependencies, instead of
  querying an arbitrary/nonexistent id and silently returning 200 with
  an empty collection.
- PageSizeParameter gains an optional maxSize to surface the cap in the
  OpenAPI schema; existing call sites are unaffected (defaults to no
  maximum).

Refs: pimcore/platform-version#308

* Clarify that object-dependencies total count is in both header and body

The success-response description for GET /user/{id}/object-dependencies
copied this bundle's standard "with total count as header param"
phrasing, but PaginatedResponseTrait::getPaginatedCollection() also
serializes totalItems in the JSON body via the Collection DTO - true for
every endpoint using that trait, not just this one. Only fixing the one
description this PR introduced; the same incomplete phrasing predates
this change on ~15 other endpoints across the bundle and is out of scope
here.

Refs: pimcore/platform-version#308, review feedback on
pimcore/studio-ui-bundle#4008

* Eliminate the objectDependencies breaking change entirely

The bounded preview (previous commit) still replaced ObjectDependencies
(dependencies + hasHidden) with a differently-shaped ObjectDependenciesPreview
(totalItems + dependencies), dropping hasHidden. That was never necessary -
adding totalItems doesn't require removing hasHidden.

Restore the original ObjectDependencies class name and its dependencies/
hasHidden fields exactly as they were, and add totalItems alongside them
as a new, additive property. GET /users/{id} keeps returning the same
shape it always has, just with dependencies now capped at 20 (down from
unbounded) and one new field. hasHidden's scope narrows to the visible
preview window rather than scanning every referencing object, which is
an unavoidable, documented consequence of no longer scanning everything -
but the schema itself has zero breaking changes: nothing was removed or
renamed, nothing changed type.

Add ObjectDependenciesServiceInterface::getPreviewForUser(), used only by
UserHydrator, alongside the existing getPaginatedDependenciesForUser()
used by the new paginated endpoint - keeps the preview's original return
type separate from the generic Collection type the real pagination uses.

Refs: pimcore/platform-version#308

* Restore UserHydrator's original constructor parameter order

Purely cosmetic: ObjectDependenciesServiceInterface had moved from its
original 3rd position to last. Autowiring resolves by type so this
never affected anything functionally, but restoring the exact original
order removes even a theoretical positional-instantiation concern.

Refs: pimcore/platform-version#308

* Fix PHPStan return-type error on getObjectsReferencingUser()

Listing::load() is typed to return the broader DataObject[], not
Concrete[], even though a per-class dynamic Listing (e.g.
Issue1106\Listing) only ever loads Concrete instances of that class.
Narrow it with an instanceof filter so the inferred return type matches
the interface's declared array{items: Concrete[], totalItems: int} -
a no-op at runtime (verified: still returns the same 50/50000 against
the real repro data, and every item is genuinely Concrete already).

Verified with a real PHPStan run (installed standalone, not part of
this bundle's own composer deps) against this file and the rest of
src/User at this bundle's configured level 6: no errors.

Refs: pimcore/platform-version#308

* Fix CI test failure: Dependency is final and can't be mocked

CI failed with PHPUnit's ClassIsFinalException: Dependency is a
`final readonly class`, so makeEmpty()/mock generators can't create a
test double for it. It's a trivial constructor-only DTO anyway -
instantiate a real one instead of doubling it.

Verified the fixed test logic directly (same code path, real classes,
not just reasoning): items=1, totalItems=2 as expected.

Refs: pimcore/platform-version#308

* Address Copilot review: fix route typo, be precise about compat impact

- The upgrade note said GET /users/{id} (plural); the actual route is
  GET /user/{id} (singular, GetUserController).
- "Not a breaking change" was an overclaim. The objectDependencies
  *schema* genuinely has no breaking change (dependencies/hasHidden
  keep their names, types, meaning; totalItems is purely additive),
  but dependencies previously contained the complete list and now
  caps at 20 - a real behavioral compatibility impact for any consumer
  that assumed completeness rather than checking totalItems. State
  that plainly instead of a blanket "not breaking" claim.

Refs: pimcore/platform-version#308

* Make totalItems optional in the schema to avoid an SDK source break

studio-ui-bundle is a real, actively-published npm package
(@pimcore/studio-ui-bundle), and UserObjectDependencies is re-exported
through its public SDK entry point (sdk/api/user/index.ts). Marking
totalItems as OpenAPI-required generated it as a non-optional TS field,
which is source-breaking for any SDK consumer constructing or mocking
a value of that type without it.

Drop totalItems from the schema's required list. The PHP property
itself is unaffected and always set - this only changes the generated
contract to totalItems?: number, which is backward compatible with
existing consumer code while still giving new consumers the real value
in every actual response.

Verified against real data: hasHidden=false, dependencies=20,
totalItems=50000 - unchanged at runtime, only the schema's required
list changed.

Refs: pimcore/platform-version#308

* Document that totalItems counts permission-hidden objects too

Per Copilot review feedback: totalItems is a raw match count that
never subtracts permission-denied objects, since accurately excluding
them would require hydrating and checking every matching object
across the whole dataset - exactly the unbounded cost this endpoint
exists to avoid. That's a legitimate tradeoff, but was previously
undocumented: a page (or the embedded preview) can come back shorter
than requested, or empty, while totalItems stays the same.

Documented in the ObjectDependencies schema description, the
totalItems property description, the paginated endpoint's operation
description, and the upgrade note.

Refs: pimcore/platform-version#308

* Address martineiber's review on object-dependencies pagination

Move pageSize validation and the admin-view permission check out of
GetObjectDependenciesController into ObjectDependenciesService, matching
the pattern already used in UserUpdateService. Split an overlong line in
ObjectDependenciesRepository (Sonar php:S103), simplify its Concrete filter
closure per suggestion, and trim the ObjectDependencies schema description
to stay under 100 chars.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add repository-level coverage for the multi-field User condition

Extract the OR-joined User-field condition building out of
createListingForClass() into a pure buildUserFieldCondition() method,
mirroring the earlier resolveClassWindow() extraction, and unit test it
directly. Addresses the remaining part of Copilot's test-coverage
comment that's actually testable without real DB-backed class fixtures
(class-boundary pages and deep offsets were already covered by the
existing resolveClassWindow() tests).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@jcPimcore
jcPimcore merged commit 593233d into 2025.4 Aug 27, 2026
15 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 27, 2026
@jcPimcore
jcPimcore deleted the fix/308-paginated-user-object-dependencies branch August 27, 2026 13:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants