Skip to content

Commit

Permalink
First pass add-on data loading
Browse files Browse the repository at this point in the history
  • Loading branch information
allanlasser committed Apr 4, 2024
1 parent dfb0083 commit f35e4e7
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 67 deletions.
8 changes: 4 additions & 4 deletions src/addons/browser/AddOnList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import ListItem from "./AddOnListItem.svelte";
import type { AddOnListItem } from "../types";
export let items: AddOnListItem[];
export let loading: boolean;
export let error: string | undefined;
export let reload: () => void | undefined;
export let items: AddOnListItem[] = [];
export let loading: boolean = false;
export let error: string | undefined = undefined;
export let reload: () => void | undefined = undefined;
$: empty = !(items && items.length > 0);
</script>
Expand Down
31 changes: 19 additions & 12 deletions src/lib/api/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,35 @@ import { BASE_API_URL } from "@/config/config.js";
import { type AddOnListItem } from "@/addons/types";
import { isErrorCode } from "../utils";
import type { Page } from "@/api/types/common";
import type { AddOnParams } from "@/api/types/addons";

export async function getPinnedAddons(
export const CATEGORIES = [
["export", "Export"],
["ai", "AI"],
["bulk", "Bulk"],
["extraction", "Extraction"],
["file", "File"],
["monitor", "Monitor"],
["statistical", "Statistical"],
];

export async function getAddons(
fetch = globalThis.fetch,
params: AddOnParams = {},
): Promise<Page<AddOnListItem>> {
const endpoint = new URL(
"/api/addons/?active=true&per_page=100",
BASE_API_URL,
);
const endpoint = new URL("/addons", BASE_API_URL);
Object.entries(params).forEach(([key, value]) => {
endpoint.searchParams.set(key, String(value));
});
const resp = await fetch(endpoint, { credentials: "include" });
if (isErrorCode(resp.status)) {
error(resp.status, resp.statusText);
}
return resp.json();
}

export async function getAddons(
export async function getPinnedAddons(
fetch = globalThis.fetch,
): Promise<Page<AddOnListItem>> {
const endpoint = new URL("/api/addons/?per_page=100", BASE_API_URL);
const resp = await fetch(endpoint, { credentials: "include" });
if (isErrorCode(resp.status)) {
error(resp.status, resp.statusText);
}
return resp.json();
return getAddons(fetch, { active: true });
}
89 changes: 38 additions & 51 deletions src/routes/app/add-ons/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { _ } from "svelte-i18n";
import { onMount } from "svelte";
import { Hourglass24 } from "svelte-octicons";
import { Hourglass24, Infinity16, Star16 } from "svelte-octicons";
import type { Page } from "@/api/types/common.js";
import type { AddOnListItem } from "$lib/api/types";
Expand All @@ -19,46 +19,19 @@
import MainLayout from "$lib/components/MainLayout.svelte";
import PageToolbar from "$lib/components/common/PageToolbar.svelte";
import Error from "@/lib/components/common/Error.svelte";
import SidebarItem from "@/lib/components/sidebar/SidebarItem.svelte";
import type { PageData } from "./$types";
import Premium from "@/common/icons/Premium.svelte";
let per_page = 10;
export let data: PageData;
$: urlParams = buildParams({
per_page,
query: $query,
filter: $filter,
});
$: url = buildUrl(urlParams);
$: next_url = res?.next ? new URL(res.next).toString() : null;
$: previous_url = res?.previous ? new URL(res.previous).toString() : null;
$: items = res?.results;
/** Network logic */
let loading = false;
let error = null;
let res: Page<AddOnListItem>;
export async function load(url) {
loading = true;
res = await fetch(url, {
credentials: "include",
})
.then(async (r) => {
const data = await r.json();
if (!r.ok) throw data;
return data;
})
.catch((err) => {
error = err;
loading = false;
return {};
});
loading = false;
function gotoPage(pageUrl: string) {
const { url } = data;
const cursor = new URL(pageUrl).searchParams.get("cursor");
if (!cursor) return;
url.searchParams.set("cursor", cursor);
goto(url);
}
onMount(() => load(url));
$: loadNext = () => load(next_url);
$: loadPrev = () => load(previous_url);
$: reload = () => load(url);
</script>

<MainLayout>
Expand All @@ -68,8 +41,22 @@
<p>{$_("addonBrowserDialog.subtitle")}</p>
</header>
<div class="filters">
<Filters />
<Categories />
<SidebarItem href="/app/add-ons">
<Infinity16 />
All
</SidebarItem>
<SidebarItem href="/app/add-ons?active=true">
<Pin />
Pinned
</SidebarItem>
<SidebarItem href="/app/add-ons?featured=true">
<Star16 />
Featured
</SidebarItem>
<SidebarItem href="/app/add-ons?premium=true">
<Premium />
Premium
</SidebarItem>
</div>
</svelte:fragment>

Expand All @@ -94,23 +81,23 @@
<p class="message">{$_("addonBrowserDialog.premiumTip")}</p>
</aside>
{/if}
{#if loading}
{#await data.addons}
<Empty icon={Hourglass24}>Loading…</Empty>
{:else if error}
<Error>{String(error)}</Error>
{:else}
{:then page}
<div class="list">
<AddOnList {loading} {items} {error} {reload} />
<AddOnList items={page.results} />
</div>
{/if}
{:catch error}
<Error>{String(error)}</Error>
{/await}

<PageToolbar slot="footer">
<svelte:fragment slot="center">
<Paginator
has_next={Boolean(next_url)}
has_previous={Boolean(previous_url)}
on:next={loadNext}
on:previous={loadPrev}
has_next={Boolean(data.next_url)}
has_previous={Boolean(data.previous_url)}
on:next={() => gotoPage(data.next_url)}
on:previous={() => gotoPage(data.previous_url)}
/>
</svelte:fragment>
</PageToolbar>
Expand Down
10 changes: 10 additions & 0 deletions src/routes/app/add-ons/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getAddons } from "@/lib/api/addons.js";

export async function load({ url, fetch }) {
const params = Object.fromEntries(url.searchParams.entries());
const addons = getAddons(fetch, params);
return {
url,
addons,
};
}

0 comments on commit f35e4e7

Please sign in to comment.