Skip to content

Commit 7f4947e

Browse files
author
Pascal Klesse
committed
feat: add global polling indicator to track active data sync requests
1 parent 78cb448 commit 7f4947e

File tree

4 files changed

+57
-0
lines changed

4 files changed

+57
-0
lines changed

projects/app/src/components/Header.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ async function uploadTemplate(e: any) {
9292
</div>
9393
</div>
9494
<div class="flex flex-1 items-center justify-end gap-x-5">
95+
<PollingIndicator />
9596
<div class="hidden lg:flex text-white/80">
9697
{{ version }}
9798
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import { usePollingState } from '~/states/polling';
3+
4+
const { isPolling } = usePollingState();
5+
</script>
6+
7+
<template>
8+
<Transition name="fade">
9+
<div v-if="isPolling" class="flex items-center" title="Syncing data...">
10+
<span class="i-bi-arrow-repeat text-lg text-primary-500 animate-spin"></span>
11+
</div>
12+
</Transition>
13+
</template>
14+
15+
<style scoped>
16+
.fade-enter-active,
17+
.fade-leave-active {
18+
transition: opacity 0.2s ease;
19+
}
20+
21+
.fade-enter-from,
22+
.fade-leave-to {
23+
opacity: 0;
24+
}
25+
</style>

projects/app/src/composables/use-polling.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { PollingOptions, PollingReturn } from '~/interfaces/polling.interface';
22

3+
import { usePollingState } from '~/states/polling';
4+
35
/**
46
* Composable for sequential polling that waits for the previous request to complete
57
* before starting the next interval timer.
@@ -26,6 +28,7 @@ export function usePolling(fn: () => Promise<unknown>, options: PollingOptions):
2628
// Variables
2729
// ============================================================================
2830
const { immediate = true, interval, maxConsecutiveErrors = 3, onError } = options;
31+
const { decrement, increment } = usePollingState();
2932

3033
const errorCount = ref<number>(0);
3134
const isActive = ref<boolean>(immediate);
@@ -58,6 +61,7 @@ export function usePolling(fn: () => Promise<unknown>, options: PollingOptions):
5861
}
5962

6063
isPending.value = true;
64+
increment();
6165

6266
try {
6367
await fn();
@@ -76,6 +80,7 @@ export function usePolling(fn: () => Promise<unknown>, options: PollingOptions):
7680
}
7781
} finally {
7882
isPending.value = false;
83+
decrement();
7984

8085
if (isActive.value) {
8186
scheduleNext();

projects/app/src/states/polling.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Global polling state to track active polling requests across the app
3+
*/
4+
const pollingState = () => useState<number>('polling_active_count', () => 0);
5+
6+
export function usePollingState() {
7+
const activeCount = pollingState();
8+
const isPolling = computed<boolean>(() => activeCount.value > 0);
9+
10+
function increment(): void {
11+
activeCount.value++;
12+
}
13+
14+
function decrement(): void {
15+
if (activeCount.value > 0) {
16+
activeCount.value--;
17+
}
18+
}
19+
20+
return {
21+
activeCount: readonly(activeCount),
22+
decrement,
23+
increment,
24+
isPolling,
25+
};
26+
}

0 commit comments

Comments
 (0)