diff --git a/package-lock.json b/package-lock.json index ccb571793..0a6bd5891 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,6 +70,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" } @@ -24672,6 +24673,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/sveltekit-flash-message": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/sveltekit-flash-message/-/sveltekit-flash-message-2.4.4.tgz", + "integrity": "sha512-CFN03chH/FMEJcBZ/8zKm7RqGee/pwb57Spbbx8QCQPhe7N9ofZHd9iYV2vVy4E9glBo/oQ1IG7VQje6L092wg==", + "dev": true, + "peerDependencies": { + "@sveltejs/kit": "1.x || 2.x", + "svelte": "3.x || 4.x || >=5.0.0-next.51" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index c551b81b4..9111b3ee7 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/app.d.ts b/src/app.d.ts index a6cb12cf6..df09b3362 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -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 {} } diff --git a/src/config/config.js b/src/config/config.js index 3b4222aa2..3bde91587 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -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; diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 1ed6a4643..a56eae4a1 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -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); diff --git a/src/langs/json/en.json b/src/langs/json/en.json index 3db79b66e..117a32423 100644 --- a/src/langs/json/en.json +++ b/src/langs/json/en.json @@ -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": { @@ -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 API documentation for details.", "save": "Save", - "cancel": "Cancel" + "cancel": "Cancel", + "success": "Metadata saved" }, "annotate": { "title": "Annotate Document", @@ -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": { @@ -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." }, @@ -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", diff --git a/src/lib/components/common/Toast.svelte b/src/lib/components/common/Toast.svelte index 6ec44ea76..9b5d8e711 100644 --- a/src/lib/components/common/Toast.svelte +++ b/src/lib/components/common/Toast.svelte @@ -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 }} >
diff --git a/src/lib/components/forms/DocumentUpload.svelte b/src/lib/components/forms/DocumentUpload.svelte index 0e9c52422..e11a55e4b 100644 --- a/src/lib/components/forms/DocumentUpload.svelte +++ b/src/lib/components/forms/DocumentUpload.svelte @@ -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[] = []; @@ -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; } @@ -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); } @@ -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; } @@ -255,6 +258,7 @@ progress through the three-part upload process. }; STATUS[id].error = error; + toast($_("uploadDialog.error"), { status: "error" }); return console.error(error); } @@ -263,6 +267,7 @@ progress through the three-part upload process. status: 500, message: "Invalid presigned URL", }; + toast($_("uploadDialog.error"), { status: "error" }); return; } @@ -276,6 +281,7 @@ progress through the three-part upload process. status: 500, message: "Upload failed", }; + toast($_("uploadDialog.error"), { status: "error" }); return; } @@ -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 diff --git a/src/lib/components/forms/EditData.svelte b/src/lib/components/forms/EditData.svelte index 578fc72d6..cc40df73c 100644 --- a/src/lib/components/forms/EditData.svelte +++ b/src/lib/components/forms/EditData.svelte @@ -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; @@ -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" }); + } }; } diff --git a/src/lib/components/forms/UserFeedback.svelte b/src/lib/components/forms/UserFeedback.svelte index a87f1a293..6912d3886 100644 --- a/src/lib/components/forms/UserFeedback.svelte +++ b/src/lib/components/forms/UserFeedback.svelte @@ -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"; @@ -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" }); } }; } diff --git a/src/lib/components/forms/stories/UserFeedback.stories.svelte b/src/lib/components/forms/stories/UserFeedback.stories.svelte index c91f94ef4..4606896a6 100644 --- a/src/lib/components/forms/stories/UserFeedback.stories.svelte +++ b/src/lib/components/forms/stories/UserFeedback.stories.svelte @@ -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", @@ -20,27 +19,23 @@
-
-
-
-
diff --git a/src/lib/components/layouts/Toaster.svelte b/src/lib/components/layouts/Toaster.svelte index 0dca92089..0bd2a88f2 100644 --- a/src/lib/components/layouts/Toaster.svelte +++ b/src/lib/components/layouts/Toaster.svelte @@ -1,12 +1,12 @@