Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39a58910f8 |
@@ -12,7 +12,7 @@
|
||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||
import Content from "@app/components/Content.svelte"
|
||||
import ReactionSummary from "@app/components/ReactionSummary.svelte"
|
||||
import ThunkStatus from "@app/components/ThunkStatus.svelte"
|
||||
import ThunkFailure from "@app/components/ThunkFailure.svelte"
|
||||
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
||||
import ChatMessageMenu from "@app/components/ChatMessageMenu.svelte"
|
||||
import ChatMessageMenuMobile from "@app/components/ChatMessageMenuMobile.svelte"
|
||||
@@ -123,7 +123,7 @@
|
||||
</div>
|
||||
</TapTarget>
|
||||
{#if isOwn && thunk}
|
||||
<ThunkStatus showToastOnRetry {thunk} class="mb-2 mr-2" />
|
||||
<ThunkFailure showToastOnRetry {thunk} class="mb-2 mr-2" />
|
||||
{/if}
|
||||
<div class="row-2 z-feature -mt-4 ml-4">
|
||||
<ReactionSummary {event} {deleteReaction} {createReaction} noTooltip />
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ThunkStatus from "@app/components/ThunkStatus.svelte"
|
||||
import ThunkFailure from "@app/components/ThunkFailure.svelte"
|
||||
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||
import ReactionSummary from "@app/components/ReactionSummary.svelte"
|
||||
@@ -127,7 +127,7 @@
|
||||
<div class:mt-2={showPubkey && event.kind !== MESSAGE}>
|
||||
<RoomItemContent {url} event={$innerEvent ?? event} />
|
||||
{#if event.pubkey === $pubkey && thunk}
|
||||
<ThunkStatus showToastOnRetry {thunk} class="mt-1 flex justify-end" />
|
||||
<ThunkFailure showToastOnRetry {thunk} class="mt-1 flex justify-end" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type {Instance} from "tippy.js"
|
||||
import {stopPropagation} from "svelte/legacy"
|
||||
import {noop} from "@welshman/lib"
|
||||
import type {AbstractThunk} from "@welshman/app"
|
||||
import ThunkStatus from "@app/components/ThunkStatus.svelte"
|
||||
import {getFailedThunkUrls, getThunkUrlsWithStatus, thunkIsComplete} from "@welshman/app"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Tippy from "@lib/components/Tippy.svelte"
|
||||
import ThunkStatusDetail from "@app/components/ThunkStatusDetail.svelte"
|
||||
|
||||
interface Props {
|
||||
thunk: AbstractThunk
|
||||
@@ -8,7 +16,35 @@
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props: Props = $props()
|
||||
const {thunk, showToastOnRetry, ...restProps}: Props = $props()
|
||||
|
||||
const failedUrls = $derived([
|
||||
...getFailedThunkUrls($thunk),
|
||||
...getThunkUrlsWithStatus(PublishStatus.Aborted, $thunk),
|
||||
])
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && failedUrls.length > 0)
|
||||
|
||||
let popover: Instance | undefined = $state()
|
||||
|
||||
const hideDetail = () => popover?.hide()
|
||||
</script>
|
||||
|
||||
<ThunkStatus {...props} />
|
||||
{#if showFailure}
|
||||
<button
|
||||
class="flex w-full justify-end px-1 text-xs {restProps.class}"
|
||||
onclick={stopPropagation(noop)}>
|
||||
<Tippy
|
||||
bind:popover
|
||||
class="flex items-center"
|
||||
component={ThunkStatusDetail}
|
||||
props={{thunk, hide: hideDetail, showToastOnRetry}}
|
||||
params={{interactive: true, maxWidth: "none"}}>
|
||||
{#snippet children()}
|
||||
<span class="flex cursor-pointer items-center gap-1 opacity-75">
|
||||
<Icon icon={Danger} class="text-error" size={3} />
|
||||
<span>Failed to send!</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
</Tippy>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type {Instance} from "tippy.js"
|
||||
import {stopPropagation} from "svelte/legacy"
|
||||
import {noop} from "@welshman/lib"
|
||||
import type {AbstractThunk} from "@welshman/app"
|
||||
import {
|
||||
abortThunk,
|
||||
getFailedThunkUrls,
|
||||
getThunkUrlsWithStatus,
|
||||
thunkHasStatus,
|
||||
thunkIsComplete,
|
||||
} from "@welshman/app"
|
||||
import {thunkIsComplete, getFailedThunkUrls, getThunkUrlsWithStatus} from "@welshman/app"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import Check from "@assets/icons/check.svg?dataurl"
|
||||
import CheckRead from "@assets/icons/check-read.svg?dataurl"
|
||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Tippy from "@lib/components/Tippy.svelte"
|
||||
import ThunkDeliveryBreakdown from "@app/components/ThunkDeliveryBreakdown.svelte"
|
||||
|
||||
type DeliveryState = "sending" | "delivered" | "partial" | "failed"
|
||||
import ThunkFailure from "@app/components/ThunkFailure.svelte"
|
||||
import ThunkPending from "@app/components/ThunkPending.svelte"
|
||||
|
||||
interface Props {
|
||||
thunk: AbstractThunk
|
||||
@@ -28,99 +13,16 @@
|
||||
|
||||
const {thunk, showToastOnRetry, ...restProps}: Props = $props()
|
||||
|
||||
const successUrls = $derived(getThunkUrlsWithStatus(PublishStatus.Success, $thunk))
|
||||
const failedUrls = $derived([
|
||||
...getFailedThunkUrls($thunk),
|
||||
...getThunkUrlsWithStatus(PublishStatus.Aborted, $thunk),
|
||||
])
|
||||
const isComplete = $derived(thunkIsComplete($thunk))
|
||||
const isSending = $derived(thunkHasStatus(PublishStatus.Sending, $thunk))
|
||||
|
||||
const deliveryState = $derived.by((): DeliveryState => {
|
||||
if (!isComplete) {
|
||||
return "sending"
|
||||
}
|
||||
|
||||
if (successUrls.length === 0 && failedUrls.length > 0) {
|
||||
return "failed"
|
||||
}
|
||||
|
||||
if (failedUrls.length > 0) {
|
||||
return "partial"
|
||||
}
|
||||
|
||||
return "delivered"
|
||||
})
|
||||
|
||||
const statusLabel = $derived(
|
||||
deliveryState === "sending"
|
||||
? "Sending..."
|
||||
: deliveryState === "delivered"
|
||||
? "Message delivered"
|
||||
: deliveryState === "partial"
|
||||
? "Partial delivery"
|
||||
: "Failed to deliver!",
|
||||
)
|
||||
|
||||
const statusIcon = $derived(
|
||||
deliveryState === "delivered" ? CheckRead : deliveryState === "partial" ? Check : Danger,
|
||||
)
|
||||
|
||||
const statusIconClass = $derived(
|
||||
deliveryState === "delivered"
|
||||
? "text-success"
|
||||
: deliveryState === "partial"
|
||||
? "text-warning"
|
||||
: deliveryState === "failed"
|
||||
? "text-error"
|
||||
: "",
|
||||
)
|
||||
|
||||
const showBreakdown = $derived(isComplete)
|
||||
|
||||
const breakdownState = $derived(
|
||||
deliveryState === "delivered" || deliveryState === "partial" || deliveryState === "failed"
|
||||
? deliveryState
|
||||
: "delivered",
|
||||
)
|
||||
|
||||
const abort = () => abortThunk(thunk)
|
||||
|
||||
let popover: Instance | undefined = $state()
|
||||
|
||||
const hideBreakdown = () => popover?.hide()
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && failedUrls.length > 0)
|
||||
const showPending = $derived(!thunkIsComplete($thunk))
|
||||
</script>
|
||||
|
||||
<div class="flex w-full justify-end px-1 text-xs {restProps.class}">
|
||||
{#if deliveryState === "sending"}
|
||||
<span class="flex items-center gap-1 opacity-50">
|
||||
<span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px"></span>
|
||||
<span>{statusLabel}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="underline transition-all"
|
||||
class:link={isSending}
|
||||
class:opacity-25={!isSending}
|
||||
class:pointer-events-none={!isSending}
|
||||
onclick={stopPropagation(abort)}>
|
||||
Cancel
|
||||
</button>
|
||||
</span>
|
||||
{:else if showBreakdown}
|
||||
<button type="button" class="flex items-center" onclick={stopPropagation(noop)}>
|
||||
<Tippy
|
||||
bind:popover
|
||||
class="flex items-center"
|
||||
component={ThunkDeliveryBreakdown}
|
||||
props={{thunk, deliveryState: breakdownState, hide: hideBreakdown, showToastOnRetry}}
|
||||
params={{interactive: true, maxWidth: "none"}}>
|
||||
{#snippet children()}
|
||||
<span class="flex cursor-pointer items-center gap-1 opacity-75">
|
||||
<Icon icon={statusIcon} class={statusIconClass} size={3} />
|
||||
<span>{statusLabel}</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
</Tippy>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if showFailure}
|
||||
<ThunkFailure class={restProps.class} {thunk} {showToastOnRetry} />
|
||||
{:else if showPending}
|
||||
<ThunkPending class={restProps.class} {thunk} />
|
||||
{/if}
|
||||
|
||||
+6
-26
@@ -18,16 +18,13 @@
|
||||
import ThunkToast from "@app/components/ThunkToast.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
type DeliveryState = "delivered" | "partial" | "failed"
|
||||
|
||||
interface Props {
|
||||
thunk: AbstractThunk
|
||||
deliveryState: DeliveryState
|
||||
hide: () => void
|
||||
showToastOnRetry?: boolean
|
||||
}
|
||||
|
||||
const {thunk, deliveryState, hide, showToastOnRetry}: Props = $props()
|
||||
const {thunk, hide, showToastOnRetry}: Props = $props()
|
||||
|
||||
const successUrls = $derived(getThunkUrlsWithStatus(PublishStatus.Success, $thunk))
|
||||
const failedUrls = $derived([
|
||||
@@ -35,30 +32,13 @@
|
||||
...getThunkUrlsWithStatus(PublishStatus.Aborted, $thunk),
|
||||
])
|
||||
const total = $derived(successUrls.length + failedUrls.length)
|
||||
const isPartial = $derived(successUrls.length > 0 && failedUrls.length > 0)
|
||||
|
||||
const title = $derived(
|
||||
deliveryState === "delivered"
|
||||
? "Message delivered"
|
||||
: deliveryState === "partial"
|
||||
? `Partial delivery ${successUrls.length}/${total} relays`
|
||||
: "Failed to deliver!",
|
||||
isPartial ? `Partial delivery ${successUrls.length}/${total} relays` : "Failed to send!",
|
||||
)
|
||||
|
||||
const titleIconClass = $derived(
|
||||
deliveryState === "delivered"
|
||||
? "text-success"
|
||||
: deliveryState === "partial"
|
||||
? "text-warning"
|
||||
: "text-error",
|
||||
)
|
||||
|
||||
const titleIcon = $derived(deliveryState === "delivered" ? CheckCircle : Danger)
|
||||
|
||||
const relayMessage = (
|
||||
url: string,
|
||||
status: PublishStatus | undefined,
|
||||
detail: string | undefined,
|
||||
) => {
|
||||
const relayMessage = (status: PublishStatus | undefined, detail: string | undefined) => {
|
||||
if (detail) {
|
||||
return detail
|
||||
}
|
||||
@@ -96,7 +76,7 @@
|
||||
<div class="card2 bg-alt flex min-w-72 max-w-sm flex-col gap-3 px-4 py-3 shadow-lg">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="flex items-center gap-2 text-sm font-medium">
|
||||
<Icon icon={titleIcon} class={titleIconClass} size={4} />
|
||||
<Icon icon={Danger} class="text-error" size={4} />
|
||||
{title}
|
||||
</span>
|
||||
<button type="button" class="opacity-50 hover:opacity-100" onclick={hide}>
|
||||
@@ -117,7 +97,7 @@
|
||||
<Icon icon={Danger} class="mt-0.5 text-error" size={4} />
|
||||
<div class="min-w-0">
|
||||
<p class="break-all">{displayRelayUrl(url)}</p>
|
||||
<p class="text-xs opacity-60">{addPeriod(relayMessage(url, status, detail))}</p>
|
||||
<p class="text-xs opacity-60">{addPeriod(relayMessage(status, detail))}</p>
|
||||
</div>
|
||||
<Button class="link shrink-0 px-1" onclick={stopPropagation(() => retryRelay(url))}>
|
||||
Retry
|
||||
Reference in New Issue
Block a user