mirror of
https://github.com/unraid/api.git
synced 2025-12-30 21:19:49 -06:00
refactor(web): add container for loading & error states
This commit is contained in:
committed by
Pujit Mehrotra
parent
060fb91546
commit
a3b171f58d
55
web/components/Loading/Error.vue
Normal file
55
web/components/Loading/Error.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { ShieldExclamationIcon } from '@heroicons/vue/24/solid';
|
||||
import { cn } from '~/components/shadcn/utils';
|
||||
|
||||
/**
|
||||
* A default container for displaying loading and error states.
|
||||
*
|
||||
* By default, this component will expand to full height and display contents
|
||||
* in the center of the container.
|
||||
*
|
||||
* Any slot/child will only render when a loading/error state isn't displayed.
|
||||
*
|
||||
* Exposes a 'retry' event (user-triggered during error state).
|
||||
*
|
||||
* @example
|
||||
* <LoadingError @retry="retryFunction" :loading="loading" :error="error" />
|
||||
*
|
||||
* <LoadingError :loading="loading" :error="error">
|
||||
* <p>Only displayed when both loading and error are false.</p>
|
||||
* </LoadingError>
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
class?: string;
|
||||
/** hasdfsa */
|
||||
loading: boolean;
|
||||
error: Error | null | undefined;
|
||||
}>(),
|
||||
{ class: '' }
|
||||
);
|
||||
|
||||
defineEmits(['retry']);
|
||||
</script>
|
||||
<template>
|
||||
<div :class="cn('h-full flex flex-col items-center justify-center gap-3', props.class)">
|
||||
<!-- Loading State -->
|
||||
<div v-if="loading" class="contents">
|
||||
<LoadingSpinner />
|
||||
<p>Loading Notifications...</p>
|
||||
</div>
|
||||
<!-- Error State -->
|
||||
<div v-else-if="error" class="space-y-3">
|
||||
<div class="flex justify-center">
|
||||
<ShieldExclamationIcon class="h-10 text-unraid-red" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold">{{ `Error` }}</h3>
|
||||
<p>{{ error.message }}</p>
|
||||
</div>
|
||||
<Button type="button" class="w-full" @click="$emit('retry')">Try Again</Button>
|
||||
</div>
|
||||
<!-- Default state -->
|
||||
<slot v-else />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { CheckIcon, ShieldExclamationIcon } from '@heroicons/vue/24/solid';
|
||||
import { CheckIcon } from '@heroicons/vue/24/solid';
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import { vInfiniteScroll } from '@vueuse/components';
|
||||
import { useFragment } from '~/composables/gql/fragment-masking';
|
||||
@@ -28,7 +28,7 @@ watch(props, () => {
|
||||
canLoadMore.value = true;
|
||||
});
|
||||
|
||||
const { result, error, loading, fetchMore } = useQuery(getNotifications, () => ({
|
||||
const { result, error, loading, fetchMore, refetch } = useQuery(getNotifications, () => ({
|
||||
filter: {
|
||||
offset: 0,
|
||||
limit: props.pageSize,
|
||||
@@ -85,24 +85,10 @@ async function onLoadMore() {
|
||||
</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">
|
||||
<LoadingError v-else :loading="loading" :error="error" @retry="refetch">
|
||||
<div v-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>
|
||||
</LoadingError>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user