mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
fix(sync): keep USE_REMOTE recovery Undo visible after routine sync
After a "Use Server Data" replace shows the persistent Undo recovery snack (#8107), a follow-up routine sync-success snack must not silently replace it. SnackService now tracks a pending persistent action (actionStr + duration 0); the header sync() skips its success feedback while one is showing. Unblocks the committed USE_REMOTE crash-resume e2e (supersync-use-remote-crash-resume.spec.ts), whose Undo assertion depends on the recovery snack surviving the sync that resumed the rebuild.
This commit is contained in:
parent
19b6fed044
commit
a3272ed138
3 changed files with 52 additions and 2 deletions
|
|
@ -25,6 +25,7 @@ import { MetricService } from '../../features/metric/metric.service';
|
|||
import { DateService } from '../../core/date/date.service';
|
||||
import { UserProfileService } from '../../features/user-profile/user-profile.service';
|
||||
import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const';
|
||||
import { SyncStatus } from '../../op-log/sync-exports';
|
||||
|
||||
// Regression test for #7477: in a project view a long title pushed the
|
||||
// right-side header actions (simple-counter / habit buttons) off screen.
|
||||
|
|
@ -166,6 +167,7 @@ describe('MainHeaderComponent focus button visibility', () => {
|
|||
{
|
||||
provide: SyncWrapperService,
|
||||
useValue: {
|
||||
sync: jasmine.createSpy('sync'),
|
||||
isEnabledAndReady$: of(false),
|
||||
syncState$: of('IN_SYNC'),
|
||||
isSyncInProgress$: of(false),
|
||||
|
|
@ -173,7 +175,13 @@ describe('MainHeaderComponent focus button visibility', () => {
|
|||
superSyncIsConfirmedInSync$: of(false),
|
||||
},
|
||||
},
|
||||
{ provide: SnackService, useValue: { open: jasmine.createSpy('open') } },
|
||||
{
|
||||
provide: SnackService,
|
||||
useValue: {
|
||||
open: jasmine.createSpy('open'),
|
||||
hasPendingPersistentAction: jasmine.createSpy('hasPendingPersistentAction'),
|
||||
},
|
||||
},
|
||||
{ provide: Router, useValue: { events: EMPTY } },
|
||||
{
|
||||
provide: GlobalConfigService,
|
||||
|
|
@ -229,4 +237,19 @@ describe('MainHeaderComponent focus button visibility', () => {
|
|||
|
||||
expect(component.isFocusButtonVisible()).toBe(false);
|
||||
});
|
||||
|
||||
it('keeps a persistent recovery action instead of showing routine sync success', async () => {
|
||||
component = createComponent();
|
||||
const syncWrapperService = TestBed.inject(
|
||||
SyncWrapperService,
|
||||
) as jasmine.SpyObj<SyncWrapperService>;
|
||||
const snackService = TestBed.inject(SnackService) as jasmine.SpyObj<SnackService>;
|
||||
syncWrapperService.sync.and.resolveTo(SyncStatus.UpdateRemote);
|
||||
snackService.hasPendingPersistentAction.and.returnValue(true);
|
||||
|
||||
component.sync();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(snackService.open).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -294,6 +294,11 @@ export class MainHeaderComponent implements OnDestroy {
|
|||
|
||||
sync(): void {
|
||||
this.syncWrapperService.sync(true).then((r) => {
|
||||
// Keep persistent recovery actions (for example USE_REMOTE Undo) visible;
|
||||
// routine sync-success feedback must not replace them.
|
||||
if (this._snackService.hasPendingPersistentAction()) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
r === SyncStatus.UpdateLocal ||
|
||||
r === SyncStatus.UpdateRemoteAll ||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|||
import { Store } from '@ngrx/store';
|
||||
import { SnackParams } from './snack.model';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { take, takeUntil } from 'rxjs/operators';
|
||||
import { DEFAULT_SNACK_CFG } from './snack.const';
|
||||
import { SnackCustomComponent } from './snack-custom/snack-custom.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
|
@ -23,6 +23,7 @@ export class SnackService {
|
|||
private _matSnackBar = inject(MatSnackBar);
|
||||
|
||||
private _ref?: MatSnackBarRef<SnackCustomComponent | SimpleSnackBar>;
|
||||
private _hasPendingPersistentAction = false;
|
||||
|
||||
constructor() {
|
||||
const _onWorkContextChange$: Observable<unknown> = this._actions$.pipe(
|
||||
|
|
@ -37,10 +38,20 @@ export class SnackService {
|
|||
if (typeof params === 'string') {
|
||||
params = { msg: params };
|
||||
}
|
||||
if (params.actionStr && params.config?.duration === 0) {
|
||||
// Set this before the debounced render so immediate follow-up feedback
|
||||
// cannot unknowingly replace a persistent recovery action.
|
||||
this._hasPendingPersistentAction = true;
|
||||
}
|
||||
this._openSnack(params);
|
||||
}
|
||||
|
||||
hasPendingPersistentAction(): boolean {
|
||||
return this._hasPendingPersistentAction;
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this._hasPendingPersistentAction = false;
|
||||
if (this._ref) {
|
||||
this._ref.dismiss();
|
||||
}
|
||||
|
|
@ -107,6 +118,17 @@ export class SnackService {
|
|||
}
|
||||
}
|
||||
|
||||
const openedRef = this._ref;
|
||||
this._hasPendingPersistentAction = !!actionStr && cfg.duration === 0;
|
||||
openedRef
|
||||
?.afterDismissed()
|
||||
.pipe(take(1))
|
||||
.subscribe(() => {
|
||||
if (this._ref === openedRef) {
|
||||
this._hasPendingPersistentAction = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (actionStr && actionId && this._ref) {
|
||||
this._ref
|
||||
.onAction()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue