feat: top-up modal, pause/resume tracker, activity timeline, admin metrics#435
Merged
ogazboiz merged 1 commit intoLabsCrypt:mainfrom Apr 29, 2026
Conversation
…trics - Dashboard.tsx: replace prompt()/alert() in handleTopUp with the existing TopUpModal wired through sorobanTopUp via Freighter (closes LabsCrypt#355). - streams/[id]/page.tsx: drive pause/resume actions through the TransactionTracker (signing -> submitted -> confirmed/failed) instead of a full page reload, with retry on failure (closes LabsCrypt#356). - activity/page.tsx + ActivityHistory.tsx: hit the configured API base URL, fix the loading-gate that suppressed the initial fetch, prefer the server-provided hasMore, and link stream IDs to the detail page so the timeline becomes navigable (closes LabsCrypt#424). - backend GET /v1/events: paginated, type-filtered event list scoped to a wallet (sender or recipient), backing the activity page with hasMore and limit/offset (or page) semantics (closes LabsCrypt#424). - backend GET /v1/admin/metrics: add the snake_case summary required by the public contract (total/active/paused/completed/cancelled streams + total_volume_streamed as a string), wrap the handler in a 60s memory cache, and surface X-Cache hit/miss for observability (closes LabsCrypt#426). - tests: integration coverage for the new metrics endpoint (shape, i128 precision, cache hit/miss) and the events listing endpoint (validation, type filter, page-based offset).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bundles four assigned issues that all touch overlapping pieces (stream actions, the activity feed, and admin observability) into a single PR so the diff stays coherent.
Replace prompt()/alert() in handleTopUp with proper TopUpModal #355 — Replace prompt()/alert() in handleTopUp with proper TopUpModal
frontend/src/components/Dashboard.tsx: removed the legacyprompt()flow and wired the row's "Add Funds" button to the existingTopUpModal, which callssorobanTopUpvia Freighter (toBaseUnitsfor amount conversion). Errors surface viatoSorobanErrorMessage.Add pause and resume buttons to stream detail page #356 — Add pause and resume buttons to stream detail page
frontend/src/app/streams/[id]/page.tsx: pause and resume now drive aTransactionTracker(signing → submitted → confirmed/failed) instead ofwindow.location.reload(). Failure state surfaces a retry that re-issues the correct action based on the current paused flag, and the page refetches the stream record after submission so SSE/state recover without a hard reload.[Frontend] Build activity page with full event history #424 — Build activity page with full event history
frontend/src/app/activity/page.tsxnow hits the configuredNEXT_PUBLIC_API_URL, drops the!loadinggate that was suppressing the initial fetch, prefers the server-providedhasMore, and resets to an empty list on error.frontend/src/components/dashboard/ActivityHistory.tsxrenders each timeline entry's stream id as a<Link>to the detail page so the audit log is navigable. The CSV export, the empty state, and the load-more pagination already existed and are kept intact.GET /v1/events?address=&type=&limit=&offset=&page=route inbackend/src/routes/v1/events.routes.tsreturns{ events, total, limit, offset, hasMore }. Type filter accepts a comma list; invalid filters 400. Pagination supports bothoffset(preferred) andpage(1-based, falls back tooffset = (page - 1) * limit). Capped at 200/page.[Backend] Add stream metrics endpoint #426 — Add stream metrics endpoint
backend/src/routes/v1/admin.routes.ts: kept the existing nested protocol-health response and added the snake_case summary the issue contract calls for (total_streams,active_streams,paused_streams,completed_streams,cancelled_streams,total_volume_streamed).total_volume_streamedsumswithdrawnAmountasBigIntso i128 precision survives the JSON boundary. The handler is now wrapped in a 60-secondMemoryCache(existingcachefromlib/redis.ts) and emitsX-Cache: HIT/MISSfor visibility.Tests
backend/tests/integration/admin-metrics.test.ts: covers the response shape, large-i128 precision (sum of two values pastNumber.MAX_SAFE_INTEGER), the cache miss → set, and a cache hit that bypasses Prisma entirely.backend/tests/integration/events-list.test.ts: covers the missing-address 400, the paged shape, the comma-separated type filter, the all-invalid type filter, andpage→offsetfallback.closes #355
closes #356
closes #424
closes #426
Test plan
vitest run tests/integration/admin-metrics.test.ts— 4/4 passvitest run tests/integration/events-list.test.ts— 5/5 passtsc --noEmitclean for the touched files (existingdashboard-view.tsx/vitest.config.tserrors are pre-existing onmain)lint-stagedran via the pre-commit hook/activitylists events, type filter narrows, "Load more" appends, stream id link navigates to/streams/[id]GET /v1/admin/metricsreturns snake_case summary; second call within 60s returnsX-Cache: HITNotes
/v1/admin/metricsnested fields (streams,events,fees,sse,cache,indexer,uptime) in place so the operator console keeps working alongside the new top-level summary.frontend/src/components/Dashboard.tsxis currently unreferenced from any route, but Replace prompt()/alert() in handleTopUp with proper TopUpModal #355 explicitly named the file, so its handler is fixed regardless.