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

add filtering to api pagination #2130

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions src/lib/holocene/api-pagination.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';

import debounce from 'just-debounce';
import { onMount } from 'svelte';

import Alert from '$lib/holocene/alert.svelte';
import Input from '$lib/holocene/input/input.svelte';
import FilterSelect from '$lib/holocene/select/filter-select.svelte';
import SkeletonTable from '$lib/holocene/skeleton/table.svelte';
import {
Expand All @@ -29,11 +31,14 @@
itemsKeyname?: string;
previousButtonLabel: string;
nextButtonLabel: string;
filterable?: boolean | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should replace the custom input on the Schedules page ⬇️ with this prop 🎉

Screenshot 2024-06-03 at 11 21 50 AM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should, I can make a follow up task for that

filterInputLabel?: string | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the input only shows up if filterable && filterInputLabel, can we make filterInputLabel required if filterable is true?

}

type PaginatedRequest<T> = (
size: number,
token: string,
query?: string,
) => Promise<{ items: T[]; nextPageToken: string }>;

export let onError: (error: Error) => void | undefined = undefined;
Expand All @@ -52,6 +57,10 @@
export let itemsKeyname = 'items';
export let previousButtonLabel: string;
export let nextButtonLabel: string;
export let filterable = false;
export let filterInputLabel: string = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about making this ⬇️ instead?

Suggested change
export let filterInputLabel: string = undefined;
export let filterInputPlaceholder: string = undefined;

Copy link
Member

Choose a reason for hiding this comment

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

I could be talked into just using placeholder to keep it inline with HTML.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

<ApiPagination placeholder="whatever" /> doesn't make a ton of sense, cause it's not clear what the placeholder is for. I'll go with Laura's suggesiton.


let query = '';

let store: PaginationStore<T> = createPaginationStore(
pageSizeOptions,
Expand Down Expand Up @@ -157,6 +166,22 @@
break;
}
}

const handleFilter = async () => {
clearError();
store.reset();
store.setUpdating();
try {
const fetchItems = await onFetch();
const response = await fetchItems($store.pageSize, '', query);
const { nextPageToken } = response;
const items = response[itemsKeyname] || [];
store.nextPageWithItems(nextPageToken, items);
} catch (err) {
error = err;
if (onError) onError(error);
}
};
</script>

<svelte:window on:keydown={handleKeydown} />
Expand All @@ -175,11 +200,27 @@
<slot name="header" visibleItems={$store.visibleItems} />
<div class="relative mb-8 flex flex-col gap-4">
<div class="flex flex-col items-center justify-between gap-4 lg:flex-row">
<div class="flex items-center gap-1 lg:gap-2 xl:gap-3">
<slot name="action-top-left" visibleItems={$store.visibleItems} />
</div>
{#if $$slots['action-top-left']}
<div class="flex shrink-0 items-center gap-1 lg:gap-2 xl:gap-3">
<slot name="action-top-left" visibleItems={$store.visibleItems} />
</div>
{/if}
{#if filterable && filterInputLabel}
<Input
id="api-pagination-search-input"
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want a search icon here, similar to our other "search" inputs?

Suggested change
id="api-pagination-search-input"
icon="search"
id="api-pagination-search-input"

class="grow"
bind:value={query}
slot="action-top-left"
label={filterInputLabel}
labelHidden
placeholder={filterInputLabel}
on:input={debounce(handleFilter, 1000)}
on:clear={handleFilter}
clearable
/>
{/if}
<nav
class="flex flex-col justify-end gap-4 md:flex-row"
class="flex shrink-0 flex-col justify-end gap-4 md:flex-row"
aria-label="{$$restProps['aria-label']} 1"
>
<slot name="action-top-center" />
Expand Down
Loading