Skip to content

Commit

Permalink
Merge pull request #896 from MuckRock/allanlasser/issue838
Browse files Browse the repository at this point in the history
More comprehensive Toast notifications
  • Loading branch information
allanlasser authored Nov 26, 2024
2 parents 6bb6e0b + 0228c64 commit f4dd243
Show file tree
Hide file tree
Showing 23 changed files with 164 additions and 37 deletions.
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"storybook-mock-date-decorator": "^1.0.1",
"svelte-check": "^3.6.0",
"svelte-fast-dimension": "^1.1.0",
"sveltekit-flash-message": "^2.4.4",
"vite": "^5.4.11",
"vitest": "^v2.1.6"
},
Expand Down
8 changes: 7 additions & 1 deletion src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
interface PageData {
flash?: {
message: string;
status?: "info" | "warning" | "success" | "error";
lifespan?: number | null;
};
}
// interface PageState {}
// interface Platform {}
}
Expand Down
2 changes: 1 addition & 1 deletion src/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const PDF_SIZE_LIMIT_READABLE = "500 MB";
export const DOCUMENT_SIZE_LIMIT = 27262976;
export const DOCUMENT_SIZE_LIMIT_READABLE = "25 MB";

export const TOAST_LENGTH = 5000;
export const TOAST_LENGTH = 2500;
export const TOAST_FADE = 800;

export const LEGACY_CUT_OFF = 20000000;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export async function handleFetch({ event, request, fetch }) {
if (request.url.startsWith(DC_BASE)) {
// handle docker issues
event.url.protocol = "https";
request.headers.set("cookie", event.request.headers.get("cookie") ?? "");
request.headers.append("cookie", event.request.headers.get("cookie") ?? "");
}

return fetch(request);
Expand Down
14 changes: 10 additions & 4 deletions src/langs/json/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@
"uploading": "Uploading",
"processing": "Processing",
"done": "Done"
}
},
"success": "Upload complete. Your documents will process in the background.",
"error": "Error during upload. See upload list for more details."
},
"authSection": {
"help": {
Expand Down Expand Up @@ -407,7 +409,8 @@
"many": "Editing {n, plural, one {one document} other {# documents}}. This will add the same values to all selected documents.",
"allowedHTML": "Limited HTML can be used for formatting. See <a target=\"_blank\" href=\"/help/api\">API documentation</a> for details.",
"save": "Save",
"cancel": "Cancel"
"cancel": "Cancel",
"success": "Metadata saved"
},
"annotate": {
"title": "Annotate Document",
Expand All @@ -433,6 +436,7 @@
"undo": "Undo",
"cancel": "Discard",
"cancelWarning": "You will lose unsaved redactions. Are you sure you want to cancel?",
"success": "Redactions saved",
"error": "Error"
},
"sections": {
Expand All @@ -451,6 +455,7 @@
"continue": "Do you wish to continue?",
"confirm": "Delete",
"cancel": "Cancel",
"success": "{n, plural, one {Document deleted} other {Documents deleted}}",
"error": "Error",
"none": "No documents selected. Close this form and select at least one document first."
},
Expand Down Expand Up @@ -490,11 +495,12 @@
"viewsource": "View Source",
"selectionHelp": "Select individual documents or run a search for the documents you want, for example “+project:mueller-docs-200005”.",
"selectionLearnMore": "Learn more about how Add-Ons work",
"editing": "Editing a previously dispatched addon",
"editing": "Editing a previously dispatched Add-On",
"instructions": "Instructions",
"dispatch": "Dispatch",
"history": "History",
"noHistory": "You have not run this add-on before"
"noHistory": "You have not run this Add-On before",
"success": "Add-On dispatched"
},
"addonBrowserDialog": {
"title": "Browse Add-Ons",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/common/Toast.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
on:mouseenter={cancel}
on:mouseleave={reset}
role="dialog"
transition:fly={{ duration: 750, easing: quintOut, y: 20 }}
transition:fly={{ duration: 750, easing: quintOut, y: -20 }}
>
<div class="icon">
<svelte:component this={statusIcons[String(status)]} />
Expand Down
9 changes: 8 additions & 1 deletion src/lib/components/forms/DocumentUpload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ progress through the three-part upload process.
import { getCsrfToken } from "$lib/utils/api";
import { getCurrentUser } from "$lib/utils/permissions";
import { getProcessLoader } from "../processing/ProcessContext.svelte";
import { toast } from "../layouts/Toaster.svelte";
export let files: File[] = getFilesToUpload();
export let projects: Project[] = [];
Expand Down Expand Up @@ -202,6 +203,7 @@ progress through the three-part upload process.
// errors are handled within each promise, so we can just wait for all to be settled
await Promise.allSettled(promises);
toast($_("uploadDialog.success"), { status: "success" });
loading = false;
}
Expand All @@ -228,6 +230,7 @@ progress through the three-part upload process.
// bail here on error, console.error to report this to sentry
if (error) {
toast($_("uploadDialog.error"), { status: "error" });
return console.error(error);
}
Expand All @@ -239,7 +242,7 @@ progress through the three-part upload process.
message: "API returned invalid document. Please try again.",
},
};
toast($_("uploadDialog.error"), { status: "error" });
return;
}
Expand All @@ -255,6 +258,7 @@ progress through the three-part upload process.
};
STATUS[id].error = error;
toast($_("uploadDialog.error"), { status: "error" });
return console.error(error);
}
Expand All @@ -263,6 +267,7 @@ progress through the three-part upload process.
status: 500,
message: "Invalid presigned URL",
};
toast($_("uploadDialog.error"), { status: "error" });
return;
}
Expand All @@ -276,6 +281,7 @@ progress through the three-part upload process.
status: 500,
message: "Upload failed",
};
toast($_("uploadDialog.error"), { status: "error" });
return;
}
Expand All @@ -289,6 +295,7 @@ progress through the three-part upload process.
));
if (error) {
toast($_("uploadDialog.error"), { status: "error" });
STATUS[id].error = error;
}
// trigger process load request
Expand Down
5 changes: 5 additions & 0 deletions src/lib/components/forms/EditData.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import KeyValue from "$lib/components/inputs/KeyValue.svelte";
import { canonicalUrl } from "$lib/api/documents";
import { toast } from "../layouts/Toaster.svelte";
export let document: Document;
Expand Down Expand Up @@ -53,6 +54,10 @@
// `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
dispatch("close");
update(result);
if (result.type === "success") {
// do something
toast($_("edit.success"), { status: "success" });
}
};
}
</script>
Expand Down
5 changes: 0 additions & 5 deletions src/lib/components/forms/UserFeedback.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import Button from "../common/Button.svelte";
import Flex from "../common/Flex.svelte";
import Avatar from "../accounts/Avatar.svelte";
import { toast } from "../layouts/Toaster.svelte";
import { APP_URL } from "@/config/config";
import { getUserName } from "$lib/api/accounts";
Expand Down Expand Up @@ -54,13 +53,9 @@
return async ({ result }) => {
if (result.type === "success") {
status = "success";
toast($_("feedback.success"), {
status: "success",
});
dispatch("close");
} else if (result.type === "failure") {
status = "error";
toast(result.error, { status: "error" });
}
};
}
Expand Down
5 changes: 0 additions & 5 deletions src/lib/components/forms/stories/UserFeedback.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import UserFeedbackForm from "../UserFeedback.svelte";
import { me } from "@/test/fixtures/accounts";
import { feedback } from "@/test/handlers/feedback";
import Toaster from "../../layouts/Toaster.svelte";
export const meta = {
title: "Forms / User Feedback",
Expand All @@ -20,27 +19,23 @@
<Story name="With User">
<div style="max-width: 45rem;">
<UserFeedbackForm user={me} />
<Toaster />
</div>
</Story>

<Story name="Without User">
<div style="max-width: 45rem;">
<UserFeedbackForm />
<Toaster />
</div>
</Story>

<Story name="Loading" parameters={{ msw: { handlers: [feedback.loading] } }}>
<div style="max-width: 45rem;">
<UserFeedbackForm />
<Toaster />
</div>
</Story>

<Story name="With Error" parameters={{ msw: { handlers: [feedback.error] } }}>
<div style="max-width: 45rem;">
<UserFeedbackForm />
<Toaster />
</div>
</Story>
13 changes: 7 additions & 6 deletions src/lib/components/layouts/Toaster.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts" context="module">
import type { ComponentType, SvelteComponent } from "svelte";
import type { ComponentType } from "svelte";
import { writable } from "svelte/store";
type ToastContents = string | ComponentType;
interface ToastOptions<P = any> {
status?: "info" | "success" | "warning" | "error";
lifespan?: number;
lifespan?: number | null;
props?: P;
}
Expand Down Expand Up @@ -49,7 +49,7 @@
}}
>
{#if typeof toast.contents === "string"}
{@html toast.contents}
{toast.contents}
{:else}
<svelte:component this={toast.contents} {...toast.props} />
{/if}
Expand All @@ -61,12 +61,13 @@
<style>
#toaster {
position: fixed;
bottom: 2.5rem;
right: 0;
top: 1rem;
right: 50%;
transform: translateX(50%);
z-index: var(--z-toast);
margin: 0.5rem;
display: flex;
flex-direction: column-reverse;
flex-direction: column;
gap: 0.5rem;
max-width: 48rem;
min-width: 24rem;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/layouts/stories/Toaster.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
>
<Button
on:click={() =>
toast("I won't go away on my own", { status: "info", lifespan: 0 })}
toast("I won't go away on my own", { status: "info", lifespan: null })}
>
Permanent Toast
</Button>
Expand Down
3 changes: 1 addition & 2 deletions src/lib/components/sidebar/DocumentActions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ Most actual actions are deferred to their own forms, so this is more of a switch
import Modal from "../layouts/Modal.svelte";
import Portal from "../layouts/Portal.svelte";
import SidebarItem from "./SidebarItem.svelte";
// forms
import ConfirmDelete from "../forms/ConfirmDelete.svelte";
Expand Down Expand Up @@ -92,7 +91,7 @@ Most actual actions are deferred to their own forms, so this is more of a switch
{#if visible}
<Portal>
<Modal on:close={close}>
<h1 slot="title">{actions[visible][0]}</h1>
<h1 slot="title">{$_(actions[visible][0])}</h1>

{#if visible === "share"}
<Share document={toShare} />
Expand Down
11 changes: 10 additions & 1 deletion src/routes/(app)/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { _ } from "svelte-i18n";
import { createFeedback, type Feedback } from "@/lib/api/feedback";
import type { Actions } from "./$types";
import { fail } from "@sveltejs/kit";
import { setFlash } from "sveltekit-flash-message/server";

export const actions = {
feedback: async ({ request, fetch }) => {
feedback: async ({ request, cookies, fetch }) => {
const data = await request.formData();
// POST form data to baserow
const feedback: Feedback = {
Expand All @@ -14,8 +15,16 @@ export const actions = {
};
try {
await createFeedback(feedback, fetch);
setFlash(
{
message: "Feedback recieved, thanks for using DocumentCloud!",
status: "success",
},
cookies,
);
return { success: true };
} catch (e) {
setFlash({ message: e.message, status: "error" }, cookies);
fail(500, { message: String(e) });
}
},
Expand Down
4 changes: 4 additions & 0 deletions src/routes/(app)/add-ons/[owner]/[repo]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fail } from "@sveltejs/kit";
import { CSRF_COOKIE_NAME } from "@/config/config.js";

import { getAddon, buildPayload, dispatch } from "$lib/api/addons";
import { setFlash } from "sveltekit-flash-message/server";

export const actions = {
async dispatch({ cookies, fetch, request, params }) {
Expand Down Expand Up @@ -33,10 +34,13 @@ export const actions = {
const { data, error } = await dispatch(payload, csrf_token, fetch);

if (error) {
setFlash({ message: error.message, status: "error" }, cookies);
return fail(error.status, { ...error });
}

const type = payload.event ? "event" : "run";
const message = payload.event ? "Event scheduled" : "Run dispatched";
setFlash({ message, status: "success" }, cookies);
return {
type,
[type]: data,
Expand Down
Loading

0 comments on commit f4dd243

Please sign in to comment.