|
24 | 24 | import Card from '../card.svelte';
|
25 | 25 | import SkeletonRepoList from './skeletonRepoList.svelte';
|
26 | 26 | import { onMount, untrack, onDestroy } from 'svelte';
|
| 27 | + import { debounce } from '$lib/helpers/debounce'; |
27 | 28 |
|
28 | 29 | let {
|
29 | 30 | action = $bindable('select'),
|
|
48 | 49 | let isLoadingRepositories = $state(null);
|
49 | 50 | let installationsMap = $state(null);
|
50 | 51 |
|
51 |
| - // Debounce and race condition handling |
52 |
| - let searchTimeout: ReturnType<typeof setTimeout> | null = null; |
53 |
| - let currentRequestId = 0; |
54 |
| - let lastResolvedRequestId = 0; |
55 |
| -
|
56 | 52 | onMount(() => {
|
57 | 53 | loadInstallations();
|
58 | 54 | });
|
59 | 55 |
|
| 56 | + const debouncedLoadRepositories = debounce( |
| 57 | + async (installationId: string, searchTerm: string) => { |
| 58 | + isLoadingRepositories = true; |
| 59 | + try { |
| 60 | + await loadRepositories(installationId, searchTerm); |
| 61 | + } finally { |
| 62 | + isLoadingRepositories = false; |
| 63 | + } |
| 64 | + }, |
| 65 | + 300 |
| 66 | + ); |
| 67 | +
|
60 | 68 | $effect(() => {
|
61 | 69 | if (selectedInstallation && search !== undefined) {
|
62 |
| - if (searchTimeout) { |
63 |
| - clearTimeout(searchTimeout); |
64 |
| - } |
65 |
| - searchTimeout = setTimeout(() => { |
66 |
| - if (selectedInstallation) { |
67 |
| - isLoadingRepositories = true; |
68 |
| - const requestId = ++currentRequestId; |
69 |
| - loadRepositories(selectedInstallation, search) |
70 |
| - .then(() => { |
71 |
| - if (requestId > lastResolvedRequestId) { |
72 |
| - lastResolvedRequestId = requestId; |
73 |
| - isLoadingRepositories = false; |
74 |
| - } |
75 |
| - }) |
76 |
| - .catch(() => { |
77 |
| - if (requestId > lastResolvedRequestId) { |
78 |
| - lastResolvedRequestId = requestId; |
79 |
| - isLoadingRepositories = false; |
80 |
| - } |
81 |
| - }); |
82 |
| - } |
83 |
| - }, 300); |
| 70 | + debouncedLoadRepositories(selectedInstallation, search); |
84 | 71 | }
|
85 | 72 | });
|
86 | 73 |
|
87 | 74 | onDestroy(() => {
|
88 |
| - if (searchTimeout) clearTimeout(searchTimeout); |
| 75 | + debouncedLoadRepositories.cancel?.(); |
89 | 76 | });
|
90 | 77 |
|
91 | 78 | async function loadInstallations() {
|
|
188 | 175 | installationsMap.find((entry) => entry.$id === selectedInstallation)
|
189 | 176 | );
|
190 | 177 |
|
191 |
| - if (searchTimeout) { |
192 |
| - clearTimeout(searchTimeout); |
193 |
| - } |
| 178 | + debouncedLoadRepositories.cancel?.(); |
194 | 179 | }}
|
195 | 180 | bind:value={selectedInstallation} />
|
196 | 181 | <InputSearch
|
|
0 commit comments