feat(webhooks): paginate list + call-history endpoints (server + web UI) (#1268)

Add total-count pagination to the webhook admin endpoints and the web UI.

Store:
- WebhookStore/WebhookCallStore gain Count; WebhookListFilter gains
  IncludeRevoked + Query (PG + SQLite, parameterized, tenant-scoped)

API:
- GET /v1/webhooks and GET /v1/webhooks/{id}/calls return
  {items, total, limit, offset} with server-side search + revoked filtering

Web UI:
- server-driven list pager + search/revoked filter; call-history dialog uses
  the real total (fixes the full-page "has more" boundary bug)
- i18n pager labels (en/vi/zh)

Tests: store pagination integration test; mock stores implement Count.
No schema migration (read-only COUNT).
This commit is contained in:
thotam authored and GitHub committed 2026-06-24 10:39:24 +07:00
1 parent 2945d4db6c
commit 06ef06ca37
22 files changed
+472 -54

No files matched your search

+14 -3
View File
@@ -89,6 +89,14 @@ func (s *adminWebhookStore) List(ctx context.Context, f store.WebhookListFilter)
return out, nil
}
func (s *adminWebhookStore) Count(ctx context.Context, f store.WebhookListFilter) (int, error) {
rows, err := s.List(ctx, f)
if err != nil {
return 0, err
}
return len(rows), nil
}
func (s *adminWebhookStore) Update(_ context.Context, id uuid.UUID, updates map[string]any) error {
s.mu.Lock()
defer s.mu.Unlock()
@@ -537,12 +545,15 @@ func TestWebhookAdmin_FullFlow_CreateListGetRotateRevoke(t *testing.T) {
if w.Code != http.StatusOK {
t.Fatalf("list: want 200, got %d: %s", w.Code, w.Body.String())
}
var rows []store.WebhookData
if err := json.NewDecoder(w.Body).Decode(&rows); err != nil {
var body struct {
Items []store.WebhookData `json:"items"`
Total int `json:"total"`
}
if err := json.NewDecoder(w.Body).Decode(&body); err != nil {
t.Fatalf("list decode: %v", err)
}
found := false
for _, row := range rows {
for _, row := range body.Items {
if row.ID == id {
found = true
}