From 1b0ee488f72f86e157799af07740bdd33cf9b3de Mon Sep 17 00:00:00 2001 From: Matti Lupari Date: Thu, 11 Jan 2024 14:53:02 +0200 Subject: [PATCH] CSCEXAM-000 Take new control flow syntax in use --- .../api/CollaborativeAttachmentInterface.java | 8 +- .../impl/CollaborationController.java | 12 +- .../transfer/impl/DataTransferController.java | 8 +- .../impl/ExternalAttachmentLoaderImpl.java | 13 +- app/impl/AutoEvaluationHandlerImpl.java | 2 +- app/models/questions/Question.java | 18 +- app/models/sections/ExamSectionQuestion.java | 2 +- app/repository/EnrolmentRepository.java | 12 +- ui/package.json | 4 +- .../categories/enrolments-report.component.ts | 25 +- .../categories/exams-report.component.ts | 41 +- .../categories/rooms-report.component.ts | 25 +- .../categories/students-report.component.ts | 19 +- .../categories/teachers-report.component.ts | 25 +- .../reports/reports.component.ts | 45 +- .../settings/settings.component.html | 301 +++--- .../settings/settings.component.ts | 10 +- .../categories/exam-statistics.component.ts | 65 +- .../categories/room-statistics.component.ts | 28 +- .../statistics/statistics.component.html | 60 +- .../statistics/statistics.component.ts | 4 +- .../administrative/users/users.component.html | 398 ++++---- .../administrative/users/users.component.ts | 4 +- ui/src/app/app.component.ts | 26 +- .../calendar/booking-calendar.component.ts | 23 +- ui/src/app/calendar/calendar.component.html | 61 +- ui/src/app/calendar/calendar.component.ts | 3 +- .../calendar/helpers/exam-info.component.ts | 37 +- .../helpers/optional-sections.component.ts | 114 ++- .../helpers/organisation-picker.component.ts | 43 +- .../helpers/selected-room.component.ts | 85 +- .../helpers/slot-picker.component.html | 153 ++- .../calendar/helpers/slot-picker.component.ts | 4 +- .../exam-list-category.component.html | 205 ++-- .../exam-list-category.component.ts | 4 +- .../teacher/teacher-dashboard.component.html | 8 +- .../teacher/teacher-dashboard.component.ts | 8 +- .../teacher/teacher-dashboard.service.ts | 6 +- .../student/student-dashboard.component.html | 22 +- .../student/student-dashboard.component.ts | 4 +- .../student/student-dashboard.service.ts | 5 +- .../active/active-enrolment.component.html | 599 ++++++------ .../active/active-enrolment.component.ts | 10 +- ...lect-examination-event-dialog.component.ts | 38 +- .../active-enrolment-menu.component.html | 167 ++-- .../active-enrolment-menu.component.ts | 3 +- .../exam-enrolment-details.component.html | 76 +- .../exams/exam-enrolment-details.component.ts | 3 +- .../exams/exam-enrolments.component.ts | 40 +- ...aborative-exam-participations.component.ts | 4 +- .../exam-answers-dialog.component.html | 300 +++--- .../finished/exam-answers-dialog.component.ts | 4 +- .../finished/exam-feedback.component.html | 320 ++++--- .../finished/exam-feedback.component.ts | 4 +- .../exam-participation.component.html | 120 ++- .../finished/exam-participation.component.ts | 3 +- .../exam-participations.component.html | 52 +- .../finished/exam-participations.component.ts | 5 +- .../collaborative-exam-search.component.ts | 26 +- .../search/exam-search-result.component.ts | 86 +- .../enrolment/search/exam-search.component.ts | 87 +- .../waiting-room/waiting-room.component.html | 203 ++-- .../waiting-room/waiting-room.component.ts | 3 +- .../wrong-location.component.html | 138 +-- .../wrong-location.component.ts | 4 +- .../wrong-location/wrong-location.service.ts | 5 +- .../collaborative-exam-listing.component.html | 94 +- .../collaborative-exam-listing.component.ts | 4 +- .../collaborative-exam.service.ts | 5 +- .../assessment/auto-evaluation.component.html | 168 ++-- .../assessment/auto-evaluation.component.ts | 9 +- .../assessment/exam-assessment.component.html | 82 +- .../assessment/exam-assessment.component.ts | 4 +- .../exam-feedback-config.component.html | 102 +- .../exam-feedback-config.component.ts | 4 +- .../basic/basic-exam-info.component.html | 156 +-- .../editor/basic/basic-exam-info.component.ts | 3 +- .../exam-inspector-picker.component.html | 30 +- .../basic/exam-inspector-picker.component.ts | 9 +- .../basic/exam-owner-picker.component.html | 32 +- .../basic/exam-owner-picker.component.ts | 10 +- .../editor/basic/software-picker.component.ts | 42 +- .../common/course-picker.component.html | 30 +- .../editor/common/course-picker.component.ts | 4 +- .../examination-type-picker.component.ts | 59 +- .../common/language-picker.component.ts | 25 +- .../creation/course-selection.component.html | 206 ++-- .../creation/course-selection.component.ts | 3 +- .../editor/creation/new-exam.component.html | 97 +- .../editor/creation/new-exam.component.ts | 9 +- .../examination-event-dialog.component.html | 67 +- .../examination-event-dialog.component.ts | 4 +- .../examination-event-search.component.html | 232 ++--- .../examination-event-search.component.ts | 4 +- .../app/exam/editor/exam-tabs.component.html | 38 +- ui/src/app/exam/editor/exam-tabs.component.ts | 14 +- ...llaborative-exam-owner-picker.component.ts | 46 +- .../exam-participant-picker.component.ts | 56 +- .../exam-pre-participant-picker.component.ts | 56 +- .../exam-publication.component.html | 456 ++++----- .../publication/exam-publication.component.ts | 4 +- .../organisation-picker.component.ts | 84 +- .../publication-dialog.component.ts | 19 +- .../publication-error-dialog.component.ts | 10 +- .../exam-material-picker.component.html | 30 +- .../exam-material-picker.component.ts | 10 +- .../sections/exam-material.component.html | 32 +- .../sections/exam-material.component.ts | 6 +- .../sections/section-question.component.html | 247 ++--- .../sections/section-question.component.ts | 4 +- .../editor/sections/section.component.html | 220 +++-- .../exam/editor/sections/section.component.ts | 4 +- .../editor/sections/sections.component.html | 92 +- .../editor/sections/sections.component.ts | 4 +- .../app/exam/listing/exam-list.component.html | 162 ++-- .../app/exam/listing/exam-list.component.ts | 4 +- .../app/exam/printout/printout.component.html | 169 ++-- .../app/exam/printout/printout.component.ts | 13 +- .../app/exam/printout/printouts.component.ts | 49 +- .../clock/examination-clock.component.ts | 39 +- .../examination/examination.component.html | 62 +- .../app/examination/examination.component.ts | 3 +- .../header/examination-header.component.ts | 24 +- .../answer-instructions.component.ts | 24 +- .../logout/examination-logout.component.ts | 8 +- .../examination-navigation.component.ts | 45 +- .../examination-toolbar.component.html | 121 +-- .../examination-toolbar.component.ts | 4 +- .../examination-cloze-test.component.ts | 26 +- .../examination-essay-question.component.html | 120 +-- .../examination-essay-question.component.ts | 4 +- ...ination-multi-choice-question.component.ts | 53 +- .../examination-question.component.html | 192 ++-- .../examination-question.component.ts | 5 +- ...eighted-multi-choice-question.component.ts | 28 +- .../section/examination-section.component.ts | 81 +- .../accessibility-picker.component.ts | 29 +- .../accessibility.component.html | 77 +- .../accessibility/accessibility.component.ts | 4 +- .../app/facility/address/address.component.ts | 6 +- ui/src/app/facility/facility.component.html | 16 +- ui/src/app/facility/facility.component.ts | 3 +- .../facility/machines/machine.component.html | 214 ++--- .../facility/machines/machine.component.ts | 4 +- .../facility/machines/machines.component.html | 71 +- .../facility/machines/machines.component.ts | 10 +- .../rooms/availability.component.html | 102 +- .../facility/rooms/availability.component.ts | 10 +- .../rooms/room-mass-edit.component.ts | 72 +- ui/src/app/facility/rooms/room.component.html | 480 +++++----- ui/src/app/facility/rooms/room.component.ts | 3 +- .../app/facility/rooms/rooms.component.html | 364 ++++--- ui/src/app/facility/rooms/rooms.component.ts | 4 +- .../exception-delete-dialog.component.ts | 22 +- .../schedule/exception-dialog.component.html | 815 ++++++++-------- .../schedule/exception-dialog.component.ts | 13 +- .../facility/schedule/exceptions.component.ts | 70 +- .../schedule/opening-hours.component.ts | 123 +-- .../schedule/starting-time.component.ts | 23 +- ui/src/app/interceptors/error-interceptor.ts | 5 +- .../language-inspections.component.ts | 31 +- .../reviewed-inspections.component.html | 200 ++-- .../listing/reviewed-inspections.component.ts | 4 +- .../unfinished-inspections.component.html | 172 ++-- .../unfinished-inspections.component.ts | 4 +- .../maturity-reporting.component.html | 105 ++- .../reporting/maturity-reporting.component.ts | 4 +- .../app/navigation/navigation.component.html | 256 ++--- ui/src/app/navigation/navigation.component.ts | 4 +- ui/src/app/navigation/navigation.service.ts | 6 +- .../basequestion/claim-choice.component.ts | 95 +- .../question/basequestion/essay.component.ts | 14 +- .../multiple-choice-option.component.ts | 18 +- .../basequestion/multiple-choice.component.ts | 122 +-- .../basequestion/question-body.component.html | 48 +- .../basequestion/question-body.component.ts | 6 +- .../basequestion/question.component.html | 35 +- .../basequestion/question.component.ts | 4 +- ...ighted-multiple-choice-option.component.ts | 5 +- .../exam-question-editor.component.ts | 17 +- .../examquestion/exam-question.component.html | 891 +++++++++--------- .../examquestion/exam-question.component.ts | 4 +- .../library-transfer-dialog.component.html | 17 +- .../library-transfer-dialog.component.ts | 4 +- .../app/question/library/library.component.ts | 19 +- .../results/library-results.component.html | 284 +++--- .../results/library-results.component.ts | 4 +- .../search/library-search.component.html | 141 ++- .../search/library-search.component.ts | 14 +- .../question-preview-dialog.component.ts | 25 +- .../app/question/tags/tag-picker.component.ts | 37 +- .../remove-reservation-dialog.component.ts | 6 +- .../reservation-details.component.html | 324 ++++--- .../reservation-details.component.ts | 4 +- ui/src/app/reservation/reservation.service.ts | 4 +- .../reservation/reservations.component.html | 162 ++-- .../app/reservation/reservations.component.ts | 11 +- .../assessment/assessment.component.html | 241 ++--- .../review/assessment/assessment.component.ts | 4 +- .../assessment/feedback/feedback.component.ts | 24 +- .../feedback/statement.component.ts | 28 +- .../general/general-info.component.html | 161 ++-- .../general/general-info.component.ts | 17 +- .../assessment/general/no-show.component.ts | 2 +- .../general/participation.component.ts | 20 +- .../assessment/grading/grading.component.html | 112 ++- .../assessment/grading/grading.component.ts | 4 +- .../grading/inspection.component.ts | 63 +- .../assessment/grading/toolbar.component.ts | 36 +- .../maturity/grading.component.html | 111 ++- .../assessment/maturity/grading.component.ts | 4 +- .../maturity/inspection-comments.component.ts | 41 +- .../assessment/maturity/toolbar.component.ts | 126 +-- .../print/printed-assessment.component.html | 456 +++++---- .../print/printed-assessment.component.ts | 4 +- .../print/printed-cloze-test.component.ts | 4 +- .../print/printed-essay.component.ts | 4 +- .../print/printed-multi-choice.component.ts | 4 +- .../print/printed-section.component.ts | 39 +- .../print/templates/cloze-test.component.html | 30 +- .../print/templates/essay.component.html | 78 +- .../templates/multi-choice.component.html | 157 +-- .../claim-choice-answer.component.ts | 56 +- .../questions/cloze-test.component.html | 120 ++- .../questions/cloze-test.component.ts | 12 +- .../questions/essay-question.component.html | 242 +++-- .../questions/essay-question.component.ts | 3 +- .../multi-choice-answer.component.ts | 118 +-- .../multi-choice-question.component.html | 211 +++-- .../multi-choice-question.component.ts | 3 +- .../weighted-multi-choice-answer.component.ts | 106 ++- .../sections/section.component.html | 185 ++-- .../assessment/sections/section.component.ts | 18 +- .../categories/archived.component.html | 318 ++++--- .../listing/categories/archived.component.ts | 4 +- .../categories/graded-logged.component.html | 542 ++++++----- .../categories/graded-logged.component.ts | 4 +- .../listing/categories/graded.component.html | 532 ++++++----- .../listing/categories/graded.component.ts | 4 +- .../in-language-inspection.component.html | 372 ++++---- .../in-language-inspection.component.ts | 4 +- .../categories/in-progress.component.html | 439 +++++---- .../categories/in-progress.component.ts | 4 +- .../categories/rejected.component.html | 348 +++---- .../listing/categories/rejected.component.ts | 4 +- .../listing/dialogs/aborted.component.html | 251 ++--- .../listing/dialogs/aborted.component.ts | 4 +- .../dialogs/archive-download.component.ts | 6 +- .../listing/dialogs/feedback.component.ts | 29 +- .../listing/dialogs/no-shows.component.html | 165 ++-- .../listing/dialogs/no-shows.component.ts | 9 +- .../review/listing/review-list.component.html | 106 ++- .../review/listing/review-list.component.ts | 4 +- .../app/review/listing/review-list.service.ts | 6 +- .../listing/speed-review.component.html | 358 +++---- .../review/listing/speed-review.component.ts | 4 +- .../summary/exam-summary.component.html | 82 +- .../listing/summary/exam-summary.component.ts | 4 +- .../listing/summary/exam-summary.service.ts | 41 +- .../assessment/essay-answer.component.html | 245 ++--- .../assessment/essay-answer.component.ts | 9 +- .../assessment/essay-answers.component.ts | 44 +- .../question-assessment.component.html | 114 ++- .../question-assessment.component.ts | 3 +- .../flow/question-flow-category.component.ts | 50 +- .../questions/flow/question-flow.component.ts | 41 +- .../listing/question-review.component.ts | 109 ++- .../listing/question-reviews.component.ts | 102 +- .../app/session/eula/eula-dialog.component.ts | 5 +- .../role/role-picker-dialog.component.ts | 21 +- .../shared/attachment/attachment.service.ts | 4 +- .../dialogs/attachment-picker.component.ts | 19 +- .../app/shared/date/date-picker.component.ts | 5 +- ui/src/app/shared/file/file.service.ts | 6 +- .../miscellaneous/common-exam.service.ts | 5 +- .../miscellaneous/course-code.component.ts | 9 +- .../shared/paginator/paginator.component.ts | 17 +- .../select/dropdown-select.component.ts | 61 +- .../app/shared/user/teacher-list.component.ts | 10 +- ui/src/app/software/software.component.html | 72 +- ui/src/app/software/software.component.ts | 10 +- 281 files changed, 11552 insertions(+), 9940 deletions(-) diff --git a/app/controllers/iop/collaboration/api/CollaborativeAttachmentInterface.java b/app/controllers/iop/collaboration/api/CollaborativeAttachmentInterface.java index 5e85d4fcb4..0d4324f748 100644 --- a/app/controllers/iop/collaboration/api/CollaborativeAttachmentInterface.java +++ b/app/controllers/iop/collaboration/api/CollaborativeAttachmentInterface.java @@ -102,12 +102,8 @@ default Either, LanguageInspection> findLanguageInspecti Http.MultipartFormData.FilePart file ) { Source> source = FileIO.fromPath(file.getRef().path()); - Http.MultipartFormData.FilePart>> filePart = new Http.MultipartFormData.FilePart<>( - "file", - file.getFilename(), - file.getContentType(), - source - ); + Http.MultipartFormData.FilePart>> filePart = + new Http.MultipartFormData.FilePart<>("file", file.getFilename(), file.getContentType(), source); return Source.from(Set.of(filePart)); } diff --git a/app/controllers/iop/collaboration/impl/CollaborationController.java b/app/controllers/iop/collaboration/impl/CollaborationController.java index 70de3e81d7..627d6ad814 100644 --- a/app/controllers/iop/collaboration/impl/CollaborationController.java +++ b/app/controllers/iop/collaboration/impl/CollaborationController.java @@ -142,30 +142,26 @@ boolean isAuthorizedToView(Exam exam, User user, String homeOrg) { } return ( user.getLoginRole() == Role.Name.ADMIN || - ( - exam + (exam .getExamOwners() .stream() .anyMatch(u -> u.getEmail().equalsIgnoreCase(user.getEmail()) || u.getEmail().equalsIgnoreCase(user.getEppn()) ) && - exam.hasState(Exam.State.PRE_PUBLISHED, Exam.State.PUBLISHED) - ) + exam.hasState(Exam.State.PRE_PUBLISHED, Exam.State.PUBLISHED)) ); } boolean isUnauthorizedToAssess(Exam exam, User user) { return ( user.getLoginRole() != Role.Name.ADMIN && - ( - exam + (exam .getExamOwners() .stream() .noneMatch(u -> u.getEmail().equalsIgnoreCase(user.getEmail()) || u.getEmail().equalsIgnoreCase(user.getEppn()) ) || - !exam.hasState(Exam.State.REVIEW, Exam.State.REVIEW_STARTED, Exam.State.GRADED) - ) + !exam.hasState(Exam.State.REVIEW, Exam.State.REVIEW_STARTED, Exam.State.GRADED)) ); } diff --git a/app/controllers/iop/transfer/impl/DataTransferController.java b/app/controllers/iop/transfer/impl/DataTransferController.java index f0d18f7223..9f6bfa2eb9 100644 --- a/app/controllers/iop/transfer/impl/DataTransferController.java +++ b/app/controllers/iop/transfer/impl/DataTransferController.java @@ -203,12 +203,8 @@ public CompletionStage exportData(Http.Request request) throws IOExcepti Attachment attachment ) { Source> source = FileIO.fromPath(Path.of(attachment.getFilePath())); - Http.MultipartFormData.FilePart>> filePart = new Http.MultipartFormData.FilePart<>( - "file", - attachment.getFileName(), - attachment.getMimeType(), - source - ); + Http.MultipartFormData.FilePart>> filePart = + new Http.MultipartFormData.FilePart<>("file", attachment.getFileName(), attachment.getMimeType(), source); return Source.from(Set.of(filePart)); } diff --git a/app/controllers/iop/transfer/impl/ExternalAttachmentLoaderImpl.java b/app/controllers/iop/transfer/impl/ExternalAttachmentLoaderImpl.java index d3c001655a..1f93dc91d4 100644 --- a/app/controllers/iop/transfer/impl/ExternalAttachmentLoaderImpl.java +++ b/app/controllers/iop/transfer/impl/ExternalAttachmentLoaderImpl.java @@ -136,12 +136,13 @@ public CompletableFuture createExternalAttachment(Attachment attachment) { return; } final Source> source = FileIO.fromPath(file.toPath()); - final Http.MultipartFormData.FilePart>> filePart = new Http.MultipartFormData.FilePart<>( - "file", - attachment.getFileName(), - attachment.getMimeType(), - source - ); + final Http.MultipartFormData.FilePart>> filePart = + new Http.MultipartFormData.FilePart<>( + "file", + attachment.getFileName(), + attachment.getMimeType(), + source + ); Http.MultipartFormData.DataPart dp = new Http.MultipartFormData.DataPart("key", "value"); updateRequest diff --git a/app/impl/AutoEvaluationHandlerImpl.java b/app/impl/AutoEvaluationHandlerImpl.java index cd1cc85acf..5117677bb4 100644 --- a/app/impl/AutoEvaluationHandlerImpl.java +++ b/app/impl/AutoEvaluationHandlerImpl.java @@ -107,7 +107,7 @@ private Optional resolveScale(Exam exam) { private Grade getGradeBasedOnScore(Exam exam) { Double totalScore = exam.getTotalScore(); Double maxScore = exam.getMaxScore(); - Double percentage = maxScore == 0 ? 0 : totalScore * 100 / maxScore; + Double percentage = maxScore == 0 ? 0 : (totalScore * 100) / maxScore; List gradeEvaluations = new ArrayList<>(exam.getAutoEvaluationConfig().getGradeEvaluations()); gradeEvaluations.sort(Comparator.comparingInt(GradeEvaluation::getPercentage)); Grade grade = null; diff --git a/app/models/questions/Question.java b/app/models/questions/Question.java index 70acdfa528..142c40e801 100644 --- a/app/models/questions/Question.java +++ b/app/models/questions/Question.java @@ -316,21 +316,15 @@ private boolean getClaimChoiceOptionsValidationResult(ArrayNode options) { } return ( - ( - type == MultipleChoiceOption.ClaimChoiceOptionType.CorrectOption && + (type == MultipleChoiceOption.ClaimChoiceOptionType.CorrectOption && defaultScore > 0 && - !option.isEmpty() - ) || - ( - type == MultipleChoiceOption.ClaimChoiceOptionType.IncorrectOption && + !option.isEmpty()) || + (type == MultipleChoiceOption.ClaimChoiceOptionType.IncorrectOption && defaultScore <= 0 && - !option.isEmpty() - ) || - ( - type == MultipleChoiceOption.ClaimChoiceOptionType.SkipOption && + !option.isEmpty()) || + (type == MultipleChoiceOption.ClaimChoiceOptionType.SkipOption && defaultScore == 0 && - !option.isEmpty() - ) + !option.isEmpty()) ); }) .map(n -> diff --git a/app/models/sections/ExamSectionQuestion.java b/app/models/sections/ExamSectionQuestion.java index 1fa58fb186..2fef1a045a 100644 --- a/app/models/sections/ExamSectionQuestion.java +++ b/app/models/sections/ExamSectionQuestion.java @@ -402,7 +402,7 @@ public Double getAssessedScore() { return 0.0; } DecimalFormat df = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US)); - double value = correct * maxScore / (correct + incorrect); + double value = (correct * maxScore) / (correct + incorrect); return Double.valueOf(df.format(value)); } case ClaimChoiceQuestion -> { diff --git a/app/repository/EnrolmentRepository.java b/app/repository/EnrolmentRepository.java index f6f5f8b5d0..c8b282a1cd 100644 --- a/app/repository/EnrolmentRepository.java +++ b/app/repository/EnrolmentRepository.java @@ -317,16 +317,12 @@ private boolean isInsideBounds(ExamEnrolment ee, int minutesToFuture) { ? ee.getExaminationEventConfiguration().getExaminationEvent() : null; return ( - ( - reservation != null && + (reservation != null && reservation.getStartAt().isBefore(latest) && - reservation.getEndAt().isAfter(earliest) - ) || - ( - event != null && + reservation.getEndAt().isAfter(earliest)) || + (event != null && event.getStart().isBefore(latest) && - event.getStart().plusMinutes(ee.getExam().getDuration()).isAfter(earliest) - ) + event.getStart().plusMinutes(ee.getExam().getDuration()).isAfter(earliest)) ); } diff --git a/ui/package.json b/ui/package.json index a3793dbfab..7bbd778293 100644 --- a/ui/package.json +++ b/ui/package.json @@ -89,10 +89,10 @@ "prettier --write" ], "../app/**/*.java": [ - "prettier --write --print-width=120 --tab-width=4" + "prettier --write --plugin=prettier-plugin-java --print-width=120 --tab-width=4" ], "../test/**/*.java": [ - "prettier --write --print-width=120 --tab-width=4" + "prettier --write --plugin=prettier-plugin-java --print-width=120 --tab-width=4" ], "src/app/**/*.ts": [ "eslint --fix" diff --git a/ui/src/app/administrative/reports/categories/enrolments-report.component.ts b/ui/src/app/administrative/reports/categories/enrolments-report.component.ts index 8b88705764..9d96c5b623 100644 --- a/ui/src/app/administrative/reports/categories/enrolments-report.component.ts +++ b/ui/src/app/administrative/reports/categories/enrolments-report.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import { Component, Input } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -30,13 +30,14 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown
- + @if (examNames) { + + }
@@ -57,13 +58,17 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown `, selector: 'xm-enrolments-report', standalone: true, - imports: [NgIf, DropdownSelectComponent, NgbPopover, TranslateModule], + imports: [DropdownSelectComponent, NgbPopover, TranslateModule], }) export class EnrolmentsReportComponent { @Input() examNames: Option[] = []; enrolment?: number; - constructor(private translate: TranslateService, private toast: ToastrService, private files: FileService) {} + constructor( + private translate: TranslateService, + private toast: ToastrService, + private files: FileService, + ) {} getExamEnrolments = () => { if (this.enrolment) { diff --git a/ui/src/app/administrative/reports/categories/exams-report.component.ts b/ui/src/app/administrative/reports/categories/exams-report.component.ts index c73adba9d5..8bfa8fbb7d 100644 --- a/ui/src/app/administrative/reports/categories/exams-report.component.ts +++ b/ui/src/app/administrative/reports/categories/exams-report.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import { Component, Input } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -25,20 +25,25 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown

{{ 'i18n_get_all_info_from_exam' | translate }} - {{ 'i18n_excel_file' | translate }} - {{ 'i18n_json_file' | translate }} + @if (fileType === 'xlsx') { + {{ 'i18n_excel_file' | translate }} + } + @if (fileType === 'json') { + {{ 'i18n_json_file' | translate }} + }

- + @if (examNames) { + + }
@@ -51,8 +56,12 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown popoverTitle="{{ 'i18n_instructions' | translate }}" ngbPopover="{{ 'i18n_download' | translate }}" > - - + @if (fileType === 'xlsx') { + + } + @if (fileType === 'json') { + + }
@@ -60,7 +69,7 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown `, selector: 'xm-exams-report', standalone: true, - imports: [NgIf, DropdownSelectComponent, NgbPopover, TranslateModule], + imports: [DropdownSelectComponent, NgbPopover, TranslateModule], }) export class ExamsReportComponent { @Input() examNames: Option[] = []; @@ -68,7 +77,11 @@ export class ExamsReportComponent { exam?: number; - constructor(private translate: TranslateService, private toast: ToastrService, private files: FileService) {} + constructor( + private translate: TranslateService, + private toast: ToastrService, + private files: FileService, + ) {} examSelected = (event?: Option) => (this.exam = event?.id); diff --git a/ui/src/app/administrative/reports/categories/rooms-report.component.ts b/ui/src/app/administrative/reports/categories/rooms-report.component.ts index 60b3156083..dfc1906669 100644 --- a/ui/src/app/administrative/reports/categories/rooms-report.component.ts +++ b/ui/src/app/administrative/reports/categories/rooms-report.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import { Component, Input } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -33,13 +33,14 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown
- + @if (rooms) { + + }
@@ -72,7 +73,7 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown `, selector: 'xm-rooms-report', standalone: true, - imports: [NgIf, DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], + imports: [DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], }) export class RoomsReportComponent { @Input() rooms: Option[] = []; @@ -81,7 +82,11 @@ export class RoomsReportComponent { startDate: Date | null = null; endDate: Date | null = null; - constructor(private translate: TranslateService, private toast: ToastrService, private files: FileService) {} + constructor( + private translate: TranslateService, + private toast: ToastrService, + private files: FileService, + ) {} roomSelected = (event?: Option) => { this.room = event?.id; diff --git a/ui/src/app/administrative/reports/categories/students-report.component.ts b/ui/src/app/administrative/reports/categories/students-report.component.ts index 25bcb85a94..f30f75c086 100644 --- a/ui/src/app/administrative/reports/categories/students-report.component.ts +++ b/ui/src/app/administrative/reports/categories/students-report.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, NgIf } from '@angular/common'; +import { DatePipe } from '@angular/common'; import { Component, Input } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -33,13 +33,14 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown
- + @if (students) { + + }
@@ -72,7 +73,7 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown `, selector: 'xm-students-report', standalone: true, - imports: [NgIf, DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], + imports: [DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], }) export class StudentsReportComponent { @Input() students: Option[] = []; diff --git a/ui/src/app/administrative/reports/categories/teachers-report.component.ts b/ui/src/app/administrative/reports/categories/teachers-report.component.ts index 3372b96f9d..bb677ecaf4 100644 --- a/ui/src/app/administrative/reports/categories/teachers-report.component.ts +++ b/ui/src/app/administrative/reports/categories/teachers-report.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import { Component, Input } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -33,13 +33,14 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown
- + @if (teachers) { + + }
@@ -72,7 +73,7 @@ import { DropdownSelectComponent, Option } from '../../../shared/select/dropdown `, selector: 'xm-teachers-report', standalone: true, - imports: [NgIf, DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], + imports: [DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule], }) export class TeachersReportComponent { @Input() teachers: Option[] = []; @@ -80,7 +81,11 @@ export class TeachersReportComponent { answerStartDate: Date | null = null; answerEndDate: Date | null = null; - constructor(private translate: TranslateService, private toast: ToastrService, private files: FileService) {} + constructor( + private translate: TranslateService, + private toast: ToastrService, + private files: FileService, + ) {} getTeacherExamsByDate = () => { const f = format(this.answerStartDate || new Date(), 'dd.MM.yyyy'); diff --git a/ui/src/app/administrative/reports/reports.component.ts b/ui/src/app/administrative/reports/reports.component.ts index 53f4a9322c..732866e24f 100644 --- a/ui/src/app/administrative/reports/reports.component.ts +++ b/ui/src/app/administrative/reports/reports.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import type { OnInit } from '@angular/core'; import { Component } from '@angular/core'; import { TranslateModule } from '@ngx-translate/core'; @@ -42,28 +42,37 @@ import { ReportsService, UserRole } from './reports.service';
-
-
- -
-
- -
-
- -
+ @if (rooms) { +
+ } + @if (examNames) { +
+ +
+ } + @if (students) { +
+ +
+ } + @if (examNames) { +
+ +
+ }
-
- -
+ @if (teachers) { +
+ +
+ }
`, standalone: true, imports: [ - NgIf, RoomsReportComponent, ExamsReportComponent, StudentsReportComponent, @@ -81,7 +90,11 @@ export class ReportsComponent implements OnInit { teachers: Option[] = []; students: Option[] = []; - constructor(private Users: UserService, private Reports: ReportsService, private Room: RoomService) {} + constructor( + private Users: UserService, + private Reports: ReportsService, + private Room: RoomService, + ) {} ngOnInit() { this.Room.getRooms$().subscribe((resp) => { diff --git a/ui/src/app/administrative/settings/settings.component.html b/ui/src/app/administrative/settings/settings.component.html index 5843aba41a..6638c533e9 100644 --- a/ui/src/app/administrative/settings/settings.component.html +++ b/ui/src/app/administrative/settings/settings.component.html @@ -5,20 +5,22 @@
-
-
- - + @if (config) { +
+
+ + +
-
+ }
-
-
- - + @if (config) { +
+
+ + +
-
+ }
-
-
- - + @if (config) { +
+
+ + +
-
+ }
-
- - - - - - - - - - - - - - - - - - - - - -
{{ 'i18n_rank' | translate }}{{ 'i18n_exam' | translate }}{{ 'i18n_amount_exams' | translate }}
{{ getRank(i, exams) }}.{{ exam.name }}{{ exam.participations }}
- {{ 'i18n_total' | translate }} - - {{ totalExams() }} -
-
+ @if (exams.length > 0) { +
+ + + + + + + + + + @for (exam of exams; track exam; let i = $index) { + + + + + + } + + + + + + + +
{{ 'i18n_rank' | translate }}{{ 'i18n_exam' | translate }}{{ 'i18n_amount_exams' | translate }}
{{ getRank(i, exams) }}.{{ exam.name }}{{ exam.participations }}
+ {{ 'i18n_total' | translate }} + + @if (exams) { + {{ totalExams() }} + } +
+
+ }
`, selector: 'xm-exam-statistics', standalone: true, - imports: [NgIf, NgFor, TranslateModule], + imports: [TranslateModule], }) export class ExamStatisticsComponent implements OnInit { @Input() queryParams: QueryParams = {}; diff --git a/ui/src/app/administrative/statistics/categories/room-statistics.component.ts b/ui/src/app/administrative/statistics/categories/room-statistics.component.ts index c7fda7dc77..b4aacb940a 100644 --- a/ui/src/app/administrative/statistics/categories/room-statistics.component.ts +++ b/ui/src/app/administrative/statistics/categories/room-statistics.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, NgFor } from '@angular/common'; +import { DatePipe } from '@angular/common'; import { Component, Input } from '@angular/core'; import { TranslateModule } from '@ngx-translate/core'; import type { ExamParticipation } from '../../../exam/exam.model'; @@ -34,23 +34,31 @@ import { StatisticsService } from '../statistics.service'; {{ 'i18n_year' | translate }} {{ 'i18n_month' | translate }} - {{ room.split('___')[1] }} + @for (room of rooms; track room) { + {{ room.split('___')[1] }} + } {{ 'i18n_total' | translate }} - - {{ month | date : 'yyyy' }} - {{ month | date : 'M' }} - {{ totalParticipations(month, room) }} - {{ totalParticipations(month) }} - + @for (month of months; track month) { + + {{ month | date: 'yyyy' }} + {{ month | date: 'M' }} + @for (room of rooms; track room) { + {{ totalParticipations(month, room) }} + } + {{ totalParticipations(month) }} + + } {{ 'i18n_total' | translate }} - {{ totalParticipations(undefined, room) }} + @for (room of rooms; track room) { + {{ totalParticipations(undefined, room) }} + } {{ totalParticipations() }} @@ -62,7 +70,7 @@ import { StatisticsService } from '../statistics.service'; `, selector: 'xm-room-statistics', standalone: true, - imports: [NgFor, DatePipe, TranslateModule], + imports: [DatePipe, TranslateModule], }) export class RoomStatisticsComponent { @Input() queryParams: QueryParams = {}; diff --git a/ui/src/app/administrative/statistics/statistics.component.html b/ui/src/app/administrative/statistics/statistics.component.html index 94cf515eb6..417b6df6f1 100644 --- a/ui/src/app/administrative/statistics/statistics.component.html +++ b/ui/src/app/administrative/statistics/statistics.component.html @@ -78,41 +78,51 @@

{{ 'i18n_department' | translate }}

- + @for (department of filteredDepartments; track department) { + + }
  • - - - + @for (department of departments; track department) { + @if (department.filtered) { + + } + }
- - - - + @if (view === 'ROOMS') { + + } + @if (view === 'RESERVATIONS') { + + } + @if (view === 'RESPONSES') { + + } + @if (view === 'EXAMS') { + + }
diff --git a/ui/src/app/administrative/statistics/statistics.component.ts b/ui/src/app/administrative/statistics/statistics.component.ts index ef3bdf9df3..6668af489f 100644 --- a/ui/src/app/administrative/statistics/statistics.component.ts +++ b/ui/src/app/administrative/statistics/statistics.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgClass, NgFor, NgIf } from '@angular/common'; +import { NgClass } from '@angular/common'; import type { OnInit } from '@angular/core'; import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -60,10 +60,8 @@ enum Tab { NgbDropdownToggle, NgbDropdownMenu, FormsModule, - NgFor, NgbDropdownItem, NgClass, - NgIf, RoomStatisticsComponent, ReservationStatisticsComponent, ResponseStatisticsComponent, diff --git a/ui/src/app/administrative/users/users.component.html b/ui/src/app/administrative/users/users.component.html index f5b83d9e18..1d7ba4d6c8 100644 --- a/ui/src/app/administrative/users/users.component.html +++ b/ui/src/app/administrative/users/users.component.html @@ -40,19 +40,20 @@ {{ 'i18n_filter_by_role' | translate }} 
- + @for (role of roles; track role) { + + }
@@ -68,19 +69,20 @@ {{ 'i18n_filter_by_permission' | translate }} 
- + @for (permission of permissions; track permission) { + + }
@@ -109,183 +111,201 @@ - - {{ user.lastName }} - {{ user.firstName }} - - {{ user.email }} - - {{ user.userIdentifier }} - {{ user.employeeNumber }} - {{ user.lastLogin | date : 'dd.MM.yyyy HH:mm:ss' }} - - - - - -
- - -
- + @for ( + user of filteredUsers | slice: currentPage * pageSize : currentPage * pageSize + pageSize; + track user + ) { + + {{ user.lastName }} + {{ user.firstName }} + + {{ user.email }} + + {{ user.userIdentifier }} + {{ user.employeeNumber }} + {{ user.lastLogin | date: 'dd.MM.yyyy HH:mm:ss' }} + + @if (hasRole(user, 'ADMIN')) { + + } + @if (hasRole(user, 'TEACHER')) { + + } + @if (hasRole(user, 'STUDENT')) { + + } +
+ -
- - - - - -
- - - - -
- - - + + + @if (hasPermission(user, 'CAN_INSPECT_LANGUAGE')) { + + } +
+ -
-
- - - - -
- - + @if (user.removablePermissions.length > 0) { + + } +
+
+ + + } -
- -
+ @if (filteredUsers && filteredUsers.length > pageSize) { +
+ +
+ }
diff --git a/ui/src/app/administrative/users/users.component.ts b/ui/src/app/administrative/users/users.component.ts index 01acdca83e..d810f1479a 100644 --- a/ui/src/app/administrative/users/users.component.ts +++ b/ui/src/app/administrative/users/users.component.ts @@ -1,4 +1,4 @@ -import { DatePipe, NgClass, NgFor, NgIf, SlicePipe } from '@angular/common'; +import { DatePipe, NgClass, SlicePipe } from '@angular/common'; import type { OnInit } from '@angular/core'; import { Component, OnDestroy } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -49,10 +49,8 @@ interface UserWithOptions extends User { NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, - NgFor, NgbDropdownItem, NgClass, - NgIf, PaginatorComponent, SlicePipe, DatePipe, diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 49fe6c7bcd..6eaff5a555 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgClass, NgIf, registerLocaleData } from '@angular/common'; +import { NgClass, registerLocaleData } from '@angular/common'; import localeEn from '@angular/common/locales/en'; import localeFi from '@angular/common/locales/fi'; import localeSv from '@angular/common/locales/sv'; @@ -29,18 +29,22 @@ import { SessionService } from './session/session.service'; @Component({ selector: 'xm-app', template: ` -
- -
-
- -
- -
-
+ @if (!user && devLoginRequired) { +
+ +
+ } + @if (user) { +
+ +
+ +
+
+ } `, standalone: true, - imports: [NgIf, DevLoginComponent, NavigationComponent, NgClass, RouterOutlet], + imports: [DevLoginComponent, NavigationComponent, NgClass, RouterOutlet], }) export class AppComponent implements OnInit, OnDestroy { user?: User; diff --git a/ui/src/app/calendar/booking-calendar.component.ts b/ui/src/app/calendar/booking-calendar.component.ts index 6f84b88edf..8d3efb4229 100644 --- a/ui/src/app/calendar/booking-calendar.component.ts +++ b/ui/src/app/calendar/booking-calendar.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgIf } from '@angular/common'; + import { AfterViewInit, ChangeDetectionStrategy, @@ -41,16 +41,20 @@ import { CalendarService } from './calendar.service'; selector: 'xm-booking-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: ` -
-
-
- + @if (visible) { +
+
+ @if (visible) { +
+ +
+ }
-
+ } `, standalone: true, - imports: [NgIf, FullCalendarModule], + imports: [FullCalendarModule], }) export class BookingCalendarComponent implements OnInit, OnChanges, AfterViewInit { @Output() eventSelected = new EventEmitter(); @@ -70,7 +74,10 @@ export class BookingCalendarComponent implements OnInit, OnChanges, AfterViewIni calendarOptions: CalendarOptions; - constructor(private translate: TranslateService, private Calendar: CalendarService) { + constructor( + private translate: TranslateService, + private Calendar: CalendarService, + ) { this.calendarOptions = { plugins: [luxon2Plugin, timeGridPlugin], initialView: 'timeGridWeek', diff --git a/ui/src/app/calendar/calendar.component.html b/ui/src/app/calendar/calendar.component.html index afc3e01009..f689de85fd 100644 --- a/ui/src/app/calendar/calendar.component.html +++ b/ui/src/app/calendar/calendar.component.html @@ -7,28 +7,33 @@

{{ 'i18n_calendar' | translate }}

- - -
- -
+ [reservationWindowSize]="reservationWindowSize" + [collaborative]="isCollaborative" + > + } + + @if (examInfo && hasOptionalSections()) { +
+ +
+ } -
- -
+ @if (isInteroperable && isExternal) { +
+ +
+ }
{{ 'i18n_course_name' | translate }}:
-
- - {{ examInfo.course.name }} -
+ @if (examInfo.course) { +
+ @if (examInfo) { + + } + {{ examInfo.course.name }} +
+ }
{{ 'i18n_exam_validity' | translate }}:
- {{ examInfo.periodStart | date : 'dd.MM.yyyy' }} - - {{ examInfo.periodEnd | date : 'dd.MM.yyyy' }} + {{ examInfo.periodStart | date: 'dd.MM.yyyy' }} - + {{ examInfo.periodEnd | date: 'dd.MM.yyyy' }}
diff --git a/ui/src/app/calendar/calendar.component.ts b/ui/src/app/calendar/calendar.component.ts index 17f0bfd47c..ae410fbd6f 100644 --- a/ui/src/app/calendar/calendar.component.ts +++ b/ui/src/app/calendar/calendar.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, NgClass, NgIf } from '@angular/common'; +import { DatePipe, NgClass } from '@angular/common'; import type { OnInit } from '@angular/core'; import { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -40,7 +40,6 @@ import { SlotPickerComponent } from './helpers/slot-picker.component'; imports: [ HistoryBackComponent, AutoFocusDirective, - NgIf, CalendarExamInfoComponent, OptionalSectionsComponent, OrganisationPickerComponent, diff --git a/ui/src/app/calendar/helpers/exam-info.component.ts b/ui/src/app/calendar/helpers/exam-info.component.ts index 9d1a9c8dd5..c69b33ff9e 100644 --- a/ui/src/app/calendar/helpers/exam-info.component.ts +++ b/ui/src/app/calendar/helpers/exam-info.component.ts @@ -1,4 +1,4 @@ -import { DatePipe, NgIf } from '@angular/common'; +import { DatePipe } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { DateTime } from 'luxon'; @@ -24,7 +24,9 @@ import type { ExamInfo } from '../calendar.service';
{{ examInfo.name }} - ({{ 'i18n_anonymous_review' | translate }}) + @if (examInfo.anonymous) { + ({{ 'i18n_anonymous_review' | translate }}) + }
@@ -33,10 +35,12 @@ import type { ExamInfo } from '../calendar.service';
{{ 'i18n_course_name' | translate }}:
-
- - {{ examInfo.course.name }} -
+ @if (!collaborative) { +
+ + {{ examInfo.course.name }} +
+ }
@@ -44,8 +48,8 @@ import type { ExamInfo } from '../calendar.service'; {{ 'i18n_exam_validity' | translate }}:
- {{ examInfo.periodStart | date : 'dd.MM.yyyy' }} - - {{ examInfo.periodEnd | date : 'dd.MM.yyyy' }} + {{ examInfo.periodStart | date: 'dd.MM.yyyy' }} - + {{ examInfo.periodEnd | date: 'dd.MM.yyyy' }}
@@ -67,17 +71,19 @@ import type { ExamInfo } from '../calendar.service';
- - - {{ getReservationWindowDescription() }} - + @if (showReservationWindowInfo()) { + + + {{ getReservationWindowDescription() }} + + }
`, standalone: true, - imports: [NgIf, CourseCodeComponent, MathJaxDirective, DatePipe, TranslateModule], + imports: [CourseCodeComponent, MathJaxDirective, DatePipe, TranslateModule], }) export class CalendarExamInfoComponent implements OnInit { @Input() examInfo!: ExamInfo; @@ -86,7 +92,10 @@ export class CalendarExamInfoComponent implements OnInit { reservationWindowEndDate = new Date(); - constructor(private translate: TranslateService, private DateTimeService: DateTimeService) {} + constructor( + private translate: TranslateService, + private DateTimeService: DateTimeService, + ) {} ngOnInit() { this.reservationWindowEndDate = DateTime.fromJSDate(this.reservationWindowEndDate) diff --git a/ui/src/app/calendar/helpers/optional-sections.component.ts b/ui/src/app/calendar/helpers/optional-sections.component.ts index c7f4d70c63..924f6ca4cd 100644 --- a/ui/src/app/calendar/helpers/optional-sections.component.ts +++ b/ui/src/app/calendar/helpers/optional-sections.component.ts @@ -1,4 +1,4 @@ -import { NgClass, NgFor, NgIf, UpperCasePipe } from '@angular/common'; +import { NgClass, UpperCasePipe } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; @@ -11,69 +11,83 @@ import type { ExamInfo } from '../calendar.service';

2. {{ 'i18n_exam_materials' | translate }}

- - - + @if (sectionSelectionOk()) { + + + + }
-
-
-
-
-
- {{ 'i18n_exam_section' | translate }}: {{ section.name }} -
-
-
- {{ 'i18n_optional_section' | translate | uppercase }} + @for (section of examInfo.examSections; track section) { +
+
+
+
+
+ {{ 'i18n_exam_section' | translate }}: {{ section.name }} +
+
+ @if (section.optional) { +
+ {{ 'i18n_optional_section' | translate | uppercase }} +
+ }
-
-
-
-
-
- {{ section.description }} -
-
-
- - +
+
+
+
+ {{ section.description }} +
+
+ @if (section.optional) { +
+ + +
+ }
+ @if (section.examMaterials.length > 0) { +
+
+ {{ 'i18n_exam_materials' | translate }} +
+
+ } + @for (material of section.examMaterials; track material) { +
+ + {{ 'i18n_name' | translate | uppercase }}: {{ material.name }} + @if (material.author) { + {{ 'i18n_author' | translate | uppercase }}: {{ material.author }} + } + @if (material.isbn) { + ISBN: {{ material.isbn }} + } + +
+ }
-
-
- {{ 'i18n_exam_materials' | translate }} -
-
-
- - {{ 'i18n_name' | translate | uppercase }}: {{ material.name }} - - {{ 'i18n_author' | translate | uppercase }}: {{ material.author }} - - ISBN: {{ material.isbn }} - -
-
+ }
`, standalone: true, - imports: [NgClass, NgIf, NgFor, FormsModule, UpperCasePipe, TranslateModule], + imports: [NgClass, FormsModule, UpperCasePipe, TranslateModule], }) export class OptionalSectionsComponent { @Input() examInfo!: ExamInfo; diff --git a/ui/src/app/calendar/helpers/organisation-picker.component.ts b/ui/src/app/calendar/helpers/organisation-picker.component.ts index 1e1d8aa2ce..9307e1207a 100644 --- a/ui/src/app/calendar/helpers/organisation-picker.component.ts +++ b/ui/src/app/calendar/helpers/organisation-picker.component.ts @@ -1,4 +1,4 @@ -import { NgClass, NgFor, NgIf } from '@angular/common'; +import { NgClass } from '@angular/common'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; @@ -17,9 +17,11 @@ import { CalendarService } from '../calendar.service'; - - - + @if (selectedOrganisation) { + + + + }
@@ -39,15 +41,16 @@ import { CalendarService } from '../calendar.service'; {{ 'i18n_faculty_name' | translate }} 
@@ -62,18 +65,20 @@ import { CalendarService } from '../calendar.service';
-
-
-
- {{ selectedOrganisation?.name }} ({{ selectedOrganisation?.code }}) + @if (selectedOrganisation) { +
+
+
+ {{ selectedOrganisation?.name }} ({{ selectedOrganisation?.code }}) +
-
+ }
`, standalone: true, - imports: [NgClass, NgIf, NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgFor, NgbDropdownItem, TranslateModule], + imports: [NgClass, NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem, TranslateModule], }) export class OrganisationPickerComponent implements OnInit { @Input() sequenceNumber = 0; diff --git a/ui/src/app/calendar/helpers/selected-room.component.ts b/ui/src/app/calendar/helpers/selected-room.component.ts index 71da906582..88c6c7b2d0 100644 --- a/ui/src/app/calendar/helpers/selected-room.component.ts +++ b/ui/src/app/calendar/helpers/selected-room.component.ts @@ -1,4 +1,4 @@ -import { DatePipe, NgClass, NgFor, NgIf, UpperCasePipe } from '@angular/common'; +import { DatePipe, NgClass, UpperCasePipe } from '@angular/common'; import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -29,46 +29,60 @@ import { CalendarService } from '../calendar.service';
-
-
{{ oh.name | uppercase }}
-
{{ oh.periodText }}
-
+ @for (oh of openingHours; track oh) { +
+
{{ oh.name | uppercase }}
+
{{ oh.periodText }}
+
+ }
-
-
{{ 'i18n_maintenance_periods' | translate }}:
-
-
- {{ period.startsAt | date : 'dd.MM.yyyy HH:mm' }} - {{ period.endsAt | date : 'dd.MM.yyyy HH:mm' }} - {{ period.description }} + @if (maintenancePeriods.length > 0) { +
+
{{ 'i18n_maintenance_periods' | translate }}:
+
+ @for (period of maintenancePeriods | orderBy: 'startsAt'; track period) { +
+ {{ period.startsAt | date: 'dd.MM.yyyy HH:mm' }} - + {{ period.endsAt | date: 'dd.MM.yyyy HH:mm' }} + {{ period.description }} +
+ }
-
-
-
{{ 'i18n_exception_datetimes' | translate }}:
-
-
- {{ eh.start }} - {{ eh.end }} + } + @if (exceptionHours.length > 0) { +
+
{{ 'i18n_exception_datetimes' | translate }}:
+
+ @for (eh of exceptionHours; track eh) { +
+ {{ eh.start }} - {{ eh.end }} +
+ }
-
-
-
{{ 'i18n_instructions' | translate }}:
-
{{ getRoomInstructions() }}
-
-
-
{{ 'i18n_room_accessibility' | translate }}:
-
{{ getRoomAccessibility() }}
-
+ } + @if (getRoomInstructions()) { +
+
{{ 'i18n_instructions' | translate }}:
+
{{ getRoomInstructions() }}
+
+ } + @if (getRoomAccessibility()) { +
+
{{ 'i18n_room_accessibility' | translate }}:
+
{{ getRoomAccessibility() }}
+
+ } `, standalone: true, - imports: [NgFor, NgIf, NgClass, NgbPopover, UpperCasePipe, DatePipe, TranslateModule, OrderByPipe], + imports: [NgClass, NgbPopover, UpperCasePipe, DatePipe, TranslateModule, OrderByPipe], }) export class SelectedRoomComponent implements OnInit, OnChanges { @Input() room!: ExamRoom; @@ -78,7 +92,10 @@ export class SelectedRoomComponent implements OnInit, OnChanges { openingHours: OpeningHours[] = []; exceptionHours: (ExceptionWorkingHours & { start: string; end: string; description: string })[] = []; - constructor(private translate: TranslateService, private Calendar: CalendarService) {} + constructor( + private translate: TranslateService, + private Calendar: CalendarService, + ) {} ngOnInit() { this.translate.onLangChange.subscribe(() => { diff --git a/ui/src/app/calendar/helpers/slot-picker.component.html b/ui/src/app/calendar/helpers/slot-picker.component.html index b475a8c38e..2959bd6e27 100644 --- a/ui/src/app/calendar/helpers/slot-picker.component.html +++ b/ui/src/app/calendar/helpers/slot-picker.component.html @@ -5,9 +5,11 @@

{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2' | translate }}

- - - + @if (selectedRoom) { + + + + }
@@ -15,30 +17,27 @@

{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
- - - {{ 'i18n_calendar_room_accessibility_info' | translate }} - + @if (!disabled) { + + } + @if (disabled) { + + {{ 'i18n_calendar_room_accessibility_info' | translate }} + + }
@@ -49,17 +48,19 @@

{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2

- - - {{ accessibility.name }} - + @for (accessibility of accessibilities; track accessibility) { + + + {{ accessibility.name }} + + }
@@ -81,51 +82,49 @@

{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2

- + @if (isInteroperable && !isExternal) { + + }
-
-
- + @if (selectedRoom) { +
+
+ +
-
-
-
- - + } + @if (selectedRoom) { +
+
+ + +
-
+ }
diff --git a/ui/src/app/calendar/helpers/slot-picker.component.ts b/ui/src/app/calendar/helpers/slot-picker.component.ts index e7c741f864..00b1eccc4a 100644 --- a/ui/src/app/calendar/helpers/slot-picker.component.ts +++ b/ui/src/app/calendar/helpers/slot-picker.component.ts @@ -1,4 +1,4 @@ -import { NgClass, NgFor, NgIf } from '@angular/common'; +import { NgClass } from '@angular/common'; import { HttpParams } from '@angular/common/http'; import type { SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core'; @@ -33,9 +33,7 @@ type AvailableSlot = Slot & { availableMachines: number }; standalone: true, imports: [ NgClass, - NgIf, NgbCollapse, - NgFor, NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, diff --git a/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.html b/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.html index 5ccdb65d3e..f591b0c19b 100644 --- a/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.html +++ b/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.html @@ -56,15 +56,17 @@ > - - - + @for (column of extraData; track column) { + + + + } - - - {{ exam.name }} - {{ exam.name }} - - - {{ 'i18n_no_name' | translate }} - {{ 'i18n_no_name' | translate }} - - - - - - {{ getExecutionTypeTranslation(exam) }} - - - - {{ exam.periodStart | date : 'dd.MM.yyyy' }} - - {{ exam.periodEnd | date : 'dd.MM.yyyy' }} - - - - - - {{ exam[column.property] }} - {{ exam[column.property] }} - -
- - - - - - - - - - - - - - - - - - - {{ 'i18n_exam_no_result' | translate }} - - + @for (exam of items | orderBy: sorting.predicate : sorting.reverse; track exam) { + + @if (exam.name) { + + @if (isOwner(exam)) { + {{ exam.name }} + } + @if (!isOwner(exam)) { + {{ exam.name }} + } + + } + @if (!exam.name) { + + @if (isOwner(exam)) { + {{ 'i18n_no_name' | translate }} + } + @if (!isOwner(exam)) { + {{ 'i18n_no_name' | translate }} + } + + } + + @if (exam.course) { + + } + + + {{ getExecutionTypeTranslation(exam) }} + + + @if (exam.periodStart && exam.periodEnd) { + + {{ exam.periodStart | date: 'dd.MM.yyyy' }} - + {{ exam.periodEnd | date: 'dd.MM.yyyy' }} + + } + + @for (column of extraData; track column) { + + + @if ( + (!column.checkOwnership || isOwner(exam)) && + exam.executionType.type !== 'PRINTOUT' + ) { + {{ exam[column.property] }} + } + @if ( + !isOwner(exam) && + column.checkOwnership && + exam.executionType.type !== 'PRINTOUT' + ) { + {{ exam[column.property] }} + } + + @if (exam.executionType.type === 'PRINTOUT') { +
+ } + + } + + + + + @if (isOwner(exam)) { + + + + } + + + + + + + + } + @if (items?.length === 0) { + + + {{ 'i18n_exam_no_result' | translate }} + + + }
diff --git a/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.ts b/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.ts index ef27b633bd..f591304860 100644 --- a/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.ts +++ b/ui/src/app/dashboard/staff/teacher/categories/exam-list-category.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, NgFor, NgIf } from '@angular/common'; +import { DatePipe } from '@angular/common'; import type { OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -47,8 +47,6 @@ export interface ExtraData { imports: [ FormsModule, TableSortComponent, - NgFor, - NgIf, RouterLink, CourseCodeComponent, TeacherListComponent, diff --git a/ui/src/app/dashboard/staff/teacher/teacher-dashboard.component.html b/ui/src/app/dashboard/staff/teacher/teacher-dashboard.component.html index 78fdecd9e5..853a188e50 100644 --- a/ui/src/app/dashboard/staff/teacher/teacher-dashboard.component.html +++ b/ui/src/app/dashboard/staff/teacher/teacher-dashboard.component.html @@ -32,9 +32,11 @@
  • {{ 'i18n_active_exams_title' | translate }}
    -
    - {{ filteredActive.length }} -
    + @if (activeExams) { +
    + {{ filteredActive.length }} +
    + }
    => forkJoin([this.Exam.listExecutionTypes$(), this.http.get('/app/reviewerexams')]).pipe( diff --git a/ui/src/app/dashboard/student/student-dashboard.component.html b/ui/src/app/dashboard/student/student-dashboard.component.html index 16ad1044ba..338a2e544c 100644 --- a/ui/src/app/dashboard/student/student-dashboard.component.html +++ b/ui/src/app/dashboard/student/student-dashboard.component.html @@ -9,14 +9,18 @@

    {{ 'i18n_user_enrolled_exams_title' | translate

  • -
    - -
    -
    - -   - {{ 'i18n_no_enrolments' | translate }} - -
    + @for (enrolment of userEnrolments | orderBy: 'startAtAggregate'; track enrolment) { +
    + +
    + } + @if (userEnrolments?.length === 0) { +
    + +   + {{ 'i18n_no_enrolments' | translate }} + +
    + }
    diff --git a/ui/src/app/dashboard/student/student-dashboard.component.ts b/ui/src/app/dashboard/student/student-dashboard.component.ts index eebcd4d313..fcc0bf3283 100644 --- a/ui/src/app/dashboard/student/student-dashboard.component.ts +++ b/ui/src/app/dashboard/student/student-dashboard.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgFor, NgIf } from '@angular/common'; + import type { OnInit } from '@angular/core'; import { Component } from '@angular/core'; import { TranslateModule } from '@ngx-translate/core'; @@ -25,7 +25,7 @@ import { StudentDashboardService } from './student-dashboard.service'; selector: 'xm-student-dashboard', templateUrl: './student-dashboard.component.html', standalone: true, - imports: [NgFor, ActiveEnrolmentComponent, NgIf, TranslateModule, OrderByPipe], + imports: [ActiveEnrolmentComponent, TranslateModule, OrderByPipe], }) export class StudentDashboardComponent implements OnInit { userEnrolments: DashboardEnrolment[] = []; diff --git a/ui/src/app/dashboard/student/student-dashboard.service.ts b/ui/src/app/dashboard/student/student-dashboard.service.ts index ab6bc837d5..af6bf4bc39 100644 --- a/ui/src/app/dashboard/student/student-dashboard.service.ts +++ b/ui/src/app/dashboard/student/student-dashboard.service.ts @@ -34,7 +34,10 @@ export interface DashboardEnrolment extends ExamEnrolment { @Injectable({ providedIn: 'root' }) export class StudentDashboardService { - constructor(private http: HttpClient, private DateTime: DateTimeService) {} + constructor( + private http: HttpClient, + private DateTime: DateTimeService, + ) {} listEnrolments = (): Observable => this.http.get('/app/student/enrolments').pipe( diff --git a/ui/src/app/enrolment/active/active-enrolment.component.html b/ui/src/app/enrolment/active/active-enrolment.component.html index 70d6d6ab08..e772c95f88 100644 --- a/ui/src/app/enrolment/active/active-enrolment.component.html +++ b/ui/src/app/enrolment/active/active-enrolment.component.html @@ -1,71 +1,81 @@
    -
    -
    - {{ enrolment.reservation!.startAt | date : 'dd' }} - {{ - enrolment.reservation!.startAt | date : 'MMM' | slice : 0 : 3 | uppercase - }} -
    -
    - {{ enrolment.examinationEventConfiguration!.examinationEvent.start | date : 'dd' }} - {{ - enrolment.examinationEventConfiguration!.examinationEvent.start - | date : 'MMM' - | slice : 0 : 3 - | uppercase - }} + @if (enrolment.reservation || enrolment.examinationEventConfiguration) { +
    + @if (enrolment.reservation) { +
    + {{ enrolment.reservation!.startAt | date: 'dd' }} + {{ + enrolment.reservation!.startAt | date: 'MMM' | slice: 0 : 3 | uppercase + }} +
    + } + @if (enrolment.examinationEventConfiguration) { +
    + {{ enrolment.examinationEventConfiguration!.examinationEvent.start | date: 'dd' }} + {{ + enrolment.examinationEventConfiguration!.examinationEvent.start + | date: 'MMM' + | slice: 0 : 3 + | uppercase + }} +
    + }
    -
    + }
    -

    - - {{ enrolment.exam.name }} - -

    -

    - {{ enrolment.collaborativeExam.name }} -

    + @if (enrolment.exam) { +

    + + {{ enrolment.exam.name }} + +

    + } + @if (enrolment.collaborativeExam) { +

    + {{ enrolment.collaborativeExam.name }} +

    + } - ({{ 'i18n_anonymous_review' | translate }}) - ({{ 'i18n_examination_type_seb' | translate }}) - ({{ 'i18n_examination_type_home_exam' | translate }}) + @if (enrolment.exam?.anonymous || enrolment.collaborativeExam?.anonymous) { + ({{ 'i18n_anonymous_review' | translate }}) + } + @if (enrolment.exam && enrolment.exam.implementation === 'CLIENT_AUTH') { + ({{ 'i18n_examination_type_seb' | translate }}) + } + @if (enrolment.exam && enrolment.exam.implementation === 'WHATEVER') { + ({{ 'i18n_examination_type_home_exam' | translate }}) + }
    - {{ 'i18n_state_ready' | translate }} - {{ 'i18n_state_needs_reservation_title' | translate }} - - {{ 'i18n_state_started' | translate }} - + @if ( + (enrolment.exam?.state === 'PUBLISHED' || + enrolment.collaborativeExam?.state === 'PUBLISHED') && + (enrolment.reservation || enrolment.examinationEventConfiguration) + ) { + {{ 'i18n_state_ready' | translate }} + } + @if ( + enrolment.exam?.state === 'PUBLISHED' && + !enrolment.reservation && + !enrolment.examinationEventConfiguration + ) { + {{ + 'i18n_state_needs_reservation_title' | translate + }} + } + @if (enrolment.exam?.state === 'STUDENT_STARTED') { + + {{ 'i18n_state_started' | translate }} + + }
    @@ -79,235 +89,268 @@

    -
    {{ 'i18n_course_name' | translate }}:
    + @if (enrolment.exam) { +
    {{ 'i18n_course_name' | translate }}:
    + } -
    - - - - {{ enrolment.exam.course.name }} -
    -
    -
    -
    {{ 'i18n_teachers' | translate }}:
    -
    - -
    - + @if (enrolment.exam && enrolment.exam.course) { +
    + + + + {{ enrolment.exam.course.name }} +
    + }
    -
    -
    -
    {{ 'i18n_exam_validity' | translate }}:
    -
    - {{ enrolment.exam?.periodStart || enrolment.collaborativeExam.periodStart | date : 'dd.MM.yyyy' }} - – - {{ enrolment.exam?.periodEnd || enrolment.collaborativeExam.periodEnd | date : 'dd.MM.yyyy' }} -
    + @if (enrolment.exam) { +
    {{ 'i18n_teachers' | translate }}:
    + } + @if (enrolment.exam) { +
    + +
    + } + @if (enrolment.exam) { + + }
    -
    + @if (!enrolment.reservation) {
    -
    {{ 'i18n_exam_room' | translate }}:
    -
    - {{ enrolment.reservation.machine.name }}  |  {{ - enrolment.reservation.machine.room.name - }} - ({{ enrolment.reservation.machine.room.roomCode }}) -
    -
    - - {{ 'i18n_faculty_name' | translate | uppercase }}: - {{ enrolment.reservation.externalReservation.orgName }} ({{ - enrolment.reservation.externalReservation.orgCode - }})
    -
    - {{ 'i18n_room_campus' | translate | uppercase }}: - {{ enrolment.reservation.externalReservation.campus }}
    - {{ 'i18n_room_building_name' | translate | uppercase }}: - {{ enrolment.reservation.externalReservation.buildingName }}
    - {{ 'i18n_exam_room' | translate | uppercase }}: - {{ enrolment.reservation.externalReservation.roomName }} - ({{ enrolment.reservation.externalReservation.roomCode }})
    - {{ 'i18n_exam_machine' | translate | uppercase }}: - {{ enrolment.reservation.externalReservation.machineName }}
    - {{ enrolment.reservation.externalReservation.mailAddress.street }}, - {{ enrolment.reservation.externalReservation.mailAddress.zip }}  - {{ enrolment.reservation.externalReservation.mailAddress.city | uppercase }} -
    - -
    -
    -
    {{ 'i18n_reservation' | translate }}:
    -
    - {{ enrolment.reservation.startAt | applyDst | date : 'dd.MM.yyyy' }} - {{ enrolment.occasion?.startAt }} – {{ enrolment.occasion?.endAt }} ({{ enrolment.occasion?.tz }}) +
    +
    {{ 'i18n_exam_validity' | translate }}:
    +
    + {{ enrolment.exam?.periodStart || enrolment.collaborativeExam.periodStart | date: 'dd.MM.yyyy' }} + – + {{ enrolment.exam?.periodEnd || enrolment.collaborativeExam.periodEnd | date: 'dd.MM.yyyy' }} +
    -
    -
    - + } + @if (enrolment.reservation) { +
    +
    +
    {{ 'i18n_exam_room' | translate }}:
    + @if (enrolment.reservation.machine) { +
    + {{ enrolment.reservation.machine.name }}  |  {{ + enrolment.reservation.machine.room.name + }} + ({{ enrolment.reservation.machine.room.roomCode }}) +
    + } + @if (enrolment.reservation.externalReservation) { +
    + @if (enrolment.reservation.externalReservation.orgName) { + + {{ 'i18n_faculty_name' | translate | uppercase }}: + {{ enrolment.reservation.externalReservation.orgName }} ({{ + enrolment.reservation.externalReservation.orgCode + }})
    +
    + } + {{ 'i18n_room_campus' | translate | uppercase }}: + {{ enrolment.reservation.externalReservation.campus }}
    + {{ 'i18n_room_building_name' | translate | uppercase }}: + {{ enrolment.reservation.externalReservation.buildingName }}
    + {{ 'i18n_exam_room' | translate | uppercase }}: + {{ enrolment.reservation.externalReservation.roomName }} + ({{ enrolment.reservation.externalReservation.roomCode }})
    + {{ 'i18n_exam_machine' | translate | uppercase }}: + {{ enrolment.reservation.externalReservation.machineName }}
    + {{ enrolment.reservation.externalReservation.mailAddress.street }}, + {{ enrolment.reservation.externalReservation.mailAddress.zip }}  + {{ enrolment.reservation.externalReservation.mailAddress.city | uppercase }} +
    + } +
    +
    +
    {{ 'i18n_reservation' | translate }}:
    +
    + {{ enrolment.reservation.startAt | applyDst | date: 'dd.MM.yyyy' }} + {{ enrolment.occasion?.startAt }} – {{ enrolment.occasion?.endAt }} ({{ + enrolment.occasion?.tz + }}) +
    -
    - {{ getRoomInstruction() }} +
    +
    + +
    +
    + {{ getRoomInstruction() }} +
    -
    -
    -
    - {{ 'i18n_canceled' | translate }} -
    -
    -
    + } + @if (!enrolment.reservation && enrolment.reservationCanceled) {
    -
    {{ 'i18n_examination_event' | translate }}:
    -
    - {{ enrolment.examinationEventConfiguration?.examinationEvent?.start | date : 'dd.MM.yyyy HH:mm zzzz' }} -
    + @if (enrolment.reservationCanceled) { +
    + {{ 'i18n_canceled' | translate }} +
    + }
    -
    - -
    -
    -
    -
    {{ 'i18n_instructions' | translate }}:
    + } + @if (enrolment.exam && enrolment.examinationEventConfiguration && enrolment.exam.implementation !== 'AQUARIUM') { +
    +
    +
    {{ 'i18n_examination_event' | translate }}:
    - - {{ enrolment.examinationEventConfiguration.examinationEvent.description }} - + {{ + enrolment.examinationEventConfiguration?.examinationEvent?.start | date: 'dd.MM.yyyy HH:mm zzzz' + }}
    -
    + } -
    -
    -
    -
    {{ 'i18n_seb_file' | translate }}:
    -
    - - - + @if (enrolment.exam && enrolment.examinationEventConfiguration && enrolment.exam.implementation !== 'AQUARIUM') { +
    +
    +
    +
    {{ 'i18n_instructions' | translate }}:
    +
    + + {{ enrolment.examinationEventConfiguration.examinationEvent.description }} + +
    -
    -
    -
    - -
    -
    -
    -
    -
    - {{ 'i18n_exam_section' | translate }} - ({{ 'i18n_required' | translate | lowercase }}): - {{ section.name }} -
    -
    -
    -
    - {{ section.description }} -
    -
    -
    -
    -
    -
    -
    - {{ 'i18n_exam_section' | translate }} - ({{ 'i18n_optional' | translate | lowercase }}): +
    +
    +
    {{ 'i18n_seb_file' | translate }}:
    +
    + +
    -
    -
    -
    - {{ section.description }} -
    + {{ 'i18n_download' | translate }} + +
    -
    -
    -
    - {{ 'i18n_exam_materials' | translate }} +
    +
    +
    + } + @if (enrolment.reservation && enrolment.optionalSections.length > 0) { +
    +
    + + @if (enrolment.reservation && enrolment.optionalSections.length > 0) { +
    + @for (section of enrolment.exam.examSections; track section) { +
    + @if (section.optional === false) { +
    +
    +
    + {{ 'i18n_exam_section' | translate }} + ({{ 'i18n_required' | translate | lowercase }}): + {{ section.name }} +
    +
    +
    +
    + {{ section.description }} +
    +
    +
    + }
    -
    -
    -
    - - {{ 'i18n_name' | translate | uppercase }}: {{ material.name }} - - {{ 'i18n_author' | translate | uppercase }}: {{ material.author }} - - ISBN: {{ material.isbn }} - + } + @for (section of enrolment.optionalSections; track section) { +
    +
    +
    + {{ 'i18n_exam_section' | translate }} + ({{ 'i18n_optional' | translate | lowercase }}): + {{ section.name }} +
    +
    +
    +
    + {{ section.description }} +
    +
    + @if (section.examMaterials.length > 0) { +
    +
    +
    + {{ 'i18n_exam_materials' | translate }} +
    +
    + @for (material of section.examMaterials; track material) { +
    +
    + + {{ 'i18n_name' | translate | uppercase }}: {{ material.name }} + @if (material.author) { + + {{ 'i18n_author' | translate | uppercase }}: + {{ material.author }} + + } + @if (material.isbn) { + ISBN: {{ material.isbn }} + } + +
    +
    + } +
    + }
    -
    + }
    -
    + }
    -
    + }
    -
    - -
    -
    - -
    + @if (!enrolment.reservation && (enrolment.exam?.implementation === 'AQUARIUM' || enrolment.collaborativeExam)) { +
    + +
    + } + @if ( + !enrolment.examinationEventConfiguration && + enrolment.exam?.implementation !== 'AQUARIUM' && + hasUpcomingAlternativeEvents() + ) { +
    + +
    + }
    diff --git a/ui/src/app/enrolment/active/active-enrolment.component.ts b/ui/src/app/enrolment/active/active-enrolment.component.ts index 5c6567f340..175b191873 100644 --- a/ui/src/app/enrolment/active/active-enrolment.component.ts +++ b/ui/src/app/enrolment/active/active-enrolment.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, LowerCasePipe, NgFor, NgIf, SlicePipe, UpperCasePipe } from '@angular/common'; +import { DatePipe, LowerCasePipe, SlicePipe, UpperCasePipe } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { RouterLink } from '@angular/router'; import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap'; @@ -32,13 +32,11 @@ import { ActiveEnrolmentMenuComponent } from './helpers/active-enrolment-menu.co templateUrl: './active-enrolment.component.html', standalone: true, imports: [ - NgIf, RouterLink, ActiveEnrolmentMenuComponent, CourseCodeComponent, TeacherListComponent, NgbCollapse, - NgFor, MathJaxDirective, UpperCasePipe, LowerCasePipe, @@ -56,7 +54,11 @@ export class ActiveEnrolmentComponent { showInstructions = false; showMaterials = false; - constructor(private translate: TranslateService, private Enrolment: EnrolmentService, private Files: FileService) {} + constructor( + private translate: TranslateService, + private Enrolment: EnrolmentService, + private Files: FileService, + ) {} hasUpcomingAlternativeEvents = () => this.Enrolment.hasUpcomingAlternativeEvents(this.enrolment); diff --git a/ui/src/app/enrolment/active/dialogs/select-examination-event-dialog.component.ts b/ui/src/app/enrolment/active/dialogs/select-examination-event-dialog.component.ts index 80bc583453..6159fb3fd7 100644 --- a/ui/src/app/enrolment/active/dialogs/select-examination-event-dialog.component.ts +++ b/ui/src/app/enrolment/active/dialogs/select-examination-event-dialog.component.ts @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and limitations under the Licence. * */ -import { DatePipe, NgFor } from '@angular/common'; +import { DatePipe } from '@angular/common'; import type { OnInit } from '@angular/core'; import { Component, Input } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; @@ -24,7 +24,7 @@ import type { Exam, ExaminationEventConfiguration } from '../../../exam/exam.mod @Component({ selector: 'xm-select-examination-event-dialog', standalone: true, - imports: [TranslateModule, DatePipe, NgFor], + imports: [TranslateModule, DatePipe], template: ` diff --git a/ui/src/app/enrolment/active/helpers/active-enrolment-menu.component.ts b/ui/src/app/enrolment/active/helpers/active-enrolment-menu.component.ts index 6b7a0d99ff..cc18592019 100644 --- a/ui/src/app/enrolment/active/helpers/active-enrolment-menu.component.ts +++ b/ui/src/app/enrolment/active/helpers/active-enrolment-menu.component.ts @@ -1,4 +1,3 @@ -import { NgIf } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { RouterLink } from '@angular/router'; import { NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle } from '@ng-bootstrap/ng-bootstrap'; @@ -14,7 +13,7 @@ import { EnrolmentService } from '../../enrolment.service'; selector: 'xm-active-enrolment-menu', templateUrl: './active-enrolment-menu.component.html', standalone: true, - imports: [NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgIf, NgbDropdownItem, RouterLink, TranslateModule], + imports: [NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem, RouterLink, TranslateModule], }) export class ActiveEnrolmentMenuComponent { @Input() enrolment!: ExamEnrolment; diff --git a/ui/src/app/enrolment/exams/exam-enrolment-details.component.html b/ui/src/app/enrolment/exams/exam-enrolment-details.component.html index b4a38317a2..d54079a278 100644 --- a/ui/src/app/enrolment/exams/exam-enrolment-details.component.html +++ b/ui/src/app/enrolment/exams/exam-enrolment-details.component.html @@ -12,39 +12,49 @@

    {{ exam.name }}

    {{ exam.name }}

    - - {{ 'i18n_state_needs_reservation_title' | translate }} - - - {{ 'i18n_state_ready' | translate }} - + @if (!exam.reservationMade && exam.alreadyEnrolled && !exam.noTrialsLeft) { + + {{ 'i18n_state_needs_reservation_title' | translate }} + + } + @if (exam.reservationMade) { + + {{ 'i18n_state_ready' | translate }} + + }
    -
    -
    - -
    - {{ 'i18n_exam_period_over' | translate }} + @if (!exam.alreadyEnrolled && !exam.noTrialsLeft) { +
    +
    + + @if (getExpiration()) { +
    + {{ 'i18n_exam_period_over' | translate }} +
    + }
    -
    -
    - {{ 'i18n_enrolled_to_exam' | translate }} -
    + } + @if (exam.alreadyEnrolled && exam.reservationMade) { +
    + {{ 'i18n_enrolled_to_exam' | translate }} +
    + }
    {{ 'i18n_course_name' | translate }}:
    - {{ exam.course?.name }} + @if (exam.course) { + + } + {{ exam.course?.name }}
    {{ 'i18n_teachers' | translate }}:
    @@ -55,7 +65,7 @@

    {{ exam.name }}

    {{ 'i18n_start_time' | translate }}:
    - {{ exam.periodStart | date : 'dd.MM.yyyy' }} - {{ exam.periodEnd | date : 'dd.MM.yyyy' }} + {{ exam.periodStart | date: 'dd.MM.yyyy' }} - {{ exam.periodEnd | date: 'dd.MM.yyyy' }}
    {{ 'i18n_exam_language' | translate }}:
    @@ -108,11 +118,13 @@

    {{ exam.name }}

    -
    -
    - + @if (!exam.reservationMade && exam.alreadyEnrolled && !exam.noTrialsLeft) { +
    +
    + +
    -
    + }
    diff --git a/ui/src/app/enrolment/exams/exam-enrolment-details.component.ts b/ui/src/app/enrolment/exams/exam-enrolment-details.component.ts index c353881b67..7871838861 100644 --- a/ui/src/app/enrolment/exams/exam-enrolment-details.component.ts +++ b/ui/src/app/enrolment/exams/exam-enrolment-details.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { DatePipe, NgIf } from '@angular/common'; +import { DatePipe } from '@angular/common'; import { Component, Input } from '@angular/core'; import { Router } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; @@ -31,7 +31,6 @@ import { EnrolmentService } from '../enrolment.service'; standalone: true, imports: [ HistoryBackComponent, - NgIf, CourseCodeComponent, TeacherListComponent, MathJaxDirective, diff --git a/ui/src/app/enrolment/exams/exam-enrolments.component.ts b/ui/src/app/enrolment/exams/exam-enrolments.component.ts index 83f72a482a..af3d8e9e45 100644 --- a/ui/src/app/enrolment/exams/exam-enrolments.component.ts +++ b/ui/src/app/enrolment/exams/exam-enrolments.component.ts @@ -12,7 +12,7 @@ * on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and limitations under the Licence. */ -import { NgFor, NgIf } from '@angular/common'; + import type { OnInit } from '@angular/core'; import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @@ -28,28 +28,36 @@ import { EnrolmentDetailsComponent } from './exam-enrolment-details.component'; selector: 'xm-exam-enrolments', template: `
    -
    -
    -

    {{ 'i18n_no_trials_left' | translate }}

    -
    -
    - -
    -
    -
    -

    {{ 'i18n_student_exams' | translate }}

    + @if (exam?.noTrialsLeft) { +
    +
    +

    {{ 'i18n_no_trials_left' | translate }}

    -
    -
    - + } + @if (exam) { + + } + @if (exams.length > 0) { +
    +
    +
    +

    {{ 'i18n_student_exams' | translate }}

    +
    + @for (exam of exams; track exam) { +
    +
    + +
    +
    + }
    -
    + }
    `, standalone: true, - imports: [NgIf, EnrolmentDetailsComponent, NgFor, ExamSearchResultComponent, TranslateModule], + imports: [EnrolmentDetailsComponent, ExamSearchResultComponent, TranslateModule], }) export class ExamEnrolmentsComponent implements OnInit { exam!: EnrolmentInfo; diff --git a/ui/src/app/enrolment/finished/collaborative-exam-participations.component.ts b/ui/src/app/enrolment/finished/collaborative-exam-participations.component.ts index 8e554e2f38..73e905d973 100644 --- a/ui/src/app/enrolment/finished/collaborative-exam-participations.component.ts +++ b/ui/src/app/enrolment/finished/collaborative-exam-participations.component.ts @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and limitations under the Licence. * */ -import { NgFor, NgIf, SlicePipe } from '@angular/common'; +import { SlicePipe } from '@angular/common'; import type { OnInit } from '@angular/core'; import { AfterViewInit, ChangeDetectorRef, Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -38,9 +38,7 @@ import { ExamParticipationComponent } from './exam-participation.component'; NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem, - NgFor, ExamParticipationComponent, - NgIf, PaginatorComponent, SlicePipe, TranslateModule, diff --git a/ui/src/app/enrolment/finished/exam-answers-dialog.component.html b/ui/src/app/enrolment/finished/exam-answers-dialog.component.html index 95a811ceb7..4c1962ad95 100644 --- a/ui/src/app/enrolment/finished/exam-answers-dialog.component.html +++ b/ui/src/app/enrolment/finished/exam-answers-dialog.component.html @@ -4,7 +4,9 @@
    @@ -26,136 +28,162 @@

    {{ 'i18n_exam_duration' | translate }}:

    - {{ participationDuration | date : 'HH:mm:ss' : 'UTC' }} + {{ participationDuration | date: 'HH:mm:ss' : 'UTC' }}
    -
    -
    - {{ 'i18n_exam_instruction' | translate }}: + @if (exam.instruction) { +
    +
    + {{ 'i18n_exam_instruction' | translate }}: +
    -
    -
    -
    -
    + } + @if (exam.instruction) { +
    +
    +
    + } -
    -
    -

    -
    - {{ 'i18n_exam_section' | translate }}: {{ section.name }} -
    -

    -
    -
    -
    - {{ 'i18n_question' | translate }}: -
    -
    -
    -
    - -
    -
    -
    - {{ 'i18n_exam_answer' | translate }}: -
    -
    -
    -
    -
    - {{ 'i18n_answer_attachment' | translate }}: -
    - + @for (section of exam.examSections; track section) { +
    +
    +

    +
    + {{ 'i18n_exam_section' | translate }}: {{ section.name }}
    -
    -
    - {{ 'i18n_answer_length' | translate }}: -
    -
    - {{ countWords(esq) }} {{ 'i18n_words' | translate }}, - {{ 'i18n_approximately' | translate }} {{ countCharacters(esq) }} - {{ 'i18n_characters' | translate }} -
    -
    -
    -
    - {{ 'i18n_essay_length_recommendation' | translate }}: -
    -
    - {{ esq.expectedWordCount }} ({{ 'i18n_approximately' | translate }} - {{ (esq.expectedWordCount || 0) * 8 }} - {{ 'i18n_characters' | translate }}) -
    -
    -
    -
    - {{ 'i18n_comments' | translate }}: -
    -
    - {{ 'i18n_word_points' | translate }}:   - {{ esq.essayAnswer?.evaluatedScore }} / {{ esq.maxScore }} +

    + @for (esq of section.sectionQuestions; track esq) { +
    +
    +
    + {{ 'i18n_question' | translate }}: +
    + @if (esq.question.type !== 'ClozeTestQuestion') { +
    + } + @if (esq.question.type === 'ClozeTestQuestion') { +
    + }
    -
    -
    - {{ 'i18n_approved' | translate | uppercase }} + + @if (esq.question.type === 'EssayQuestion') { +
    +
    +
    + {{ 'i18n_exam_answer' | translate }}: +
    +
    +
    + @if (esq.essayAnswer?.attachment) { +
    +
    + {{ 'i18n_answer_attachment' | translate }}: +
    + +
    + } +
    +
    + {{ 'i18n_answer_length' | translate }}: +
    +
    + {{ countWords(esq) }} {{ 'i18n_words' | translate }}, + {{ 'i18n_approximately' | translate }} {{ countCharacters(esq) }} + {{ 'i18n_characters' | translate }} +
    +
    + @if (esq.expectedWordCount) { +
    +
    + {{ 'i18n_essay_length_recommendation' | translate }}: +
    +
    + {{ esq.expectedWordCount }} ({{ 'i18n_approximately' | translate }} + {{ (esq.expectedWordCount || 0) * 8 }} + {{ 'i18n_characters' | translate }}) +
    +
    + } +
    +
    + {{ 'i18n_comments' | translate }}: +
    + @if (esq.evaluationType === 'Points') { +
    + {{ 'i18n_word_points' | translate }}:   + {{ esq.essayAnswer?.evaluatedScore }} / {{ esq.maxScore }} +
    + } + @if (esq.evaluationType === 'Selection') { +
    + @if (esq.essayAnswer?.evaluatedScore === 1) { +
    + {{ 'i18n_approved' | translate | uppercase }} +
    + } + @if (esq.essayAnswer?.evaluatedScore !== 1) { +
    + {{ 'i18n_rejected' | translate | uppercase }} +
    + } +
    + } +
    -
    - {{ 'i18n_rejected' | translate | uppercase }} + } + + + @if (isMultiChoice(esq)) { +
    +
    +
    + {{ 'i18n_exam_answer' | translate }}: +
    +
    + @for (option of getAnsweredOptions(esq); track option) { +
    +
    +
    + } +
    +
    +
    +
    + {{ 'i18n_comments' | translate }}: +
    +
    + {{ esq.derivedAssessedScore }} / {{ esq.derivedMaxScore }} +
    +
    -
    -
    -
    - - - -
    -
    -
    - {{ 'i18n_exam_answer' | translate }}: -
    -
    -
    -
    + } + + @if (esq.question.type === 'ClozeTestQuestion') { +
    +
    +
    + {{ 'i18n_comments' | translate }}: +
    +
    + {{ esq.derivedAssessedScore }} / {{ esq.derivedMaxScore }} +
    +
    -
    -
    -
    -
    - {{ 'i18n_comments' | translate }}: -
    -
    {{ esq.derivedAssessedScore }} / {{ esq.derivedMaxScore }}
    -
    -
    - -
    -
    -
    - {{ 'i18n_comments' | translate }}: -
    -
    {{ esq.derivedAssessedScore }} / {{ esq.derivedMaxScore }}
    + }
    -
    + }
    -
    + }

    {{ 'i18n_exam_review_settings' | translate }}

    @@ -163,9 +191,11 @@

    {{ 'i18n_exam_review_settings' | translate }}

    {{ 'i18n_exam_grade' | translate }}:
    -
    - {{ getGradeName(exam.grade.name) }} -
    + @if (exam.grade) { +
    + {{ getGradeName(exam.grade.name) }} +
    + }
    @@ -173,18 +203,22 @@

    {{ 'i18n_exam_review_settings' | translate }}

    {{ exam.totalScore }} / {{ exam.maxScore }}
    -
    -
    - {{ 'i18n_teachers_comment' | translate }}: + @if (exam.examFeedback?.comment) { +
    +
    + {{ 'i18n_teachers_comment' | translate }}: +
    +
    -
    -
    -
    -
    - {{ 'i18n_exam_credit' | translate }} (op): + } + @if (exam.course?.credits) { +
    +
    + {{ 'i18n_exam_credit' | translate }} (op): +
    +
    {{ exam.course?.credits }}
    -
    {{ exam.course?.credits }}
    -
    + }