mirror of
https://github.com/logos-storage/ethcc-demo.git
synced 2026-01-05 22:53:06 +00:00
Split out loading of request and request details
On the requests page, only show details relating to the StorageRequested event On the request details page, load more detailed information, including slot info. If already fetched, do not re-fetch
This commit is contained in:
parent
a44f23719d
commit
ed378e1a77
@ -6,7 +6,7 @@ import Balance from '@/components/Balance.vue'
|
||||
import BlockNumber from '@/components/BlockNumber.vue'
|
||||
import AppNav from '@/components/AppNav.vue'
|
||||
import ContractEventAlerts from '@/components/ContractEventAlerts.vue'
|
||||
import { initDrawers } from 'flowbite'
|
||||
import { initDrawers, initDismisses } from 'flowbite'
|
||||
|
||||
const alerts = ref([])
|
||||
const id = ref(0)
|
||||
@ -38,10 +38,11 @@ function addSlotAlert(type, event, state) {
|
||||
onBeforeMount(async () => {})
|
||||
|
||||
onMounted(async () => {
|
||||
await requestsStore.fetch()
|
||||
await requestsStore.fetchPastRequests()
|
||||
initDrawers()
|
||||
initDismisses()
|
||||
|
||||
function onStorageRequested(blockNumber, requestId, request, state) {
|
||||
function onStorageRequested(blockNumber, requestId, state) {
|
||||
alerts.value.push({
|
||||
type: 'info',
|
||||
event: 'StorageRequested',
|
||||
|
||||
@ -1,16 +1,9 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { initDrawers } from 'flowbite'
|
||||
|
||||
onMounted(() => {
|
||||
initDrawers()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="mx-auto max-w-screen-xl flex flex-wrap items-center justify-between">
|
||||
<!-- <div class=""> -->
|
||||
<a href="https://codex.storage/" class="flex items-center rtl:space-x-reverse">
|
||||
<img src="../assets/logo.svg" class="h-8 hidden dark:inline" alt="Codex Logo" />
|
||||
<img src="../assets/logo-black.svg" class="h-8 inline dark:hidden" alt="Codex Logo" />
|
||||
@ -73,7 +66,6 @@ onMounted(() => {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { initDismisses } from 'flowbite'
|
||||
import AlertWithContent from '@/components/alerts/AlertWithContent.vue'
|
||||
|
||||
const alerts = defineModel()
|
||||
onMounted(() => {
|
||||
initDismisses()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { getRelativeTime } from '@feelinglovelynow/get-relative-time'
|
||||
import Tooltip from '@/components/Tooltip.vue'
|
||||
|
||||
@ -9,14 +9,7 @@ const props = defineProps({
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const date = ref(Date.now())
|
||||
const relativeTime = ref(getRelativeTime(props.timestamp))
|
||||
watch(date, () => (relativeTime.value = getRelativeTime(props.timestamp)))
|
||||
let intervalId
|
||||
// onMounted(() => {
|
||||
// intervalId = setInterval(() => (date.value = Date.now()), 10000)
|
||||
// })
|
||||
// onUnmounted(() => clearInterval(intervalId))
|
||||
const relativeTime = computed(() => getRelativeTime(props.timestamp))
|
||||
</script>
|
||||
<template>
|
||||
<Tooltip>
|
||||
|
||||
@ -17,8 +17,9 @@ defineProps({
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<Tooltip>
|
||||
{{shorten(value, ellipses, chars)}}
|
||||
<!-- <Tooltip>
|
||||
<template #text>{{ shorten(value, ellipses, chars) }}</template>
|
||||
<template #tooltip-content>{{ value }}</template>
|
||||
</Tooltip>
|
||||
</Tooltip> -->
|
||||
</template>
|
||||
|
||||
@ -20,14 +20,13 @@ defineProps({
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">SlotID</th>
|
||||
<th scope="col" class="px-6 py-3">Index</th>
|
||||
<th scope="col" class="px-6 py-3">Proofs Missed</th>
|
||||
<th scope="col" class="px-6 py-3">Provider</th>
|
||||
<th scope="col" class="px-6 py-3">State</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="({ slotId, slotIdx, state, proofsMissed, provider }, idx) in slots"
|
||||
v-for="({ slotId, slotIdx, state, provider }, idx) in slots"
|
||||
:key="{ slotId }"
|
||||
class="bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-600"
|
||||
>
|
||||
@ -38,7 +37,6 @@ defineProps({
|
||||
<div class="text-base font-semibold">{{ shorten(slotId) }}</div>
|
||||
</th>
|
||||
<td class="px-6 py-4">{{ slotIdx }}</td>
|
||||
<td class="px-6 py-4">{{ proofsMissed }}</td>
|
||||
<td class="px-6 py-4">{{ shorten(provider) }}</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { initTooltips } from 'flowbite'
|
||||
import { getStateColour, price } from '@/utils/requests'
|
||||
import { autoPluralize } from '@/utils/strings'
|
||||
|
||||
@ -20,6 +21,10 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initTooltips()
|
||||
})
|
||||
|
||||
const totalPrice = computed(() => price(props.request))
|
||||
const maxSlotLoss = computed(() => autoPluralize(props.request.ask.maxSlotLoss, 'slot'))
|
||||
const slots = computed(() => autoPluralize(props.request.ask.slots, 'slot'))
|
||||
@ -30,7 +35,7 @@ const stateColour = computed(() => getStateColour(props.request.state))
|
||||
<div class="flex flex-wrap">
|
||||
<CodexImage
|
||||
class="flex-initial mx-auto my-8 lg:my-16 min-w-sm max-w-md w-full rounded"
|
||||
:cid="request.content.cid"
|
||||
:cid="props.request.content.cid"
|
||||
:local-only="!['New', 'Fulfilled'].includes(request.state)"
|
||||
></CodexImage>
|
||||
<div class="py-8 px-4 ml-4 max-w-2xl lg:py-16 flex-1">
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
<script setup>
|
||||
import { inject, ref, onMounted, computed } from 'vue'
|
||||
import { initModals } from 'flowbite'
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRequestsStore } from '@/stores/requests'
|
||||
import { initTooltips } from 'flowbite'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import CodexImage from '@/components/CodexImage.vue'
|
||||
import { useRequestsStore } from '@/stores/requests'
|
||||
import StateIndicator from '@/components/StateIndicator.vue'
|
||||
import RelativeTime from '@/components/RelativeTime.vue'
|
||||
import ShortenValue from '@/components/ShortenValue.vue'
|
||||
import { shorten } from '@/utils/ids'
|
||||
import { getStateColour } from '@/utils/requests'
|
||||
|
||||
const requestsStore = useRequestsStore()
|
||||
@ -20,6 +18,9 @@ const requestsOrdered = computed(() => {
|
||||
)
|
||||
return sorted
|
||||
})
|
||||
onMounted(() => {
|
||||
initTooltips()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -132,14 +133,13 @@ const requestsOrdered = computed(() => {
|
||||
>
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">RequestID</th>
|
||||
<th scope="col" class="px-6 py-3">CID</th>
|
||||
<th scope="col" class="px-6 py-3">State</th>
|
||||
<th scope="col" class="px-6 py-3">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="([requestId, { requestedAt, content, state }], idx) in requestsOrdered"
|
||||
v-for="([requestId, { requestedAt, state }], idx) in requestsOrdered"
|
||||
:key="{ requestId }"
|
||||
class="cursor-pointer bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-600"
|
||||
@click="router.push(`/request/${requestId}`)"
|
||||
@ -148,11 +148,6 @@ const requestsOrdered = computed(() => {
|
||||
scope="row"
|
||||
class="flex items-center px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
|
||||
>
|
||||
<CodexImage
|
||||
:local-only="!['New', 'Fulfilled'].includes(state)"
|
||||
:cid="content.cid"
|
||||
class="w-10 h-10 rounded-full mt-1"
|
||||
/>
|
||||
<div class="ps-3">
|
||||
<div class="text-base font-semibold">
|
||||
<ShortenValue :value="requestId"></ShortenValue>
|
||||
@ -162,16 +157,12 @@ const requestsOrdered = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
<td class="px-6 py-4">
|
||||
<ShortenValue :value="content.cid"></ShortenValue>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<StateIndicator :text="state" :color="getStateColour(state)"></StateIndicator>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<!-- Modal toggle -->
|
||||
<a
|
||||
href="#"
|
||||
type="button"
|
||||
|
||||
@ -1,19 +1,11 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { initTooltips } from 'flowbite'
|
||||
// defineProps({
|
||||
// id: {
|
||||
// type: String,
|
||||
// required: true
|
||||
// }
|
||||
// })
|
||||
import { onMounted } from 'vue'
|
||||
onMounted(() => {
|
||||
initTooltips()
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <slot :id="$idRef('tooltip')" name="text"></slot> -->
|
||||
<p :data-tooltip-target="$id('tooltip')" class="cursor-help">
|
||||
<slot name="text"></slot>
|
||||
</p>
|
||||
|
||||
@ -63,14 +63,20 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
}
|
||||
|
||||
const getSlots = async (requestId, numSlots) => {
|
||||
console.log(`fetching ${numSlots} slots`)
|
||||
let start = Date.now()
|
||||
let slots = []
|
||||
for (let slotIdx = 0; slotIdx < numSlots; slotIdx++) {
|
||||
let id = slotId(requestId, slotIdx)
|
||||
const startSlotState = Date.now()
|
||||
let state = await getSlotState(id)
|
||||
let proofsMissed = await marketplace.missingProofs(id)
|
||||
console.log(`fetched slot state in ${(Date.now() - startSlotState) / 1000}s`)
|
||||
const startGetHost = Date.now()
|
||||
let provider = await marketplace.getHost(id)
|
||||
slots.push({ slotId: id, slotIdx, state, proofsMissed, provider })
|
||||
console.log(`fetched slot provider in ${(Date.now() - startGetHost) / 1000}s`)
|
||||
slots.push({ slotId: id, slotIdx, state, provider })
|
||||
}
|
||||
console.log(`fetched ${numSlots} slots in ${(Date.now() - start) / 1000}s`)
|
||||
return slots
|
||||
// blockNumbers.value.add(blockNumber)
|
||||
}
|
||||
@ -85,40 +91,34 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetch() {
|
||||
async function addRequest(requestId, blockHash) {
|
||||
let state = await getRequestState(requestId)
|
||||
let block = await getBlock(blockHash)
|
||||
let reqExisting = requests.value.get(requestId) // just in case it already exists
|
||||
let request = {
|
||||
...reqExisting,
|
||||
state,
|
||||
requestedAt: block.timestamp,
|
||||
requestFinishedId: null,
|
||||
detailsFetched: false
|
||||
}
|
||||
requests.value.set(requestId, request)
|
||||
return request
|
||||
}
|
||||
|
||||
async function fetchPastRequests() {
|
||||
// query past events
|
||||
console.log('fetching past requests')
|
||||
loading.value = true
|
||||
try {
|
||||
let events = await marketplace.queryFilter(StorageRequested)
|
||||
console.log('got ', events.length, ' StorageRequested events')
|
||||
let reqs = new Map()
|
||||
events.forEach(async (event, i) => {
|
||||
console.log('getting details for StorageRequested event ', i)
|
||||
let start = Date.now()
|
||||
// let event = events[i]
|
||||
// await events.forEach(async (event) => {
|
||||
let { requestId, ask, expiry } = event.args
|
||||
let { blockHash, blockNumber } = event
|
||||
let arrRequest = await marketplace.getRequest(requestId)
|
||||
let request = arrayToObject(arrRequest)
|
||||
let state = await getRequestState(requestId)
|
||||
let slots = await getSlots(requestId, request.ask.slots)
|
||||
let block = await getBlock(blockHash)
|
||||
// populate temp map to constrain state update volume
|
||||
// reqs.set(requestId, {
|
||||
// ...request,
|
||||
// state,
|
||||
// slots: [],
|
||||
// requestedAt: block.timestamp,
|
||||
// requestFinishedId: null
|
||||
// })
|
||||
requests.value.set(requestId, {
|
||||
...request,
|
||||
state,
|
||||
slots,
|
||||
requestedAt: block.timestamp,
|
||||
requestFinishedId: null
|
||||
})
|
||||
await addRequest(requestId, blockHash)
|
||||
console.log(`got details for ${i} in ${(Date.now() - start) / 1000} seconds`)
|
||||
if (i === events.length - 1) {
|
||||
loading.value = false
|
||||
@ -127,32 +127,59 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
if (events.length === 0) {
|
||||
loading.value = false
|
||||
}
|
||||
// reqs.forEach((request, requestId) => requests.value.set(requestId, request))
|
||||
} catch (error) {
|
||||
console.error(`failed to load past contract events: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchRequest(requestId) {
|
||||
let start = Date.now()
|
||||
console.log('fetching request ', requestId)
|
||||
const preFetched = requests.value.get(requestId)
|
||||
if (preFetched?.detailsFetched) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
let arrRequest = await marketplace.getRequest(requestId)
|
||||
let request = arrayToObject(arrRequest)
|
||||
let slots = await getSlots(requestId, request.ask.slots)
|
||||
const reqExisting = requests.value.get(requestId)
|
||||
requests.value.set(requestId, {
|
||||
...reqExisting, // state, requestedAt, requestFinishedId (null)
|
||||
...request,
|
||||
slots,
|
||||
detailsFetched: true
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`failed to load slots for request ${requestId}: ${error}`)
|
||||
throw error
|
||||
} finally {
|
||||
console.log(`fetched request in ${(Date.now() - start) / 1000}s`)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function updateRequestState(requestId, newState) {
|
||||
let { request, state, slots, requestFinishedId } = requests.value.get(requestId)
|
||||
let { state, ...rest } = requests.value.get(requestId)
|
||||
state = newState
|
||||
requests.value.set(requestId, { request, state, slots, requestFinishedId })
|
||||
requests.value.set(requestId, { state, ...rest })
|
||||
}
|
||||
|
||||
function updateRequestFinishedId(requestId, newRequestFinishedId) {
|
||||
let { request, state, slots, requestFinishedId } = requests.value.get(requestId)
|
||||
let { requestFinishedId, ...rest } = requests.value.get(requestId)
|
||||
requestFinishedId = newRequestFinishedId
|
||||
requests.value.set(requestId, { request, state, slots, requestFinishedId })
|
||||
requests.value.set(requestId, { requestFinishedId, ...rest })
|
||||
}
|
||||
|
||||
function updateRequestSlotState(requestId, slotIdx, newState) {
|
||||
let { request, state, slots, requestFinishedId } = requests.value.get(requestId)
|
||||
let { slots, ...rest } = requests.value.get(requestId)
|
||||
slots = slots.map((slot) => {
|
||||
if (slot.slotIdx == slotIdx) {
|
||||
slot.state = newState
|
||||
}
|
||||
})
|
||||
requests.value.set(requestId, { request, state, slots, requestFinishedId })
|
||||
requests.value.set(requestId, { slots, ...rest })
|
||||
}
|
||||
|
||||
function waitForRequestFinished(requestId, duration, onRequestFinished) {
|
||||
@ -184,22 +211,11 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
) {
|
||||
marketplace.on(StorageRequested, async (requestId, ask, expiry, event) => {
|
||||
let { blockNumber, blockHash } = event.log
|
||||
let arrRequest = await marketplace.getRequest(requestId)
|
||||
let request = arrayToObject(arrRequest)
|
||||
let state = await getRequestState(requestId)
|
||||
let slots = await getSlots(requestId, request.ask.slots)
|
||||
let block = await getBlock(blockHash)
|
||||
requests.value.set(requestId, {
|
||||
...request,
|
||||
state,
|
||||
slots,
|
||||
requestedAt: block.timestamp,
|
||||
requestFinishedId: null
|
||||
})
|
||||
const request = addRequest(requestId, blockHash)
|
||||
|
||||
// callback
|
||||
if (onStorageRequested) {
|
||||
onStorageRequested(blockNumber, requestId, request, state)
|
||||
onStorageRequested(blockNumber, requestId, request.state)
|
||||
}
|
||||
})
|
||||
|
||||
@ -254,11 +270,6 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
})
|
||||
}
|
||||
|
||||
// const eventsByBlock = computed(() =>)
|
||||
// const doubleCount = computed(() => count.value * 2)
|
||||
// function increment() {
|
||||
// count.value++
|
||||
// }
|
||||
return {
|
||||
requests,
|
||||
// slots,
|
||||
@ -270,7 +281,8 @@ export const useRequestsStore = defineStore('request', () => {
|
||||
// requestCancelledEvents,
|
||||
// requestFailedEvents,
|
||||
// requestFinishedEvents,
|
||||
fetch,
|
||||
fetchPastRequests,
|
||||
fetchRequest,
|
||||
listenForNewEvents,
|
||||
loading
|
||||
}
|
||||
|
||||
@ -10,32 +10,43 @@ const requestsStore = useRequestsStore()
|
||||
const { requests, loading } = storeToRefs(requestsStore)
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const isLoading = computed(() => loading.value)
|
||||
const requestId = ref(route.params.requestId)
|
||||
const request = ref(requests?.value?.get(requestId.value))
|
||||
const requestNotFound = computed(
|
||||
() =>
|
||||
!isLoading.value && requests.value !== undefined && !requests.value.get(route.params.requestId)
|
||||
)
|
||||
function getRequestFromStore(_) {
|
||||
let req = requests?.value?.get(route.params.requestId)
|
||||
if (requestNotFound.value) {
|
||||
const request = ref(undefined)
|
||||
|
||||
async function fetch(requestId) {
|
||||
try {
|
||||
await requestsStore.fetchRequest(requestId)
|
||||
} catch (error) {
|
||||
if (error.message.includes('Unknown request')) {
|
||||
router.push({ name: 'NotFound' })
|
||||
} else {
|
||||
request.value = req
|
||||
}
|
||||
}
|
||||
request.value = requests.value.get(requestId)
|
||||
}
|
||||
|
||||
const hasRequest = computed(() => {
|
||||
return request.value !== undefined
|
||||
})
|
||||
|
||||
watch(() => route.params.requestId, fetch)
|
||||
|
||||
if (loading.value) {
|
||||
watch(
|
||||
() => loading.value,
|
||||
(isLoading) => {
|
||||
if (!isLoading) {
|
||||
fetch(route.params.requestId)
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
} else {
|
||||
fetch(route.params.requestId)
|
||||
}
|
||||
watch(() => route.params.requestId, getRequestFromStore)
|
||||
watch(() => isLoading.value, getRequestFromStore)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<SkeletonLoading v-if="isLoading" type="image" />
|
||||
<StorageRequest
|
||||
v-else-if="!requestNotFound"
|
||||
:requestId="route.params.requestId"
|
||||
:request="request"
|
||||
/>
|
||||
<SkeletonLoading v-if="loading" type="image" />
|
||||
<StorageRequest v-else-if="hasRequest" :requestId="route.params.requestId" :request="request" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -3,16 +3,14 @@ import { storeToRefs } from 'pinia'
|
||||
import { useRequestsStore } from '@/stores/requests'
|
||||
import StorageRequests from '@/components/StorageRequests.vue'
|
||||
import SkeletonLoading from '@/components/SkeletonLoading.vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const requestsStore = useRequestsStore()
|
||||
const { loading, requests } = storeToRefs(requestsStore)
|
||||
const isLoading = computed(() => loading.value || !requests.value)
|
||||
const { loading } = storeToRefs(requestsStore)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<SkeletonLoading v-if="isLoading" type="text" />
|
||||
<SkeletonLoading v-if="loading" type="text" />
|
||||
<StorageRequests v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user