-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[PM-26687] send skeleton #17333
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
[PM-26687] send skeleton #17333
Conversation
|
Claude finished @Jingo88's task —— View job Code Review CompleteThe implementation looks solid overall. The PR successfully adds skeleton loading to the browser send page with a feature flag toggle. Previous review feedback has been addressed - the FindingsFinding 1: Missing 💭 The However, given that send data loads very quickly (as noted in review discussion), and there's a separate ticket (PM-27710) to address loading flicker, this may be intentional. The vault implementation has more complex dependencies that justify the Finding 2: Test coverage missing for new loading state logic
Example test structure: it("should show spinner loaders when loading and skeleton flag is disabled", () => {
configService.getFeatureFlag$.mockReturnValue(of(false));
sendItemsService.loading$ = of(true);
// Assert showSpinnerLoaders$ emits true
});Finding 3: Mixed control flow syntax in template 💭 The template mixes modern control flow ( Summary✅ Strengths:
📝 Notes:
|
|
New Issues (1)Checkmarx found the following issues in this Pull Request
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #17333 +/- ##
==========================================
+ Coverage 40.74% 40.93% +0.18%
==========================================
Files 3541 3544 +3
Lines 101415 101725 +310
Branches 15188 15240 +52
==========================================
+ Hits 41321 41637 +316
+ Misses 58353 58334 -19
- Partials 1741 1754 +13 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5878efd to
c0d1044
Compare
| protected sendsLoading$ = this.sendItemsService.loading$.pipe( | ||
| distinctUntilChanged(), | ||
| tap((loading) => { | ||
| const key = loading ? "loadingSendPage" : "sendPageLoaded"; | ||
| void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite"); | ||
| }), | ||
| ); |
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.
tap() side effect will fire multiple times per state change.
Recommendation: Add shareReplay({ bufferSize: 1, refCount: true }) to the pipe to prevent duplicate announcements:
protected sendsLoading$ = this.sendItemsService.loading$.pipe(
distinctUntilChanged(),
tap((loading) => {
const key = loading ? "loadingSendPage" : "sendPageLoaded";
void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite");
}),
shareReplay({ bufferSize: 1, refCount: true }),
);Also consider adding startWith(true) like vault-popup-loading.service.ts:25 to ensure skeleton displays immediately on init.
| private skeletonFeatureFlag$ = this.configService.getFeatureFlag$( | ||
| FeatureFlag.VaultLoadingSkeletons, | ||
| ); | ||
| protected sendsLoading$ = this.sendItemsService.loading$.pipe( |
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.
startWith(true) for initial skeleton display
The observable doesn't include startWith(true), which means the skeleton won't display on initial component load before the first emission from sendItemsService.loading$.
Recommended addition:
protected sendsLoading$ = this.sendItemsService.loading$.pipe(
startWith(true), // Add this
distinctUntilChanged(),
tap((loading) => {
const key = loading ? "loadingSendPage" : "sendPageLoaded";
void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite");
}),
shareReplay({ bufferSize: 1, refCount: true }),
);Reference: vault-popup-loading.service.ts:25 uses startWith(true) to ensure skeleton displays immediately on init.
| </div> | ||
| <app-send-list-items-container [headerText]="title | i18n" [sends]="sends$ | async" /> | ||
| </ng-container> | ||
| @if (sendsLoading$ | async) { |
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.
💭 Inconsistent control flow syntax
The template mixes modern control flow syntax (@if on line 49) with legacy structural directives (*ngIf on lines 4, 10, 13, 20, 28, 30, 37, 39).
While both are valid, consistent use of one pattern improves maintainability. Consider whether modernizing all to @if/@for is in scope for this PR or should be addressed separately.
| private skeletonFeatureFlag$ = this.configService.getFeatureFlag$( | ||
| FeatureFlag.VaultLoadingSkeletons, | ||
| ); | ||
| protected sendsLoading$ = this.sendItemsService.loading$.pipe( |
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.
🎨 Consider extracting to dedicated loading service
The vault implementation uses VaultPopupLoadingService (vault-popup-loading.service.ts:11-27) to centralize loading logic, improving testability and maintainability.
Consider creating a SendPopupLoadingService that:
- Combines
sendItemsService.loading$with any future dependencies - Includes
startWith(true)andshareReplay()for proper initialization and sharing - Can be easily mocked in tests (current tests don't verify loading behavior - see send-v2.component.spec.ts)
This would improve consistency with the vault implementation and make the component logic cleaner. However, this is an optional enhancement.
| protected sendsLoading$ = this.sendItemsService.loading$.pipe( | ||
| distinctUntilChanged(), | ||
| tap((loading) => { | ||
| const key = loading ? "loadingSendPage" : "sendPageLoaded"; | ||
| void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite"); | ||
| }), | ||
| shareReplay({ bufferSize: 1, refCount: true }), | ||
| ); |
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.
❌ Missing startWith(true) for initial loading state
Without startWith(true), the skeleton won't display during initial component load before the first emission from sendItemsService.loading$. This can cause a flash of empty content.
Add this line after line 86:
protected sendsLoading$ = this.sendItemsService.loading$.pipe(
startWith(true), // Add this
distinctUntilChanged(),
tap((loading) => {
const key = loading ? "loadingSendPage" : "sendPageLoaded";
void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite");
}),
shareReplay({ bufferSize: 1, refCount: true }),
);Also import startWith on line 5.
Reference: vault-popup-loading.service.ts:25
| protected sendsLoading$ = this.sendItemsService.loading$.pipe( | ||
| distinctUntilChanged(), | ||
| tap((loading) => { | ||
| const key = loading ? "loadingSendPage" : "sendPageLoaded"; | ||
| void this.liveAnnouncer.announce(this.i18nService.translate(key), "polite"); | ||
| }), | ||
| shareReplay({ bufferSize: 1, refCount: true }), | ||
| ); |
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.
question: Will this actually provide value? In most cases this will be very quick and might be quite annoying.
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.
That's a fair point. I was following the skeleton loading patterns we're implementing in vault. But sends should be way quicker to load. I'll bring this up to design.
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.
It seems the skeleton components have a 1s delay, the announce should probably mirror this.
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.
Removed. Thanks!
Edit (did not see previous comment) - We're going to keep it removed for now. We have another ticket for avoiding a flicker where we can revisit this if needed.


🎟️ Tracking
Note branch name shows incorrect ticket. it should be the one below
PM-26687
📔 Objective
Adding the new vault loading skeleton to the browser send page.
📸 Screen Recording (slowed down to see loading)
Empty Send Does not show skeleton (Skeleton Feature Flag On)
PM-26687-send-empty-no-skeleton.mov
Has Items (Skeleton Feature Flag On)
PM-27523-send-skeleton-items.mov
Show Loading Spinner (Skeleton Feature Flag Off)
PM-27523-loading-spinner.mov
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes