added search to links page

pull/3/head
TZGyn 2 years ago
parent 6ad56232bc
commit 5ab9b27d85
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -1,5 +1,5 @@
import { db } from '$lib/db' import { db } from '$lib/db'
import { and, count, eq } from 'drizzle-orm' import { and, count, eq, ilike } from 'drizzle-orm'
import { shortener } from '$lib/db/schema' import { shortener } from '$lib/db/schema'
import type { PageServerLoad } from './$types' import type { PageServerLoad } from './$types'
@ -7,6 +7,7 @@ export const load = (async (event) => {
const user = event.locals.userObject const user = event.locals.userObject
const project_uuid = event.url.searchParams.get('project') const project_uuid = event.url.searchParams.get('project')
const search = event.url.searchParams.get('search')
let page = parseInt(event.url.searchParams.get('page') ?? '1') let page = parseInt(event.url.searchParams.get('page') ?? '1')
let perPage = parseInt( let perPage = parseInt(
event.url.searchParams.get('perPage') ?? '10', event.url.searchParams.get('perPage') ?? '10',
@ -47,22 +48,28 @@ export const load = (async (event) => {
project: true, project: true,
}, },
orderBy: (shortener, { desc }) => [desc(shortener.createdAt)], orderBy: (shortener, { desc }) => [desc(shortener.createdAt)],
where: (shortener, { eq, and, isNull }) => where: (shortener, { eq, and, ilike }) =>
and( and(
eq(shortener.userId, user.id), eq(shortener.userId, user.id),
project_id ? eq(shortener.projectId, project_id) : undefined, project_id ? eq(shortener.projectId, project_id) : undefined,
search
? ilike(shortener.link, `%${decodeURI(search)}%`)
: undefined,
), ),
offset: perPage * (page - 1), offset: perPage * (page - 1),
limit: perPage, limit: perPage,
}) })
const pagination = await db const pagination = db
.select({ count: count() }) .select({ count: count() })
.from(shortener) .from(shortener)
.where( .where(
and( and(
eq(shortener.userId, user.id), eq(shortener.userId, user.id),
project_id ? eq(shortener.projectId, project_id) : undefined, project_id ? eq(shortener.projectId, project_id) : undefined,
search
? ilike(shortener.link, `%${decodeURI(search)}%`)
: undefined,
), ),
) )
@ -81,6 +88,7 @@ export const load = (async (event) => {
settings, settings,
page, page,
perPage, perPage,
pagination: pagination[0], search,
pagination,
} }
}) satisfies PageServerLoad }) satisfies PageServerLoad

@ -1,5 +1,9 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types' import type { PageData } from './$types'
import { cn } from '$lib/utils'
import { goto } from '$app/navigation'
import { browser } from '$app/environment'
import { Button } from '$lib/components/ui/button' import { Button } from '$lib/components/ui/button'
import * as Dialog from '$lib/components/ui/dialog' import * as Dialog from '$lib/components/ui/dialog'
import * as Card from '$lib/components/ui/card' import * as Card from '$lib/components/ui/card'
@ -9,6 +13,10 @@
import * as Popover from '$lib/components/ui/popover' import * as Popover from '$lib/components/ui/popover'
import { Badge } from '$lib/components/ui/badge' import { Badge } from '$lib/components/ui/badge'
import * as Pagination from '$lib/components/ui/pagination' import * as Pagination from '$lib/components/ui/pagination'
import { Input } from '$lib/components/ui/input'
import ScrollArea from '$lib/components/ui/scroll-area/scroll-area.svelte'
import { Skeleton } from '$lib/components/ui/skeleton'
import { import {
BarChart, BarChart,
ExternalLink, ExternalLink,
@ -17,15 +25,12 @@
Check, Check,
ChevronsUpDown, ChevronsUpDown,
} from 'lucide-svelte' } from 'lucide-svelte'
import { cn } from '$lib/utils'
import Qr from '$lib/components/QR.svelte' import Qr from '$lib/components/QR.svelte'
import AddShortenerDialog from './(component)/AddShortenerDialog.svelte' import AddShortenerDialog from './(component)/AddShortenerDialog.svelte'
import ScrollArea from '$lib/components/ui/scroll-area/scroll-area.svelte'
import { Skeleton } from '$lib/components/ui/skeleton'
import EditShortenerDialog from './(component)/EditShortenerDialog.svelte' import EditShortenerDialog from './(component)/EditShortenerDialog.svelte'
import DeleteShortenerDialog from './(component)/DeleteShortenerDialog.svelte' import DeleteShortenerDialog from './(component)/DeleteShortenerDialog.svelte'
import { goto } from '$app/navigation' import { onMount } from 'svelte'
import { browser } from '$app/environment'
export let data: PageData export let data: PageData
@ -78,21 +83,26 @@
let page: number = data.page let page: number = data.page
let perPage: any = { label: data.perPage, value: data.perPage } let perPage: any = { label: data.perPage, value: data.perPage }
let selectedProjectUUID: string | null let selectedProjectUUID: string | null
let search: string | null = data.search
let searchUpdateTimeout: any
$: browser && updateUrl(selectedProjectUUID, page, perPage) $: browser && updateUrl(selectedProjectUUID, page, perPage, search)
const updateUrl = ( const updateUrl = (
selectedProjectUUID: string | null, selectedProjectUUID: string | null,
page: number, page: number,
perPage: any, perPage: any,
search: string | null,
) => { ) => {
let query = [`page=${page}`, `perPage=${perPage.value}`]
if (selectedProjectUUID) { if (selectedProjectUUID) {
goto( query.push(`project=${selectedProjectUUID}`)
`/links?project=${selectedProjectUUID}&page=${page}&perPage=${perPage.value}`, }
) if (search) {
} else { query.push(`search=${encodeURI(search)}`)
goto(`/links?page=${page}&perPage=${perPage.value}`)
} }
goto(`/links?${query.join('&')}`)
} }
</script> </script>
@ -152,6 +162,20 @@
</Command.Root> </Command.Root>
</Popover.Content> </Popover.Content>
</Popover.Root> </Popover.Root>
<Input
type="text"
placeholder="search"
class="max-w-[250px]"
value={search}
on:keyup={({ target, key }) => {
if (key !== 'Enter') return
clearTimeout(searchUpdateTimeout)
searchUpdateTimeout = setTimeout(() => {
search = target.value
}, 500)
}} />
<Button disabled={!search} on:click={() => (search = '')}
>Clear</Button>
<AddShortenerDialog bind:dialogOpen projects={data.projects} /> <AddShortenerDialog bind:dialogOpen projects={data.projects} />
</div> </div>
@ -258,55 +282,6 @@
{/each} {/each}
</div> </div>
</ScrollArea> </ScrollArea>
<div class="flex items-center justify-between border-t p-4">
<Select.Root bind:selected={perPage}>
<Select.Trigger class="w-[180px]">
<Select.Value placeholder="Page Size" />
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Page Size</Select.Label>
{#each [10, 20, 50, 100] as pageSize}
<Select.Item
value={pageSize}
label={pageSize.toString()}>{pageSize}</Select.Item>
{/each}
</Select.Group>
</Select.Content>
<Select.Input name="favoriteFruit" />
</Select.Root>
<Pagination.Root
class="items-end "
count={data.pagination.count}
bind:page
perPage={perPage.value}
let:pages
let:currentPage>
<Pagination.Content>
<Pagination.Item>
<Pagination.PrevButton />
</Pagination.Item>
{#each pages as page (page.key)}
{#if page.type === 'ellipsis'}
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
{:else}
<Pagination.Item isVisible={currentPage == page.value}>
<Pagination.Link
{page}
isActive={currentPage == page.value}>
{page.value}
</Pagination.Link>
</Pagination.Item>
{/if}
{/each}
<Pagination.Item>
<Pagination.NextButton />
</Pagination.Item>
</Pagination.Content>
</Pagination.Root>
</div>
{:else} {:else}
<div class="flex h-full w-full items-center justify-center"> <div class="flex h-full w-full items-center justify-center">
<div class="flex flex-col items-center gap-12"> <div class="flex flex-col items-center gap-12">
@ -323,6 +298,59 @@
{/if} {/if}
{/await} {/await}
{#await data.pagination}
<!-- promise is pending -->
{:then pagination}
<div class="flex items-center justify-between border-t p-4">
<Select.Root bind:selected={perPage}>
<Select.Trigger class="w-[180px]">
<Select.Value placeholder="Page Size" />
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Page Size</Select.Label>
{#each [10, 20, 50, 100] as pageSize}
<Select.Item value={pageSize} label={pageSize.toString()}
>{pageSize}</Select.Item>
{/each}
</Select.Group>
</Select.Content>
<Select.Input name="favoriteFruit" />
</Select.Root>
<Pagination.Root
class="items-end "
count={pagination[0].count}
bind:page
perPage={perPage.value}
let:pages
let:currentPage>
<Pagination.Content>
<Pagination.Item>
<Pagination.PrevButton />
</Pagination.Item>
{#each pages as page (page.key)}
{#if page.type === 'ellipsis'}
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
{:else}
<Pagination.Item isVisible={currentPage == page.value}>
<Pagination.Link
{page}
isActive={currentPage == page.value}>
{page.value}
</Pagination.Link>
</Pagination.Item>
{/if}
{/each}
<Pagination.Item>
<Pagination.NextButton />
</Pagination.Item>
</Pagination.Content>
</Pagination.Root>
</div>
{/await}
<EditShortenerDialog <EditShortenerDialog
projects={data.projects} projects={data.projects}
bind:editDialogOpen bind:editDialogOpen

Loading…
Cancel
Save