From 0a7ed2b26b4a8d7ef4e6b3caf7266573aa2ae7ff Mon Sep 17 00:00:00 2001 From: Nikola Luburic Date: Mon, 26 Aug 2024 14:49:06 +0200 Subject: [PATCH 1/4] fix: Adds additional error messages when LT update is not successful. --- .../learning-task/learning-task.component.html | 7 ++++--- .../learning-task/learning-task.component.scss | 7 ++++++- .../learning-task/learning-task.component.ts | 13 ++++++++++++- src/app/shared/generics/model/request-status.ts | 12 ++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/app/shared/generics/model/request-status.ts diff --git a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.html b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.html index 26159658..0014dd5a 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.html +++ b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.html @@ -67,10 +67,11 @@
- - + + -
\ No newline at end of file diff --git a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.scss b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.scss index c73d1d75..c8f48b6d 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.scss +++ b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.scss @@ -1,4 +1,9 @@ .viewport { height: calc(100vh - 210px); width: 100%; -} \ No newline at end of file +} + +.mat-mdc-progress-bar { + --mdc-linear-progress-track-height: 5px; + --mdc-linear-progress-active-indicator-height: 5px; + } \ No newline at end of file diff --git a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.ts b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.ts index 950472c4..c857fbb7 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.ts +++ b/src/app/modules/authoring/learning-tasks/learning-task/learning-task.component.ts @@ -9,6 +9,7 @@ import { DeleteFormComponent } from 'src/app/shared/generics/delete-form/delete- import { MatSnackBar } from '@angular/material/snack-bar'; import { Title } from '@angular/platform-browser'; import { MarkdownPanelComponent } from 'src/app/shared/markdown/markdown-panel/markdown-panel.component'; +import { RequestStatus } from 'src/app/shared/generics/model/request-status'; @Component({ selector: 'cc-learning-task', @@ -20,6 +21,7 @@ export class LearningTaskComponent implements OnInit, OnDestroy { courseId: number; unitId: number; + updateStatus: RequestStatus = RequestStatus.None; task: LearningTask; mode: string = 'task'; @@ -70,6 +72,7 @@ export class LearningTaskComponent implements OnInit, OnDestroy { } private selectStep(step: Activity, mode: string) { + this.updateStatus = RequestStatus.None; this.selectedStep = step; this.mode = mode; if (this.mode === 'subactivities') { @@ -181,17 +184,25 @@ export class LearningTaskComponent implements OnInit, OnDestroy { } updateTask(task: LearningTask) { + this.updateStatus = RequestStatus.Started; this.taskService.update(this.unitId, task) .subscribe({ next: updatedTask => { + this.updateStatus = RequestStatus.Completed; this.setupTaskAndActivities(updatedTask); if (this.selectedStep) { this.setParams(this.task.steps.find(s => s.id === this.selectedStep.id || s.code === this.selectedStep.code), this.mode); } }, error: (error) => { - if (error.error.status === 409) + this.updateStatus = RequestStatus.Error; + if (error.error.status === 409) { this.errorsBar.open('Greška: Aktivnost sa datim kodom već postoji u zadatku. Izmeni kod.', "OK", { horizontalPosition: 'right', verticalPosition: 'top' }); + } else if(error.status === 0) { + this.errorsBar.open('Greška: Server nije prihvatio zahtev. Probaj da ponoviš operaciju.', "OK", { horizontalPosition: 'right', verticalPosition: 'top' }); + } else { + this.errorsBar.open('Greška: Zahtev nije obrađen. Kod greške je: ' + error.error.status + ' Probaj da ponoviš operaciju.', "OK", { horizontalPosition: 'right', verticalPosition: 'top' }); + } } }); } diff --git a/src/app/shared/generics/model/request-status.ts b/src/app/shared/generics/model/request-status.ts new file mode 100644 index 00000000..2f29ac7f --- /dev/null +++ b/src/app/shared/generics/model/request-status.ts @@ -0,0 +1,12 @@ +export enum RequestStatus { + None = 0, + Started = 1, + Completed = 2, + Error = 3 +} + +export function isRequestStartedOrError(changes: {currentValue: RequestStatus, previousValue: RequestStatus}) { + if(!changes) return false; + if(changes.currentValue === changes.previousValue) return false; // Change was triggered by another field + return changes.currentValue === RequestStatus.Started || changes.currentValue === RequestStatus.Error; +} \ No newline at end of file From 9be14239ad83212465c78440f090075ef391da95 Mon Sep 17 00:00:00 2001 From: Nikola Luburic Date: Mon, 26 Aug 2024 14:51:52 +0200 Subject: [PATCH 2/4] fix: Improves form behavior when LT authoring is not successful. --- .../learning-task/activities/activities.component.html | 6 +++--- .../learning-task/activities/activities.component.ts | 8 +++++--- .../activity-details/activity-details.component.html | 10 ++++------ .../activity-details/activity-details.component.ts | 8 +++++--- .../task-details/task-details.component.html | 4 ++-- .../task-details/task-details.component.ts | 8 +++++--- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.html b/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.html index 3e6cca2a..0163410f 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.html +++ b/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.html @@ -27,10 +27,10 @@ {{subactivity.order}}. {{subactivity.code}}: {{subactivity.name}} - - @@ -43,6 +43,6 @@
- +
\ No newline at end of file diff --git a/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.ts b/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.ts index e9a27190..2ca618cf 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.ts +++ b/src/app/modules/authoring/learning-tasks/learning-task/activities/activities.component.ts @@ -1,7 +1,8 @@ -import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { DeleteFormComponent } from 'src/app/shared/generics/delete-form/delete-form.component'; import { Activity } from '../../model/activity'; +import { isRequestStartedOrError, RequestStatus } from 'src/app/shared/generics/model/request-status'; @Component({ selector: 'cc-activities', @@ -10,6 +11,7 @@ import { Activity } from '../../model/activity'; }) export class ActivitiesComponent implements OnChanges { @Input() activities: Activity[]; + @Input() updateStatus: RequestStatus; activeActivity: Activity; @@ -18,7 +20,8 @@ export class ActivitiesComponent implements OnChanges { constructor(private dialog: MatDialog) { } - ngOnChanges(): void { + ngOnChanges(changes: SimpleChanges): void { + if(isRequestStartedOrError(changes.updateStatus)) return; // Triggers from parent when HTTP request starts if(this.activeActivity) { let correspondingActivity = this.activities.find(a => a.id === this.activeActivity.id || a.code === this.activeActivity.code); if(correspondingActivity) { @@ -60,7 +63,6 @@ export class ActivitiesComponent implements OnChanges { save(activity: Activity) { this.activitySaved.emit(activity); - this.activeActivity = activity; } delete(activity: Activity) { diff --git a/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.html b/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.html index 6a310d71..a35d430f 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.html +++ b/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.html @@ -4,9 +4,7 @@ Kod - - Mora biti jedinstven za zadatak - + Jedinstven za zadatak Naziv @@ -19,11 +17,11 @@ edit - diff --git a/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.ts b/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.ts index 00c5c48c..cc5510b8 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.ts +++ b/src/app/modules/authoring/learning-tasks/learning-task/activity-details/activity-details.component.ts @@ -1,6 +1,7 @@ -import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { Activity } from '../../model/activity'; +import { isRequestStartedOrError, RequestStatus } from 'src/app/shared/generics/model/request-status'; @Component({ selector: 'cc-activity-details', @@ -10,6 +11,7 @@ import { Activity } from '../../model/activity'; export class ActivityDetailsComponent implements OnChanges { @Input() activity: Activity; @Input() activities: Activity[]; + @Input() updateStatus: RequestStatus; @Output() activitySaved = new EventEmitter(); activityForm: FormGroup; @@ -17,7 +19,8 @@ export class ActivityDetailsComponent implements OnChanges { constructor(private builder: FormBuilder) { } - ngOnChanges(): void { + ngOnChanges(changes: SimpleChanges): void { + if(isRequestStartedOrError(changes.updateStatus)) return; // Triggers from parent when HTTP request starts this.createForm(); if (this.activity.id || this.activity.name) { this.view(); @@ -145,7 +148,6 @@ export class ActivityDetailsComponent implements OnChanges { changedActivity.parentId = this.activity.parentId; changedActivity.order = this.activity.order; this.activitySaved.emit(changedActivity); - this.view(); } } diff --git a/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.html b/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.html index 21924a00..78a8e136 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.html +++ b/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.html @@ -21,11 +21,11 @@ matTooltip="Izmeni" [color]="task?.description ? '' : 'primary'"> edit - - diff --git a/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.ts b/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.ts index eecb3130..6c02128b 100644 --- a/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.ts +++ b/src/app/modules/authoring/learning-tasks/learning-task/task-details/task-details.component.ts @@ -1,6 +1,7 @@ -import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { LearningTask } from '../../model/learning-task'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { isRequestStartedOrError, RequestStatus } from 'src/app/shared/generics/model/request-status'; @Component({ selector: 'cc-task-details', @@ -10,6 +11,7 @@ import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms' export class TaskDetailsComponent implements OnChanges { @Input() task: LearningTask; + @Input() updateStatus: RequestStatus; @Output() taskSaved = new EventEmitter(); taskForm: FormGroup; @@ -17,7 +19,8 @@ export class TaskDetailsComponent implements OnChanges { constructor(private builder: FormBuilder) { } - ngOnChanges(): void { + ngOnChanges(changes: SimpleChanges): void { + if(isRequestStartedOrError(changes.updateStatus)) return; // Triggers from parent when HTTP request starts this.createForm(); if (this.task) { this.setInitialValues(this.task); @@ -43,7 +46,6 @@ export class TaskDetailsComponent implements OnChanges { submitForm() { if (this.taskForm.valid) { - this.editMode = false; this.task.name = this.taskForm.value.name; this.task.description = this.taskForm.value.description; this.task.isTemplate = this.taskForm.value.isTemplate; From 9ee369057ef650f7dd7366866fc588ad0feb74c9 Mon Sep 17 00:00:00 2001 From: Nikola Luburic Date: Tue, 27 Aug 2024 09:51:58 +0200 Subject: [PATCH 3/4] fix: Markdown editor commands now do not completely reset scroll position. --- .../markdown-editor/markdown-editor.component.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/app/shared/markdown/markdown-editor/markdown-editor.component.ts b/src/app/shared/markdown/markdown-editor/markdown-editor.component.ts index d31044fa..1b487ee5 100644 --- a/src/app/shared/markdown/markdown-editor/markdown-editor.component.ts +++ b/src/app/shared/markdown/markdown-editor/markdown-editor.component.ts @@ -139,6 +139,15 @@ export class MarkdownEditorComponent implements OnChanges, AfterViewInit { selectionStart, selectionStart + tagText.length ); + + // Scroll the textarea to make the selected text visible + const textarea = this.textArea.nativeElement; + const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight, 10); + const scrollHeight = textarea.scrollHeight; + const textBeforeSelection = textarea.value.slice(0, selectionStart); + const linesBeforeSelection = (textBeforeSelection.match(/\n/g) || []).length; + const scrollPosition = linesBeforeSelection * lineHeight; + textarea.scrollTop = Math.min(scrollPosition, scrollHeight - textarea.clientHeight); }); } From 4a2cf95ef61959f3c7b2477c44afae0a543c4796 Mon Sep 17 00:00:00 2001 From: Nikola Luburic Date: Tue, 27 Aug 2024 10:50:38 +0200 Subject: [PATCH 4/4] fix: Errors from answering questions now get correct responses. --- .../multiple-choice-question.component.ts | 12 +++++++++--- .../multiple-response-question.component.ts | 12 +++++++++--- .../short-answer-question.component.ts | 12 +++++++++--- .../submission-result/submission-result.component.ts | 10 +++++++++- .../model/learning-objects/feedback.model.ts | 5 +++-- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-choice-question/multiple-choice-question.component.ts b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-choice-question/multiple-choice-question.component.ts index b50b1f78..ae580929 100644 --- a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-choice-question/multiple-choice-question.component.ts +++ b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-choice-question/multiple-choice-question.component.ts @@ -51,9 +51,15 @@ export class MultipleChoiceQuestionComponent implements OnInit, OnDestroy, Learn reattemptCount: this.submissionReattemptCount }; this.submissionIsProcessing = true; - this.submissionService.submit(this.learningObject.id, submission).subscribe((feedback) => { - this.submissionReattemptCount++; - this.feedbackConnector.sendToFeedback(feedback); + this.submissionService.submit(this.learningObject.id, submission).subscribe({ + next: feedback => { + this.submissionReattemptCount++; + this.feedbackConnector.sendToFeedback(feedback); + }, + error: error => { + console.log(error); + this.feedbackConnector.sendToFeedback({type: feedbackTypes.error}); + } }); } diff --git a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-response-question/multiple-response-question.component.ts b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-response-question/multiple-response-question.component.ts index ffa9a802..e9cde807 100644 --- a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-response-question/multiple-response-question.component.ts +++ b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/multiple-response-question/multiple-response-question.component.ts @@ -65,9 +65,15 @@ export class MultipleResponseQuestionComponent implements OnInit, OnDestroy, Lea reattemptCount: this.submissionReattemptCount }; this.submissionIsProcessing = true; - this.submissionService.submit(this.learningObject.id, submission).subscribe((feedback) => { - this.submissionReattemptCount++; - this.feedbackConnector.sendToFeedback(feedback); + this.submissionService.submit(this.learningObject.id, submission).subscribe({ + next: feedback => { + this.submissionReattemptCount++; + this.feedbackConnector.sendToFeedback(feedback); + }, + error: error => { + console.log(error); + this.feedbackConnector.sendToFeedback({type: feedbackTypes.error}); + } }); } diff --git a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/short-answer-question/short-answer-question.component.ts b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/short-answer-question/short-answer-question.component.ts index a2b4a115..26b4ad3e 100644 --- a/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/short-answer-question/short-answer-question.component.ts +++ b/src/app/modules/learning/knowledge-component/learning-objects/assessment-items/short-answer-question/short-answer-question.component.ts @@ -49,9 +49,15 @@ export class ShortAnswerQuestionComponent implements LearningObjectComponent { reattemptCount: this.submissionReattemptCount }; this.submissionIsProcessing = true; - this.submissionService.submit(this.learningObject.id, submission).subscribe(feedback => { - this.submissionReattemptCount++; - this.feedbackConnector.sendToFeedback(feedback); + this.submissionService.submit(this.learningObject.id, submission).subscribe({ + next: feedback => { + this.submissionReattemptCount++; + this.feedbackConnector.sendToFeedback(feedback); + }, + error: error => { + console.log(error); + this.feedbackConnector.sendToFeedback({type: feedbackTypes.error}); + } }); } } diff --git a/src/app/modules/learning/knowledge-component/submission-result/submission-result.component.ts b/src/app/modules/learning/knowledge-component/submission-result/submission-result.component.ts index 68992849..926fa999 100644 --- a/src/app/modules/learning/knowledge-component/submission-result/submission-result.component.ts +++ b/src/app/modules/learning/knowledge-component/submission-result/submission-result.component.ts @@ -4,7 +4,7 @@ import { Output, EventEmitter } from '@angular/core'; import { Subscription } from 'rxjs'; import { ActivatedRoute, Params } from '@angular/router'; import { KnowledgeComponentService } from '../knowledge-component.service'; -import { Feedback } from '../../model/learning-objects/feedback.model'; +import { Feedback, feedbackTypes } from '../../model/learning-objects/feedback.model'; import { KnowledgeComponentStatistics } from '../../model/knowledge-component-statistics.model'; import { createResponse, welcomeMessage } from './instructional-feedback/feedback-message-creator'; @@ -48,6 +48,14 @@ export class SubmissionResultComponent implements OnInit, OnDestroy { getKnowledgeComponentStatistics(feedback: Feedback): void { this.feedbackProcessed = false; this.feedbackMessage = ""; + if(feedback?.type === feedbackTypes.error) { + this.messageTimeout = setTimeout(() => { + this.feedbackMessage = "🤕 Nešto sam se pokvario i nisam uspeo da obradim tvoj odgovor.\nAko ti radi internet probaj ponovo.\nAko se problem nastavi javi se mentoru." + this.feedbackProcessed = true; + this.assessmentConnector.sendToAssessment(feedback); + }, 400); + return; + } this.kcService.getKnowledgeComponentStatistics(this.kcId).subscribe(result => { if(feedback) { let isFirstSatisfaction = this.statistics.isSatisfied !== result.isSatisfied diff --git a/src/app/modules/learning/model/learning-objects/feedback.model.ts b/src/app/modules/learning/model/learning-objects/feedback.model.ts index d6501d2c..5be8c4cf 100644 --- a/src/app/modules/learning/model/learning-objects/feedback.model.ts +++ b/src/app/modules/learning/model/learning-objects/feedback.model.ts @@ -2,8 +2,8 @@ import { Evaluation } from "./evaluation.model"; export interface Feedback { type: string; - hint: string; - evaluation: Evaluation; + hint?: string; + evaluation?: Evaluation; } export const feedbackTypes = { @@ -11,4 +11,5 @@ export const feedbackTypes = { hint: 'Hint', correctness: 'Correctness', solution: 'Solution', + error: "Error" };