From 2db02db9edf164649657ca0068317498445a21f1 Mon Sep 17 00:00:00 2001 From: Nathaniel Paulus Date: Wed, 21 Oct 2026 16:30:58 +0000 Subject: [PATCH] SF-1523 Prevent project deleted dialog from being shown repeatedly --- .../ClientApp/src/app/app.component.spec.ts | 19 ++++++++++++++++++- .../ClientApp/src/app/app.component.ts | 6 +++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts index 56c789402cd..0d408c26b0c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts @@ -372,6 +372,20 @@ describe('AppComponent', () => { expect(env.location.path()).toEqual('/projects'); })); + it('shows the removed from project dialog once when the project keeps changing', fakeAsync(() => { + const env = new TestEnvironment(); + env.navigate(['/projects', 'project01']); + env.init(); + + expect(env.selectedProjectId).toEqual('project01'); + // The sync that removes the user goes on to change the project before the app has navigated away + env.removeUserFromProject('project01', { thenChangeProjectTimes: 2 }); + + verify(mockedDialogService.message(anything())).once(); + verify(mockedSFProjectService.localDelete('project01')).once(); + expect(env.location.path()).toEqual('/projects'); + })); + it('response to remote project change for serval admin', fakeAsync(() => { const env = new TestEnvironment(); env.setCurrentUser('user05'); @@ -1009,9 +1023,12 @@ class TestEnvironment { this.wait(); } - removeUserFromProject(projectId: string): void { + removeUserFromProject(projectId: string, { thenChangeProjectTimes = 0 } = {}): void { const projectDoc = this.realtimeService.get(SFProjectProfileDoc.COLLECTION, projectId); projectDoc.submitJson0Op(op => op.unset(p => p.userRoles['user01']), false); + for (let i = 0; i < thenChangeProjectTimes; i++) { + projectDoc.submitJson0Op(op => op.inc(p => p.sync.queuedCount, 1), false); + } this.wait(); } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts index 05313ffed77..89794967ba1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts @@ -377,9 +377,13 @@ export class AppComponent extends DataLoadingComponent implements OnInit, OnDest } // See if the user was removed from the project if (!(this.currentUserDoc.id in this._selectedProjectDoc.data.userRoles)) { - // The user has been removed from the project + // The user has been removed from the project, so unsubscribe to prevent multiple notices + this.selectedProjectChangedSub?.unsubscribe(); + this.selectedProjectDeleteSub?.unsubscribe(); void this.showProjectDeletedDialog(); void this.projectService.localDelete(this._selectedProjectDoc.id); + // showProjectDeletedDialog redirects, so return early to avoid redirect checkAppAccess would do + return; } checkAppAccess(