mirror of
https://github.com/wukko/cobalt.git
synced 2025-05-01 14:44:28 +02:00
web/ProcessingQueueItem: refactor, retry action, rtl optimization
also: - added a spinner to "running" state - moved steps counter to the starting state, aka when the worker is loading in
This commit is contained in:
parent
6a4de1be28
commit
4a1780ab7f
@ -5,7 +5,12 @@
|
|||||||
"stub.remux": "remuxing",
|
"stub.remux": "remuxing",
|
||||||
|
|
||||||
"state.waiting": "queued",
|
"state.waiting": "queued",
|
||||||
"state.starting": "starting...",
|
"state.retrying": "retrying",
|
||||||
|
|
||||||
|
"state.starting": "starting",
|
||||||
|
"state.starting.fetch": "starting downloading",
|
||||||
|
"state.starting.remux": "starting muxing",
|
||||||
|
|
||||||
"state.running.remux": "remuxing",
|
"state.running.remux": "remuxing",
|
||||||
"state.running.fetch": "downloading",
|
"state.running.fetch": "downloading",
|
||||||
"estimated_storage_usage": "estimated storage usage:"
|
"estimated_storage_usage": "estimated storage usage:"
|
||||||
|
@ -3,14 +3,18 @@
|
|||||||
import { formatFileSize } from "$lib/util";
|
import { formatFileSize } from "$lib/util";
|
||||||
import { downloadFile } from "$lib/download";
|
import { downloadFile } from "$lib/download";
|
||||||
import { removeItem } from "$lib/state/queen-bee/queue";
|
import { removeItem } from "$lib/state/queen-bee/queue";
|
||||||
|
import { savingHandler } from "$lib/api/saving-handler";
|
||||||
|
|
||||||
import type { CobaltQueueItem } from "$lib/types/queue";
|
import type { CobaltQueueItem } from "$lib/types/queue";
|
||||||
|
import type { CobaltWorkerProgress } from "$lib/types/workers";
|
||||||
import type { CobaltCurrentTaskItem } from "$lib/types/queen-bee";
|
import type { CobaltCurrentTaskItem } from "$lib/types/queen-bee";
|
||||||
|
|
||||||
import ProgressBar from "$components/queue/ProgressBar.svelte";
|
import ProgressBar from "$components/queue/ProgressBar.svelte";
|
||||||
|
|
||||||
import IconX from "@tabler/icons-svelte/IconX.svelte";
|
import IconX from "@tabler/icons-svelte/IconX.svelte";
|
||||||
import IconCheck from "@tabler/icons-svelte/IconCheck.svelte";
|
import IconCheck from "@tabler/icons-svelte/IconCheck.svelte";
|
||||||
|
import IconReload from "@tabler/icons-svelte/IconReload.svelte";
|
||||||
|
import IconLoader2 from "@tabler/icons-svelte/IconLoader2.svelte";
|
||||||
import IconDownload from "@tabler/icons-svelte/IconDownload.svelte";
|
import IconDownload from "@tabler/icons-svelte/IconDownload.svelte";
|
||||||
import IconExclamationCircle from "@tabler/icons-svelte/IconExclamationCircle.svelte";
|
import IconExclamationCircle from "@tabler/icons-svelte/IconExclamationCircle.svelte";
|
||||||
|
|
||||||
@ -29,8 +33,17 @@
|
|||||||
export let runningWorker: CobaltCurrentTaskItem | undefined;
|
export let runningWorker: CobaltCurrentTaskItem | undefined;
|
||||||
export let runningWorkerId: string | undefined;
|
export let runningWorkerId: string | undefined;
|
||||||
|
|
||||||
$: progress = runningWorker?.progress;
|
let retrying = false;
|
||||||
$: size = formatFileSize(runningWorker?.progress?.size);
|
|
||||||
|
const retry = async (info: CobaltQueueItem) => {
|
||||||
|
if (info.canRetry && info.originalRequest) {
|
||||||
|
retrying = true;
|
||||||
|
await savingHandler({
|
||||||
|
request: info.originalRequest,
|
||||||
|
});
|
||||||
|
retrying = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const download = (file: File) =>
|
const download = (file: File) =>
|
||||||
downloadFile({
|
downloadFile({
|
||||||
@ -38,6 +51,64 @@
|
|||||||
type: info.mimeType,
|
type: info.mimeType,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: progress = runningWorker?.progress;
|
||||||
|
$: size = formatFileSize(runningWorker?.progress?.size);
|
||||||
|
|
||||||
|
type StatusText = {
|
||||||
|
info: CobaltQueueItem;
|
||||||
|
runningWorker: CobaltCurrentTaskItem | undefined;
|
||||||
|
progress: CobaltWorkerProgress | undefined;
|
||||||
|
size: string;
|
||||||
|
retrying: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateStatusText = ({ info, runningWorker, progress, retrying, size }: StatusText) => {
|
||||||
|
switch (info.state) {
|
||||||
|
case "running":
|
||||||
|
if (runningWorker) {
|
||||||
|
const running = $t(`queue.state.running.${runningWorker.type}`);
|
||||||
|
if (progress && progress.percentage) {
|
||||||
|
return `${running}: ${Math.ceil(progress.percentage)}%, ${size}`;
|
||||||
|
}
|
||||||
|
else if (runningWorker && progress && size) {
|
||||||
|
return `${running}: ${size}`;
|
||||||
|
}
|
||||||
|
else if (runningWorker?.type) {
|
||||||
|
const starting = $t(`queue.state.starting.${runningWorker.type}`);
|
||||||
|
|
||||||
|
if (info.pipeline.length > 1) {
|
||||||
|
const currentPipeline = (info.completedWorkers?.length || 0) + 1;
|
||||||
|
return `${starting} (${currentPipeline}/${info.pipeline.length})`;
|
||||||
|
}
|
||||||
|
return starting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $t("queue.state.starting");
|
||||||
|
|
||||||
|
case "done":
|
||||||
|
return formatFileSize(info.resultFile?.file?.size);
|
||||||
|
|
||||||
|
case "error":
|
||||||
|
return !retrying ? info.errorCode : $t("queue.state.retrying");
|
||||||
|
|
||||||
|
case "waiting":
|
||||||
|
return $t("queue.state.waiting");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
params are passed here because svelte will re-run
|
||||||
|
the function every time either of them is changed,
|
||||||
|
which is what we want in this case :3
|
||||||
|
*/
|
||||||
|
$: statusText = generateStatusText({
|
||||||
|
info,
|
||||||
|
runningWorker,
|
||||||
|
progress,
|
||||||
|
retrying,
|
||||||
|
size,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="processing-item">
|
<div class="processing-item">
|
||||||
@ -64,48 +135,53 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="file-status {info.state}">
|
<div class="file-status {info.state}" class:retrying>
|
||||||
{#if info.state === "done"}
|
<div class="status-icon">
|
||||||
<IconCheck /> {formatFileSize(info.resultFile?.file?.size)}
|
{#if info.state === "done"}
|
||||||
{/if}
|
<IconCheck />
|
||||||
|
|
||||||
{#if info.state === "error"}
|
|
||||||
<IconExclamationCircle /> {info.errorCode}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if info.state === "running"}
|
|
||||||
{#if info.pipeline.length > 1}
|
|
||||||
{(info.completedWorkers?.length || 0) + 1}/{info.pipeline.length}
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if runningWorker && progress && progress.percentage}
|
{#if info.state === "error" && !retrying}
|
||||||
{$t(`queue.state.running.${runningWorker.type}`)}: {Math.ceil(
|
<IconExclamationCircle />
|
||||||
progress.percentage
|
|
||||||
)}%, {size}
|
|
||||||
{:else if runningWorker && progress && size}
|
|
||||||
{$t(`queue.state.running.${runningWorker.type}`)}: {size}
|
|
||||||
{:else}
|
|
||||||
{$t("queue.state.starting")}
|
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{#if info.state === "running" || retrying}
|
||||||
|
<div class="status-spinner">
|
||||||
|
<IconLoader2 />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if info.state === "waiting"}
|
<div class="status-text">
|
||||||
{$t("queue.state.waiting")}
|
{statusText}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="file-actions">
|
<div class="file-actions">
|
||||||
{#if info.state === "done" && info.resultFile}
|
{#if info.state === "done" && info.resultFile}
|
||||||
<button
|
<button
|
||||||
class="action-button"
|
class="button action-button"
|
||||||
on:click={() => download(info.resultFile.file)}
|
on:click={() => download(info.resultFile.file)}
|
||||||
>
|
>
|
||||||
<IconDownload />
|
<IconDownload />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="action-button" on:click={() => removeItem(id)}>
|
|
||||||
<IconX />
|
{#if !retrying}
|
||||||
</button>
|
{#if info.state === "error" && info?.canRetry}
|
||||||
|
<button
|
||||||
|
class="button action-button"
|
||||||
|
on:click={() => retry(info)}
|
||||||
|
>
|
||||||
|
<IconReload />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
<button
|
||||||
|
class="button action-button"
|
||||||
|
on:click={() => removeItem(id)}
|
||||||
|
>
|
||||||
|
<IconX />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -170,10 +246,9 @@
|
|||||||
line-break: anywhere;
|
line-break: anywhere;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-status.error {
|
.file-status.error:not(.retrying) {
|
||||||
color: var(--medium-red);
|
color: var(--medium-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +258,29 @@
|
|||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-icon,
|
||||||
|
.status-spinner,
|
||||||
|
.status-text {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
margin is used instead of gap cuz queued state doesn't have an icon.
|
||||||
|
margin is applied only to the visible icon, so there's no awkward gap.
|
||||||
|
*/
|
||||||
|
.status-icon :global(svg) {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global([dir="rtl"]) .status-icon :global(svg) {
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spinner :global(svg) {
|
||||||
|
animation: spinner 0.7s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
.file-actions {
|
.file-actions {
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
@ -206,6 +304,18 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global([dir="rtl"]) .file-actions {
|
||||||
|
left: 0;
|
||||||
|
right: unset;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 18px;
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
-90deg,
|
||||||
|
rgba(255, 255, 255, 0) 0%,
|
||||||
|
rgba(0, 0, 0, 1) 20%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
.processing-item:hover .file-actions {
|
.processing-item:hover .file-actions {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user