Skip to content

UN-3770 [FEAT] Opt-in pagination for list endpoints; wire Workflows page#2187

Merged
chandrasekharan-zipstack merged 6 commits into
mainfrom
feat/UN-3770-list-pagination
Jul 21, 2026
Merged

UN-3770 [FEAT] Opt-in pagination for list endpoints; wire Workflows page#2187
chandrasekharan-zipstack merged 6 commits into
mainfrom
feat/UN-3770-list-pagination

Conversation

@chandrasekharan-zipstack

@chandrasekharan-zipstack chandrasekharan-zipstack commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What & why

Jira: UN-3770

Four listing endpoints — workflows, prompt studio, adapters, connectors — return every row as a bare array and filter client-side, so the pages get slow to load as an org grows (noticeably Prompt Studio projects and Workflows). This adds opt-in server-side pagination.

The regression constraint

These endpoints are shared. Besides the listing page they feed dropdowns/selectors that expect a bare array:

  • /adapter?adapter_type=…CombinedOutput, OutputForDocModal, AdapterSelectionModal, AddLlmProfile, DefaultTriad
  • connector/ConfigureDs
  • workflow/ list → EtlTaskDeploy

Attaching a DRF pagination_class unconditionally would turn all their responses into the {count,next,previous,results} envelope and break every one of those consumers.

Approach

  • OptionalPagination (utils/pagination.py): paginates only when the request carries ?page/?page_size, otherwise returns None → DRF serialises the bare array. Only the listing page opts in.
  • Attached to the 4 viewsets + server-side name search (?search= icontains).
  • WorkflowViewSet gets a deterministic order (-modified_at, id) — its manager uses plain .distinct() with no default order, which pagination needs for stable pages. The other three already order by DISTINCT ON (id/tool_id).
  • Frontend: Workflows page only — server-side page + search, reusing the existing usePaginatedList hook and the Pipelines wiring pattern. Bare-array fallback (data.results ?? data) kept.

Scope / follow-ups

This is the first vertical slice. The prompt-studio, adapters and connectors frontend pages are intentionally not converted yet — their backends already ship the (dormant) pagination, and each page has intricate search/refresh flows that warrant live validation one at a time under the same ticket.

Testing

  • backend/utils/tests/test_pagination.py pins the opt-in contract (bare array without a page param; envelope with one). Verified standalone (backend test tier needs the full env).
  • Backend ruff + frontend biome clean.
  • ⚠️ Live UX validation of the Workflows page (search, page nav, refresh-after-create/delete/share) still pending — hence draft.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z

Four list endpoints (workflows, prompt studio, adapters, connectors)
returned every row as a bare array and filtered client-side, making the
pages slow to load as orgs grow.

Backend: add `OptionalPagination` — it paginates only when the caller sends
`?page`/`?page_size`, otherwise returns None so DRF serialises the bare
array. These endpoints are shared with dropdown/selector consumers that
expect an array, so the opt-in keeps their responses byte-identical while
the listing page opts in and receives the {count,next,previous,results}
envelope. Attach it to the four viewsets and add server-side name search;
Workflow also gets a deterministic order (id tiebreaker) for stable pages.

Frontend: the Workflows page now paginates + searches server-side, reusing
the existing `usePaginatedList` hook and the Pipelines wiring pattern. This
is the first vertical slice — the prompt-studio, adapters and connectors
pages will follow (their backends already ship the dormant pagination).

Test: utils/tests/test_pagination.py pins the opt-in contract (bare array
without a page param; envelope with one).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bfb1e2e5-9134-41e9-a10b-b9e5657bb0fc

📥 Commits

Reviewing files that changed from the base of the PR and between aecd00a and 1c77732.

📒 Files selected for processing (2)
  • backend/utils/tests/test_pagination.py
  • frontend/src/components/workflows/workflow/Workflows.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/workflows/workflow/Workflows.jsx

Summary by CodeRabbit

  • New Features
    • Added server-side name search for adapters, connectors, tools, and workflows.
    • Introduced optional pagination for list endpoints (bare results unless pagination is explicitly requested).
    • Added deterministic ordering (including id tie-breakers) to stabilize pagination.
  • Bug Fixes
    • Workflow list refresh preserves active page/search across edit, delete, and share; avoids showing an empty page after deleting the last item.
    • Updated workflow pagination/search UI behavior and empty-state messaging.
  • Tests
    • Added contract tests for optional pagination opt-in and edge cases.
  • Chores
    • Minor UI styling updates for workflow pagination layout.

Walkthrough

The change adds opt-in pagination and server-side name search to backend list endpoints, then updates the workflow frontend to request, render, and refresh paginated results while preserving bare-array responses when pagination is not requested.

Changes

Pagination and search flow

Layer / File(s) Summary
Optional pagination contract
backend/utils/pagination.py, backend/utils/tests/test_pagination.py
Adds opt-in pagination when page or page_size is supplied, with tests covering blank values, slicing, counts, and maximum page sizes.
Backend list filtering and ordering
backend/*/views.py
Configures optional pagination, adds case-insensitive name search, and applies deterministic ordering to adapter, connector, tool, and workflow listings.
Workflow paginated list integration
frontend/src/components/workflows/workflow/Workflows.jsx, frontend/src/components/workflows/workflow/workflow-service.js, frontend/src/components/workflows/workflow/Workflows.css
Passes pagination and search parameters, normalizes responses, refreshes after mutations, renders loading and empty states, and displays styled pagination controls.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Workflows
  participant usePaginatedList
  participant workflowService
  participant WorkflowViewSet
  Workflows->>usePaginatedList: request page, page size, and search
  usePaginatedList->>workflowService: getProjectList(params)
  workflowService->>WorkflowViewSet: GET workflow list
  WorkflowViewSet-->>workflowService: filtered results and pagination metadata
  workflowService-->>Workflows: update project list and pagination state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the opt-in pagination rollout and Workflows frontend wiring.
Description check ✅ Passed It covers the main What/Why, approach, breakage, scope, and testing details; only some optional template sections are omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/UN-3770-list-pagination

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

SonarCloud python:S5332 flags the clear-text http:// scheme in the
request-stub build_absolute_uri; the scheme is inert in this DB-free
contract test but tripping the B security rating on the PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z
@chandrasekharan-zipstack
chandrasekharan-zipstack marked this pull request as ready for review July 20, 2026 15:15
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds opt-in pagination for shared list endpoints and wires it into the Workflows page. The main changes are:

  • Optional pagination that keeps bare-array responses unless pagination is requested.
  • Server-side search and deterministic ordering for workflows, prompt studio, adapters, and connectors.
  • Workflows page pagination, search, refresh handling, and pagination control styling.
  • Contract tests for paginated, non-paginated, and blank-parameter requests.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
backend/utils/pagination.py Adds optional pagination that preserves bare-array responses when no pagination parameter is provided.
backend/utils/tests/test_pagination.py Adds contract tests for the opt-in pagination behavior and blank pagination parameters.
backend/workflow_manager/workflow_v2/views.py Adds optional pagination, server-side workflow search, and deterministic workflow ordering.
backend/adapter_processor_v2/views.py Adds optional pagination, adapter name search, and deterministic adapter ordering.
backend/connector_v2/views.py Adds optional pagination, connector name search, and deterministic connector ordering.
backend/prompt_studio/prompt_studio_core_v2/views.py Adds optional pagination, prompt studio search, and deterministic prompt studio ordering.
frontend/src/components/workflows/workflow/Workflows.jsx Updates the Workflows page to fetch paginated results, run server-side search, and refresh the active page after mutations.
frontend/src/components/workflows/workflow/workflow-service.js Updates the workflow list API helper to send pagination and search parameters.
frontend/src/components/workflows/workflow/Workflows.css Adds layout styling for the Workflows pagination control.

Reviews (4): Last reviewed commit: "UN-3770 [FIX] Lock blank-pagination-para..." | Re-trigger Greptile

Comment thread backend/utils/pagination.py

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🧹 Nitpick comments (2)
frontend/src/components/workflows/workflow/Workflows.jsx (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unused Typography import.

The Typography component from antd is imported but never used in this file.

♻️ Proposed refactor
-import { Pagination, Typography } from "antd";
+import { Pagination } from "antd";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/workflows/workflow/Workflows.jsx` at line 2, Remove
the unused Typography import from the antd import declaration in Workflows.jsx,
while retaining the Pagination import.
frontend/src/components/workflows/workflow/workflow-service.js (1)

27-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare options to prevent global variable leakage.

The options object is assigned without a variable declaration, which creates an implicit global variable. While this appears to be a pre-existing pattern in this service file, it is best practice to declare variables locally.

♻️ Proposed refactor
     getProjectList: (params = {}) => {
-      options = {
+      const options = {
         url: `${path}/workflow/`,
         method: "GET",
         params,
       };
       return axiosPrivate(options);
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/workflows/workflow/workflow-service.js` around lines
27 - 34, Declare options locally within getProjectList before assigning the
request configuration, preventing implicit global leakage while preserving the
existing axiosPrivate call and request parameters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/adapter_processor_v2/views.py`:
- Around line 193-196: Ensure stable pagination ordering after the for_user()
queryset filtering: in backend/adapter_processor_v2/views.py lines 193-196,
backend/connector_v2/views.py lines 108-112, and
backend/prompt_studio/prompt_studio_core_v2/views.py lines 177-180, apply an
explicit descending modified_at ordering with ascending id as the unique
tiebreaker before returning each queryset (including qs in the prompt studio
view).

In `@frontend/src/components/workflows/workflow/Workflows.jsx`:
- Around line 155-163: Remove the unconditional handleListRefresh() call after
setAlertDetails in the workflow update success handler, preserving the existing
refresh inside the editingProject?.name branch while retaining the refresh
behavior for non-edit updates.
- Around line 139-141: Update the getProjectList failure handler in the workflow
component to set projectList to an empty array before logging the error,
ensuring the existing projectList-based rendering shows the empty state rather
than an indefinite SpinnerLoader after the initial request fails.
- Around line 128-137: Update the paginated workflow fetch handling around the
results assignment and setProjectList call so an empty results array on a page
greater than the first automatically refetches or navigates to the previous page
before updating the displayed list. Keep page 1 empty behavior unchanged, and
ensure pagination state reflects the fallback page so controls remain usable.

---

Nitpick comments:
In `@frontend/src/components/workflows/workflow/workflow-service.js`:
- Around line 27-34: Declare options locally within getProjectList before
assigning the request configuration, preventing implicit global leakage while
preserving the existing axiosPrivate call and request parameters.

In `@frontend/src/components/workflows/workflow/Workflows.jsx`:
- Line 2: Remove the unused Typography import from the antd import declaration
in Workflows.jsx, while retaining the Pagination import.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8c025dc8-c7d4-4a4e-b448-90c184af9b36

📥 Commits

Reviewing files that changed from the base of the PR and between 4eb8811 and dab4e69.

📒 Files selected for processing (9)
  • backend/adapter_processor_v2/views.py
  • backend/connector_v2/views.py
  • backend/prompt_studio/prompt_studio_core_v2/views.py
  • backend/utils/pagination.py
  • backend/utils/tests/test_pagination.py
  • backend/workflow_manager/workflow_v2/views.py
  • frontend/src/components/workflows/workflow/Workflows.css
  • frontend/src/components/workflows/workflow/Workflows.jsx
  • frontend/src/components/workflows/workflow/workflow-service.js

Comment thread backend/adapter_processor_v2/views.py Outdated
Comment thread frontend/src/components/workflows/workflow/Workflows.jsx
Comment thread frontend/src/components/workflows/workflow/Workflows.jsx
Comment thread frontend/src/components/workflows/workflow/Workflows.jsx Outdated
chandrasekharan-zipstack and others added 2 commits July 20, 2026 21:14
…pty-page fallback

- OptionalPagination: treat blank ?page=/?page_size= as not opting in so shared
  callers keep their bare-array response (Greptile).
- adapter/connector/prompt-studio get_queryset: order by the DISTINCT ON field
  for deterministic pagination, incl. the admin/service branch that has no
  distinct; not modified_at (conflicts with DISTINCT ON) (CodeRabbit).
- Workflows.jsx: step back a page when a delete empties the current page
  (CodeRabbit).
- Drop redundant "server-side name search" WHAT comments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z
…tch failure

- Drop the unconditional handleListRefresh() after edit; the branch already
  refreshes existing edits and navigates for new ones (CodeRabbit).
- Default projectList to [] on fetch failure so the empty state shows instead of
  an indefinite spinner (CodeRabbit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/workflows/workflow/Workflows.jsx (1)

148-150: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Prevent early clearance of loading state during chained requests.

Using an unconditional .finally() block to clear the shared loading state inadvertently hides the spinner when a chained operation has already initiated a new request. This causes the UI to temporarily freeze while the second network call is in flight.

  • frontend/src/components/workflows/workflow/Workflows.jsx#L148-L150: In getProjectList, finally clears the loading state even when falling back to the previous page (getProjectList(page - 1)). Remove .finally() and explicitly call setLoading(false) inside .then() (after state updates, skipping the fallback return) and .catch().
  • frontend/src/components/workflows/workflow/Workflows.jsx#L179-L181: In editProject, finally clears the loading state immediately after handleListRefresh() triggers a new list fetch. Remove .finally() and let the list refresh manage the loading state, while explicitly clearing it in the openProject and .catch() paths.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/workflows/workflow/Workflows.jsx` around lines 148 -
150, The loading state is cleared prematurely by unconditional finally blocks
during chained requests. In
frontend/src/components/workflows/workflow/Workflows.jsx lines 148-150, update
getProjectList to remove finally and call setLoading(false) in then after state
updates, except before returning for the previous-page fallback, and in catch.
In lines 179-181, update editProject to remove finally, let handleListRefresh
manage loading after refresh, and explicitly clear loading in the openProject
and catch paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@frontend/src/components/workflows/workflow/Workflows.jsx`:
- Around line 148-150: The loading state is cleared prematurely by unconditional
finally blocks during chained requests. In
frontend/src/components/workflows/workflow/Workflows.jsx lines 148-150, update
getProjectList to remove finally and call setLoading(false) in then after state
updates, except before returning for the previous-page fallback, and in catch.
In lines 179-181, update editProject to remove finally, let handleListRefresh
manage loading after refresh, and explicitly clear loading in the openProject
and catch paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7153dbac-8d3d-4cc9-ab52-3e1ac91d512a

📥 Commits

Reviewing files that changed from the base of the PR and between dab4e69 and 845f2a7.

📒 Files selected for processing (7)
  • backend/adapter_processor_v2/views.py
  • backend/connector_v2/views.py
  • backend/prompt_studio/prompt_studio_core_v2/views.py
  • backend/utils/pagination.py
  • backend/utils/tests/test_pagination.py
  • backend/workflow_manager/workflow_v2/views.py
  • frontend/src/components/workflows/workflow/Workflows.jsx
💤 Files with no reviewable changes (1)
  • backend/workflow_manager/workflow_v2/views.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/utils/pagination.py
  • backend/utils/tests/test_pagination.py
  • backend/prompt_studio/prompt_studio_core_v2/views.py
  • backend/adapter_processor_v2/views.py
  • backend/connector_v2/views.py

Comment thread backend/utils/pagination.py
…e size

Cover the mixed blank/non-blank pagination params. A blank ?page= alongside a
real ?page_size= serves the first page rather than raising NotFound, since DRF
resolves the page number as `query_params.get("page") or 1`.

Also drop the Workflows page size from 12 to 10 to match the other paginated
listing pages, which use the usePaginatedList default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzUpb2Dyunz2DCdwegR62Z
@github-actions

Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 16.3
e2e-coowners e2e 1 0 0 0 1.3
e2e-etl e2e 1 0 0 0 8.3
e2e-login e2e 2 0 0 0 1.2
e2e-prompt-studio e2e 1 0 0 0 5.0
e2e-smoke e2e 2 0 0 0 1.1
e2e-workflow e2e 1 0 0 0 16.5
integration-backend integration 124 0 0 27 53.3
integration-connectors integration 1 0 0 7 6.3
unit-backend unit 160 0 0 0 23.3
unit-connectors unit 63 0 0 0 11.0
unit-core unit 27 0 0 0 1.3
unit-platform-service unit 15 0 0 0 2.9
unit-rig unit 76 0 0 0 4.5
unit-sdk1 unit 490 0 0 0 22.0
unit-workers unit 723 0 0 0 39.4
TOTAL 1690 0 0 34 213.7

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

@chandrasekharan-zipstack
chandrasekharan-zipstack merged commit eda02f4 into main Jul 21, 2026
12 checks passed
@chandrasekharan-zipstack
chandrasekharan-zipstack deleted the feat/UN-3770-list-pagination branch July 21, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants