-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🪟 🎉 Connection job list pagination #15938
Conversation
refetchInterval: 2500, // every 2,5 seconds, | ||
keepPreviousData: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was necessary to prevent the jobs from disappearing and the loading spinner showing every time Load more
is clicked. With this keepPreviousData option set to true, it now seamlessly appends the new query results to the end once they are available. For more info see the official docs on this: https://react-query-v3.tanstack.com/guides/paginated-queries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really cool solution for this.
@@ -145,6 +170,11 @@ const StatusView: React.FC<StatusViewProps> = ({ connection }) => { | |||
> | |||
{jobs.length ? <JobsList jobs={jobs} /> : <EmptyResource text={<FormattedMessage id="sources.noSync" />} />} | |||
</ContentCard> | |||
<footer className={styles.footer}> | |||
<Button onClick={onLoadMoreJobs} disabled={jobs.length < jobPageSize}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two things:
-
I think it would be cool if we could show the button in a loading state while we're still loading the query. To do that we must use
useQuery
directly instead of our customuseSuspenseQuery
wrapper in theJobService
so we can get access to the underlying react-query properties. There isisPreviousValue
which will be true while we're still loading the next data but show the previous, which we can use as an indicator that we're still loading. -
In general I'd consider it good UX to not hide buttons but disable them if they are not available. For this specific case of paginating an "infinite list" I feel it might be more appropriate (and more commonly used as a pattern) to actually hide the button and not disable it, if there are no further items to paginate over. Since a disabled button might leave the question: "Why can't I load more jobs anymore?" and looks more like an issue than "the end of the list".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@timroes thanks for the suggestions, both make sense to me!
I have pushed up the changes to accomplish this, and I think it looks cleaner now.
I recorded a new video to demonstrate how it looks now, and to also show one small quirk of this implementation (I lowered the page size increment from 25 to 2 for this demonstration to make it a bit easier to show the behavior, but I've kept it as 25 in the PR):
https://www.loom.com/share/edc11614687b4f4f8b60f348abb982d4
Notice that at the end of the video, I click the Load more
button, which causes it to load, but then it disappears. This is because the total number of jobs for this connection is a multiple of the page size increment (2 in that demonstration). So when all jobs are loaded, the logic of moreJobPagesAvailable = jobs && jobs.length === jobPageSize
evaluates to true, because our code can only make an assumption about there being more jobs available based on the fact that we displaying the full page size number of jobs.
It isn't until we click the Load more
button once more that our code can understand that the page size is higher than the number of jobs being returned by the API, so we can assume there are no more jobs to load.
In production, I doubt anyone will run into this case very often, as it would require that the number of jobs for their connection is an exact multiple of 25. And regardless, I don't think the UX for this is all that confusing, since the user clicks Load more
, it loads, and the button disappears, indicating that there are no more jobs to show.
Sorry if what I said above was super verbose or confusing - I just wanted to confirm that that edge case is acceptable behavior!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(also, the style of the loading state of the button in that loom is a bit different than in the current state of the PR, since I just now realized we have a LoadingButton
component. I have switched to using that instead of inserting a spinner into the button conditionally)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In production, I doubt anyone will run into this case very often, as it would require that the number of jobs for their connection is an exact multiple of 25. And regardless, I don't think the UX for this is all that confusing, since the user clicks Load more, it loads, and the button disappears, indicating that there are no more jobs to show.
I thought about that as well when I suggested that and feel it's an "okay" behavior int his case. Given we'll still do the request we're shortly in a loading state and then hide the button, which feels like users get the idea that there is nothing more to add. If we'd want to solve that really well, we'd need to adjust the API to also return us the totalCount
as part of the response (which shouldn't be too expensive to get via SQL directly), so we can basically use this as a boundary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep exactly. I think this solution is good enough for now, but if we see complaints about this we can do the totalCount
solution at that time
@lmossman is the backend issue for this already fixed? Since we can only merge this once the BE issue is solved (since otherwise the check to disable/hide the button won't work properly). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more nitpicks and comments. Other than that functionality looks great :)
|
||
.footer { | ||
width: 100%; | ||
height: 50px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎨 Minor nitpick: Usually we should try to avoid setting explicit heights
. This comes with the problem that if any styling of elements changes inside we could end up overflowing this height
at a later point. Usually in all cases you'd want to set a height to a container, you'll likely just want to apply padding
or margin
instead, to give spacing to the surrounding elements (or its contents in case of padding).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense! Removed
</ContentCard> | ||
<footer className={styles.footer}> | ||
{(moreJobPagesAvailable || isJobPageLoading) && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎨 Given that the footer
itself has some dimension (atm because of the height
, if that's changed likely still because of the margin
/padding
), I'd suggest to also hide that if the button isn't shown, so we don't leave unnecessary "white-space" on the page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
refetchInterval: 2500, // every 2,5 seconds, | ||
}).jobs; | ||
keepPreviousData: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd now want to pass the suspense: true
here, that the useSuspenseQuery
usually set. This will cause React to not render the component (beyond the point of this method call) as long as the initial data is still loaded, and instead show the fallback
element of the React.Suspense
next up in the React tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code LGTM. tested locally on Chrome Linux. works as expected.
* add load more jobs button * add pagination to query key * add keepPreviousData: true to prevent loading spinner when fetching new data * show loading spinner when loading more jobs * set page size increment back to 25 * extend input html attributes instead of adding className explicitly * use LoadingButton instead of inserting a spinner conditionally into the button * use suspense: true * get rid of unnecessary undefined * remove footer height and hide if no more jobs to load
What
Resolves #10323
Adds pagination of jobs to the status view of a connection. On initial load, the most recent 25 jobs are shown, and when the user clicks the new
Load more
button below the job list, the page size is increased by 25 per click until there are no more jobs to fetch, at which point theLoad more
button is disabled.How
This utilizes the already-existing pagination functionality available in the
listJobs
API endpoint, by increasing the page size sent in the API request each timeLoad more
is clicked.As explained in the issue linked above, this page uses auto-polling to refetch jobs every few seconds, so I needed to always keep the offset set to the default of 0 and only increase the page size that was being requested, since the request is continuously re-sent.
An analytics event is also fired whenever the
Load more
button is clicked, as specified in the ticket.Here is a screen recording showing this functionality in action:
https://www.loom.com/share/44fde86ef61d48cc80552ff9d9a91700
Recommended reading order
StatusView.tsx
JobService.tsx
🚨 User Impact 🚨
Users can now page through jobs in a connection, which will improve performance and usability especially for connections with many jobs