fix: show real API errors and stop stuck loading states - #316
Merged
Merged
Conversation
ts-client rejects with the raw Response on a non-OK status. The ad-hoc
`JSON.stringify(err.response || err.message || err)` formatting showed
"{}" or "[object Response]" instead of the reason.
Move describeError to common/errors.ts and use it at every site. Add
readError, which also reads the body of an unread Response, and use it
where the API body carries the useful message (settings, bulk and form
saves).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Several actions caught the error, showed an error toast, then carried on to the success toast. Return early on failure instead: - recompileDriver - bulk driver update (now uses allSettled and reports the failed count) - joinModule, removeModule, addZones, removeZone on systems - system zones keep pending zones when the save fails Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Return after notifyError instead of rethrowing into template handlers (groups, users, zones, api keys, Azure integration) - Catch trigger selection errors and always close the select modal - Catch list loader errors and always clear the loading state (admin interfaces, edge, brokers, schemas, cluster, platform details, metadata history) - Validate schema JSON before save and catch save errors - Close the confirm modal and report the error on failed deletes (storage, uploads, api keys) - Read api key resources with hasValue(), as value() throws in the error state - Skip zones the user cannot load instead of failing the whole list - Use allSettled for auth sources so one failing type does not hide all - Report group and user membership load errors instead of showing an empty list - Authenticated images: check response.ok, ignore stale results, log failures, and bound the wait for the API authority - uploadFileWithPermissions always settles - Catch service worker update check failures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Several loaders toggled one shared `_loading` signal, so the first loader to finish hid the progress bar while others still ran. Loaders that returned a promise without awaiting it cleared the flag at once. Derive `loading` from the resources' isLoading() in the group, user, zone, driver and trigger state services. Bulk adds keep their own flag. The system module loader now ignores results from an aborted load or a system that is no longer active, so it cannot overwrite the current module list or clear its loading flag. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- AsyncHandler.timeout clears the stored handle before it calls the callback, so a callback that reschedules itself under the same name keeps its new handle. The name and callback error messages were swapped. - waitForSignalValue rejects after a max wait (60s by default). Guards, settings, item service and app init handle the timeout. - App init uses the bounded wait in place of its own 30s user timer, and catches staff tenant check failures. - Image list uploads start the status poll only after an upload starts, and a cancelled permissions modal no longer leaks the interval. - Remove the second current user loader in user-state.ts. It could leave current_user null forever. BackofficeUsersService now publishes the user there, so current_user and BackofficeUsersService.user are the same signal. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With zoneless change detection, a plain field set after an await does not re-render. - Trigger comparison form: status variable lists are signals, and a failed module query shows an error. - System trigger form: loading is a signal, and it resets when saving the trigger settings fails. The failure no longer rethrows into the template handler. - Object list field: emit new objects and arrays instead of mutating the parent's objects through ngModel. The delete button is type="button" so it cannot submit the parent form. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Entity form saves use readError instead of JSON.stringify on the
response body, so toasts show the API message, short text, or the
status instead of escaped JSON, HTML pages, or "{}"
- Domain settings save, extension save, zone tree import/export and
signage AI provider removal report the error body too
- Tenant delete says "tenant", and a successful delete now shows the
success toast and reloads the list
- Test readError with a JSON error field and an empty body
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Resource imports: skip the system lookup when no resource has an email, and catch lookup and import failures so loading resets - Upload library: drop cancelled uploads before polling, and show an error when the uploads list fails to load - Zone about: catch parent zone load failures - Zone and system trigger removal: notify and return instead of rethrowing Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Metadata delete, execute method, module power toggle, signage AI provider save and storage provider save no longer rethrow into template handlers, so no unhandled rejection reaches the console - Signage AI provider and storage provider save toasts include the API error detail Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
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.
Problem
Error handling was inconsistent across the app:
Response. Most toasts printed{},[object Response], escaped JSON or a whole HTML error page._loadingsignal, so the first to finish hid the bar.waitForSignalValueand upload polling had no limit.AsyncHandlerlost the handle of a timer that set itself again.This is part of a stack of 6 PRs from a review of the whole app. Merge them in order: confirm-cancel, security, data loss, broken features, async errors, cleanup. Each PR targets the branch before it, so the diff shows only its own changes.
Fix
common/errors.tshasdescribeErrorandreadError.readErrorreads the JSONmessageorerror, short text, or falls back to the status. All error toasts use one of them.finally.isLoading().waitForSignalValuerejects after 60 s. Guards send the user to the unauthorised page. Upload polling has a limit.current_userandBackofficeUsersService.userare one signal.Checks
tsc,bun run lint,bunx vitest run(1034 tests) pass. New tests coverreadError, the timer fix and the wait limit.Made by Claude Opus 5.5 (1M context) in Claude Code (T3 Code).
🤖 Generated with Claude Code