-
Notifications
You must be signed in to change notification settings - Fork 301
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add files manually to resolve merge conflict
- Loading branch information
Showing
7 changed files
with
510 additions
and
1 deletion.
There are no files selected for viewing
65 changes: 65 additions & 0 deletions
65
...-exams/course-exam-attempt-review-detail/course-exam-attempt-review-detail.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
@if (studentExam) { | ||
<div (click)="openStudentExam()"> | ||
<!-- To clearly indicate a StudentExam within the working time, which can be resumed, the card should be displayed in blue --> | ||
<div | ||
[ngClass]="{ | ||
'row card-body justify-content-center card-general-settings': true, | ||
'bg-primary text-white': withinWorkingTime, | ||
clickable: withinWorkingTime || studentExam.submitted | ||
}" | ||
> | ||
<div class="row"> | ||
<!-- Two variants: Play-Icon, if the studentExam is still within the working time and thus can be resumed. | ||
Magnifying Class for finished StudentExams, to indicate the possibility to review the exam --> | ||
<h4 class="col-sm-auto icon-settings"> | ||
@if (withinWorkingTime) { | ||
<fa-icon [icon]="faCirclePlay" size="2x" /> | ||
} | ||
@if (!withinWorkingTime && studentExam.submitted) { | ||
<fa-icon [icon]="faMagnifyingGlass" size="2x" /> | ||
} | ||
@if (!withinWorkingTime && !studentExam.submitted) { | ||
<fa-icon [icon]="faFileCircleXmark" size="2x" /> | ||
} | ||
</h4> | ||
<div class="col-sm"> | ||
<div class="row"> | ||
<div class="col"> | ||
<h5 class="text-start"> | ||
{{ 'artemisApp.exam.overview.testExam.' + (withinWorkingTime ? 'resumeAttempt' : 'reviewAttempt') | artemisTranslate: { attempt: index } }} | ||
</h5> | ||
</div> | ||
<div class="col-auto"> | ||
@if (withinWorkingTime) { | ||
<div class="text-end"> | ||
{{ 'artemisApp.exam.overview.testExam.workingTimeLeft' | artemisTranslate }} {{ workingTimeLeftInSeconds() | artemisDurationFromSeconds: true }} | ||
</div> | ||
} | ||
@if (studentExam.submitted) { | ||
<div> | ||
@if (studentExam.submissionDate) { | ||
<div class="text-end"> | ||
{{ 'artemisApp.exam.overview.testExam.submissionDate' | artemisTranslate }} {{ studentExam.submissionDate | artemisDate }} | ||
</div> | ||
} | ||
@if (studentExam.submissionDate && studentExam.startedDate) { | ||
<div class="text-end"> | ||
{{ 'artemisApp.exam.overview.testExam.workingTimeCalculated' | artemisTranslate }} | ||
<jhi-testexam-working-time [studentExam]="studentExam" /> | ||
</div> | ||
} | ||
</div> | ||
} | ||
<!-- test exams have to be submitted by the students, just as it is the case with real exams --> | ||
@if (!withinWorkingTime && !studentExam.submitted) { | ||
<div> | ||
<div class="text-end">{{ 'artemisApp.exam.overview.testExam.notSubmitted' | artemisTranslate }}</div> | ||
</div> | ||
} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
} |
23 changes: 23 additions & 0 deletions
23
...-exams/course-exam-attempt-review-detail/course-exam-attempt-review-detail.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.icon-settings { | ||
display: flex; | ||
justify-content: left; | ||
align-items: center; | ||
min-height: 50px; | ||
} | ||
|
||
.card-general-settings { | ||
padding: 5px 0; | ||
border: 1px; | ||
border-color: var(--primary); | ||
border-radius: 3px; | ||
transition: box-shadow 0.1s linear; | ||
|
||
.row { | ||
min-height: 35px; | ||
align-items: center; | ||
} | ||
|
||
&:hover { | ||
box-shadow: 0 2px 4px 0 var(--primary); | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
...se-exams/course-exam-attempt-review-detail/course-exam-attempt-review-detail.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; | ||
import { Router } from '@angular/router'; | ||
import { faCirclePlay, faFileCircleXmark, faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; | ||
import { StudentExam } from 'app/entities/student-exam.model'; | ||
import dayjs from 'dayjs/esm'; | ||
import { Exam } from 'app/entities/exam.model'; | ||
import { Subscription, interval } from 'rxjs'; | ||
|
||
@Component({ | ||
selector: 'jhi-course-exam-attempt-review-detail', | ||
templateUrl: './course-exam-attempt-review-detail.component.html', | ||
styleUrls: ['./course-exam-attempt-review-detail.component.scss'], | ||
}) | ||
export class CourseExamAttemptReviewDetailComponent implements OnInit, OnDestroy { | ||
@Input() studentExam: StudentExam; | ||
// Both needed for routing (and for the exam.workingTime) | ||
@Input() exam: Exam; | ||
@Input() courseId: number; | ||
// Index used to enumerate the attempts per student | ||
@Input() index: number; | ||
@Input() latestExam: boolean; | ||
studentExamState: Subscription; | ||
|
||
// Helper-Variables | ||
withinWorkingTime: boolean; | ||
|
||
// Icons | ||
faMagnifyingGlass = faMagnifyingGlass; | ||
faCirclePlay = faCirclePlay; | ||
faFileCircleXmark = faFileCircleXmark; | ||
|
||
constructor(private router: Router) {} | ||
|
||
/** | ||
* Calculate the individual working time for every submitted StudentExam. As the StudentExam needs to be submitted, the | ||
* working time cannot change. | ||
* For the latest StudentExam, which is still within the allowed working time, a subscription is used to periodically check this. | ||
*/ | ||
ngOnInit() { | ||
if (this.studentExam.started && this.studentExam.submitted && this.studentExam.startedDate && this.studentExam.submissionDate) { | ||
this.withinWorkingTime = false; | ||
} else if (this.latestExam) { | ||
// A subscription is used here to limit the number of calls for the countdown of the remaining workingTime. | ||
this.studentExamState = interval(1000).subscribe(() => { | ||
this.isWithinWorkingTime(); | ||
// If the StudentExam is no longer within the working time, the subscription can be unsubscribed, as the state will not change anymore | ||
if (!this.withinWorkingTime) { | ||
this.unsubscribeFromExamStateSubscription(); | ||
} | ||
}); | ||
} else { | ||
this.withinWorkingTime = false; | ||
} | ||
} | ||
|
||
ngOnDestroy() { | ||
this.unsubscribeFromExamStateSubscription(); | ||
} | ||
|
||
/** | ||
* Used to unsubscribe from the studentExamState Subscriptions | ||
*/ | ||
unsubscribeFromExamStateSubscription() { | ||
this.studentExamState?.unsubscribe(); | ||
} | ||
|
||
/** | ||
* Determines if the given StudentExam is (still) within the working time | ||
*/ | ||
isWithinWorkingTime() { | ||
if (this.studentExam.started && !this.studentExam.submitted && this.studentExam.startedDate && this.exam.workingTime) { | ||
const endDate = dayjs(this.studentExam.startedDate).add(this.exam.workingTime, 'seconds'); | ||
this.withinWorkingTime = dayjs(endDate).isAfter(dayjs()); | ||
} | ||
} | ||
|
||
/** | ||
* Dynamically calculates the remaining working time of an attempt, if the attempt is started, within the working time and not yet submitted | ||
*/ | ||
workingTimeLeftInSeconds(): number { | ||
if (this.studentExam.started && !this.studentExam.submitted && this.studentExam.startedDate && this.exam.workingTime) { | ||
return this.studentExam.startedDate.add(this.exam.workingTime, 'seconds').diff(dayjs(), 'seconds'); | ||
} | ||
return 0; | ||
} | ||
|
||
/** | ||
* navigate to /courses/:courseId/exams/:examId/test-exam/:studentExamId | ||
* Used to open the corresponding studentExam | ||
*/ | ||
openStudentExam(): void { | ||
if (this.studentExam.submitted || this.withinWorkingTime) { | ||
this.router.navigate(['courses', this.courseId, 'exams', this.exam.id, 'test-exam', this.studentExam.id]); | ||
} | ||
} | ||
} |
131 changes: 131 additions & 0 deletions
131
...ain/webapp/app/overview/course-exams/course-exam-detail/course-exam-detail.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
@if (exam) { | ||
<div [ngClass]="{ clickable: !maxAttemptsReached && !(exam.testExam && examState === 'CLOSED') }" (click)="openExam()" id="exam-{{ exam.id }}"> | ||
<!-- Signature colors for the header: Blue for test exams and Green for RedExams --> | ||
<div | ||
[ngClass]="{ | ||
'row card-header': true, | ||
'bg-primary': exam.testExam, | ||
'bg-success': !exam.testExam | ||
}" | ||
> | ||
<h5 class="text-center text-white">{{ exam.title }}</h5> | ||
</div> | ||
<!-- Body of the Component. Content changes depending on the exam state--> | ||
<div class="row d-flex justify-content-center"> | ||
@if (examState === 'UNDEFINED') { | ||
<h4 class="icon-settings"> | ||
<!-- Case 7: Undefined exam state. show Pencil without further information --> | ||
<fa-icon [icon]="faPenAlt" size="3x" /> | ||
</h4> | ||
} @else { | ||
<div class="col-3 icon-settings my-3"> | ||
@switch (examState) { | ||
<!-- Calender to indicate an upcoming exam --> | ||
@case ('UPCOMING') { | ||
<fa-icon [icon]="faCalendarDay" size="2x" /> | ||
} | ||
<!-- Play Button without circle to indicate, the exam starts shortly --> | ||
@case ('IMMINENT') { | ||
<fa-icon [icon]="faPlay" size="2x" /> | ||
} | ||
<!-- Play-Button to indicate, the exam can be started --> | ||
@case ('CONDUCTING') { | ||
<fa-icon [icon]="faCirclePlay" size="2x" /> | ||
} | ||
<!-- User with a clock to indicate indivial time extensions --> | ||
@case ('TIMEEXTENSION') { | ||
<fa-icon [icon]="faUserClock" size="2x" /> | ||
} | ||
<!-- Magnifying Glass to indicate, the exam can be reviewed --> | ||
@case ('STUDENTREVIEW') { | ||
<fa-icon [icon]="faMagnifyingGlass" size="2x" /> | ||
} | ||
<!-- Book to indicate, the exam is closed --> | ||
@case ('CLOSED') { | ||
<fa-icon [icon]="faBook" size="2x" /> | ||
} | ||
<!-- Stop to indicate, no more attemps are possible --> | ||
@case ('NO_MORE_ATTEMPTS') { | ||
<fa-icon [icon]="faCircleStop" size="2x" /> | ||
} | ||
} | ||
</div> | ||
<div class="col-9 row justify-content-center align-content-center"> | ||
@switch (examState) { | ||
@case ('UPCOMING') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'upcoming' | artemisTranslate }}</h5> | ||
<div class="text-center"> | ||
{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'imminent' | artemisTranslate }} | ||
{{ timeLeftToStart | artemisDurationFromSeconds }} | ||
</div> | ||
</div> | ||
} | ||
@case ('IMMINENT') { | ||
<div> | ||
<h5 class="text-center"> | ||
{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'imminent' | artemisTranslate }} | ||
{{ timeLeftToStart | artemisDurationFromSeconds }} | ||
</h5> | ||
<div class="text-center">{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'imminentExplanation' | artemisTranslate }}</div> | ||
</div> | ||
} | ||
@case ('CONDUCTING') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'conducting' | artemisTranslate }}</h5> | ||
</div> | ||
} | ||
@case ('TIMEEXTENSION') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.timeExtension' | artemisTranslate }}</h5> | ||
<div class="text-center">{{ 'artemisApp.exam.overview.timeExtensionExplanation' | artemisTranslate }}</div> | ||
</div> | ||
} | ||
@case ('CLOSED') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.' + (exam.testExam ? 'testExam.' : '') + 'closed' | artemisTranslate }}</h5> | ||
</div> | ||
} | ||
@case ('STUDENTREVIEW') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.review' | artemisTranslate }}</h5> | ||
<div class="text-center">{{ 'artemisApp.exam.overview.reviewExplanation' | artemisTranslate }} {{ exam.examStudentReviewEnd | artemisDate }}</div> | ||
</div> | ||
} | ||
@case ('NO_MORE_ATTEMPTS') { | ||
<div> | ||
<h5 class="text-center">{{ 'artemisApp.exam.overview.testExam.noMoreAttempts' | artemisTranslate }}</h5> | ||
<div class="text-center">{{ 'artemisApp.exam.overview.testExam.noMoreAttemptsExplanation' | artemisTranslate }}</div> | ||
</div> | ||
} | ||
} | ||
</div> | ||
} | ||
</div> | ||
<!-- Footer --> | ||
<div class="card-footer row"> | ||
<!-- For real exams, the start date is shown. For test exams, the working window is shown to the students --> | ||
@if (!exam.testExam && exam.startDate) { | ||
<div class="col-sm">{{ 'artemisApp.exam.overview.start' | artemisTranslate: { start: exam.startDate | artemisDate } }}</div> | ||
} | ||
@if (exam.testExam && exam.startDate && exam.endDate) { | ||
<div class="col-12"> | ||
{{ | ||
'artemisApp.exam.overview.testExam.available' | ||
| artemisTranslate | ||
: { | ||
startDate: exam.startDate | artemisDate, | ||
endDate: exam.endDate | artemisDate | ||
} | ||
}} | ||
</div> | ||
} | ||
@if (exam.startDate && exam.endDate) { | ||
<div class="col-12">{{ 'artemisApp.exam.overview.duration' | artemisTranslate }} {{ exam.workingTime! | artemisDurationFromSeconds: true }}</div> | ||
} | ||
@if (exam.examMaxPoints) { | ||
<div class="col-sm">{{ 'artemisApp.exam.overview.maxPoints' | artemisTranslate: { points: exam.examMaxPoints } }}</div> | ||
} | ||
</div> | ||
</div> | ||
} |
13 changes: 13 additions & 0 deletions
13
...ain/webapp/app/overview/course-exams/course-exam-detail/course-exam-detail.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.icon-settings { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
text-align: center; | ||
} | ||
|
||
.card-general-settings { | ||
padding: 5px 0; | ||
border: 1px; | ||
border-radius: 3px; | ||
transition: box-shadow 0.1s linear; | ||
} |
Oops, something went wrong.