Skip to content
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

Lectures: Add dismiss modal for unsaved changes to title or period section #10023

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c8b3b47
Add dismiss modal to lecture update component
florian-glombik Dec 14, 2024
a18c443
Do not display modal if in wizard mode (will be removed soon, no test…
florian-glombik Dec 14, 2024
8bb74b8
Add translations
florian-glombik Dec 14, 2024
be41e86
Remove unused translations
florian-glombik Dec 14, 2024
4eee57b
Remove outdated wizard component
florian-glombik Dec 14, 2024
e9b8930
Fix accidental import of translation mock
florian-glombik Dec 14, 2024
f9def97
Fix reactivity for date selection
florian-glombik Dec 14, 2024
e14fd54
Convert outputs to signals
florian-glombik Dec 14, 2024
1a3fa85
Fix reactivity for description change
florian-glombik Dec 14, 2024
e5bcb3b
Fix valiation if description text is added and deleted again to no de…
florian-glombik Dec 14, 2024
0a372fe
Fix client tests
florian-glombik Dec 14, 2024
89847ed
Fix client tests
florian-glombik Dec 14, 2024
f008e8e
Reduce imports and mocks
florian-glombik Dec 14, 2024
fc38c08
Reduce imports and mocks
florian-glombik Dec 14, 2024
c7c839b
Fix client test
florian-glombik Dec 14, 2024
0127ac3
Reduce imports and add mocks where possible
florian-glombik Dec 14, 2024
e7bcd0f
Add test for skipping dismiss modal
florian-glombik Dec 14, 2024
2861df7
Add another test not requiring opening the modal
florian-glombik Dec 14, 2024
7e8225e
Add test that uses modal response
florian-glombik Dec 14, 2024
5c1c0bd
Add tests for true and false mock modal
florian-glombik Dec 14, 2024
c919351
Add tests for isChangeMadeTo Title/Period section methods
florian-glombik Dec 14, 2024
08a15b1
Make pre compiler happy
florian-glombik Dec 14, 2024
86032c7
Make pre compiler happy
florian-glombik Dec 14, 2024
18880e0
Make pre compiler happy
florian-glombik Dec 14, 2024
d32e120
Fix validation when clearing date that was empty
florian-glombik Dec 14, 2024
91571b4
Simplify solution
florian-glombik Dec 14, 2024
0b5e78c
Add test for edge case
florian-glombik Dec 14, 2024
a66c70b
Add title to "title"-section
florian-glombik Dec 15, 2024
cc23408
Merge branch 'develop' into feature/lectures/add-dismiss-modal-for-un…
florian-glombik Dec 15, 2024
c8a5fef
Merge branch 'develop' into feature/lectures/add-dismiss-modal-for-un…
florian-glombik Dec 15, 2024
d4e54e6
Remove not required ArtemisSharedModule
florian-glombik Dec 16, 2024
c249e87
Merge branch 'develop' into feature/lectures/add-dismiss-modal-for-un…
florian-glombik Dec 16, 2024
4afc64f
Address Ramonas Feedback
florian-glombik Dec 17, 2024
5f5d966
Fix nominative
florian-glombik Dec 17, 2024
b82155b
Merge branch 'develop' into feature/lectures/add-dismiss-modal-for-un…
florian-glombik Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, effect, inject, input, signal } from '@angular/core';
import { Component, Input, OnChanges, SimpleChanges, ViewChild, effect, inject, input, output, signal } from '@angular/core';
import { Course, isCommunicationEnabled } from 'app/entities/course.model';
import { Exercise } from 'app/entities/exercise.model';
import { TitleChannelNameComponent } from 'app/shared/form/title-channel-name/title-channel-name.component';
Expand All @@ -22,8 +22,8 @@ export class ExerciseTitleChannelNameComponent implements OnChanges {

@ViewChild(TitleChannelNameComponent) titleChannelNameComponent: TitleChannelNameComponent;

@Output() onTitleChange = new EventEmitter<string>();
@Output() onChannelNameChange = new EventEmitter<string>();
onTitleChange = output<string>();
onChannelNameChange = output<string>();

private readonly exerciseService: ExerciseService = inject(ExerciseService);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div class="modal-header">
<h4 class="modal-title" jhiTranslate="artemisApp.lecture.dismissChangesModal.title"></h4>
</div>
<div class="modal-body">
<span jhiTranslate="artemisApp.lecture.dismissChangesModal.message" class="fw-bold"></span><br />
<!-- check if translation should be singular or plural, to be exchanged
with computed signals once input signals are supported with ng-bootstrap modals -->
@if (hasUnsavedChangesInTitleSection && hasUnsavedChangesInPeriodSection) {
florian-glombik marked this conversation as resolved.
Show resolved Hide resolved
<span jhiTranslate="artemisApp.lecture.dismissChangesModal.sectionsThatContainUnsavedChangesPlural"></span>
} @else {
<span jhiTranslate="artemisApp.lecture.dismissChangesModal.sectionsThatContainUnsavedChangesSingular"></span>
}
<ul>
@if (hasUnsavedChangesInTitleSection) {
<li>
<span jhiTranslate="artemisApp.lecture.wizardMode.steps.titleStepTitle"></span>
</li>
}
@if (hasUnsavedChangesInPeriodSection) {
<li>
<span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepTitle"></span>
</li>
}
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-default" (click)="closeWindow(true)">
<span jhiTranslate="entity.action.discardChanges"></span>
</button>
<button type="button" (click)="closeWindow(false)" class="btn btn-primary" type="submit">
<fa-icon [icon]="faTimes" />
<span class="ms-1" jhiTranslate="entity.action.cancel"></span>
</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Component, Input, inject } from '@angular/core';
import { TranslateDirective } from 'app/shared/language/translate.directive';
import { faTimes } from '@fortawesome/free-solid-svg-icons';
import { ArtemisSharedCommonModule } from 'app/shared/shared-common.module';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
selector: 'jhi-close-edit-lecture-modal',
standalone: true,
imports: [TranslateDirective, ArtemisSharedCommonModule],
templateUrl: './close-edit-lecture-modal.component.html',
})
export class CloseEditLectureModalComponent {
protected readonly faTimes = faTimes;

protected readonly activeModal = inject(NgbActiveModal);

// no input signals yet as they can not be initialized with current ng-bootstrap version https://stackoverflow.com/a/79094268/16540383
@Input() hasUnsavedChangesInTitleSection: boolean;
@Input() hasUnsavedChangesInPeriodSection: boolean;

closeWindow(isCloseConfirmed: boolean): void {
this.activeModal.close(isCloseConfirmed);
}
}
28 changes: 28 additions & 0 deletions src/main/webapp/app/lecture/hasLectureUnsavedChanges.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { inject } from '@angular/core';
import { CanDeactivateFn } from '@angular/router';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { LectureUpdateComponent } from 'app/lecture/lecture-update.component';
import { Observable, from, of } from 'rxjs';
import { CloseEditLectureModalComponent } from 'app/lecture/close-edit-lecture-dialog/close-edit-lecture-modal.component';

export const hasLectureUnsavedChangesGuard: CanDeactivateFn<LectureUpdateComponent> = (component: LectureUpdateComponent): Observable<boolean> => {
if (!component.shouldDisplayDismissWarning || component.isShowingWizardMode) {
return of(true);
}

if (component.isChangeMadeToTitleOrPeriodSection) {
const modalService = inject(NgbModal);

const modalRef: NgbModalRef = modalService.open(CloseEditLectureModalComponent, {
size: 'lg',
backdrop: 'static',
animation: true,
});
modalRef.componentInstance.hasUnsavedChangesInTitleSection = component.isChangeMadeToTitleSection();
modalRef.componentInstance.hasUnsavedChangesInPeriodSection = component.isChangeMadeToPeriodSection();

return from(modalRef.result);
}

return of(true);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<div>
<h1><span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepTitle"></span></h1>
<h2 id="artemisApp.lecture.wizardMode.steps.periodStepTitle"><span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepTitle"></span></h2>
<p><span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepMessage"></span></p>
<div class="d-flex">
<div class="form-group flex-grow-1">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.visibleDate' | artemisTranslate }}"
[(ngModel)]="lecture.visibleDate"
[(ngModel)]="lecture().visibleDate"
(valueChange)="validateDatesFunction()"
name="visibleDate"
id="visible-date"
Expand All @@ -14,7 +14,7 @@ <h1><span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepTitle"></s
<div class="form-group flex-grow-1 ms-3">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.startDate' | artemisTranslate }}"
[(ngModel)]="lecture.startDate"
[(ngModel)]="lecture().startDate"
(valueChange)="validateDatesFunction()"
name="startDate"
id="start-date"
Expand All @@ -23,7 +23,7 @@ <h1><span jhiTranslate="artemisApp.lecture.wizardMode.steps.periodStepTitle"></s
<div class="form-group flex-grow-1 ms-3">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.endDate' | artemisTranslate }}"
[(ngModel)]="lecture.endDate"
[(ngModel)]="lecture().endDate"
(valueChange)="validateDatesFunction()"
name="endDate"
id="end-date"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Component, Input, Signal, computed, input, viewChildren } from '@angular/core';
import { Lecture } from 'app/entities/lecture.model';
import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component';

@Component({
selector: 'jhi-lecture-update-period',
templateUrl: './lecture-period.component.html',
})
export class LectureUpdatePeriodComponent {
lecture = input.required<Lecture>();
@Input() validateDatesFunction: () => void;

periodSectionDatepickers = viewChildren(FormDateTimePickerComponent);

isPeriodSectionValid: Signal<boolean> = computed(() => {
for (const periodSectionDatepicker of this.periodSectionDatepickers()) {
if (!periodSectionDatepicker.isValid()) {
return false;
}
}
return true;
});
}
florian-glombik marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, viewChild } from '@angular/core';
import { isCommunicationEnabled } from 'app/entities/course.model';
import { Lecture } from 'app/entities/lecture.model';
import { TitleChannelNameComponent } from 'app/shared/form/title-channel-name/title-channel-name.component';

@Component({
selector: 'jhi-lecture-title-channel-name',
Expand All @@ -9,6 +10,8 @@ import { Lecture } from 'app/entities/lecture.model';
export class LectureTitleChannelNameComponent implements OnInit {
@Input() lecture: Lecture;

titleChannelNameComponent = viewChild.required(TitleChannelNameComponent);

hideChannelNameInput = false;
ngOnInit() {
this.hideChannelNameInput = !this.requiresChannelName(this.lecture);
Expand Down
56 changes: 21 additions & 35 deletions src/main/webapp/app/lecture/lecture-update.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[toggleModeFunction]="toggleModeFunction"
[saveLectureFunction]="saveLectureFunction"
[validateDatesFunction]="onDatesValuesChanged"
[lecture]="lecture"
[lecture]="lecture()"
[isSaving]="isSaving"
/>
}
Expand All @@ -27,45 +27,24 @@ <h2 id="jhi-lecture-heading" jhiTranslate="artemisApp.lecture.home.createOrEditL
</div>
</div>
<div>
<jhi-lecture-title-channel-name [lecture]="lecture" />
<h2 id="artemisApp.lecture.wizardMode.steps.titleStepTitle"><span jhiTranslate="artemisApp.lecture.wizardMode.steps.titleStepTitle"></span></h2>
<p><span jhiTranslate="artemisApp.lecture.wizardMode.steps.titleStepMessage"></span></p>
florian-glombik marked this conversation as resolved.
Show resolved Hide resolved
<jhi-lecture-title-channel-name [lecture]="lecture()" />
<div class="form-group" id="field_description">
<label class="form-control-label" jhiTranslate="artemisApp.lecture.description" for="field_description"></label>
<jhi-markdown-editor-monaco class="markdown-editor" [domainActions]="domainActionsDescription" [(markdown)]="lecture.description" />
</div>
<div class="d-flex">
<div class="form-group flex-grow-1">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.visibleDate' | artemisTranslate }}"
[(ngModel)]="lecture.visibleDate"
(valueChange)="onDatesValuesChanged()"
name="visibleDate"
id="visible-date"
/>
</div>
<div class="form-group flex-grow-1 ms-3">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.startDate' | artemisTranslate }}"
[(ngModel)]="lecture.startDate"
(valueChange)="onDatesValuesChanged()"
name="startDate"
id="start-date"
/>
</div>
<div class="form-group flex-grow-1 ms-3">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.endDate' | artemisTranslate }}"
[(ngModel)]="lecture.endDate"
(valueChange)="onDatesValuesChanged()"
name="endDate"
id="end-date"
/>
</div>
<jhi-markdown-editor-monaco
class="markdown-editor"
[domainActions]="domainActionsDescription"
[(markdown)]="lecture().description"
(markdownChange)="updateIsChangesMadeToTitleOrPeriodSection()"
/>
</div>
@if (lecture.course) {
<jhi-lecture-update-period [lecture]="lecture()" [validateDatesFunction]="onDatesValuesChanged" />
@if (lecture().course) {
<div class="form-group">
<label class="form-control-label" jhiTranslate="artemisApp.lecture.course" for="field_course"></label>
<div class="d-flex">
<input id="field_course" disabled type="text" class="form-control" name="course" [(ngModel)]="lecture.course.title" />
<input id="field_course" disabled type="text" class="form-control" name="course" [(ngModel)]="lecture().course!.title" />
</div>
</div>
}
Expand Down Expand Up @@ -116,7 +95,14 @@ <h2 id="jhi-lecture-heading" jhiTranslate="artemisApp.lecture.home.createOrEditL
<button type="button" id="cancel-save" class="btn btn-secondary" (click)="previousState()">
<fa-icon [icon]="faBan" />&nbsp;<span jhiTranslate="entity.action.cancel"></span>
</button>
<button type="submit" id="save-entity" [disabled]="editForm.form.invalid || isSaving || processUnitMode" class="btn btn-primary">
<button
type="submit"
id="save-entity"
[disabled]="
editForm.form.invalid || isSaving || processUnitMode || !isChangeMadeToTitleOrPeriodSection || !lecturePeriodSection()?.isPeriodSectionValid()
"
class="btn btn-primary"
>
<fa-icon [icon]="faSave" />&nbsp;<span jhiTranslate="entity.action.save"></span>
</button>
</div>
Expand Down
Loading
Loading