feat(ui): Lightning channels panel renders from cached resources (B4)
Some checks failed
Demo images / Build & push demo images (push) Failing after 2m1s
Some checks failed
Demo images / Build & push demo images (push) Failing after 2m1s
lnd.listchannels (+summary) and lnd.closedchannels become separate useCachedResource entries: reopening the panel paints the last channel lists instantly and revalidates behind them; a closed-history failure keeps its last list without touching the main view (same semantics as the old nested try). Open/close mutations still force a refresh. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
43e50e669e
commit
a969f892ea
@ -377,8 +377,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { useCachedResource } from '@/composables/useCachedResource'
|
||||
import { useTxExplorer } from '@/composables/useTxExplorer'
|
||||
|
||||
defineProps<{ compact?: boolean }>()
|
||||
@ -462,11 +463,41 @@ const feePresets: { key: FeePreset; label: string; hint?: string; confTarget?: n
|
||||
{ key: 'custom', label: 'Custom' },
|
||||
]
|
||||
|
||||
const loading = ref(true)
|
||||
const error = ref<string | null>(null)
|
||||
const channels = ref<Channel[]>([])
|
||||
const closedChannels = ref<ClosedChannel[]>([])
|
||||
const summary = ref({ total_inbound: 0, total_outbound: 0 })
|
||||
// Cached: revisits paint the channel lists instantly and revalidate behind
|
||||
// them. Open and closed history are separate entries so a closed-history
|
||||
// failure keeps its last list without touching the main channel view.
|
||||
interface ChannelsData { channels: Channel[]; total_inbound: number; total_outbound: number }
|
||||
const channelsRes = useCachedResource<ChannelsData>({
|
||||
key: 'lnd.channels',
|
||||
fetcher: async (signal) => {
|
||||
const result = await rpcClient.call<ChannelsData>({
|
||||
method: 'lnd.listchannels', timeout: 15000, signal, dedup: true, maxRetries: 1,
|
||||
})
|
||||
return {
|
||||
channels: result.channels || [],
|
||||
total_inbound: result.total_inbound || 0,
|
||||
total_outbound: result.total_outbound || 0,
|
||||
}
|
||||
},
|
||||
})
|
||||
const closedRes = useCachedResource<ClosedChannel[]>({
|
||||
key: 'lnd.closed-channels',
|
||||
fetcher: async (signal) => {
|
||||
const closed = await rpcClient.call<{ channels: ClosedChannel[] }>({
|
||||
method: 'lnd.closedchannels', timeout: 15000, signal, dedup: true, maxRetries: 1,
|
||||
})
|
||||
return closed.channels || []
|
||||
},
|
||||
})
|
||||
const loading = computed(() =>
|
||||
channelsRes.loadState.value === 'loading' || channelsRes.loadState.value === 'refreshing')
|
||||
const error = computed(() => channelsRes.error.value)
|
||||
const channels = computed(() => channelsRes.data.value?.channels ?? [])
|
||||
const closedChannels = computed(() => closedRes.data.value ?? [])
|
||||
const summary = computed(() => ({
|
||||
total_inbound: channelsRes.data.value?.total_inbound ?? 0,
|
||||
total_outbound: channelsRes.data.value?.total_outbound ?? 0,
|
||||
}))
|
||||
|
||||
// Olympus by ZEUS — the LSP node behind the Zeus mobile wallet.
|
||||
// Channel limits: min 150,000 / max 1,500,000 sats.
|
||||
@ -538,37 +569,9 @@ function capacityPercent(amount: number, capacity: number): number {
|
||||
return Math.round((amount / capacity) * 100)
|
||||
}
|
||||
|
||||
async function loadChannels() {
|
||||
const hadChannels = channels.value.length > 0
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const result = await rpcClient.call<{ channels: Channel[]; total_inbound: number; total_outbound: number }>({
|
||||
method: 'lnd.listchannels',
|
||||
timeout: 15000,
|
||||
})
|
||||
channels.value = result.channels || []
|
||||
summary.value = {
|
||||
total_inbound: result.total_inbound || 0,
|
||||
total_outbound: result.total_outbound || 0,
|
||||
}
|
||||
// Closed history is a separate RPC — a failure here keeps the previous
|
||||
// list rather than blanking the main channel view.
|
||||
try {
|
||||
const closed = await rpcClient.call<{ channels: ClosedChannel[] }>({
|
||||
method: 'lnd.closedchannels',
|
||||
timeout: 15000,
|
||||
})
|
||||
closedChannels.value = closed.channels || []
|
||||
} catch {
|
||||
/* keep previous closed list */
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
error.value = err instanceof Error ? err.message : 'Failed to load channels'
|
||||
if (!hadChannels) channels.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
function loadChannels(): Promise<void> {
|
||||
void closedRes.refresh()
|
||||
return channelsRes.refresh()
|
||||
}
|
||||
|
||||
function feeParams(): { target_conf?: number; sat_per_vbyte?: number } | null {
|
||||
@ -647,7 +650,5 @@ async function closeChannel() {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadChannels)
|
||||
|
||||
defineExpose({ channels, loadChannels })
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user