mirror of
https://github.com/unraid/api.git
synced 2025-12-31 13:39:52 -06:00
feat(web): add loading and error states to notification sidebar
This commit is contained in:
committed by
Pujit Mehrotra
parent
af1994cb62
commit
060fb91546
12
web/components/Loading/Bar.vue
Normal file
12
web/components/Loading/Bar.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '~/components/shadcn/utils';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{ class?: string }>(), { class: '' });
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="cn('h-5 animate-pulse bg-gray-300 w-full', props.class)"
|
||||||
|
role="progressbar"
|
||||||
|
aria-label="Loading"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
19
web/components/Loading/Spinner.vue
Normal file
19
web/components/Loading/Spinner.vue
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '~/components/shadcn/utils';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{ class?: string }>(), { class: '' });
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<!-- adapted from https://tw-elements.com/docs/standard/components/spinners/ -->
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'inline-block h-8 w-8 animate-spin rounded-full border-2 border-solid border-current border-e-transparent align-[-0.125em] text-primary motion-reduce:animate-[spin_1.5s_linear_infinite]',
|
||||||
|
props.class
|
||||||
|
)
|
||||||
|
"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { CheckIcon } from '@heroicons/vue/24/solid';
|
import { CheckIcon, ShieldExclamationIcon } from '@heroicons/vue/24/solid';
|
||||||
import { useQuery } from '@vue/apollo-composable';
|
import { useQuery } from '@vue/apollo-composable';
|
||||||
import { vInfiniteScroll } from '@vueuse/components';
|
import { vInfiniteScroll } from '@vueuse/components';
|
||||||
import { useFragment } from '~/composables/gql/fragment-masking';
|
import { useFragment } from '~/composables/gql/fragment-masking';
|
||||||
@@ -28,7 +28,7 @@ watch(props, () => {
|
|||||||
canLoadMore.value = true;
|
canLoadMore.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const { result, error, fetchMore } = useQuery(getNotifications, () => ({
|
const { result, error, loading, fetchMore } = useQuery(getNotifications, () => ({
|
||||||
filter: {
|
filter: {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: props.pageSize,
|
limit: props.pageSize,
|
||||||
@@ -69,10 +69,6 @@ async function onLoadMore() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="notifications?.length === 0" class="h-full flex flex-col items-center justify-center gap-3">
|
|
||||||
<CheckIcon class="h-10 text-green-600" />
|
|
||||||
{{ `No ${props.importance?.toLowerCase() ?? ''} notifications to see here!` }}
|
|
||||||
</div>
|
|
||||||
<!-- The horizontal padding here adjusts for the scrollbar offset -->
|
<!-- The horizontal padding here adjusts for the scrollbar offset -->
|
||||||
<div
|
<div
|
||||||
v-if="notifications?.length > 0"
|
v-if="notifications?.length > 0"
|
||||||
@@ -84,5 +80,29 @@ async function onLoadMore() {
|
|||||||
:key="notification.id"
|
:key="notification.id"
|
||||||
v-bind="notification"
|
v-bind="notification"
|
||||||
/>
|
/>
|
||||||
|
<div v-if="loading" class="py-5 grid place-content-center">
|
||||||
|
<LoadingSpinner />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="h-full flex flex-col items-center justify-center gap-3">
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div v-if="loading" class="contents">
|
||||||
|
<LoadingSpinner />
|
||||||
|
<p>Loading Notifications...</p>
|
||||||
|
</div>
|
||||||
|
<!-- Error State -->
|
||||||
|
<div v-else-if="error" class="flex gap-3">
|
||||||
|
<ShieldExclamationIcon class="h-10 text-unraid-red translate-y-1" />
|
||||||
|
<div>
|
||||||
|
<h3 class="font-bold">{{ `Error` }}</h3>
|
||||||
|
<p>{{ error.message }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Empty State -->
|
||||||
|
<div v-else-if="notifications?.length === 0" class="contents">
|
||||||
|
<CheckIcon class="h-10 text-green-600 translate-y-3" />
|
||||||
|
{{ `No ${props.importance?.toLowerCase() ?? ''} notifications to see here!` }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user