flotilla/src/app/components/ThunkStatus.svelte

96 lines
2.9 KiB
Svelte
Raw Normal View History

2024-10-16 22:57:18 +00:00
<script lang="ts">
2025-05-12 22:35:13 +00:00
import {stopPropagation} from "svelte/legacy"
import {nth, noop} from "@welshman/lib"
2024-10-16 22:57:18 +00:00
import {PublishStatus} from "@welshman/net"
2025-04-14 23:45:52 +00:00
import {
MergedThunk,
publishThunk,
isMergedThunk,
thunkIsComplete,
thunkHasStatus,
} from "@welshman/app"
import type {Thunk} from "@welshman/app"
2024-10-17 23:03:50 +00:00
import Icon from "@lib/components/Icon.svelte"
2024-10-17 18:56:13 +00:00
import Tippy from "@lib/components/Tippy.svelte"
2024-10-17 23:03:50 +00:00
import ThunkStatusDetail from "@app/components/ThunkStatusDetail.svelte"
2024-10-31 19:24:40 +00:00
import {userSettingValues} from "@app/state"
2024-10-16 22:57:18 +00:00
2025-02-04 00:37:14 +00:00
interface Props {
thunk: Thunk | MergedThunk
class?: string
2025-02-04 00:37:14 +00:00
}
let {thunk, ...restProps}: Props = $props()
2024-10-16 22:57:18 +00:00
2024-10-17 18:27:17 +00:00
const abort = () => thunk.controller.abort()
2024-10-16 22:57:18 +00:00
2024-10-17 18:56:13 +00:00
const retry = () => {
2025-04-14 23:45:52 +00:00
thunk = isMergedThunk(thunk)
? new MergedThunk(thunk.thunks.map(t => publishThunk(t.options)))
: publishThunk(thunk.options)
2024-10-17 18:56:13 +00:00
}
2025-04-14 23:45:52 +00:00
const statuses = $derived(Object.entries($thunk.status))
const isSending = $derived(thunkHasStatus($thunk, PublishStatus.Sending))
const canCancel = $derived(isSending && $userSettingValues.send_delay > 0)
const failedUrls = $derived(
statuses
.filter(([_, status]) => [PublishStatus.Failure, PublishStatus.Timeout].includes(status))
2025-04-16 21:19:09 +00:00
.map(nth(0)),
)
2024-10-31 17:37:20 +00:00
2025-04-14 23:45:52 +00:00
const showFailure = $derived(thunkIsComplete($thunk) && failedUrls.length > 0)
let isPending = $state(thunkHasStatus($thunk, PublishStatus.Pending))
const showPending = $derived(canCancel || isPending)
2024-10-31 17:37:20 +00:00
// Delay updating isPending so users can see that the message is sent
$effect(() => {
2025-04-14 23:45:52 +00:00
isPending = isPending || thunkHasStatus($thunk, PublishStatus.Pending)
2025-04-14 23:45:52 +00:00
if (!thunkHasStatus($thunk, PublishStatus.Pending)) {
2024-10-31 17:37:20 +00:00
setTimeout(() => {
isPending = false
}, 2000)
}
})
2024-10-16 22:57:18 +00:00
</script>
2025-04-16 21:19:09 +00:00
{#if showFailure}
{@const url = failedUrls[0]}
{@const status = $thunk.status[url]}
{@const message = $thunk.details[url]}
2025-05-13 17:35:42 +00:00
<button
class="flex w-full justify-end px-1 text-xs {restProps.class}"
onclick={stopPropagation(noop)}>
2025-04-16 21:19:09 +00:00
<Tippy
2025-05-13 17:35:42 +00:00
class="flex items-center"
2025-04-16 21:19:09 +00:00
component={ThunkStatusDetail}
props={{url, message, status, retry}}
params={{interactive: true}}>
{#snippet children()}
<span class="flex cursor-pointer items-center gap-1 text-error">
<Icon icon="danger" size={3} />
<span>Failed to send!</span>
</span>
{/snippet}
</Tippy>
2025-05-12 22:35:13 +00:00
</button>
2025-04-16 21:19:09 +00:00
{:else if showPending}
2025-05-13 17:35:42 +00:00
<div class="flex w-full justify-end px-1 text-xs {restProps.class}">
<span class="flex items-center gap-1">
2025-04-16 21:19:09 +00:00
<span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px"></span>
<span class="opacity-50">Sending...</span>
<button
type="button"
class="underline transition-all"
class:link={canCancel}
class:opacity-25={!canCancel}
2025-05-12 22:35:13 +00:00
onclick={stopPropagation(abort)}>
2025-04-16 21:19:09 +00:00
Cancel
</button>
</span>
2025-01-15 01:23:27 +00:00
</div>
{/if}