Skip to content

Commit 03c1df1

Browse files
committed
feat: add skeleton to the task info page
1 parent 1138c01 commit 03c1df1

File tree

3 files changed

+150
-32
lines changed

3 files changed

+150
-32
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script setup lang="ts">
2+
import type { HTMLAttributes } from "vue"
3+
import { cn } from "@/lib/utils"
4+
5+
interface SkeletonProps {
6+
class?: HTMLAttributes["class"]
7+
}
8+
9+
const props = defineProps<SkeletonProps>()
10+
</script>
11+
12+
<template>
13+
<div
14+
data-slot="skeleton"
15+
:class="cn('animate-pulse rounded-md bg-primary/10', props.class)"
16+
/>
17+
</template>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as Skeleton } from "./Skeleton.vue"

app/pages/tasks/[id].vue

Lines changed: 132 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<script setup lang="ts">
2+
import { computed, ref, watch } from 'vue'
23
import { toast } from 'vue-sonner'
34
import { formatDate } from '~/lib/utils'
45
import { Button } from '~/components/ui/button'
56
import { CopyIcon, LoaderCircleIcon } from 'lucide-vue-next'
67
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
8+
import { Skeleton } from '@/components/ui/skeleton'
79
import { useIntervalFn } from '@vueuse/core'
810
import { useRoute, useRouter } from 'vue-router'
911
import { useFetch } from '#imports'
@@ -14,15 +16,26 @@ const router = useRouter()
1416
const {
1517
data: task,
1618
error,
17-
refresh
19+
refresh,
20+
pending
1821
} = useFetch<TaskSelect>(`/api/tasks/${route.params.id}`)
1922
const copyToClipboard = (value: string) => {
2023
navigator.clipboard.writeText(value)
2124
}
2225
2326
useIntervalFn(() => {
2427
refresh()
25-
}, 1500)
28+
}, 2000)
29+
30+
const hasLoadedOnce = ref(Boolean(task.value))
31+
32+
watch(task, (current) => {
33+
if (current) {
34+
hasLoadedOnce.value = true
35+
}
36+
})
37+
38+
const isLoading = computed(() => !hasLoadedOnce.value)
2639
2740
const handleCopy = (value: string) => {
2841
copyToClipboard(value)
@@ -50,80 +63,167 @@ const handleCopy = (value: string) => {
5063
</CardHeader>
5164
<CardContent>
5265
<table>
53-
<tbody v-if="task">
66+
<tbody>
5467
<tr>
5568
<th>ID</th>
5669
<td class="flex items-center justify-start gap-2">
57-
<span>{{ task.id }}</span>
58-
<Button
59-
@click="handleCopy(task.id)"
60-
class="cursor-pointer"
61-
variant="ghost"
62-
><CopyIcon
63-
/></Button>
70+
<template v-if="!isLoading">
71+
<span>{{ task?.id }}</span>
72+
<Button
73+
@click="task && handleCopy(task.id)"
74+
class="cursor-pointer"
75+
variant="ghost"
76+
>
77+
<CopyIcon />
78+
</Button>
79+
</template>
80+
<Skeleton
81+
v-else
82+
class="h-4 w-50"
83+
/>
6484
</td>
6585
</tr>
6686
<tr>
6787
<th>Name</th>
68-
<td>{{ task.name }}</td>
88+
<td>
89+
<template v-if="!isLoading">
90+
{{ task?.name }}
91+
</template>
92+
<Skeleton
93+
v-else
94+
class="h-4 w-80"
95+
/>
96+
</td>
6997
</tr>
7098

7199
<tr>
72100
<th>State</th>
73101
<td>
74-
<TaskState :state="task.state" />
102+
<template v-if="!isLoading && task">
103+
<TaskState :state="task.state" />
104+
</template>
105+
<Skeleton
106+
v-else
107+
class="h-4 w-24"
108+
/>
75109
</td>
76110
</tr>
77111
<tr>
78112
<th>args</th>
79-
<td>{{ task.args }}</td>
113+
<td>
114+
<template v-if="!isLoading">
115+
{{ task?.args }}
116+
</template>
117+
<Skeleton
118+
v-else
119+
class="h-4 w-full max-w-2xl"
120+
/>
121+
</td>
80122
</tr>
81123
<tr>
82124
<th>kwargs</th>
83-
<td>{{ task.kwargs }}</td>
125+
<td>
126+
<template v-if="!isLoading">
127+
{{ task?.kwargs }}
128+
</template>
129+
<Skeleton
130+
v-else
131+
class="h-4 w-full max-w-2xl"
132+
/>
133+
</td>
84134
</tr>
85135
<tr>
86136
<th>Return Value</th>
87137
<td>
88-
{{
89-
task.returnValue?.return_value
90-
? task.returnValue?.return_value
91-
: 'null'
92-
}}
138+
<template v-if="!isLoading">
139+
{{
140+
task?.returnValue?.return_value
141+
? task?.returnValue?.return_value
142+
: 'null'
143+
}}
144+
</template>
145+
<Skeleton
146+
v-else
147+
class="h-4 w-80"
148+
/>
93149
</td>
94150
</tr>
95151
<tr>
96152
<th>Queued At</th>
97-
<td>{{ formatDate(String(task.queuedAt), true) }}</td>
153+
<td>
154+
<template v-if="!isLoading">
155+
{{ formatDate(String(task?.queuedAt), true) }}
156+
</template>
157+
<Skeleton
158+
v-else
159+
class="h-4 w-40"
160+
/>
161+
</td>
98162
</tr>
99163
<tr>
100164
<th>Started At</th>
101-
<td v-if="task.startedAt">
102-
{{ formatDate(String(task.startedAt), true) }}
103-
</td>
104-
<td v-else>
105-
<LoaderCircleIcon class="animate-spin" />
165+
<td>
166+
<template v-if="isLoading">
167+
<Skeleton class="h-4 w-40" />
168+
</template>
169+
<template v-else-if="task?.startedAt">
170+
{{ formatDate(String(task.startedAt), true) }}
171+
</template>
172+
<template v-else>
173+
<LoaderCircleIcon class="animate-spin" />
174+
</template>
106175
</td>
107176
</tr>
108177
<tr>
109178
<th>Finished At</th>
110-
<td v-if="task.state === 'running'">
111-
<LoaderCircleIcon class="animate-spin" />
179+
<td>
180+
<template v-if="isLoading">
181+
<Skeleton class="h-4 w-40" />
182+
</template>
183+
<template v-else-if="task?.state === 'running'">
184+
<LoaderCircleIcon class="animate-spin" />
185+
</template>
186+
<template v-else-if="task?.state === 'abandoned'"></template>
187+
<template v-else>
188+
{{ formatDate(String(task?.finishedAt), true) }}
189+
</template>
112190
</td>
113-
<td v-else-if="task.state === 'abandoned'"></td>
114-
<td v-else>{{ formatDate(String(task.finishedAt), true) }}</td>
115191
</tr>
116192
<tr>
117193
<th>Error</th>
118-
<td>{{ task.error }}</td>
194+
<td>
195+
<template v-if="!isLoading">
196+
{{ task?.error }}
197+
</template>
198+
<Skeleton
199+
v-else
200+
class="h-4 w-full max-w-2xl"
201+
/>
202+
</td>
119203
</tr>
120204
<tr>
121205
<th>Worker</th>
122-
<td>{{ task.worker }}</td>
206+
<td>
207+
<template v-if="!isLoading">
208+
{{ task?.worker }}
209+
</template>
210+
<Skeleton
211+
v-else
212+
class="h-4 w-32"
213+
/>
214+
</td>
123215
</tr>
124216
<tr>
125217
<th>Runtime</th>
126-
<td>{{ task.executionTime }}</td>
218+
<td>
219+
<template v-if="!isLoading">
220+
{{ task?.executionTime }}
221+
</template>
222+
<Skeleton
223+
v-else
224+
class="h-4 w-24"
225+
/>
226+
</td>
127227
</tr>
128228
</tbody>
129229
</table>

0 commit comments

Comments
 (0)