StorageRequest.vue
1 <script setup> 2 import { onMounted, computed } from 'vue' 3 import { useRouter } from 'vue-router' 4 import { initTooltips } from 'flowbite' 5 import { getStateColour, moderatedState, price, timestampsFor } from '@/utils/requests' 6 import { autoPluralize } from '@/utils/strings' 7 8 import CodexImage from '@/components/CodexImage.vue' 9 import StateIndicator from '@/components/StateIndicator.vue' 10 import RelativeTime from '@/components/RelativeTime.vue' 11 import ShortenValue from '@/components/ShortenValue.vue' 12 import Slots from './Slots.vue' 13 import SkeletonLoading from './SkeletonLoading.vue' 14 15 const router = useRouter() 16 const request = defineModel() 17 const emit = defineEmits(['updateModerated']) 18 const props = defineProps({ 19 requestId: { 20 type: String, 21 required: true 22 }, 23 enableModeration: { 24 type: Boolean, 25 default: false 26 }, 27 slotsLoading: { 28 type: Boolean, 29 default: false 30 }, 31 slotsFetched: { 32 type: Boolean, 33 default: false 34 } 35 }) 36 37 onMounted(() => { 38 initTooltips() 39 }) 40 41 const totalPrice = computed(() => price(request.value.request)) 42 const maxSlotLoss = computed(() => autoPluralize(request.value.request.ask.maxSlotLoss, 'slot')) 43 const slots = computed(() => autoPluralize(request.value.request.ask.slots, 'slot')) 44 const stateColour = computed(() => getStateColour(request.value.state)) 45 const timestamps = computed(() => { 46 let { requestedAt } = request.value 47 let { ask, expiry } = request.value.request 48 let { endsAt, expiresAt } = timestampsFor(ask, expiry, requestedAt) 49 return { 50 requested: requestedAt ? new Date(requestedAt * 1000) : undefined, 51 expires: requestedAt ? new Date(expiresAt * 1000) : undefined, 52 ends: requestedAt ? new Date(endsAt * 1000) : undefined 53 } 54 }) 55 const requestDetails = computed(() => request.value.request) 56 function updateEventModerated() { 57 emit('updateModerated', props.requestId, request.value.moderated) 58 } 59 </script> 60 61 <template> 62 <div class="flex flex-wrap"> 63 <CodexImage 64 class="flex-initial mx-auto my-4 min-w-sm max-w-md w-full rounded" 65 :cid="requestDetails.content.cid" 66 :moderated="enableModeration ? 'approved' : request.moderated" 67 ></CodexImage> 68 <div class="py-4 px-4 ml-4 max-w-2xl flex-1"> 69 <div 70 v-if="enableModeration === true" 71 class="flex flex-col space-between mb-4 p-5 w-full border border-gray-300 rounded-lg b-1 bg-gray-100 dark:bg-gray-800" 72 > 73 <label for="moderation" class="block mb-2 text-lg font-medium text-gray-900 dark:text-white" 74 >Moderation station</label 75 > 76 <div class="flex items-center justify-between space-x-4"> 77 <div class="flex-1"> 78 <select 79 id="moderation" 80 class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" 81 v-model="request.moderated" 82 @change="updateEventModerated" 83 > 84 <option v-for="(value, key) in moderatedState" :value="key" :key="key"> 85 {{ value.text }} 86 </option> 87 </select> 88 </div> 89 <StateIndicator 90 class="flex-none h-7 inline-block align-middle" 91 :text="moderatedState[request.moderated].text" 92 :color="moderatedState[request.moderated].color" 93 size="lg" 94 ></StateIndicator> 95 </div> 96 <a 97 :href="router.resolve({ path: `/request/${requestId}` }).href" 98 target="_blank" 99 class="mt-4 font-medium text-blue-600 dark:text-blue-500 hover:underline" 100 @click.stop 101 >Preview</a 102 > 103 </div> 104 <div class="flex justify-between items-center mb-2"> 105 <h2 class="text-xl font-semibold leading-none text-gray-900 md:text-2xl dark:text-white"> 106 Request <ShortenValue :value="requestId" :chars="8"></ShortenValue> 107 </h2> 108 <StateIndicator :text="request.state" :color="stateColour" size="lg"></StateIndicator> 109 </div> 110 <p 111 class="mb-4 text-xl font-extrabold leading-none text-gray-900 md:text-2xl dark:text-white flex justify-between" 112 > 113 {{ totalPrice }} CDX 114 </p> 115 <dl> 116 <dd class="mb-4 flex justify-between font-light text-gray-500 sm:mb-5 dark:text-gray-400"> 117 <div> 118 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Requested</dt> 119 <RelativeTime 120 v-if="timestamps.requested" 121 :timestamp="timestamps.requested" 122 ></RelativeTime> 123 </div> 124 <div> 125 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Expires</dt> 126 <RelativeTime v-if="timestamps.expires" :timestamp="timestamps.expires"></RelativeTime> 127 </div> 128 <div> 129 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Ends</dt> 130 <RelativeTime v-if="timestamps.ends" :timestamp="timestamps.ends"></RelativeTime> 131 </div> 132 </dd> 133 </dl> 134 <dl> 135 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Dataset CID</dt> 136 <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400"> 137 {{ requestDetails.content.cid }} 138 </dd> 139 </dl> 140 <dl> 141 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Client</dt> 142 <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400"> 143 {{ requestDetails.client }} 144 </dd> 145 </dl> 146 <dl> 147 <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Merkle root</dt> 148 <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400"> 149 {{ requestDetails.content.merkleRoot }} 150 </dd> 151 </dl> 152 <div class="relative overflow-x-auto overflow-y-auto max-h-screen mb-10"> 153 <table 154 class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 mx-auto" 155 > 156 <tbody> 157 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 158 <td 159 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 160 > 161 Expiry 162 </td> 163 <td class="px-6 py-2 font-light">{{ requestDetails.expiry }} seconds</td> 164 </tr> 165 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 166 <td 167 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 168 > 169 Duration 170 </td> 171 <td class="px-6 py-2 font-light">{{ requestDetails.ask.duration }} seconds</td> 172 </tr> 173 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 174 <td 175 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 176 > 177 Slot size 178 </td> 179 <td class="px-6 py-2 font-light">{{ requestDetails.ask.slotSize }} bytes</td> 180 </tr> 181 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 182 <td 183 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 184 > 185 Proof probability 186 </td> 187 <td class="px-6 py-2 font-light">{{ requestDetails.ask.proofProbability }}</td> 188 </tr> 189 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 190 <td 191 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 192 > 193 Reward 194 </td> 195 <td class="px-6 py-2 font-light">{{ requestDetails.ask.reward }} CDX</td> 196 </tr> 197 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 198 <td 199 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 200 > 201 Collateral 202 </td> 203 <td class="px-6 py-2 font-light">{{ requestDetails.ask.collateral }} CDX</td> 204 </tr> 205 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 206 <td 207 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 208 > 209 Slots 210 </td> 211 <td class="px-6 py-2 font-light">{{ slots }}</td> 212 </tr> 213 <tr class="hover:bg-gray-50 dark:hover:bg-gray-600 text-base"> 214 <td 215 class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white border-r" 216 > 217 Max slot loss 218 </td> 219 <td class="px-6 py-2 font-light"> 220 {{ maxSlotLoss }} 221 </td> 222 </tr> 223 </tbody> 224 </table> 225 </div> 226 227 <SkeletonLoading v-if="slotsLoading" type="text" /> 228 <Slots v-else-if="request.slots" :slots="request.slots"></Slots> 229 </div> 230 </div> 231 </template>