fix(editor): Show error when eligible reviewers fail to load (#37089)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sandra Zollner
2026-08-27 07:18:34 +00:00
committed by GitHub
parent c96f329fde
commit 45a104a15c
3 changed files with 29 additions and 5 deletions
@@ -4715,6 +4715,7 @@
"workflowReviews.submitForReview.submit": "Submit",
"workflowReviews.submitForReview.error.title": "Workflow couldn't be submitted for review",
"workflowReviews.submitForReview.error.save": "Save the workflow and try again.",
"workflowReviews.submitForReview.error.loadReviewers": "Couldn't load reviewers",
"workflowReviews.updateReview.title": "Submit latest changes to existing review",
"workflowReviews.updateReview.description": "This workflow already has an {review}. Submit latest changes to the existing review, to get them approved.",
"workflowReviews.updateReview.description.review": "open review",
@@ -487,15 +487,33 @@ describe('WorkflowSubmitForReviewDialog', () => {
expect(getByTestId('workflow-review-submit-button')).toBeEnabled();
});
it('keeps submission blocked when loading the reviewers fails', async () => {
vi.mocked(fetchEligibleReviewers).mockRejectedValue(new Error('nope'));
it('shows error toast and keeps submission blocked when loading the reviewers fails', async () => {
const error = new Error('nope');
vi.mocked(fetchEligibleReviewers).mockRejectedValue(error);
const { getByTestId, goToStep2 } = await renderDialog();
await goToStep2();
await waitFor(() => expect(mockShowError).toHaveBeenCalledWith(error, expect.any(String)));
await goToStep2();
await userEvent.type(getByTestId('workflow-review-title-input'), 'Review payments');
expect(getByTestId('workflow-review-submit-button')).toBeDisabled();
expect(createWorkflowReviewRequest).not.toHaveBeenCalled();
});
it('stays silent when the reviewer load fails after the dialog has closed', async () => {
let rejectLoad!: (error: unknown) => void;
const pendingLoad = new Promise<never>((_resolve, reject) => {
rejectLoad = reject;
});
vi.mocked(fetchEligibleReviewers).mockReturnValue(pendingLoad);
const { rerender, flushSave } = await renderDialog();
// Close before the in-flight load settles, then let it fail.
await rerender({ open: false, workflowId: 'workflow-1', flushSave });
rejectLoad(new Error('nope'));
await pendingLoad.catch(() => {});
expect(mockShowError).not.toHaveBeenCalled();
});
@@ -101,9 +101,10 @@ const loadEligibleReviewers = async () => {
});
if (sequence !== loadReviewersSequence) return;
eligibleReviewers.value = data;
} catch {
} catch (error) {
if (sequence !== loadReviewersSequence) return;
eligibleReviewers.value = [];
toast.showError(error, i18n.baseText('workflowReviews.submitForReview.error.loadReviewers'));
} finally {
if (sequence === loadReviewersSequence) isLoadingReviewers.value = false;
}
@@ -112,7 +113,11 @@ const loadEligibleReviewers = async () => {
watch(
() => props.open,
(isOpen) => {
if (!isOpen) return;
if (!isOpen) {
// Invalidate any in-flight load so it can't toast after the dialog closes.
loadReviewersSequence++;
return;
}
step.value = 1;
reviewTitle.value = '';