feat: view info submitted

for transparency, see the exact details that is sent automatically to the owner of the instance:
- job id
- convert from
- convert to
- ffmpeg stderr
- actual video file (if submitted)
This commit is contained in:
Maya 2025-10-18 20:57:52 +03:00
parent 91a061a2ef
commit e5ff309d83
No known key found for this signature in database
7 changed files with 170 additions and 38 deletions

View File

@ -85,6 +85,13 @@
"vertd_generic_yes": "Submit video",
"vertd_generic_no": "Don't submit",
"vertd_failed_to_keep": "Failed to keep the video on the server: {error}",
"vertd_details": "View error details",
"vertd_details_body": "If you submit your file, <b>your video will also be attached</b> alongside the error log being sent to us for review. The following information is the log that we automatically receive:",
"vertd_details_job_id": "<b>Job ID:</b> {jobId}",
"vertd_details_from": "<b>From format:</b> {from}",
"vertd_details_to": "<b>To format:</b> {to}",
"vertd_details_error_message": "<b>Error message:</b> [view_link]View error logs[/view_link]",
"vertd_details_close": "Close",
"unsupported_format": "Only image, video, audio, and document files are supported",
"vertd_not_found": "Could not find the vertd instance to start video conversion. Are you sure the instance URL is set correctly?",
"worker_downloading": "The {type} converter is currently being initialized, please wait a few moments.",

View File

@ -3,19 +3,13 @@
import { removeDialog } from "$lib/store/DialogProvider";
import { BanIcon, CheckIcon, InfoIcon, TriangleAlert } from "lucide-svelte";
import { quintOut } from "svelte/easing";
import type { Dialog as DialogType } from "$lib/store/DialogProvider";
type Props = {
id: number;
title: string;
message: string;
buttons: {
text: string;
action: () => void;
}[];
type: "success" | "error" | "info" | "warning";
};
type Props = DialogType;
let { id, title, message, buttons, type }: Props = $props();
let props: Props = $props();
const { id, title, message, buttons, type } = props;
const additional = "additional" in props ? props.additional : undefined;
const colors = {
success: "purple",
@ -59,7 +53,14 @@
</div>
</div>
<div class="flex flex-col gap-1 w-full">
<p class="text-sm font-normal text-muted">{message}</p>
{#if typeof message === "string"}
<p class="text-sm font-normal text-muted whitespace-pre-wrap">{message}</p>
{:else}
{@const MessageComponent = message}
<div class="text-sm font-normal text-muted">
<MessageComponent {id} {title} {type} {buttons} {additional} />
</div>
{/if}
</div>
<div class="flex flex-row items-center gap-4 w-full">
{#each buttons as { text, action }, i}

View File

@ -2,6 +2,10 @@
export interface VertdErrorProps {
jobId: string;
auth: string;
from?: string;
to?: string;
errorMessage?: string;
fileName?: string;
}
</script>
@ -10,6 +14,8 @@
import { m } from "$lib/paraglide/messages";
import { ToastManager, type ToastProps } from "$lib/toast/index.svelte";
import { addDialog } from "$lib/store/DialogProvider";
import VertdErrorDetails from "./VertdErrorDetails.svelte";
const toast: ToastProps<VertdErrorProps> = $props();
@ -52,22 +58,50 @@
ToastManager.remove(toast.id);
};
const showDetails = () => {
addDialog(
m["convert.errors.vertd_details"](),
VertdErrorDetails as any,
[
{
text: "Close",
action: () => {},
},
],
"info",
{
jobId: toast.additional.jobId || "Unknown",
from: toast.additional.from || "Unknown",
to: toast.additional.to || "Unknown",
errorMessage: toast.additional.errorMessage || "Unknown error",
},
);
};
</script>
<div class="flex flex-col gap-4">
<p class="text-black">{m["convert.errors.vertd_generic_body"]()}</p>
<div class="flex gap-4">
<div class="flex flex-col gap-2">
<button
onclick={submit}
class="btn rounded-lg h-fit py-2 w-full bg-accent-red-alt text-white"
onclick={showDetails}
class="btn rounded-lg h-fit py-2 w-full bg-accent-blue text-black"
disabled={submitting}
>{m["convert.errors.vertd_generic_yes"]()}</button
>
<button
onclick={remove}
class="btn rounded-lg h-fit py-2 w-full"
disabled={submitting}
>{m["convert.errors.vertd_generic_no"]()}</button
>View Details Submitted</button
>
<div class="flex gap-4">
<button
onclick={submit}
class="btn rounded-lg h-fit py-2 w-full bg-accent-red-alt text-white"
disabled={submitting}
>{m["convert.errors.vertd_generic_yes"]()}</button
>
<button
onclick={remove}
class="btn rounded-lg h-fit py-2 w-full"
disabled={submitting}
>{m["convert.errors.vertd_generic_no"]()}</button
>
</div>
</div>
</div>

View File

@ -0,0 +1,52 @@
<script lang="ts">
import { m } from "$lib/paraglide/messages";
import type { DialogProps } from "$lib/store/DialogProvider";
import { link } from "$lib/store/index.svelte";
interface VertdErrorDetailsProps {
jobId: string;
from: string;
to: string;
errorMessage: string;
}
type Props = DialogProps<VertdErrorDetailsProps>;
let { additional }: Props = $props();
</script>
<div class="flex flex-col gap-2">
<p>{@html m["convert.errors.vertd_details_body"]()}</p>
<p>
<span class="text-black dynadark:text-white">
{@html m["convert.errors.vertd_details_job_id"]({
jobId: additional.jobId,
})}
</span>
</p>
<p>
<span class="text-black dynadark:text-white">
{@html m["convert.errors.vertd_details_from"]({ from: additional.from })}
</span>
</p>
<p>
<span class="text-black dynadark:text-white">
{@html m["convert.errors.vertd_details_to"]({ to: additional.to })}
</span>
</p>
<p>
<span class="text-black dynadark:text-white">
{@html link(
["view_link"],
m["convert.errors.vertd_details_error_message"](),
[
URL.createObjectURL(
new Blob([additional.errorMessage], { type: "text/plain" })
)
],
[true],
["text-blue-500 font-normal hover:underline"]
)}
</span>
</p>
</div>

View File

@ -26,9 +26,9 @@
easing: quintOut,
}}
>
{#each dialogList as { id, title, message, buttons, type }, i}
{#each dialogList as dialog, i}
{#if i === 0}
<Dialog {id} {title} {message} {buttons} {type} />
<Dialog {...dialog} />
{/if}
{/each}
</div>

View File

@ -377,6 +377,9 @@ export class VertdConverter extends Converter {
additional: {
jobId: uploadRes.id,
auth: uploadRes.auth,
from: input.from,
to: to,
errorMessage: msg.data.message,
},
});
}

View File

@ -1,17 +1,39 @@
import type { Component } from "svelte";
import { writable } from "svelte/store";
type DialogType = "success" | "error" | "info" | "warning";
export interface Dialog {
type BaseDialog = {
id: number;
title: string;
message: string;
buttons: {
text: string;
action: () => void;
}[];
type: DialogType;
}
};
export type StringDialog = BaseDialog & {
message: string;
};
export type ComponentDialog<T = unknown> = BaseDialog & {
message: Component<DialogProps<T>>;
additional: T;
};
export type Dialog<T = unknown> = StringDialog | ComponentDialog<T>;
export type DialogProps<T = unknown> = {
id: number;
title: string;
type: DialogType;
buttons: {
text: string;
action: () => void;
}[];
additional: T;
};
const dialogs = writable<Dialog[]>([]);
@ -19,20 +41,33 @@ let dialogId = 0;
function addDialog(
title: string,
message: string,
buttons: Dialog["buttons"],
message: string | Component<DialogProps>,
buttons: BaseDialog["buttons"],
type: DialogType,
) {
additional?: unknown,
): number {
const id = dialogId++;
const newDialog: Dialog = {
id,
title,
message,
buttons,
type,
};
dialogs.update((currentDialogs) => [...currentDialogs, newDialog]);
if (typeof message === "string") {
const newDialog: StringDialog = {
id,
title,
message,
buttons,
type,
};
dialogs.update((currentDialogs) => [...currentDialogs, newDialog]);
} else {
const newDialog: ComponentDialog = {
id,
title,
message,
buttons,
type,
additional,
};
dialogs.update((currentDialogs) => [...currentDialogs, newDialog]);
}
return id;
}