Skip to content
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

[EuiPagination] add a variation with next/previous buttons only #4506

Closed
katrin-freihofner opened this issue Feb 10, 2021 · 42 comments · Fixed by #5362
Closed

[EuiPagination] add a variation with next/previous buttons only #4506

katrin-freihofner opened this issue Feb 10, 2021 · 42 comments · Fixed by #5362
Assignees

Comments

@katrin-freihofner
Copy link

I'd like to discuss an additional variation of the pagination that only uses next and previous buttons (without showing the number of pages). This could be especially useful for us when it comes to performance improvements.

Although there might be some usability drawbacks (not knowing the total number of pages), the load performance of our tables would benefit and therefore the user experience.

@shahzad31
Copy link
Contributor

This will be defenitely useful for many usecases, in uptime we had to do a custom implementation below table.

@weltenwort
Copy link
Member

This is also true for the Logs UI. A common pattern would be a good idea. 👍

@jasonrhodes
Copy link
Member

I'd go even further than Katrin to say that I think this should probably be the default for EUI pagination, given the way that Elasticsearch is designed to work. We've uncovered the situation a ton in our UIs where we are doing queries to show the full range of pages when we really didn't need to show the full range of pages. By having the default pagination work in the way it does now, it encourages a query pattern that doesn't align with how most of our data is stored.

That being said, at least having a simple option and common component to do this kind of next/prev pagination would be fantastic. Thanks for logging, @katrin-freihofner !

@chandlerprall
Copy link
Contributor

Was going to suggest making some minor breaking changes to EuiPagination to require activePage and remove the default for pageCount, but I think a pagination bar with unbounded/unknown pages needs to be more flexible. Everyone please correct me / add to this list, practical needs appear to be:

  • unknown page count, has lower bound - starts at page N but unknown length of result set
  • unknown page count, unknown bounds - starts at a page of data, unknown beginning or end

Which makes me think there are two valid UIs: one with only prev|next arrows and a second with prev|{activePage}|next. Instead of enabling/disabling the arrows by comparing activePage with pageCount, a component would need an additional prop or props allowing the app to turn navigation on/off. Because of these needs, I'm leaning toward a new top-level pagination component. It may even be best to resume/take over #3962 , providing the functionality through a hook instead of a full component.

@cchaos
Copy link
Contributor

cchaos commented Feb 16, 2021

Before we get into the specifics of the engineering side, I'd love to hear more about the proposed user experience of it. @katrin-freihofner I'm guessing this is stemming from a specific problem being faced in Observability. Could you explain more of the type of feedback you've been receiving on the current implementation and how this proposal will mitigate those?

@hbharding
Copy link
Contributor

hbharding commented Feb 17, 2021

Hi @cchaos - happy to chime in here. @jasonrhodes and others, please correct me if anything I say is wrong, or add more detail as you see fit.

Could you explain more of the type of feedback you've been receiving on the current implementation and how this proposal will mitigate those?

My understanding of the problem is that showing page numbers ( i.e. 1 2 3 4 ... 999 ) requires ES to lookup the entire dataset, even though we might only be showing 10 results at a time. For large datasets, this can be a very memory-intensive query for ES which causes long load times for the user. This pagination performance issue seems to compound itself when combined with allowing the user to sort the results.

I ran into this problem while I was working on a design for the Metrics UI. I designed a table for showing processes that run on a particular host. This table included sparklines (time series data) which added to the overall size of the query.

See screenshot

image

Our quick workaround to this was to remove pagination and to only show the top 10 results. While this solution dramatically improved load times, it creates some tradeoffs. Without pagination:

  1. Users see an incomplete picture and might miss something of interest. For example, they can't access result number 11 or 957
  2. They can't jump to the first or last results, or somewhere inbetween. In the case of our "top N" table in Metrics UI, users could get to the "bottom result" by reversing the sort order, but other UIs with pagination may not be using sortable tables.
  3. There is no indication of the total # of results. We do a show a total elsewhere in the UI, but this would need to be handled differently on a case-by-case basis for other UIs

The team thinks that if we remove the display of page numbers (i.e. 1 2 3 4 ... 999), we can dramatically reduce the size of the query and improve load times, while still allowing the user to navigate through the results with "next" and "previous" buttons.

I'd love to hear more about the proposed user experience of it.

Great question... I have to admit there are some devil in the details and maybe more than 1 option we could explore. With the simplest option (number 1), we would simply remove the page numbers and include 2 buttons for navigating "next" and "previous".

Option 1

image

  • If the user is on the "first page", the "previous" button would appear disabled.
  • If the user clicks "next", the "previous" button would no longer be disabled.
  • If the user were to click "next" enough times to get to the end of the results, the "next" button would appear disabled.
    • if clicking "next" returns no results or a # less than the current "rows per page" setting, we can likely infer that they are on the last page.
  • The "rows per page" setting remains optional.
  • Side Note: Im on the fence with using empty buttons w/ text or just icon buttons, but this isn't super important for describing the UX.

Option 2

image

  • Same as option 1, with the addition of:
  • Buttons to jump to the "first" and "last" results. This mimics the behavior of our existing numbered pagination, but does so without showing page numbers. It could be useful for users to be able to jump to the end of the results so they don't have to click the next/prev buttons a bajillion times.
    • From an implementation standpoint, I don't know if this is possible. I think it would require us to know how many results to expect, but I'm hoping we could figure this out without fetching the entire dataset.
  • The logic for disabled state on the "first" and "last" buttons would be similar to option 1.

Option 3

image

  • Same as option 1 and 2, with the addition of:
  • Text that shows A) the total # of results and B) the range and location of the currently displayed results. This information helps the user understand where each item ranks relative to the total without displaying page numbers.
    • Again from an implementation standpoint, I don't know if this is possible. Perhaps we could store the current location in browser memory
  • Side note: We could explore other options for the location of the text, but again, not super important for describing the UX.

@weltenwort
Copy link
Member

weltenwort commented Feb 18, 2021

Very well put, @hbharding 👏

If I may try to answer those...

Option 2

[...]

* Buttons to jump to the "first" and "last" results. This mimics the behavior of our existing numbered pagination, but does so without showing page numbers. It could be useful for users to be able to jump to the end of the results so they don't have to click the next/prev buttons a bajillion times.
  
  * From an implementation standpoint, I don't know if this is possible. I think it would require us to know how many results to expect, but I'm hoping we could figure this out without fetching the entire dataset.

It would be possible by inverting the sort order while querying and then inverting again when displaying. The performance characteristics should be the same as displaying the first page, because the last page is essentially the first page when sorted the opposite direction.

Option 3

[...]

* Text that shows A) the total # of results and B) the range and location of the currently displayed results. This information helps the user understand where each item ranks relative to the total without displaying page numbers.
  
  * Again from an implementation standpoint, I don't know if this is possible. Perhaps we could store the current location in browser memory

Showing the total count is relatively expensive because the query couldn't terminate early. The impact can be limited by specifying an upper bound for the exact number (such as "more than 1000"), but performance would still be worse than without numbers in the general case. Another possible compromise is that this number could be queried separately from the table content, in which case it wouldn't slow down the table itself.


In general the usefulness of the ability to jump to page N with no way to anticipate what that page will contain is not clear to me. Providing meaningful filters and sorting options generally seems like the better way to enable the user to find what they are looking for.

@cchaos
Copy link
Contributor

cchaos commented Feb 19, 2021

Thank you @hbharding for the detailed writeup and possible options. ❤️

This is a great example of trying to compromise between user experience and the underlying tech. Though, just "removing" options from the user seems like a poor compromise. The one thing that the current pagination does clearly is give the user the knowledge of how many entries that table contains. "5 pages of 5 rows" 👍 . Remove the number of pages and all you have is "5 rows per page" 😕 .

Setting the expectation with the user as to how many "results" there are, has a huge impact on usability and understanding. Obviously performance does too, but again this gets to where we need a better compromise.

Another possible compromise is that this number could be queried separately from the table content, in which case it wouldn't slow down the table itself.

It sounds like the main problem, mostly with EuiBasicTable/EuiInMemoryTable, is that the pagination is currently too coupled with the actual data supplied to these components. It is possible to fully build your own table with EuiTable components, including hooking up your own pagination.

I think this should probably be the default for EUI pagination, given the way that Elasticsearch is designed to work.

This would not be ideal. While EUI certainly is geared for Elastic products, it is not always or even normally the case that it's used to display Elasticsearch results.


All that said, I lean towards Henry's 3rd option. It sets the expectation for the user as to the number of total results. Then in EUI we'd need a way to decouple/customize the pagination of EuiBasicTable. This would allow consumers to fetch data on each, or certain, page changes. But I'd go even further and require that if there is custom pagination then the consumer must provide some text for showing total results.

It seems, though that there may also be some considerations for how sort is handled as well.

Somewhat related is #4010


One extra question, and I've seen this idea pop up somewhere else too, is how to handle the querying of "more" data. As we know Elasticsearch is capped at a certain amount of results. If the total number of results could be more than this, and the user reaches the end (last page) of that first set, how do we want to handle the manual fetching of the next set?

  1. Where would this "button" exist in the UI?
  2. What does it do with the previous results? Append or replace?

@chandlerprall
Copy link
Contributor

Re: last page button in options 2&3:

It would be possible by inverting the sort order while querying and then inverting again when displaying. The performance characteristics should be the same as displaying the first page, because the last page is essentially the first page when sorted the opposite direction.

@weltenwort is that still possible if the dataset is unsorted?

@hbharding
Copy link
Contributor

Thanks @cchaos.

Setting the expectation with the user as to how many "results" there are, has a huge impact on usability and understanding.

I think that's what I was going for with option 3, buy you've articulated it way better, kudos 🎉

In case the "first" and "last" buttons in option 2&3 are problematic, I realize there could be a 4th option, which would be the same as option 3 but without these buttons.

@katrin-freihofner
Copy link
Author

I'd like to add that there might be different use cases. The two examples that come to my mind are:

  1. I have a small environment (maybe just set up) with < 100 hosts.
  2. I have a very large environment with ~10,000 nodes.

While for the first use case it might be interesting to know the exact number of hosts, for the second one it is probably not important. Such a large environment is likely autoscaling as needed. As a user, my main focus is that all of those ~10,000 nodes are healthy.

That is why I think in addition to our current pagination we need one that performs well with a large number of elements. An option that has not been discussed yet is showing the limit with something like "> 1,000":

Screenshot 2021-02-22 at 09 38 42

@shahzad31
Copy link
Contributor

shahzad31 commented Feb 22, 2021

I think performance aspect of pagination may not be as prominent as we think if we think of pagination in terms of how people use it. I mean really in most cases pagination is mostly for visibility purpose, i don't have a data to back this, but user hardly click beyond first page, maybe in rare case second page. Users are more likely to use pagination if they have few pages and data is sorted. Most people if they don't see data on first page, they will filter the data.

Compared to pages, virtual scroll is the most useful thing for a larger data.Where user will go beyond even 10th pages, by just virtue of scrolling.

So for example if we have more than 10 pages, i guess that's where you might see a performance hit if user clicked 11th pages or something. But are they ever gonna do that? what's the use case?

Numbered pagination is something that's probably not that useful, but if you don't have it on the list , user will complain, "ohh we can't even have number pagination on the list, really?"

So if we are talking about < 100 hosts, even <1000 hosts, where we are just show list of hosts.

I think ES can be as performant as on 1st page or 10th, i mean different is probably negligible. Fetching 10 terms aggs vs 1000 aggs.

IMO we should always go with number pagination, only in a case, where performance difference is noticeable, in that case composite aggs before/after pagination make sense.

@jasonrhodes
Copy link
Member

Hey all!

Thanks for the write-up, @hbharding -- I think it's an excellent summary of the problems we've encountered.

Though, just "removing" options from the user seems like a poor compromise.

This is fair, I'd just like to challenge some of our assumptions about features that users need in all cases, or even most cases. Especially in light of the type of data we are typically showing in our UIs and the capabilities we can offer them. We'll always have the full pagination component if it's the thing that works best for a use-case.

My main concern is that Elasticsearch is great at search, but we don't always take advantage of that fact very well. Switching from "here is all of the data in a paginated table" to "here is the top X data sorted by Y, you can page through to the next page if you need to see a few more pages, but if you are looking for something different, you can sort, filter, or search differently" not only speeds up experiences across the board but also encourages us to build a UX that may actually be more helpful in many cases.

Obviously, we can do both (filtering/search + showing all results), but if a user is unlikely to need to jump to page 925 of 1800 pages, I think we should think hard about how much performance improvement we can gain from UX options that don't incur that cost.

I love a sort of progressively enhanced hierarchy, something like:

  • start with a simple restricted count table,
  • then add next/prev buttons,
  • then add "jump to last/jump to first",
  • then add "showing x of y (where y is maxed at a certain number and over that it says > y, like Katrin suggested),
  • then add "showing x of y (with no y limit)"
  • then add all individual pages (this is where we usually start today)

@jasonrhodes
Copy link
Member

IMO we should always go with number pagination, only in a case, where performance difference is noticeable, in that case composite aggs before/after pagination make sense.

@shahzad31 can you elaborate? It sounded like you were saying numbered pagination may not be that useful but then this last sentence says you think we should always go with number pagination? Just trying to make sure I understand what you are suggesting, thanks!

@shahzad31
Copy link
Contributor

@jasonrhodes i think in most cases where performance isn't a big concern we should go with number pagination. Performance only becomes a concern if user wants to view i guess 20th page or 150th page depending on the data set, which almost never happens.

Even though user is unlikely to use all pages but from UX perspective number pagination is most familiar approach.

@jasonrhodes
Copy link
Member

@shahzad31 the performance problem (one of them) is in the query that is needed to retrieve all pages and show them as a numbered set.

@shahzad31
Copy link
Contributor

@jasonrhodes i got your point so it seems like it's an offline paginated pages instead of using 'from' parameter in es query. In that case it make sense.

@weltenwort
Copy link
Member

I think ES can be as performant as on 1st page or 10th, i mean different is probably negligible. Fetching 10 terms aggs vs 1000 aggs.

@shahzad31 There is a limit as to how far you can paginate with from, which is set to 10000 by default. And since that limit can be configured by the ES admin you can't even rely it being a well-known value. It also limits the ability of ES to rewrite the query to skip shards, which can be significant when dealing with cold data tiers and runtime fields.

@jasonrhodes That hierarchy makes total sense to me. Well put. 👍

@weltenwort
Copy link
Member

@weltenwort is that still possible if the dataset is unsorted?

Is it ever really "unsorted", not just implicitly so sometimes? You could always sort by _doc for the cheapest consistent order.

@lukeelmers
Copy link
Member

lukeelmers commented Feb 22, 2021

I was asked to chime in based on a related discussion happening in Kibana -- thought I would add a few thoughts on UX as well as some more context on Elasticsearch's technical constraints here.

First, on the UX side, I'm +1 to Jason's proposal, in particular this observation:

My main concern is that Elasticsearch is great at search, but we don't always take advantage of that fact very well. Switching from "here is all of the data in a paginated table" to "here is the top X data sorted by Y, you can page through to the next page if you need to see a few more pages, but if you are looking for something different, you can sort, filter, or search differently" not only speeds up experiences across the board but also encourages us to build a UX that may actually be more helpful in many cases.

IMHO the UX question to be asking is: Why does someone need to be paging through hundreds of pages of hits, and how can we enable them to more easily narrow results down to a manageable number?

Now in terms of Elasticsearch's technical constraints, a bit more background:

There is a limit as to how far you can paginate with from, which is set to 10000 by default. And since that limit can be configured by the ES admin you can't even rely it being a well-known value.

This setting is the max_result_window which is set per-index. When you need to page through a number of results that's greater than the max_result_window, you need to use search_after, where the next page of results is retrieved using the sort value from the last hit on the previous page of results.

The implication here is that when you are using search_after, you don't actually know the number of pages/hits in advance, or even if the next page will have any values at all. And it bears repeating: max_result_window is configurable and could be any number besides the default of 10k. So any UX which is displaying data from Elasticsearch needs to contend with this problem if it wants to page through large numbers of hits.

On the Kibana Core team, we are planning on adding a helper for paging through large sets of saved objects using search_after which may make this easier for folks building these apps in Kibana, but of course it will only be useful if the UI components can work around the search_after limitations.

That said, I do agree there are several possible solutions:

  1. Just go with a prev/next button similar to scrolling through commits on Github:
    Screen Shot 2021-02-22 at 9 26 35 AM
  2. Take a perf hit and request some extra pages up-front in order to provide a Google-like experience where a user can jump to the next few pages but not any arbitrary page, and only gets links to the next 5 pages once they move outside of that window:
    Screen Shot 2021-02-22 at 9 23 29 AM
  3. Embrace the page size limitations and indicate if the max has been met or exceeded, as suggested above:

An option that has not been discussed yet is showing the limit with something like "> 1,000"

@cchaos
Copy link
Contributor

cchaos commented Feb 22, 2021

Great discussion!

I'm going to summarize in terms of what we can/should be doing in EUI to support these use cases.

  1. Always be clear to the user about the total results. There needs to be a clear indicator of how many (and if not all results) have been returned and are included in the table. Just a simple count can do. Also, a nice summary of results at the top of the table goes a long way to signify what paging can't.
  2. Give control over the total rows per page (with large increments). The default and threshold of pages per row need to coincide with the total number of results. For instance 1000+ results shouldn't start with 10 rows per page, but probably more like 25 or even 50. Possibly even add an option for "All".
  3. Allow some form of pagination, but reduce complexity when page count reaches a certain threshold. This might be something we can build into the EuiPagination component. So that if there's something like 20+ pages of results, we reduce to just the previous/next arrows (maybe first and last too).
  4. Give users better ways to find what they're looking for. For any results style table there should absolutely be ways to filter, search, etc for the thing that the user wants. This is where pagination can then come back into play. If they've reduced the 1000+ results to just 100, but there's not more ways to filter/sort to find their "thing", let them page quickly especially if the results are alphanumeric and they can guess at what page number their result will be.

@weltenwort
Copy link
Member

weltenwort commented Feb 22, 2021

Thank you for the concise summary. I'm not sure it pays tribute to the motivation that underlies the original ask, though. And I see a mismatch between the suggested patterns and the best practices of using the Elasticsearch API.

For example, "Always be clear to the user about the total results" is not something that aligns with what makes Elasticsearch efficient. It forces the developer to choose the slow option of asking Elasticsearch for the total count. In some cases (e.g. when basing the list entries on a terms aggregation) it might not even be possible to get that information from the API with total confidence.

Or "The default and threshold of pages per row need to coincide with the total number of results." suggests that we could somehow known in advance how many results there will be. We can (in a potentially expensive way) ask Elasticsearch for that count using multiple queries, but, as @jasonrhodes argued, it doesn't make sense to default to that in the general case.

"Allow some form of pagination, but reduce complexity when page count reaches a certain threshold." also indicates that we should ask Elasticsearch for a count.

As a developer faced with the semantics and performance characteristics of APIs such as Elasticsearch's, the answer I'm looking for would be something like "Given I know neither the total number of result entries nor the position of the currently displayed chunk of entries within the full set of result entries, which EUI component should I use to implement the pagination?".

@cchaos
Copy link
Contributor

cchaos commented Feb 22, 2021

I respectfully disagree with your assumption that these UX behaviors mismatch with Elasticsearch.

"Always be clear to the user about the total results"

Does not necessarily mean you have to give a concrete number. You just have to be clear about what the current results showcase. For instance it can say "Showing first 100 results" or "Search results maxed at 1000" or "Results fetched at runtime". This is how you communicate to the user what the Elasticsearch API is returning. Not all users of Kibana, et al, actually know how ES works, they just care about the data that's being shown to them.

"The default and threshold of pages per row need to coincide with the total number of results."

You can make a best guess based on the context of that specific table, whether there's most likely going to be tens or thousands of results. So from there you can make a best guess as to whether you should be, by default, showing 5 rows per page or 50.

"Allow some form of pagination, but reduce complexity when page count reaches a certain threshold." also indicates that we should ask Elasticsearch for a count.

But you have to supply the table with data right? Are you going to fetch new data every time the user clicks the next page button? How would the table's inherit sort work, or do you do another ES call instead?

I, also, am speaking about how EUI could automatically handle this as an option. How it would be possible for EUI's pagination component to be smarter than it currently is which is incredibly manual.


"Given I know neither the total number of result entries nor the position of the currently displayed chunk of entries within the full set of result entries, which EUI component should I use to implement the pagination?".

Pagination is simply is a string of buttons lined up in a row. EUI provide all the base components on export. You can build out a completely custom table with all the EuiTable components and at the bottom add some EuiButtonEmpty's to hook up to you style of pagination needs.


I'll also reiterate, that while EUI mainly supports Elastic and ES products, there are many wide uses for tables and table pagination that are not getting results fetched from this API and so we can't assume.

I am also in no way arguing over the validity of offering a number-less pagination option. I'm pretty sure I've already Ok'd this idea. What I'm mostly trying to give are some general UX guidelines on pagination usages. Ones that I'll most likely write up in our docs too.

@jasonrhodes
Copy link
Member

But you have to supply the table with data right? Are you going to fetch new data every time the user clicks the next page button? How would the table's inherit sort work, or do you do another ES call instead?

Yeah, I think in many cases this is the most performant approach (fetching new data when the user clicks next, and doing a new ES call on every sort). Especially in cases where, like most observability cases, we don't expect a user to need to move past the first page of results very often.

This reminds me of the discussions around how to bundle JS files, whereas we used to try to limit the number of downloads and bundle everything together, and then at some point we decided to try to make the initial load as fast as possible and "lazy load" other bits of JS only when a user clicks somewhere and needs them. I think we're finding more and more use cases in Kibana where "lazy loading" data makes a lot of sense, which means we need a clear/simple way to avoid things like "showing the total count" because it invalidates the entire lazy load approach by requiring a lookup of the total count.

You just have to be clear about what the current results showcase. For instance it can say "Showing first 100 results" or "Search results maxed at 1000" or "Results fetched at runtime". This is how you communicate to the user what the Elasticsearch API is returning. Not all users of Kibana, et al, actually know how ES works, they just care about the data that's being shown to them.

This makes sense to me. I think possibly what I was getting at earlier in this thread is that we are trying to get away from communicating to the user by way of telling them the total number of results and move to other forms of communication, like "showing top 20 results sorted by column x" and "narrow your search by doing this" etc.

I am also in no way arguing over the validity of offering a number-less pagination option. I'm pretty sure I've already Ok'd this idea. What I'm mostly trying to give are some general UX guidelines on pagination usages. Ones that I'll most likely write up in our docs too.

Sounds good to me! I appreciate your engagement as always :) I'm also not entirely sure if we're asking for changes to the paginated table components or if we're asking for a new component that defaults to the other way around, but I think the hierarchy I listed above feels right to us in observability (and possibly to Luke), and maybe to others in Kibana solutions. And so ultimately I just want our Observability design folks to have the tools they need to produce designs that align with the UX we're trying to give our users, which I know is EUI's goal too. Thanks for hashing it out with us!

@cchaos
Copy link
Contributor

cchaos commented Feb 23, 2021

So from an implementation stand point, we're good with the design of being able to simply remove the numbering (similar to the mobile version) and adding optional first/last button. @hbharding's design here:

Image 2021-02-23 at 1 08 54 PM

I think this can simply be an alteration of the current EuiPagination. My guess is that consumers would still need to use the custom implementation of the EuiTable components because of all the other built-in functionality from EuiBasicTable+ like sorting and such.

The EUI team currently has a heavy load as of our latest roadmap planning, but we're happy to review a PR!

@weltenwort
Copy link
Member

@cchaos you're right, I was viewing it primarily from the perspective of someone implementing UIs for Elasticsearch, where incremental loading and lazy fetching is a valuable pattern.

I probably interpreted the "always" and "needs to" in your summary more strongly than I should have. Thanks for clarifying.

@hbharding
Copy link
Contributor

Thanks @cchaos.

re: "Always be clear to the user about the total results" ... I still think it's important for the user to have some form of indication, but I get that it might be challenging to build this into a pagination component. When working with data of an unknown size from ES, this information probably needs to come from a separate query for performance reasons, and the text itself may be different depending on the context. In other words, this very much feels like an "it depends" situation and we may not be able to provide a good "one size fits all" solution. I'd be happy if someone could prove me wrong :)

With that said, I think it would be helpful to include an example of "total results" (like in Katrin's example) as a reminder / pattern for designers and developers to follow.

@andrewvc
Copy link

andrewvc commented Mar 1, 2021

Just jumping in here to say that I'm a big fan of the proposal for next/prev pagination. It makes way more sense for aggregation results (which is why we used it in the Uptime UI).

Also, let's be clear, historically the reason for numbered pagination was that SQL databases made this easy (though they always had the same perf issues ES has). Cursors existed, but were more exotic, but where present you would occasionally see numberless pagination. I can't prove this was true, but every tutorial I read in the early 2000s just explained that you did pagination with FROM and SIZE, and there was no discussion of UX.

Numbered pagination was always a way of pushing the hard problems of data exploration onto the user IMHO. Sorting and filtering is extra work and search was a major feature that was rarely well supported by databases at the time (if you were lucky your data was small enough you could get away with an ILIKE. Besides, technically, you gave the user all the data, if they couldn't find anything, that was their problem.

In other words, numbered pagination is a legacy of ancient technical implementations more than a conscious UX choice. We now have powerful search tools, let's use them.

@cchaos cchaos changed the title [Pagination] add a variation with next/previous buttons only [EuiPagination] add a variation with next/previous buttons only Mar 19, 2021
@j-m
Copy link
Contributor

j-m commented Mar 30, 2021

Please don't make this the default.

When filtering, the user should be told how many results (roughly, if in the millions) will be returned as this gives them immediate feedback as to how precise their queries need to be. The first thing you see on a Google results page is "About X million results". The reason you can skip to 10 pages at a time is because when you search the same thing again, it'll be in the same place. This is why I proposed #4118

Yes, it's antiquated to give the user all the data and make them sift through 1000 pages, but that's got nothing to do with showing page numbers itself; that's just poor filtering, something you should do before even using the datagrid.

In my opinion, this option would encourage poor design.

@jasonrhodes
Copy link
Member

@j-m Thanks for the feedback!

When filtering, the user should be told how many results (roughly, if in the millions) will be returned as this gives them immediate feedback as to how precise their queries need to be.

I think what we've found over and over is that this just really depends on the type of query and the type of UI you're designing, and that we need the tools to be able to adapt to that more easily. In fact, because of how powerful the ES search functions are, some of us are proposing that we build up from a simple list to a full, paginated list of results with full information about the total result set.

For example, in many observability cases, we're trying to build views focused on triage and investigation. In those cases, we want to get the user "top x results" based on a search filter as soon as possible. Let's say, top 10 hosts sorted by CPU percent. If all 10 hosts that return are pegged at 100%, the user will likely want to continue exploring the next 10, until they start to normalize, to see how many hosts are at that spiking value. Maybe they can even adjust the "x" there to see "top 100".

But in none of these cases does the user care about how many hosts they have, total. For that reason, we want to be able to easily drop that part of the UI in favor of the fastest query speed possible.

Of course there will be situations where the total result count is incredibly important, so we don't want to throw full pagination in the trash by any means, but we do need more options so that we can be flexible and choose the best set of trade-offs for a given UI.

@j-m
Copy link
Contributor

j-m commented Apr 9, 2021

@jasonrhodes Thank you for clarifying. I don't use ES, so it's a little difficult to understand all the intricacies.

I still think the default pagination should be as is, even if just for EuiDataGrid as it doesn't handle dynamic/pending data particularly well; has no loading state, needs to know rowCount, and sorting would be redundant or janky (rows would reorder as new data is loaded).

I don't know the full context but would it be worth keeping page numbers for loaded results? akin to changing rowCount based on the current number of results, then the user can still jump around. Or do you refetch data?

@andrewvc
Copy link

andrewvc commented May 3, 2021

Thank you for raising those concerns @j-m, I think it's a great idea to include the total number of results and as you say that has nothing to do with previous next pagination. Would you be OK with previous / next pagination if we also showed the total number of results?

@j-m
Copy link
Contributor

j-m commented May 4, 2021

@andrewvc Sounds great!

@github-actions
Copy link

github-actions bot commented Nov 1, 2021

👋 Hey there. This issue hasn't had any activity for 180 days. We'll automatically close it if that trend continues for another week. If you feel this issue is still valid and needs attention please let us know with a comment.

@weltenwort
Copy link
Member

Nothing has changed in regard to this, right?

@cchaos
Copy link
Contributor

cchaos commented Nov 1, 2021

I think from an EUI standpoint we're just unclear on what the final ask is now.

@weltenwort
Copy link
Member

weltenwort commented Nov 1, 2021

From my perspective what you described in #4506 (comment) would work for the cases when we can't know the total number of pages.

@cchaos cchaos self-assigned this Nov 1, 2021
@cchaos cchaos removed the stale-issue label Nov 1, 2021
@cchaos cchaos added this to the Elastic Stack 8.1 milestone Nov 1, 2021
@cchaos cchaos removed the discussion label Nov 1, 2021
@cchaos
Copy link
Contributor

cchaos commented Nov 1, 2021

As I'm working through this, I'm still skeptical at this notion of:

we can't know the total number of pages

If you don't know the total pages, how would the "last" button work?

@weltenwort
Copy link
Member

When querying Elasticsearch we can reverse the sort order in the query, ask for the first page and then reverse the result before displaying.

@cchaos
Copy link
Contributor

cchaos commented Nov 1, 2021

Ok so further question, The EuiPagination component passes back the activePage +/- 1 whenever the arrow buttons are clicked. What do you expect the component do pass back when both totalCount and activePage are unknown?

@weltenwort
Copy link
Member

weltenwort commented Nov 4, 2021

Intuitive I'd have expected the component to have something like onNextPage, onPreviousPage, onFirstPage and onLastPage props that are called when the corresponding button is clicked. It would also need props to indicate whether there are previous or next pages (isFirstPage/isLastPage or hasPagesBefore/hasPagesAfter?).

Looking at the current pagination component's props it seems cramming the extra functionality in there would pollute the API a lot. Maybe a dedicated EuiUnquantifiedPagination (sorry, couldn't think of a proper name here) component would keep it cleaner?

@cchaos
Copy link
Contributor

cchaos commented Nov 9, 2021

PR is up: #5362

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
10 participants