Skip to content

SF-3768 Add assignee and resolution to draft request detail page#3780

Draft
Nateowami wants to merge 1 commit intomasterfrom
feature/SF-3768-update-draft-request-detail-ui
Draft

SF-3768 Add assignee and resolution to draft request detail page#3780
Nateowami wants to merge 1 commit intomasterfrom
feature/SF-3768-update-draft-request-detail-ui

Conversation

@Nateowami
Copy link
Copy Markdown
Collaborator

@Nateowami Nateowami commented Apr 6, 2026

This change takes this capability:
Screenshot from 2026-04-06 19-35-51

...and copies it here, while trying to avoid duplicating logic too much.
Screenshot from 2026-04-06 19-36-01


This change is Reviewable


Open with Devin

@Nateowami Nateowami added the will require testing PR should not be merged until testers confirm testing is complete label Apr 6, 2026
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +135 to 137
get availableAssigneeIds(): string[] {
return this.onboardingRequestService.getCurrentlyAssignedUserIdsFromRequestList(this.requests);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 availableAssigneeIds getter creates new array on every access, defeating optimistic UI updates

The availableAssigneeIds getter at onboarding-requests.component.ts:135-137 returns a new array from getCurrentlyAssignedUserIdsFromRequestList() on every call. In the template, it's bound as [knownAssigneeIds]="availableAssigneeIds". Angular's change detection compares by reference, so it sees a "change" on every cycle, triggering ngOnChanges() in OnboardingRequestAssigneeSelectComponent (onboarding-request-assignee-select.component.ts:30-32). That handler resets internalValue back to the parent's value input, immediately undoing the optimistic UI update set in onSelectionChange. The dropdown visually reverts to the old assignee before the API call completes.

Prompt for agents
The availableAssigneeIds getter in OnboardingRequestsComponent creates a new array on every access. When used as a template binding [knownAssigneeIds]="availableAssigneeIds", Angular detects a reference change on every change detection cycle and triggers ngOnChanges in OnboardingRequestAssigneeSelectComponent, which resets internalValue to the parent value, defeating the optimistic UI update.

Possible fixes:
1. Cache the computed array as a class property (e.g. availableAssigneeIds: string[] = []) and recompute it only when this.requests changes (in loadRequests, onAssigneeChange, onResolutionChange) rather than using a getter. This is the approach used in the detail component.
2. Alternatively, make OnboardingRequestAssigneeSelectComponent.ngOnChanges smarter by using SimpleChanges to only reset internalValue when the value input specifically changes, not when knownAssigneeIds changes.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What might a solution be?

Comment on lines +126 to +134
async onAssigneeChange(newAssigneeId: string): Promise<void> {
if (this.request == null) return;
this.request = await this.onboardingRequestService.setAssignee(this.request.id, newAssigneeId);
}

async onResolutionChange(newResolution: DraftRequestResolutionKey | null): Promise<void> {
if (this.request == null) return;
this.request = await this.onboardingRequestService.setResolution(this.request.id, newResolution);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Detail component's onAssigneeChange/onResolutionChange lack error handling unlike the list component

In DraftRequestDetailComponent, onAssigneeChange (line 126-129) and onResolutionChange (line 131-134) have no try/catch. If the API call fails, the error will be an unhandled promise rejection since these are invoked from the template via (selectionChange). By contrast, OnboardingRequestsComponent wraps the same calls in try/catch with error messages and state recovery (onboarding-requests/onboarding-requests.component.ts:187-203). This inconsistency means failures in the detail view silently fail with no user feedback.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 6, 2026

Codecov Report

❌ Patch coverage is 52.63158% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.12%. Comparing base (50ffeaf) to head (d81b37a).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...boarding-requests/onboarding-requests.component.ts 0.00% 11 Missing ⚠️
...ate/draft-generation/onboarding-request.service.ts 0.00% 4 Missing ⚠️
...l-administration/draft-request-detail.component.ts 81.81% 2 Missing ⚠️
...on/onboarding-request-assignee-select.component.ts 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3780      +/-   ##
==========================================
- Coverage   81.27%   81.12%   -0.15%     
==========================================
  Files         622      624       +2     
  Lines       39322    39480     +158     
  Branches     6391     6423      +32     
==========================================
+ Hits        31958    32029      +71     
- Misses       6379     6460      +81     
- Partials      985      991       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Nateowami Nateowami force-pushed the feature/SF-3768-update-draft-request-detail-ui branch from 0f418e3 to 51cd3d6 Compare April 7, 2026 17:56
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +126 to +134
async onAssigneeChange(newAssigneeId: string): Promise<void> {
if (this.request == null) return;
this.request = await this.onboardingRequestService.setAssignee(this.request.id, newAssigneeId);
}

async onResolutionChange(newResolution: DraftRequestResolutionKey | null): Promise<void> {
if (this.request == null) return;
this.request = await this.onboardingRequestService.setResolution(this.request.id, newResolution);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Missing error handling in onAssigneeChange/onResolutionChange causes stale optimistic UI on API failure

In DraftRequestDetailComponent, both onAssigneeChange (draft-request-detail.component.ts:126-129) and onResolutionChange (draft-request-detail.component.ts:131-134) lack try/catch error handling, unlike their counterparts in OnboardingRequestsComponent (onboarding-requests.component.ts:187-206 and onboarding-requests.component.ts:212-231) which have proper try/catch/finally.

When the API call fails:

  1. The OnboardingRequestAssigneeSelectComponent has already performed an optimistic update to internalValue (onboarding-request-assignee-select.component.ts:35), and since this.request is never updated on failure, the parent's [value] input doesn't change, ngOnChanges won't fire, and the dropdown permanently shows the wrong value.
  2. Similarly, the resolution mat-select will display the user's new selection while request.resolution remains unchanged.
  3. No error message is shown to the user.
  4. An unhandled promise rejection occurs since Angular event handlers don't await the returned promise.
Prompt for agents
Both onAssigneeChange and onResolutionChange in DraftRequestDetailComponent need try/catch/finally error handling, following the same pattern used in OnboardingRequestsComponent (onboarding-requests.component.ts:187-206 and 212-231). On error, show a user-facing error notification via this.noticeService.showError(), and reload the request data to restore the correct UI state. This is needed because on failure the OnboardingRequestAssigneeSelectComponent has already optimistically updated its internal display value, and the resolution mat-select has visually changed. Without reverting these, the UI will permanently show incorrect state.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +34 to +64
function createTestRequest(overrides: Partial<OnboardingRequest> = {}): OnboardingRequest {
return {
id: REQUEST_ID,
submittedAt: '2024-01-01T00:00:00Z',
submittedBy: { name: 'Test User', email: 'test@example.com' },
submission: {
projectId: 'project01',
userId: 'user03',
timestamp: '2024-01-01T00:00:00Z',
formData: {
name: 'Test User',
email: 'test@example.com',
organization: 'Test Org',
partnerOrganization: 'Partner Org',
translationLanguageName: 'English',
translationLanguageIsoCode: 'en',
completedBooks: [40, 41, 42, 43],
nextBooksToDraft: [44],
sourceProjectA: 'ptproject01',
draftingSourceProject: 'ptproject02',
backTranslationStage: 'None',
backTranslationProject: null
}
},
assigneeId: '',
status: 'new',
resolution: 'unresolved',
comments: [],
...overrides
};
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Helper function createTestRequest is defined outside the TestEnvironment class

The createTestRequest function is defined at module level outside both the describe block and the TestEnvironment class. AGENTS.md mandates: "Do not put helper functions outside of TestEnvironment classes; helper functions or setup functions should be in the TestEnvironment class." This function should be a static method on the TestEnvironment class.

Prompt for agents
Move the createTestRequest function into the TestEnvironment class (defined at draft-request-detail.component.spec.ts:149) as a static method. It is currently at module level (line 34-64) but AGENTS.md requires helper functions to be inside the TestEnvironment class. Since it is used both in the TestEnvironment constructor and in individual test cases, make it static createTestRequest(...) and call it as TestEnvironment.createTestRequest(...).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 121 to 130
const requests = await this.onboardingRequestService.getAllRequests();
if (requests != null) {
this.requests = requests;
this.initializeRequestData();
this.filterRequests();
void this.loadProjectNames();
}
this.loadingFinished();
} catch (error) {
console.error('Error loading draft requests:', error);
this.noticeService.showError('Failed to load draft requests');
} finally {
this.loadingFinished();
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 loadRequests error handling changed from catch-and-notify to finally-only

In onboarding-requests.component.ts:118-130, the old code had a catch block that logged the error and called noticeService.showError('Failed to load draft requests'). The new code uses only try/finally, so errors will propagate as unhandled rejections without a user-facing message. Since this is called via void this.loadRequests() from ngOnInit(), the rejection won't be caught. This is a pre-existing pattern shift—the detail component's loadRequest also uses try/finally without catch. Both are consistent with each other now, but the user loses the error notification.

(Refers to lines 118-130)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@Nateowami Nateowami force-pushed the feature/SF-3768-update-draft-request-detail-ui branch from 51cd3d6 to d81b37a Compare April 9, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

will require testing PR should not be merged until testers confirm testing is complete

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant