Move relay action items to top of page

This commit is contained in:
Jon Staab
2026-03-19 12:41:23 -07:00
parent 1f5be54cb1
commit f9c7ed4936
7 changed files with 142 additions and 158 deletions
@@ -1,58 +1,140 @@
<script lang="ts">
import type {Readable} from "svelte/store"
import {derived} from "svelte/store"
import {shuffle, partition, ifLet} from "@welshman/lib"
import {RelayMode} from "@welshman/util"
import {
pubkey,
derivePubkeyRelays,
getRelay,
setWriteRelays,
setReadRelays,
setSearchRelays,
setMessagingRelays,
} from "@welshman/app"
import Stars from "@assets/icons/stars.svg?dataurl"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
import DangerTriangle from "@assets/icons/danger-triangle.svg?dataurl"
import Stethoscope from "@assets/icons/stethoscope.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import type {ActionItem} from "@app/components/RelaySettingsActionItem.svelte"
import RelaySettingsActionItem from "@app/components/RelaySettingsActionItem.svelte"
import {hasNip50, DEFAULT_RELAYS, DEFAULT_MESSAGING_RELAYS, PLATFORM_NAME} from "@app/core/state"
interface Props {
actionItems: Readable<ActionItem[]>
}
const readRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Read)
const writeRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Write)
const searchRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Search)
const messagingRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Messaging)
const {actionItems}: Props = $props()
const actionItems = derived(
[readRelayUrls, writeRelayUrls, messagingRelayUrls, searchRelayUrls],
([$readRelayUrls, $writeRelayUrls, $messagingRelayUrls, $searchRelayUrls]) => {
const $actionItems: ActionItem[] = []
const back = () => history.back()
if ($readRelayUrls.length <= 1) {
$actionItems.push({
title: "Missing Inbox Relays",
subtitle: "Other people aren't currently able to reliably tag you in public notes.",
action: "Update",
apply: () => setReadRelays(DEFAULT_RELAYS),
})
}
if ($writeRelayUrls.length <= 1) {
$actionItems.push({
title: "Missing Outbox Relays",
subtitle: "Other people aren't currently able to reliably find your public notes.",
action: "Update",
apply: () => setWriteRelays(DEFAULT_RELAYS),
})
}
if ($messagingRelayUrls.length <= 1) {
$actionItems.push({
title: "Missing DM Relays",
subtitle: "You aren't currently able to reliably send or receive direct messages.",
action: "Update",
apply: () => setMessagingRelays(DEFAULT_MESSAGING_RELAYS),
})
}
if ($readRelayUrls.length > 8) {
$actionItems.push({
title: "Too Many Inbox Relays",
subtitle:
"You have more inbox relays than is really necessary, which can affect resource usage.",
action: "Prune Selections",
apply: () => setReadRelays(shuffle($readRelayUrls).slice(0, 5)),
})
}
if ($writeRelayUrls.length > 8) {
$actionItems.push({
title: "Too Many Outbox Relays",
subtitle:
"You have more outbox relays than is really necessary, which can affect resource usage.",
action: "Prune Selections",
apply: () => setWriteRelays(shuffle($writeRelayUrls).slice(0, 5)),
})
}
if ($messagingRelayUrls.length > 8) {
$actionItems.push({
title: "Too Many DM Relays",
subtitle:
"You have more DM relays than is really necessary, which can affect resource usage.",
action: "Prune Selections",
apply: () => setMessagingRelays(shuffle($messagingRelayUrls).slice(0, 5)),
})
}
const [okSearchRelays, badSearchRelays] = partition(
url => Boolean(ifLet(getRelay(url), hasNip50)),
$searchRelayUrls,
)
if (badSearchRelays.length > 0) {
$actionItems.push({
title: "Invalid Search Relays",
subtitle: `Some of your search relays don't support search.`,
action: "Remove Invalid",
apply: () => setSearchRelays(okSearchRelays),
})
}
return $actionItems
},
)
const applyAll = () => {
for (const actionItem of $actionItems) {
actionItem.apply()
}
}
$effect(() => {
if ($actionItems.length === 0) {
back()
}
})
</script>
<Modal>
<ModalBody>
<div class="flex gap-2 items-center">
<Icon icon={DangerTriangle} />
<strong class="text-lg">Action Items</strong>
</div>
<p class="text-sm">
Below are recommendations for adjustments to your relay selections that you might consider.
</p>
{#each $actionItems as actionItem}
<RelaySettingsActionItem {...actionItem} />
{/each}
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back}>
<Icon icon={AltArrowLeft} />
Go Back
</Button>
<div class="card2 bg-alt flex flex-col gap-4 shadow-md">
<div class="flex justify-between items-center">
<strong class="flex items-center gap-3 text-lg">
<Icon icon={Stethoscope} />
Health Check
</strong>
<span class="flex items-center gap-2 text-sm">
<Icon icon={$actionItems.length === 0 ? CheckCircle : DangerTriangle} />
{$actionItems.length} Issue{$actionItems.length === 1 ? "" : "s"} Detected
</span>
</div>
<p>
{PLATFORM_NAME} actively checks your connection to the network in the background to discover relays
that are offline, that you don't have access to, or are otherwise causing trouble.
</p>
{#each $actionItems as actionItem}
<RelaySettingsActionItem {...actionItem} />
{/each}
{#if $actionItems.length > 0}
<Button class="btn btn-primary" onclick={applyAll}>
<Icon icon={Stars} />
Apply All Recommendations
</Button>
</ModalFooter>
</Modal>
{/if}
</div>
+2 -2
View File
@@ -26,7 +26,7 @@
const back = () => history.back()
const onDelete = () => {
const onResolved = () => {
if ($reports.size === 0) {
back()
}
@@ -40,7 +40,7 @@
<ModalSubtitle>All reports for this event are shown below.</ModalSubtitle>
</ModalHeader>
{#each $reports.values() as report (report.id)}
<ReportItem {url} event={report} {onDelete} />
<ReportItem {url} event={report} {onResolved} />
{/each}
</ModalBody>
<ModalFooter>
+6 -6
View File
@@ -20,10 +20,10 @@
type Props = {
url: string
event: TrustedEvent
onDelete?: () => void
onResolved?: () => void
}
const {url, event, onDelete}: Props = $props()
const {url, event, onResolved}: Props = $props()
const shouldProtect = canEnforceNip70(url)
const userIsAdmin = deriveUserIsSpaceAdmin(url)
@@ -40,7 +40,7 @@
const deleteReport = async () => {
publishDelete({event, relays: [url], protect: await shouldProtect})
onDelete?.()
onResolved?.()
}
const dismissReport = async () => {
@@ -54,7 +54,7 @@
} else {
pushToast({message: "Content has successfully been deleted!"})
repository.removeEvent(event.id)
onDelete?.()
onResolved?.()
}
}
@@ -77,7 +77,7 @@
repository.removeEvent(event.id)
repository.removeEvent(id)
history.back()
setTimeout(() => onDelete?.())
setTimeout(() => onResolved?.())
}
},
})
@@ -101,7 +101,7 @@
pushToast({message: "User has successfully been banned!"})
repository.removeEvent(event.id)
history.back()
setTimeout(() => onDelete?.())
setTimeout(() => onResolved?.())
}
},
})
+3 -3
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import {getTagValue} from "@welshman/util"
import {getTagValue, ManagementMethod} from "@welshman/util"
import type {TrustedEvent, PublishedRoomMeta} from "@welshman/util"
import {repository} from "@welshman/app"
import {repository, manageRelay} from "@welshman/app"
import Button from "@lib/components/Button.svelte"
import ProfileName from "@app/components/ProfileName.svelte"
import ProfileDetail from "@app/components/ProfileDetail.svelte"
@@ -30,7 +30,7 @@
try {
const {error} = await manageRelay(url, {
method: ManagementMethod.BanEvent,
params: [event.id, "Join request dismissed"]
params: [event.id, "Join request dismissed"],
})
if (error) {
+2 -2
View File
@@ -23,7 +23,7 @@
const back = () => history.back()
const onDelete = () => {
const onResolved = () => {
if ($reports.length === 0) {
back()
}
@@ -38,7 +38,7 @@
</ModalHeader>
<div class="flex flex-col gap-2">
{#each $reports as event (event.id)}
<ReportItem {url} {event} {onDelete} />
<ReportItem {url} {event} {onResolved} />
{:else}
<p class="py-12 text-center">No reports found.</p>
{/each}