Skip to content

Commit

Permalink
Exam mode: Add save exercise button to exercises (#9569)
Browse files Browse the repository at this point in the history
  • Loading branch information
edkaya authored Nov 16, 2024
1 parent 7896ff9 commit f472c21
Show file tree
Hide file tree
Showing 22 changed files with 343 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,40 @@
<div [hidden]="i !== activePageIndex" [id]="'exercise-' + exercise.id">
@switch (exercise.type) {
@case (QUIZ) {
<jhi-quiz-submission-exam
[quizConfiguration]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions![0]"
/>
@if (exercise.studentParticipations[0].submissions) {
<jhi-quiz-submission-exam
[quizConfiguration]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions[0]"
(saveCurrentExercise)="triggerSave(false)"
/>
}
}
@case (FILEUPLOAD) {
<jhi-file-upload-submission-exam
[exercise]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions![0]"
/>
@if (exercise.studentParticipations[0].submissions) {
<jhi-file-upload-submission-exam
[exercise]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions[0]"
/>
}
}
@case (TEXT) {
<jhi-text-editor-exam [exercise]="exercise" [studentSubmission]="exercise.studentParticipations[0].submissions![0]" />
@if (exercise.studentParticipations[0].submissions) {
<jhi-text-editor-exam
[exercise]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions[0]"
(saveCurrentExercise)="triggerSave(false)"
/>
}
}
@case (MODELING) {
<jhi-modeling-submission-exam [exercise]="exercise" [studentSubmission]="exercise.studentParticipations[0].submissions![0]" />
@if (exercise.studentParticipations[0].submissions) {
<jhi-modeling-submission-exam
[exercise]="exercise"
[studentSubmission]="exercise.studentParticipations[0].submissions[0]"
[isSubmissionSynced]="exercise.studentParticipations[0].submissions[0].isSynced"
(saveCurrentExercise)="triggerSave(false)"
/>
}
}
@case (PROGRAMMING) {
<jhi-programming-submission-exam
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ArtemisCodeEditorModule } from 'app/exercises/programming/shared/code-e
import { ArtemisFullscreenModule } from 'app/shared/fullscreen/fullscreen.module';
import { ArtemisModelingEditorModule } from 'app/exercises/modeling/shared/modeling-editor.module';
import { ArtemisProgrammingSubmissionPolicyStatusModule } from 'app/exercises/programming/participate/programming-submission-policy-status.module';
import { ExerciseSaveButtonComponent } from './exercise-save-button/exercise-save-button.component';

@NgModule({
declarations: [
Expand All @@ -42,6 +43,7 @@ import { ArtemisProgrammingSubmissionPolicyStatusModule } from 'app/exercises/pr
ArtemisModelingEditorModule,
ArtemisProgrammingSubmissionPolicyStatusModule,
ExamExerciseUpdateHighlighterModule,
ExerciseSaveButtonComponent,
],
exports: [FileUploadExamSubmissionComponent, QuizExamSubmissionComponent, ProgrammingExamSubmissionComponent, TextExamSubmissionComponent, ModelingExamSubmissionComponent],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<button id="save-exam" type="submit" [disabled]="submission()?.isSynced" class="btn btn-primary" (click)="onSave()">
<fa-icon class="saved" [fixedWidth]="true" [icon]="submission()?.submitted && submission()?.isSynced ? facSaveSuccess : faFloppyDisk"> </fa-icon>
<span
class="d-none d-sm-inline"
[jhiTranslate]="submission()?.submitted && submission()?.isSynced ? 'artemisApp.examParticipation.exerciseSaved' : 'artemisApp.examParticipation.saveExercise'"
>
</span>
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.saved {
--fa-secondary-opacity: 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Component, input, output } from '@angular/core';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { faFloppyDisk } from '@fortawesome/free-solid-svg-icons';
import { facSaveSuccess } from '../../../../../content/icons/icons';
import { Submission } from 'app/entities/submission.model';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-exercise-save-button',
templateUrl: './exercise-save-button.component.html',
styleUrls: ['./exercise-save-button.component.scss'],
standalone: true,
imports: [FaIconComponent, TranslateDirective],
})
export class ExerciseSaveButtonComponent {
protected readonly faFloppyDisk = faFloppyDisk;
protected readonly facSaveSuccess = facSaveSuccess;

submission = input<Submission>();
save = output<void>();

onSave() {
this.save.emit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ <h3 class="text-align-left fw-normal">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<!-- prettier-ignore -->
<span left-header>&nbsp;({{ exercise.maxPoints }} {{ 'artemisApp.examParticipation.points' | artemisTranslate }}@if (exercise.bonusPoints) {
<span
>, {{ exercise.bonusPoints }} {{ 'artemisApp.examParticipation.bonus' | artemisTranslate }}</span>
}) @if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge
[includedInOverallScore]="exercise.includedInOverallScore" />
}</span>
<span
[jhiTranslate]="exercise.bonusPoints ? 'artemisApp.examParticipation.bonus' : 'artemisApp.examParticipation.points'"
[translateValues]="{ points: exercise.maxPoints, bonusPoints: exercise.bonusPoints }"
>
</span>
@if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge [includedInOverallScore]="exercise.includedInOverallScore" />
}
</h3>
<hr />
<jhi-resizeable-container [examTimeline]="examTimeline">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
@if (exercise) {
<h3 class="text-align-left fw-normal">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<!-- prettier-ignore -->
<span left-header>&nbsp;({{ exercise.maxPoints }} {{ 'artemisApp.examParticipation.points' | artemisTranslate }}@if (exercise.bonusPoints) {
<div class="d-flex justify-content-between align-items-center">
<h3 class="text-align-left fw-normal mb-0">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<span
>, {{ exercise.bonusPoints }} {{ 'artemisApp.examParticipation.bonus' | artemisTranslate }}</span>
}) @if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge
[includedInOverallScore]="exercise.includedInOverallScore" />
}</span>
</h3>
[jhiTranslate]="exercise.bonusPoints ? 'artemisApp.examParticipation.bonus' : 'artemisApp.examParticipation.points'"
[translateValues]="{ points: exercise.maxPoints, bonusPoints: exercise.bonusPoints }"
>
</span>
@if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge [includedInOverallScore]="exercise.includedInOverallScore" />
}
</h3>
<jhi-exercise-save-button [submission]="studentSubmission" (save)="notifyTriggerSave()" />
</div>
<hr />

<jhi-resizeable-container class="col-12" [examTimeline]="examTimeline">
Expand All @@ -38,7 +41,7 @@ <h3 class="text-align-left fw-normal">
</div>
<!--endregion-->
<!--region Right Panel-->
<fa-icon right-header [icon]="farListAlt" />&nbsp;
<fa-icon right-header [icon]="faListAlt" />&nbsp;
<span right-header jhiTranslate="artemisApp.modelingSubmission.problemStatement"></span>
<!-- problem statement update & difference highlighter -->
<ng-container right-body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild, input, output } from '@angular/core';
import { UMLModel } from '@ls1intum/apollon';
import dayjs from 'dayjs/esm';
import { ModelingSubmission } from 'app/entities/modeling-submission.model';
Expand Down Expand Up @@ -34,12 +34,17 @@ export class ModelingExamSubmissionComponent extends ExamSubmissionComponent imp
exercise: ModelingExercise;
umlModel: UMLModel; // input model for Apollon+

// explicitly needed to track if submission.isSynced is changed, otherwise component
// does not update the state due to onPush strategy
isSubmissionSynced = input<boolean>();
saveCurrentExercise = output<void>();

explanationText: string; // current explanation text

readonly IncludedInOverallScore = IncludedInOverallScore;

// Icons
farListAlt = faListAlt;
protected readonly faListAlt = faListAlt;

constructor(changeDetectorReference: ChangeDetectorRef) {
super(changeDetectorReference);
Expand Down Expand Up @@ -154,4 +159,11 @@ export class ModelingExamSubmissionComponent extends ExamSubmissionComponent imp
this.changeDetectorReference.detectChanges();
}
}

/**
* Trigger save action in exam participation component
*/
notifyTriggerSave() {
this.saveCurrentExercise.emit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ <h3 class="text-align-left fw-normal">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<!-- prettier-ignore -->
<span left-header>&nbsp;({{ exercise.maxPoints }} {{ 'artemisApp.examParticipation.points' | artemisTranslate }}@if (exercise.bonusPoints) {
<span
>, {{ exercise.bonusPoints }} {{ 'artemisApp.examParticipation.bonus' | artemisTranslate }}</span>
}) @if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge
[includedInOverallScore]="exercise.includedInOverallScore" />
}</span>
<span
[jhiTranslate]="exercise.bonusPoints ? 'artemisApp.examParticipation.bonus' : 'artemisApp.examParticipation.points'"
[translateValues]="{ points: exercise.maxPoints, bonusPoints: exercise.bonusPoints }"
>
</span>
@if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge [includedInOverallScore]="exercise.includedInOverallScore" />
}
</h3>
<hr />
<!-- ngIf online-code-editor -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<h3 class="text-align-left fw-normal">
<span>
{{ quizConfiguration.exerciseGroup?.title }}
</span>
<span
>({{ quizConfiguration.maxPoints }} {{ 'artemisApp.examParticipation.points' | artemisTranslate }})
<div class="d-flex justify-content-between align-items-center">
<h3 class="text-align-left fw-normal mb-0">
<span>
{{ quizConfiguration.exerciseGroup?.title }}
</span>
<span jhiTranslate="artemisApp.examParticipation.points" [translateValues]="{ points: quizConfiguration.maxPoints }"></span>
@if (quizConfiguration.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge [includedInOverallScore]="quizConfiguration.includedInOverallScore" />
}
</span>
</h3>
</h3>
<jhi-exercise-save-button [submission]="studentSubmission" (save)="notifyTriggerSave()" />
</div>
<hr />

<div class="w-auto m-0 pb-5">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectorRef, Component, Input, OnInit, QueryList, ViewChildren } from '@angular/core';
import { ChangeDetectorRef, Component, Input, OnInit, QueryList, ViewChildren, output } from '@angular/core';
import { Exercise, ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model';
import { AbstractQuizSubmission } from 'app/entities/quiz/abstract-quiz-exam-submission.model';
import { AnswerOption } from 'app/entities/quiz/answer-option.model';
Expand Down Expand Up @@ -53,6 +53,8 @@ export class QuizExamSubmissionComponent extends ExamSubmissionComponent impleme
@Input() examTimeline = false;
@Input() quizConfiguration: QuizConfiguration;

saveCurrentExercise = output<void>();

selectedAnswerOptions = new Map<number, AnswerOption[]>();
dragAndDropMappings = new Map<number, DragAndDropMapping[]>();
shortAnswerSubmittedTexts = new Map<number, ShortAnswerSubmittedText[]>();
Expand Down Expand Up @@ -285,4 +287,11 @@ export class QuizExamSubmissionComponent extends ExamSubmissionComponent impleme
this.submissionVersion = submissionVersion;
this.updateViewFromSubmissionVersion();
}

/**
* Trigger save action in exam participation component
*/
notifyTriggerSave() {
this.saveCurrentExercise.emit();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
@if (exercise) {
<h3 class="text-align-left fw-normal">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<!-- prettier-ignore -->
<span left-header>&nbsp;({{ exercise.maxPoints }} {{ 'artemisApp.examParticipation.points' | artemisTranslate }}@if (exercise.bonusPoints) {
<div class="d-flex justify-content-between align-items-center">
<h3 class="text-align-left fw-normal mb-0">
<span>
{{ exercise.exerciseGroup?.title }}
</span>
<span
>, {{ exercise.bonusPoints }} {{ 'artemisApp.examParticipation.bonus' | artemisTranslate }}</span>
}) @if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge
[includedInOverallScore]="exercise.includedInOverallScore" />
}</span>
</h3>
[jhiTranslate]="exercise.bonusPoints ? 'artemisApp.examParticipation.bonus' : 'artemisApp.examParticipation.points'"
[translateValues]="{ points: exercise.maxPoints, bonusPoints: exercise.bonusPoints }"
>
</span>
@if (exercise.includedInOverallScore !== IncludedInOverallScore.INCLUDED_COMPLETELY) {
<jhi-included-in-score-badge [includedInOverallScore]="exercise.includedInOverallScore" />
}
</h3>
<jhi-exercise-save-button [submission]="studentSubmission" (save)="notifyTriggerSave()" />
</div>
<hr />
<!--resizable container-->
<jhi-resizeable-container class="col-12" [examTimeline]="examTimeline">
Expand Down Expand Up @@ -40,7 +43,7 @@ <h3 class="text-align-left fw-normal">
</div>
<!--endregion-->
<!--region Right Panel-->
<fa-icon right-header [icon]="farListAlt" />&nbsp;
<fa-icon right-header [icon]="faListAlt" />&nbsp;
<span right-header jhiTranslate="artemisApp.exercise.problemStatement"></span>
<!-- problem statement update & difference highlighter -->
<ng-container right-body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, Input, OnInit, output } from '@angular/core';
import { TextEditorService } from 'app/exercises/text/participate/text-editor.service';
import { Subject } from 'rxjs';
import { TextSubmission } from 'app/entities/text/text-submission.model';
import { StringCountService } from 'app/exercises/text/participate/string-count.service';
import { Exercise, ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model';
import { ExamSubmissionComponent } from 'app/exam/participate/exercises/exam-submission.component';
import { Submission } from 'app/entities/submission.model';
import { faListAlt } from '@fortawesome/free-regular-svg-icons';
import { faListAlt } from '@fortawesome/free-solid-svg-icons';
import { MAX_SUBMISSION_TEXT_LENGTH } from 'app/shared/constants/input.constants';
import { SubmissionVersion } from 'app/entities/submission-version.model';
import { htmlForMarkdown } from 'app/shared/util/markdown.conversion.util';
Expand All @@ -26,6 +26,8 @@ export class TextExamSubmissionComponent extends ExamSubmissionComponent impleme
@Input()
exercise: Exercise;

saveCurrentExercise = output<void>();

readonly IncludedInOverallScore = IncludedInOverallScore;
readonly maxCharacterCount = MAX_SUBMISSION_TEXT_LENGTH;

Expand All @@ -35,7 +37,7 @@ export class TextExamSubmissionComponent extends ExamSubmissionComponent impleme
private textEditorInput = new Subject<string>();

// Icons
farListAlt = faListAlt;
protected readonly faListAlt = faListAlt;

constructor(
private textService: TextEditorService,
Expand Down Expand Up @@ -121,4 +123,11 @@ export class TextExamSubmissionComponent extends ExamSubmissionComponent impleme
this.submissionVersion = submissionVersion;
this.updateViewFromSubmissionVersion();
}

/**
* Trigger save action in exam participation component
*/
notifyTriggerSave() {
this.saveCurrentExercise.emit();
}
}
Loading

0 comments on commit f472c21

Please sign in to comment.