Skip to content

Add pagination to credentials and project credentials page#4672

Open
sharleenawinja wants to merge 5 commits into
OpenFn:mainfrom
sharleenawinja:credentials-pagination
Open

Add pagination to credentials and project credentials page#4672
sharleenawinja wants to merge 5 commits into
OpenFn:mainfrom
sharleenawinja:credentials-pagination

Conversation

@sharleenawinja

Copy link
Copy Markdown

Description

This PR adds pagination to the credentials, keychain credentials, and OAuth clients tables on the credentials list pages (10 items per page, with Previous/Next control). OAuth clients are now in a collapsible section, collapsed by default. Tables are ordered: credentials first, keychain credentials second, OAuth clients last.

Closes #4301

Validation steps

  1. Go to /credentials with more than 10 credentials — confirm the table paginates

  2. Confirm the OAuth Clients section is collapsed by default and the toggle shows/hides it.

  3. If there are more than 10 OAuth clients, expand the section and confirm pagination works.

  4. Verify the same behaviour on Project Settings → Credentials.

Additional notes for the reviewer

  1. (Is there anything else the reviewer should know or look out for?)

AI Usage

Please disclose whether you've used AI anywhere in this PR (it's cool, we just
want to know!):

  • I have used Claude Code
  • I have used another model
  • I have not used AI

You can read more details in our
Responsible AI Policy

Pre-submission checklist

  • I have performed an AI review of my code (we recommend using /review
    with Claude Code)
  • I have implemented and tested all related authorization policies.
    (e.g., :owner, :admin, :editor, :viewer)
  • I have updated the changelog.
  • I have ticked a box in "AI usage" in this PR

@sharleenawinja sharleenawinja marked this pull request as draft April 28, 2026 10:37
@github-project-automation github-project-automation Bot moved this to New Issues in Core Apr 28, 2026
@sharleenawinja sharleenawinja marked this pull request as ready for review April 28, 2026 10:39
@sharleenawinja

Copy link
Copy Markdown
Author

@midigofrank could you please review this PR when you have a moment? Thanks!

@midigofrank

Copy link
Copy Markdown
Collaborator

Hey @sharleenawinja , thank you. I will review this today

@josephjclark

Copy link
Copy Markdown
Collaborator

Hi @sharleenawinja, thank you for this! There are two tests failing in CI, I think just because some of the HTML structures have changed. Would you mind taking a look before Frank reviews this properly? You can see the errors here: https://app.circleci.com/pipelines/github/OpenFn/lightning/17326/workflows/2b9ed83e-0bac-4f14-9180-2958451d29ac/jobs/93782/tests

@midigofrank midigofrank left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hey @sharleenawinja , thank you for picking this up, you've picked a tough one, pagination in a page with multiple lists is an unchartered territory in lightning.

The credentials page is gnarly, it has multiple lists and the lists are shared in both the credentials page and the project settings page.

I see that you've chosen to do the pagination in the UI, I think that's understandable given the complexity of the page. I'm just not sure if that's the direction we want to take given that every other place does pagination using db queries. @elias-ba what do you think about this approach?

I also noticed that you created a new pagination component, could you try and reuse the one in https://github.com/OpenFn/lightning/blob/main/lib/lightning_web/pagination.ex ?

Also, test this in both pages (project settings and credentials page)

@github-project-automation github-project-automation Bot moved this from New Issues to In review in Core May 4, 2026
@midigofrank midigofrank requested a review from elias-ba May 4, 2026 08:49
@sharleenawinja

Copy link
Copy Markdown
Author

@midigofrank Thanks for the context. I'll rework the pagination to use DB queries to stay consistent with the rest of the app, and I'll reuse the existing pagination component instead of the one I added. I'll update the PR once that's done.

@sharleenawinja sharleenawinja force-pushed the credentials-pagination branch from d0a4068 to a4ab2f0 Compare May 6, 2026 02:08
@sharleenawinja

Copy link
Copy Markdown
Author

@josephjclark @midigofrank @elias-ba I have switched to DB-level pagination and reused the existing pagination_bar component. Each table now paginates via URL params. For the pipeline, the elixir tests job is failing due to pre-existing flaky tests.

@elias-ba elias-ba 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.

Hey @sharleenawinja, really nice work on this 🙌 I pulled it down, ran the credentials and oauth suites and read through it carefully. It reads well, and the scoping and tests look right to me.

Nothing blocking from me. A few things I'd love us to look at, mostly questions:

  • A bit of duplication I'd like to consolidate (inline). The display-mapping helpers are now copy-pasted into both index.ex and settings.ex; they used to live once inside the shared component. This is the one I'd most like tidied.
  • The paginater change (inline). Works, but I think we can name the actual Ecto struct instead of matching a bare map, and it's worth a test since it's a shared file.
  • A couple of smaller things (inline): the repeated empty-page maps, the Map.put display fields, and a question about whether create/edit reliably refreshes the list now that close_active_modal no longer reloads.

Honestly it's close. Lift the duplicated helpers into one home and I'm happy. Thanks for taking this one on 🙏

end
end

defp map_credentials(%Scrivener.Page{} = page) do

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.

This block (map_credentials / add_credential_display_fields / map_oauth_clients / add_oauth_client_display_fields) is now identical to the one in credential_live/index.ex. It lived in one place inside CredentialIndexComponent before the refactor pulled loading up into the two parents. Could we lift these into a shared home so they don't drift, maybe Credentials.with_display_fields/1 in the context, or a small helper both LiveViews call? Non-blocking, but it's the thing I'd most like sorted before merge.

active_menu_item: :settings,
can_receive_failure_alerts: can_receive_failure_alerts,
collaborators_to_invite: [],
credentials_page: %{

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.

Small one: these placeholder pages are hand-written maps (and there's another as @empty_page in CredentialIndexComponent), while the real values from apply_action are %Scrivener.Page{} structs. Safe today since :index always overwrites before render, but it's easy for the shapes to drift apart. Maybe one empty_page() helper, or just %Scrivener.Page{page_number: 1}, so there's a single source of truth?

%{
group_bys: [
%Ecto.Query.QueryExpr{
%{

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.

This one I'd like to think through with you. Loosening %Ecto.Query.QueryExpr{} to a bare %{expr: ...} works, but it now matches any map with an expr key rather than the actual struct. I think the precise fix is %Ecto.Query.ByExpr{}, that's what group_by builds in Ecto 3.13, which keeps the type guard. It's also a shared file every grouped-paginated query flows through, with no test hitting it directly. Could we name the struct and add a small test for the grouped-count path? More a robustness worry than a blocker.

socket
|> assign(active_modal: nil, credential: nil, oauth_client: nil)
|> load_credentials()}
|> assign(active_modal: nil, credential: nil, oauth_client: nil)}

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.

More of a question than a problem. close_active_modal used to reload the lists; now it just clears the modal, so a create/edit only appears if the save handler remembers to push_patch to return_to (the delete paths now do). It works in the tests, I just want to be sure the create-then-close path always routes back through handle_params so the new row shows up, rather than leaning on each handler to remember. Did the new-credential flow refresh cleanly when you tested it?

credential |> Map.get(:credential_bodies, []) |> Enum.map(& &1.name)

credential
|> Map.put(:project_names, project_names)

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.

Non-blocking, and carried over from the old component rather than something you introduced: we're adding :project_names/:environment_names onto the %Credential{} struct with Map.put, which quietly turns it into a struct with keys that aren't in the schema. Fine for display, but since we're already reshaping this, deriving them in the template (or a small view struct) would keep the schema honest. Happy to leave it for a follow-up.

@elias-ba

elias-ba commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Oh, and the red test_elixir, I don't think that one's on you. The two failures are both outside what this PR touches. A rebase on main and a re-push should give it a fresh run. If either still fails after that, let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

Add pagination to credentials and project credentials page

4 participants