Commit 126cf22
fix(client): thread deletion fixes and load all available threads (#77)
* fix(client): prevent deleted threads from reappearing via API polling
After deletion, the Amp internal API has eventual consistency — deleted
threads may still appear in listThreads results for a brief period.
This caused threads to reappear in the UI after the 30s auto-refresh
poll re-fetched the list, making deletion appear broken.
Track recently-deleted thread IDs with a 2-minute grace period and
filter them from all fetch results, preventing zombie threads from
resurfacing during the API consistency lag.
Co-authored-by: Amp <amp@ampcode.com>
* fix(client): load all available threads instead of first 50
The client was requesting only 50 threads from the server, but the
server fetches up to 500 from the Amp API. This meant users with many
threads only saw ~42 entries (50 minus stacked children), and deleting
a thread appeared to have no effect on the count because a previously-
hidden thread would backfill into the 50-thread window.
Now requests limit=500 to match the server's Amp API cap, showing all
available threads. The Amp API hard-caps at 500 — no pagination support
— so this is the maximum we can display.
Co-authored-by: Amp <amp@ampcode.com>
* fix: paginate Amp API to load 1000 threads, stop premature refetch on bulk ops
Three changes:
1. Paginate the Amp listThreads API using offset to fetch up to 1000
threads (the API caps at 500 per request). Previously only the
first 500 were loaded.
2. Move refetch() in bulk delete/archive to only fire on failure.
Previously refetch() ran unconditionally after bulk operations,
which would immediately re-fetch the full list and undo the
optimistic removal before the server finished processing.
3. Bump client request limit from 500 to 1000 to match.
Co-authored-by: Amp <amp@ampcode.com>
* fix(client): prevent thread backfill after deletion
When deleting a thread with 1000+ total threads, the Amp API would
return a new thread from beyond the original window to replace the
deleted one, keeping the count unchanged despite the deletion.
Fix: snapshot the set of known thread IDs before the first delete.
While deletes are pending (2-minute grace period), only show threads
from the known set — filtering both the deleted thread and any
backfill. Genuinely new threads (created after the delete) are still
allowed through.
Co-authored-by: Amp <amp@ampcode.com>
* feat: lazy-load threads with auto-pagination and total count display
Start with 500 threads (1 API call). When user navigates to the last
page, automatically load the next 500. Shows total count in the
pagination bar: 'Showing 1-25 of 465 threads (1,000 total)'.
Server changes:
- getThreads uses offset-based pagination (replaces cursor-based)
- listAllThreads accepts limit param, fetches only what's needed
- hasMore based on whether full limit was returned
- totalCount reflects actual loaded thread count
Client changes:
- useThreads starts with 500, loadMore adds 500 more
- ThreadList auto-triggers loadMore when reaching last page
- PaginationBar shows total count when it differs from loaded count
Co-authored-by: Amp <amp@ampcode.com>
* fix(ui): show '465+' instead of misleading total count
Replace '(500 total)' / '(1,000 total)' with a simple '+' suffix
on the thread count when more are available. Shows 'Showing 1-25 of
465+ threads' until all threads are loaded, then drops the '+'.
Remove unused totalCount/serverTotalCount props.
Co-authored-by: Amp <amp@ampcode.com>
* feat(ui): show 'Loading more…' in pagination while fetching next batch
Wire loadingMore state through the context chain to PaginationBar.
When auto-load triggers on the last page, the page indicator shows
'Loading more…' instead of 'Page X of Y'.
Co-authored-by: Amp <amp@ampcode.com>
* fix: increase initial batch to 1000, fix lazy-load UX
- Bump BATCH_SIZE from 500→1000 to capture all top-level threads
upfront (handoff stacking collapses ~530 children into existing
entries, so 500 extra threads only added ~8 visible entries)
- Change auto-load from useEffect-based to click-based: load more
only triggers when user clicks » or »» past the last page, not
automatically on reaching it (prevents infinite loop)
- Keep » and »» enabled on last page when hasMore is true so user
can explicitly request more data
Co-authored-by: Amp <amp@ampcode.com>
* fix: remove lazy-load pagination, keep simple 1000-thread upfront load
The lazy-load-on-paginate approach didn't work well because handoff
stacking absorbs most additional threads into existing entries — loading
500 more threads only added ~8 visible entries, making it seem broken.
Simplified to: load 1000 threads upfront (2 API calls), show '465+'
to indicate more raw threads exist as stacked children. Standard
pagination buttons with normal disabled behavior on last page.
Co-authored-by: Amp <amp@ampcode.com>
* fix(ui): remove misleading '+' from thread count
The '+' suffix implied more threads could be loaded, but handoff
stacking means all meaningful top-level threads are already visible
with the 1000-thread fetch. Loading more only adds ~8 entries since
extra threads are children absorbed into existing stacks.
Now shows a clean '465 threads' count.
Co-authored-by: Amp <amp@ampcode.com>
* refactor: load all threads, remove anti-backfill complexity
Load all threads from the Amp API (paginating internally at 500/call)
instead of capping at 1000 with anti-backfill workarounds. After the
bulk delete, thread count is ~496 which fits in a single API call.
Removes: knownIdsRef, deletedIdsRef, lastDeleteTimeRef, pruneDeleted,
loadMore, hasMore, totalCount, loadingMore — all the complexity added
to work around partial loading. The hook is now ~90 lines instead of
~165.
Delete now works simply: optimistic removal + server delete. The next
poll shows the real state with no backfill because ALL threads are
loaded.
Co-authored-by: Amp <amp@ampcode.com>
* fix(threads): replace broken API pagination with hybrid API+local loading
The Amp internal API's offset parameter is silently ignored — it always
returns the same threads regardless of offset value. The pagination loop
in listThreads() never actually paginated.
Changes:
- listThreads(): single API call with limit=500 (API max), no loop
- listAllThreads(): hybrid approach — API for up to 500 threads, then
supplements with local thread files not in the API response
- Local file scan only triggers when API returns its max (500), meaning
there are likely more threads on disk
- Remove unused limit/cursor params from getThreads() and route handler
- Client no longer sends limit=10000 query param
Co-authored-by: Amp <amp@ampcode.com>
* fix(threads): always scan local files, not just when API returns 500
The conditional scan missed older threads when API returned <500
(e.g., after archiving/deleting). Local file scan is fast and
ensures threads beyond the API's 500 limit are always visible.
Co-authored-by: Amp <amp@ampcode.com>
* fix(threads): delete local thread JSON file on delete to prevent zombie threads
cleanupThreadFiles() deleted artifacts and SQLite records but left the
thread JSON file in THREADS_DIR. After the hybrid loading change, the
local file scan would rediscover deleted threads on the next poll.
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: Amp <amp@ampcode.com>1 parent 7d368fa commit 126cf22
File tree
6 files changed
+152
-82
lines changed- server
- lib
- routes
- src/hooks
6 files changed
+152
-82
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
178 | | - | |
179 | | - | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
180 | 192 | | |
181 | 193 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
| 17 | + | |
26 | 18 | | |
27 | 19 | | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | 20 | | |
40 | | - | |
41 | | - | |
42 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
43 | 24 | | |
44 | 25 | | |
45 | 26 | | |
| |||
121 | 102 | | |
122 | 103 | | |
123 | 104 | | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
124 | 109 | | |
125 | 110 | | |
126 | 111 | | |
| |||
139 | 124 | | |
140 | 125 | | |
141 | 126 | | |
| 127 | + | |
142 | 128 | | |
143 | 129 | | |
144 | 130 | | |
| 131 | + | |
145 | 132 | | |
146 | 133 | | |
147 | 134 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
52 | 60 | | |
53 | | - | |
| 61 | + | |
54 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
55 | 70 | | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
| 71 | + | |
60 | 72 | | |
61 | 73 | | |
62 | 74 | | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
63 | 82 | | |
64 | 83 | | |
65 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
66 | 164 | | |
67 | 165 | | |
68 | 166 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
39 | | - | |
| 37 | + | |
40 | 38 | | |
41 | 39 | | |
42 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| 148 | + | |
148 | 149 | | |
149 | | - | |
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| |||
171 | 171 | | |
172 | 172 | | |
173 | 173 | | |
| 174 | + | |
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
177 | 178 | | |
| 179 | + | |
178 | 180 | | |
179 | | - | |
180 | 181 | | |
181 | 182 | | |
182 | 183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | 11 | | |
13 | | - | |
14 | | - | |
15 | 12 | | |
16 | 13 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
| 14 | + | |
| 15 | + | |
23 | 16 | | |
24 | 17 | | |
25 | 18 | | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
| 19 | + | |
30 | 20 | | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
48 | 33 | | |
49 | | - | |
50 | | - | |
51 | | - | |
| 34 | + | |
| 35 | + | |
52 | 36 | | |
53 | 37 | | |
54 | 38 | | |
| |||
59 | 43 | | |
60 | 44 | | |
61 | 45 | | |
62 | | - | |
63 | 46 | | |
64 | 47 | | |
65 | 48 | | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | 49 | | |
73 | 50 | | |
74 | 51 | | |
| |||
79 | 56 | | |
80 | 57 | | |
81 | 58 | | |
82 | | - | |
| 59 | + | |
83 | 60 | | |
84 | 61 | | |
85 | 62 | | |
| |||
94 | 71 | | |
95 | 72 | | |
96 | 73 | | |
97 | | - | |
| 74 | + | |
98 | 75 | | |
99 | 76 | | |
100 | 77 | | |
| |||
111 | 88 | | |
112 | 89 | | |
113 | 90 | | |
114 | | - | |
115 | 91 | | |
116 | | - | |
117 | | - | |
118 | | - | |
| 92 | + | |
119 | 93 | | |
120 | 94 | | |
121 | 95 | | |
0 commit comments