Skip to content

Commit

Permalink
Merge pull request #880 from MuckRock/829-infinite-scroll-errors
Browse files Browse the repository at this point in the history
Use getApiResponse on infinite scrolls, too
  • Loading branch information
eyeseast authored Nov 25, 2024
2 parents f832f88 + 31f55fb commit 112b4cd
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 43 deletions.
4 changes: 3 additions & 1 deletion src/langs/json/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@
"pageAbbrev": "p.",
"pageCount": "{n, plural, one {# page} other {# pages}}",
"select": "Select",
"noteCount": "{n, plural, one {# note} other {# notes}}"
"noteCount": "{n, plural, one {# note} other {# notes}}",
"more": "Load more",
"retry": "Please try again."
},
"error": {
"report": "Report a problem"
Expand Down
35 changes: 22 additions & 13 deletions src/lib/components/addons/History.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,46 @@
import type { Run } from "$lib/api/types";
import { _ } from "svelte-i18n";
import { History16, History24, Hourglass24 } from "svelte-octicons";
import { Alert24, History16, History24, Hourglass24 } from "svelte-octicons";
import HistoryEvent from "./HistoryEvent.svelte";
import Paginator from "$lib/components/common/Paginator.svelte";
import SidebarGroup from "../sidebar/SidebarGroup.svelte";
import SidebarItem from "../sidebar/SidebarItem.svelte";
import Empty from "../common/Empty.svelte";
import { getApiResponse } from "$lib/utils/api";
export let runs: Run[];
export let previous: Maybe<Nullable<string>> = undefined;
export let next: Maybe<Nullable<string>> = undefined;
export let loading = false;
let error: string = "";
$: empty = runs.length === 0;
// load the next set of results
async function load(url: URL) {
loading = true;
// todo: better error handling
const res = await fetch(url, { credentials: "include" }).catch(
const resp = await fetch(url, { credentials: "include" }).catch(
console.error,
);
if (!res) return console.error("API error");
if (!res.ok) {
console.error(res.statusText);
loading = false;
const { data: results, error: err } = await getApiResponse<Page<Run>>(resp);
if (err) {
error = err.message;
}
const results: Page<Run> = await res.json();
if (results) {
runs = results.results;
next = results.next;
previous = results.previous;
}
runs = results.results;
next = results.next;
previous = results.previous;
loading = false;
}
</script>
Expand All @@ -50,6 +55,10 @@

{#if loading}
<Empty icon={Hourglass24}>Loading past runs…</Empty>
{:else if error}
<Empty icon={Alert24}>
{error}
</Empty>
{:else}
{#each runs as run}
<HistoryEvent {run} />
Expand All @@ -62,10 +71,10 @@
<Paginator
has_next={Boolean(next)}
has_previous={Boolean(previous)}
on:next={(e) => {
on:next={() => {
if (next) load(new URL(next));
}}
on:previous={(e) => {
on:previous={() => {
if (previous) load(new URL(previous));
}}
/>
Expand Down
36 changes: 23 additions & 13 deletions src/lib/components/addons/Scheduled.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,45 @@
import type { Maybe, Nullable, Page, Event } from "$lib/api/types";
import { _ } from "svelte-i18n";
import { Clock16, Hourglass24 } from "svelte-octicons";
import { Alert24, Clock16, Hourglass24 } from "svelte-octicons";
import ScheduledEvent from "./ScheduledEvent.svelte";
import SidebarGroup from "../sidebar/SidebarGroup.svelte";
import SidebarItem from "../sidebar/SidebarItem.svelte";
import Paginator from "$lib/components/common/Paginator.svelte";
import Empty from "../common/Empty.svelte";
import { getApiResponse } from "$lib/utils/api";
export let events: Event[];
export let previous: Maybe<Nullable<string>> = undefined;
export let next: Maybe<Nullable<string>> = undefined;
export let loading = false;
let error: string = "";
// load the next set of results
async function load(url: URL) {
loading = true;
// todo: better error handling
const res = await fetch(url, { credentials: "include" }).catch(
const resp = await fetch(url, { credentials: "include" }).catch(
console.error,
);
if (!res) return console.error("API error");
if (!res.ok) {
console.error(res.statusText);
loading = false;
const { data: results, error: err } =
await getApiResponse<Page<Event>>(resp);
if (err) {
error = err.message;
}
const results: Page<Event> = await res.json();
if (results) {
events = results.results;
next = results.next;
previous = results.previous;
}
events = results.results;
next = results.next;
previous = results.previous;
loading = false;
}
</script>
Expand All @@ -47,6 +53,10 @@

{#if loading}
<Empty icon={Hourglass24}>{$_("common.loading")}</Empty>
{:else if error}
<Empty icon={Alert24}>
{error}
</Empty>
{:else}
{#each events as event}
<ScheduledEvent {event} />
Expand All @@ -61,12 +71,12 @@
<Paginator
has_next={Boolean(next)}
has_previous={Boolean(previous)}
on:next={(e) => {
on:next={() => {
if (next) {
load(new URL(next));
}
}}
on:previous={(e) => {
on:previous={() => {
if (previous) {
load(new URL(previous));
}
Expand Down
46 changes: 31 additions & 15 deletions src/lib/components/documents/ResultsList.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script context="module" lang="ts">
import type { Document, DocumentResults, Maybe } from "$lib/api/types";
import {
derived,
writable,
type Readable,
type Writable,
} from "svelte/store";
import type { Document, DocumentResults, Maybe } from "$lib/api/types";
// IDs might be strings or numbers, depending on the API endpoint
// enforce type consistency here to avoid comparison bugs later
Expand All @@ -32,6 +32,8 @@
import NoteHighlights from "./NoteHighlights.svelte";
import PageHighlights from "./PageHighlights.svelte";
import { getApiResponse } from "$lib/utils/api";
export let results: Document[] = [];
export let count: Maybe<number> = undefined;
export let next: string | null = null;
Expand All @@ -41,6 +43,7 @@
let loading = false;
let end: HTMLElement;
let observer: IntersectionObserver;
let error: string = "";
const embed: boolean = getContext("embed");
Expand All @@ -50,24 +53,25 @@
// load the next set of results
async function load(url: URL) {
loading = true;
const res = await fetch(url, { credentials: "include" }).catch(
const resp = await fetch(url, { credentials: "include" }).catch(
console.error,
);
// todo: better error handling
if (!res) return console.error("API error");
if (!res.ok) {
console.error(res.statusText);
loading = false;
const { data, error: err } = await getApiResponse<DocumentResults>(resp);
if (err) {
// show an error message, but let the user try loading more
error = err.message;
}
const r: DocumentResults = await res.json();
if (data) {
results = [...results, ...data.results];
$total = data.count ?? $total;
next = data.next;
if (auto) watch(end);
}
results = [...results, ...r.results];
$total = r.count ?? $total;
next = r.next;
loading = false;
if (auto) watch(end);
}
function watch(el: HTMLElement) {
Expand Down Expand Up @@ -145,12 +149,17 @@
}}
>
{#if loading}
Loading &hellip;
{$_("common.loading")}
{:else}
Load more
{$_("documents.more")}
{/if}
</Button>
{/if}

{#if error}
<p class="error">{error}</p>
<p class="error">{$_("documents.retry")}</p>
{/if}
</div>

<slot name="end" />
Expand All @@ -177,6 +186,13 @@
.end {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.error {
text-align: center;
color: var(--error, red);
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import Unverified from "../../accounts/Unverified.svelte";
import { me } from "@/test/fixtures/accounts";
import { documents as mock } from "@/test/handlers/documents";
// typescript complains without the type assertion
import searchResults from "@/test/fixtures/documents/search-highlight.json";
Expand All @@ -24,7 +25,6 @@
export const meta = {
title: "Components / Documents / Results list",
component: ResultsList,
tags: ["autodocs"],
};
const user = { ...me, verified_journalist: false };
Expand Down Expand Up @@ -57,3 +57,7 @@
<Unverified {user} slot="start" />
</ResultsList>
</Story>

<Story name="Loading error" parameters={{ msw: { handlers: [mock.error] } }}>
<ResultsList {results} {count} {next} auto />
</Story>
4 changes: 4 additions & 0 deletions src/test/handlers/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export const documents = {
new URL("documents/pending/", BASE_API_URL).href,
(req, res, ctx) => res(ctx.json(pending)),
),
error: rest.get(
new URL("documents/search/", "https://api.www.documentcloud.org/api/").href,
(req, res, ctx) => res(ctx.status(500, "Something went wrong")),
),
};

export const revisionControl = {
Expand Down

0 comments on commit 112b4cd

Please sign in to comment.