Skip to content

Commit

Permalink
Development: Replace deprecated before unload event with pending chan…
Browse files Browse the repository at this point in the history
…ges guard (#9479)
  • Loading branch information
coolchock authored Oct 27, 2024
1 parent b90667c commit b8c922a
Show file tree
Hide file tree
Showing 18 changed files with 44 additions and 144 deletions.
2 changes: 2 additions & 0 deletions src/main/webapp/app/admin/admin.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { BuildAgentSummaryComponent } from 'app/localci/build-agents/build-agent
import { StandardizedCompetencyManagementComponent } from 'app/admin/standardized-competencies/standardized-competency-management.component';
import { BuildAgentDetailsComponent } from 'app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component';
import { AdminImportStandardizedCompetenciesComponent } from 'app/admin/standardized-competencies/import/admin-import-standardized-competencies.component';
import { PendingChangesGuard } from 'app/shared/guard/pending-changes.guard';

export const adminState: Routes = [
{
Expand Down Expand Up @@ -116,6 +117,7 @@ export const adminState: Routes = [
data: {
pageTitle: 'artemisApp.standardizedCompetency.title',
},
canDeactivate: [PendingChangesGuard],
},
{
// Create a new path without a component defined to prevent the StandardizedCompetencyManagementComponent from being always rendered
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { faChevronRight, faDownLeftAndUpRightToCenter, faEye, faFileExport, faFileImport, faPlus, faUpRightAndDownLeftFromCenter } from '@fortawesome/free-solid-svg-icons';
import {
KnowledgeAreaDTO,
Expand Down Expand Up @@ -576,14 +576,4 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe
get canDeactivateWarning(): string {
return this.translateService.instant('pendingChanges');
}

/**
* Displays the alert for confirming refreshing or closing the page if there are unsaved changes
*/
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.canDeactivateWarning;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, HostListener, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { CompetencyService } from 'app/course/competencies/competency.service';
import { AlertService } from 'app/core/util/alert.service';
import { onError } from 'app/shared/util/global.utils';
Expand Down Expand Up @@ -249,14 +249,4 @@ export class GenerateCompetenciesComponent implements OnInit, ComponentCanDeacti
get canDeactivateWarning(): string {
return this.translateService.instant('pendingChanges');
}

/**
* Only allow to refresh the page if no pending changes exist
*/
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.canDeactivateWarning;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'app/entities/competency/standardized-competency.model';
import { faBan, faDownLeftAndUpRightToCenter, faFileImport, faSort, faTrash, faUpRightAndDownLeftFromCenter } from '@fortawesome/free-solid-svg-icons';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, HostListener, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { onError } from 'app/shared/util/global.utils';
import { forkJoin, map } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
Expand Down Expand Up @@ -168,16 +168,6 @@ export abstract class CourseImportStandardizedCourseCompetenciesComponent extend
return this.translateService.instant('pendingChanges');
}

/**
* Displays the alert for confirming refreshing or closing the page if there are unsaved changes
*/
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.canDeactivateWarning;
}
}

private convertToKnowledgeAreaForImport(knowledgeAreaDTO: KnowledgeAreaDTO, isVisible = true, level = 0, selected = false): KnowledgeAreaForImport {
const children = knowledgeAreaDTO.children?.map((child) => this.convertToKnowledgeAreaForImport(child, isVisible, level + 1));
const competencies = knowledgeAreaDTO.competencies?.map((competency) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CourseCompetency, CourseCompetencyType } from 'app/entities/competency.
import { AlertService } from 'app/core/util/alert.service';
import { SortService } from 'app/shared/service/sort.service';
import { onError } from 'app/shared/util/global.utils';
import { Component, HostListener, OnInit, inject } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { faBan, faFileImport, faSave, faTrash } from '@fortawesome/free-solid-svg-icons';
import { ButtonType } from 'app/shared/components/button.component';
import { ActivatedRoute, Router } from '@angular/router';
Expand Down Expand Up @@ -204,14 +204,4 @@ export abstract class ImportCourseCompetenciesComponent implements OnInit, Compo
get canDeactivateWarning(): string {
return this.translateService.instant('pendingChanges');
}

/**
* Displays the alert for confirming refreshing or closing the page if there are unsaved changes
*/
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.canDeactivateWarning;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, HostListener, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { JhiWebsocketService } from 'app/core/websocket/websocket.service';
import { ExamParticipationService } from 'app/exam/participate/exam-participation.service';
Expand Down Expand Up @@ -246,14 +246,6 @@ export class ExamParticipationComponent implements OnInit, OnDestroy, ComponentC
return this.translateService.instant('artemisApp.examParticipation.pendingChanges');
}

// displays the alert for confirming leaving the page if there are unsaved changes
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any): void {
if (!this.canDeactivate()) {
event.returnValue = this.canDeactivateWarning;
}
}

get activePageIndex(): number {
if (!this.activeExamPage || this.activeExamPage.isOverviewPage) {
return -1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, HostListener, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Patch, Selection, UMLDiagramType, UMLElementType, UMLModel, UMLRelationshipType } from '@ls1intum/apollon';
import { TranslateService } from '@ngx-translate/core';
Expand Down Expand Up @@ -642,14 +642,6 @@ export class ModelingSubmissionComponent implements OnInit, OnDestroy, Component
return false;
}

// displays the alert for confirming leaving the page if there are unsaved changes
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any): void {
if (!this.canDeactivate()) {
event.returnValue = this.translateService.instant('pendingChanges');
}
}

/**
* counts the number of model elements
* is used in the submit() function
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Component, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { isEmpty as _isEmpty, fromPairs, toPairs, uniq } from 'lodash-es';
import { CodeEditorFileService } from 'app/exercises/programming/shared/code-editor/service/code-editor-file.service';
import { ComponentCanDeactivate } from 'app/shared/guard/can-deactivate.model';
import { CodeEditorGridComponent } from 'app/exercises/programming/shared/code-editor/layout/code-editor-grid.component';
import {
CommitState,
Expand Down Expand Up @@ -37,7 +36,7 @@ export enum CollapsableCodeEditorElement {
templateUrl: './code-editor-container.component.html',
styleUrls: ['./code-editor-container.component.scss'],
})
export class CodeEditorContainerComponent implements OnChanges, ComponentCanDeactivate {
export class CodeEditorContainerComponent implements OnChanges {
readonly CommitState = CommitState;
readonly EditorState = EditorState;
readonly CollapsableCodeEditorElement = CollapsableCodeEditorElement;
Expand Down Expand Up @@ -262,13 +261,6 @@ export class CodeEditorContainerComponent implements OnChanges, ComponentCanDeac
this.alertService.error(`artemisApp.editor.errors.${errorTranslationKey}`, translationParams);
}

/**
* The user will be warned if there are unsaved changes when trying to leave the code-editor.
*/
canDeactivate() {
return _isEmpty(this.unsavedFiles);
}

getText(): string {
return this.monacoEditor.getText() ?? '';
}
Expand All @@ -286,14 +278,6 @@ export class CodeEditorContainerComponent implements OnChanges, ComponentCanDeac
this.monacoEditor.highlightLines(startLine, endLine);
}

// displays the alert for confirming refreshing or closing the page if there are unsaved changes
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.translateService.instant('pendingChanges');
}
}

onToggleCollapse(event: InteractableEvent, collapsableElement: CollapsableCodeEditorElement) {
this.grid.toggleCollapse(event, collapsableElement);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnChanges, OnInit, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnChanges, OnInit, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { QuizExerciseService } from './quiz-exercise.service';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
Expand Down Expand Up @@ -355,16 +355,6 @@ export class QuizExerciseUpdateComponent extends QuizExerciseValidationDirective
return !this.pendingChangesCache;
}

/**
* Displays the alert for confirming refreshing or closing the page if there are unsaved changes
*/
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.translateService.instant('pendingChanges');
}
}

/**
* @desc Callback for datepicker to decide whether given date should be disabled
* All dates which are in the past (< today) are disabled
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, HostListener, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ActivatedRoute } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
Expand Down Expand Up @@ -248,14 +248,6 @@ export class TextEditorComponent implements OnInit, OnDestroy, ComponentCanDeact
return this.stringCountService.countCharacters(this.answer);
}

// Displays the alert for confirming refreshing or closing the page if there are unsaved changes
@HostListener('window:beforeunload', ['$event'])
unloadNotification(event: any) {
if (!this.canDeactivate()) {
event.returnValue = this.translateService.instant('pendingChanges');
}
}

canDeactivate(): boolean {
if (!this.submission) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
import { UserRouteAccessService } from 'app/core/auth/user-route-access-service';
import { TextEditorComponent } from './text-editor.component';
import { Authority } from 'app/shared/constants/authority.constants';
import { PendingChangesGuard } from 'app/shared/guard/pending-changes.guard';

export const textEditorRoute: Routes = [
{
Expand All @@ -12,5 +13,6 @@ export const textEditorRoute: Routes = [
pageTitle: 'artemisApp.textExercise.home.title',
},
canActivate: [UserRouteAccessService],
canDeactivate: [PendingChangesGuard],
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,10 @@ describe('GenerateCompetenciesComponent', () => {
expect(warnMock).toHaveBeenCalled();
});

it('should send a warning when trying to reload', () => {
it('should not deactivate when loading', () => {
generateCompetenciesComponent.isLoading = true;
const event = { returnValue: undefined };
generateCompetenciesComponent.unloadNotification(event);
expect(event.returnValue).toBe(generateCompetenciesComponent.canDeactivateWarning);
const canDeactivate = generateCompetenciesComponent.canDeactivate();
expect(canDeactivate).toBeFalse();
});

function createCompetencyFormGroup(title?: string, description?: string, taxonomy?: CompetencyTaxonomy, viewed = false): FormGroup<CompetencyFormControlsWithViewed> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,15 @@ describe('ImportCourseCompetenciesComponent', () => {
expect(component.disabledIds).toHaveLength(3);
});

it('should not unload with pending changes', () => {
const deactivateWarningSpy = jest.spyOn(component, 'canDeactivateWarning', 'get');

it('should not deactivate with pending changes', () => {
let canDeactivate;
component['isSubmitted'] = true;
component.selectedCourseCompetencies = { resultsOnPage: [{ id: 1 }], numberOfPages: 0 };
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).not.toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeTrue();

component['isSubmitted'] = false;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeFalse();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -767,16 +767,6 @@ describe('ExamParticipationComponent', () => {
});
});

describe('unloadNotification', () => {
it('should set event return value', () => {
jest.spyOn(comp, 'canDeactivate').mockReturnValue(false);
jest.spyOn(comp, 'canDeactivateWarning', 'get').mockReturnValue('warning');
const event = { returnValue: undefined };
comp.unloadNotification(event);
expect(event.returnValue).toBe('warning');
});
});

describe('isOver', () => {
it('should return true if exam has ended', () => {
const studentExam = new StudentExam();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,18 +633,16 @@ describe('QuizExerciseUpdateComponent', () => {
expect(comp.canDeactivate()).toBeTrue();
});

it('should set event return value to translate if not canDeactivate', () => {
it('should not deactivate with pending changes', () => {
comp.pendingChangesCache = true;
const ev = { returnValue: undefined };
comp.unloadNotification(ev);
expect(ev.returnValue).toBe('pendingChanges');
const canDeactivate = comp.canDeactivate();
expect(canDeactivate).toBeFalse();
});

it('should not set event return value to translate if canDeactivate', () => {
it('should deactivate with no pending changes', () => {
comp.pendingChangesCache = false;
const ev = { returnValue: undefined };
comp.unloadNotification(ev);
expect(ev.returnValue).toBeUndefined();
const canDeactivate = comp.canDeactivate();
expect(canDeactivate).toBeTrue();
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@ describe('CourseImportStandardizedCompetenciesComponent', () => {
});

it('should not deactivate with pending changes', () => {
const deactivateWarningSpy = jest.spyOn(component as any, 'canDeactivateWarning', 'get');
let canDeactivate;

component['isLoading'] = false;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).not.toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeTrue();

component['isLoading'] = true;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeFalse();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@ describe('CourseImportStandardizedPrerequisitesComponent', () => {
});

it('should not deactivate with pending changes', () => {
const deactivateWarningSpy = jest.spyOn(component as any, 'canDeactivateWarning', 'get');
let canDeactivate;

component['isLoading'] = false;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).not.toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeTrue();

component['isLoading'] = true;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeFalse();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -479,15 +479,15 @@ describe('StandardizedCompetencyManagementComponent', () => {
});

it('should not deactivate with pending changes', () => {
const deactivateWarningSpy = jest.spyOn(component, 'canDeactivateWarning', 'get');
let canDeactivate;

component['isEditing'] = false;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).not.toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeTrue();

component['isEditing'] = true;
component['unloadNotification']({ returnValue: '' });
expect(deactivateWarningSpy).toHaveBeenCalled();
canDeactivate = component.canDeactivate();
expect(canDeactivate).toBeFalse();
});

function prepareAndExecuteCompetencyUpdate(tree: KnowledgeAreaDTO[], competencyToUpdate: StandardizedCompetencyDTO, updatedCompetency: StandardizedCompetencyDTO) {
Expand Down

0 comments on commit b8c922a

Please sign in to comment.