-
Notifications
You must be signed in to change notification settings - Fork 365
NAS-138979 / 26.04 / feat: implement immediate updates for disk forms and list #13050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Claude finished @mattwyatt-ix's task —— View job PR Review: Immediate Updates for Disk Forms and ListGreat approach to solving the race condition! 🎯 The solution elegantly handles the slow API response by optimistically updating the UI with client-side data while waiting for the real API response. ✅ What Works WellThe implementation correctly addresses the core issue by returning the update payload from both form components and using it for immediate UI updates in the list component. The test coverage is solid and properly validates the new return types. 🔍 Issues to Address1. Data Inconsistency Risk ( The current implementation updates // User edits disk sda (currently in unusedDisks)
// diskUpdates$ fires and updates this.disks
this.disks = this.disks.map((disk) => {
if (disk.identifier === diskUpdate.identifier) {
return { ...disk, ...diskUpdate }; // ✅ Updated
}
return disk;
});
// But this.unusedDisks still has stale data!
// getPoolColumn() reads from this.unusedDisks (line 374)
// So the Pool column may show stale dataSolution: Either update both arrays or refactor to eliminate the dual source of truth: this.diskUpdates$.pipe(
takeUntilDestroyed(this.destroyRef),
).subscribe((diskUpdate) => {
// Update disks array
this.disks = this.disks.map((disk) => {
if (disk.identifier === diskUpdate.identifier) {
return { ...disk, ...diskUpdate };
}
return disk;
});
// Update unusedDisks if the disk exists there
this.unusedDisks = this.unusedDisks.map((disk) => {
if (disk.identifier === diskUpdate.identifier) {
return { ...disk, ...diskUpdate };
}
return disk;
});
this.dataProvider.setRows(this.disks);
});2. Missing Client-Side Pool Recalculation ( When you update a disk, the // In diskUpdates$ handler, you do:
return { ...disk, ...diskUpdate }; // ❌ Doesn't recalculate pool
// Should be:
const updatedDisk = { ...disk, ...diskUpdate };
return {
...updatedDisk,
pool: this.getPoolColumn(updatedDisk), // ✅ Recalculate derived data
};3. Incomplete Bulk Edit Error Handling ( When // Current code on partial failure:
this.slideInRef.close({ response: [] }); // ❌ Loses successful updates
// Better approach - return the successful ones:
const successfulUpdates = req
.filter((_, idx) => job.result[idx].error === null)
.map((diskUpdate) => ({
identifier: diskUpdate[0],
...diskUpdate[1],
}));
this.slideInRef.close({ response: successfulUpdates });4. Test Gap ( The bulk edit test verifies that // disk-form.component.spec.ts:112-119 ✅ Checks response content
expect(spectator.inject(SlideInRef).close).toHaveBeenCalledWith({
response: [{
identifier: '{serial}VB9fbb6dfe-9cf26570',
advpowermgmt: '64',
// ... validates full payload
}],
});
// disk-bulk-edit.component.spec.ts:124 ❌ Only checks it was called
expect(spectator.inject(SlideInRef).close).toHaveBeenCalled();Add assertions to verify the response payload structure. 📝 Minor Observations
SummarySolid architectural approach with proper type safety and test coverage. Address the data consistency issues (particularly the unusedDisks and pool recalculation) to ensure the optimistic update fully mirrors the API response. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #13050 +/- ##
==========================================
+ Coverage 86.69% 86.72% +0.02%
==========================================
Files 1846 1847 +1
Lines 69371 69429 +58
Branches 8574 8586 +12
==========================================
+ Hits 60143 60211 +68
+ Misses 9228 9218 -10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
aervin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
works as described
|
This PR has been merged and conversations have been locked. |
Changes:
when saving the disk edit form or the bulk disk edit form, we call
AsyncDataProvider.loadwhich calls the API methodsdisk.queryanddisk.details. since these take a while to finish executing, we were seeing inconsistency if you went to edit a disk that you had just edited. this PR updates that information client-side in the interim while we wait for the API to give us back the real data.there is a minor concern for a data race in the following scenario: if a user were to quickly make two edits to one disk, there would be a period of time where we may receive the first edit from the API, but not the second, and the user sees their latest edit revert. this would happen due to the API being slightly behind. i think this has an acceptably-low chance of happening and causing any confusion.
also, we now clear the contents of the SED password field when checking the box. if the box is checked, the password is actually cleared in the logic and on the backend, but users may get confused if it looks like the password is still in the box.
Testing:
note that the clear SED password checkbox visually clears it too.
Downstream