Skip to content

Feature/apollon2 migration #10923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,025 changes: 1,007 additions & 18 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@siemens/ngx-datatable": "22.4.1",
"@swimlane/ngx-charts": "22.0.0",
"@swimlane/ngx-graph": "10.0.0",
"@tumaet/apollon": "4.0.0-alpha.0",
"@vscode/codicons": "0.0.36",
"@vscode/markdown-it-katex": "1.1.1",
"bootstrap": "5.3.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public boolean isEmpty(ObjectMapper jacksonObjectMapper) {
return false;
}
// TODO: further improve this!!
return model == null || model.isBlank() || jacksonObjectMapper.readTree(getModel()).get("elements").isEmpty();
return model == null || model.isBlank() || jacksonObjectMapper.readTree(getModel()).get("nodes").isEmpty();
}
catch (JsonProcessingException ex) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ <h3 class="top-container flex-wrap flex-lg-nowrap">
@if (isAssessor && (!hasComplaint || exercise?.isAtLeastInstructor)) {
<span id="assessmentLockedCurrentUser" class="text-danger m-2" style="font-size: 65%" jhiTranslate="artemisApp.assessment.assessmentLockedCurrentUser"></span>
}

<!-- Highlight the difference between first and second correction -->
@if (!isProgrammingExercise && result && correctionRound > 0) {
<button class="btn ms-2 btn-primary" (click)="toggleHighlightDifferences()" [disabled]="saveBusy || submitBusy || cancelBusy">
Expand Down Expand Up @@ -147,6 +148,7 @@ <h3 class="top-container flex-wrap flex-lg-nowrap">
@if (submitBusy) {
<fa-icon [icon]="faSpinner" animation="spin" />
}
<span>submit override</span>
<span jhiTranslate="artemisApp.assessment.button.overrideAssessment"></span>
</button>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, Input, inject } from '@angular/core';
import { SafeHtml } from '@angular/platform-browser';
import { UMLDiagramType, UMLModel } from '@ls1intum/apollon';
import { UMLDiagramType, UMLModel } from '@tumaet/apollon';
import { ArtemisMarkdownService } from 'app/shared/service/markdown.service';
import { Exercise, ExerciseType } from 'app/exercise/shared/entities/exercise/exercise.model';
import { TextExercise } from 'app/text/shared/entities/text-exercise.model';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ExampleSubmission } from 'app/assessment/shared/entities/example-submis
import { ArtemisMarkdownService } from 'app/shared/service/markdown.service';
import { TextExercise } from 'app/text/shared/entities/text-exercise.model';
import { ModelingExercise } from 'app/modeling/shared/entities/modeling-exercise.model';
import { UMLModel } from '@ls1intum/apollon';
import { UMLModel } from '@tumaet/apollon';
import { ComplaintService } from 'app/assessment/shared/services/complaint.service';
import { Complaint, ComplaintType } from 'app/assessment/shared/entities/complaint.model';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, OnInit, input, output, viewChild } from '@angular/core';
import { UMLModel } from '@ls1intum/apollon';
import { UMLModel } from '@tumaet/apollon';
import dayjs from 'dayjs/esm';
import { ModelingSubmission } from 'app/modeling/shared/entities/modeling-submission.model';
import { ModelingExercise } from 'app/modeling/shared/entities/modeling-exercise.model';
Expand Down Expand Up @@ -108,8 +108,8 @@ export class ModelingExamSubmissionComponent extends ExamSubmissionComponent imp
if (!this.modelingEditor() || !this.modelingEditor().getCurrentModel()) {
return;
}
const currentApollonModel = this.modelingEditor().getCurrentModel();
const diagramJson = JSON.stringify(currentApollonModel);

const diagramJson = JSON.stringify(this.modelingEditor().getCurrentModel());

if (this.studentSubmission()) {
if (diagramJson) {
Expand Down Expand Up @@ -158,7 +158,6 @@ export class ModelingExamSubmissionComponent extends ExamSubmissionComponent imp
// and need to remove the content that was added before the string is saved to the db to get valid JSON
let model = this.submissionVersion.content.substring(0, this.submissionVersion.content.indexOf('; Explanation:'));
// if we do not wait here for apollon, the redux store might be undefined
await this.modelingEditor()!.apollonEditor!.nextRender;
model = model.replace('Model: ', '');
// updates the Apollon editor model state (view) with the latest modeling submission
this.umlModel = JSON.parse(model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
</div>
}
<div class="editor-container flex-grow-1">
<span>before assessment</span>
@if (submission) {
<jhi-modeling-assessment
[diagramType]="modelingExercise?.diagramType"
Expand All @@ -66,16 +67,18 @@
</div>
<div class="row mt-3">
@if (result && result.id) {
<jhi-unreferenced-feedback
[(feedbacks)]="unreferencedFeedback"
[feedbackSuggestions]="unreferencedFeedbackSuggestions"
(feedbacksChange)="validateFeedback()"
[readOnly]="readOnly"
[highlightDifferences]="highlightDifferences"
(onAcceptSuggestion)="removeSuggestion($event)"
(onDiscardSuggestion)="removeSuggestion($event)"
[resultId]="result.id"
/>
<div>
<jhi-unreferenced-feedback
[(feedbacks)]="unreferencedFeedback"
[feedbackSuggestions]="unreferencedFeedbackSuggestions"
(feedbacksChange)="validateFeedback()"
[readOnly]="readOnly"
[highlightDifferences]="highlightDifferences"
(onAcceptSuggestion)="removeSuggestion($event)"
(onDiscardSuggestion)="removeSuggestion($event)"
[resultId]="result.id"
/>
</div>
}
@if ((hasAutomaticFeedback || highlightMissingFeedback) && !result?.completionDate) {
<div class="col-md-6">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Location } from '@angular/common';
import { UnreferencedFeedbackComponent } from 'app/exercise/unreferenced-feedback/unreferenced-feedback.component';
import { firstValueFrom } from 'rxjs';
import { AlertService } from 'app/shared/service/alert.service';
import { UMLDiagramType, UMLModel } from '@ls1intum/apollon';
import { UMLDiagramType, UMLModel } from '@tumaet/apollon';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { AccountService } from 'app/core/auth/account.service';
import { HttpErrorResponse } from '@angular/common/http';
Expand Down Expand Up @@ -191,6 +191,7 @@ export class ModelingAssessmentEditorComponent implements OnInit {
private loadSubmission(submissionId: number): void {
this.modelingSubmissionService.getSubmission(submissionId, this.correctionRound, this.resultId).subscribe({
next: (submission: ModelingSubmission) => {
// console.log('DEBUG received submission,', submission);
this.handleReceivedSubmission(submission);
this.validateFeedback();
},
Expand Down Expand Up @@ -427,7 +428,9 @@ export class ModelingAssessmentEditorComponent implements OnInit {
}

onSubmitAssessment() {
if ((this.model && this.referencedFeedback.length < Object.keys(this.model.elements).length) || !this.assessmentsAreValid) {
const totalNumberOfElements = (this.model?.nodes.length ?? 0) + (this.model?.edges.length ?? 0);
// console.log('DEBUG onSubmit assessment is triggered totalNumberOfElements:', totalNumberOfElements);
if ((this.model && this.referencedFeedback.length < totalNumberOfElements) || !this.assessmentsAreValid) {
const confirmationMessage = this.translateService.instant('artemisApp.modelingAssessmentEditor.messages.confirmSubmission');

// if the assessment is before the assessment due date, don't show the confirm submission button
Expand All @@ -454,6 +457,7 @@ export class ModelingAssessmentEditorComponent implements OnInit {
return;
}

// console.log('DEBUG before modelingAssessmentService.saveAssessment is called', this.feedback);
this.modelingAssessmentService.saveAssessment(this.result!.id!, this.feedback, this.submission!.id!, this.result!.assessmentNote?.note, true).subscribe({
next: (result: Result) => {
result.participation!.results = [result];
Expand Down Expand Up @@ -530,6 +534,7 @@ export class ModelingAssessmentEditorComponent implements OnInit {
* @param feedback The feedback present in the editor.
*/
onFeedbackChanged(feedback: Feedback[]) {
// console.log('DEBUG on feedbackChanged,', feedback);
this.updateApollonEditorWithFeedback(feedback);
}

Expand Down Expand Up @@ -590,7 +595,12 @@ export class ModelingAssessmentEditorComponent implements OnInit {
: new Map<string, string>();

const referenceIds = this.referencedFeedback.map((feedback) => feedback.referenceId);
for (const element of Object.values(this.model.elements)) {
for (const element of Object.values(this.model.nodes)) {
if (!referenceIds.includes(element.id)) {
this.highlightedElements.set(element.id, FeedbackHighlightColor.RED);
}
}
for (const element of Object.values(this.model.edges)) {
if (!referenceIds.includes(element.id)) {
this.highlightedElements.set(element.id, FeedbackHighlightColor.RED);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ $draggable-width: 15px;
}

.apollon-container {
display: flex;
flex-grow: 1;
height: 100%;
width: 100%;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, inject } from '@angular/core';
import { ApollonEditor, ApollonMode, Assessment, Selection, UMLDiagramType, UMLElementType, UMLModel, UMLRelationshipType, addOrUpdateAssessment } from '@ls1intum/apollon';
import { ApollonEditor, ApollonMode, Assessment, Selection, UMLDiagramType, UMLModel } from '@tumaet/apollon';
import { Feedback, FeedbackType } from 'app/assessment/shared/entities/feedback.model';
import { ModelElementCount } from 'app/modeling/shared/entities/modeling-submission.model';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
Expand Down Expand Up @@ -78,12 +78,14 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
}

ngOnDestroy() {
// console.log('DEUBUG Modelin-assessment component ngOnDestroy');
if (this.apollonEditor) {
this.apollonEditor.destroy();
}
}

async ngOnChanges(changes: SimpleChanges): Promise<void> {
// console.log('DEBUG ngOnChanges, ', changes);
if (changes.umlModel && changes.umlModel.currentValue && this.apollonEditor) {
this.apollonEditor!.model = changes.umlModel.currentValue;
this.handleFeedback();
Expand All @@ -99,7 +101,7 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
}

if ((changes.highlightedElements || changes.highlightDifferences) && this.apollonEditor) {
await this.updateApollonAssessments(this.referencedFeedbacks);
this.updateApollonAssessments(this.referencedFeedbacks);
await this.applyStateConfiguration();
}
}
Expand All @@ -110,7 +112,8 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
*/
private initializeApollonEditor() {
if (this.apollonEditor) {
this.apollonEditor.destroy();
// console.log('DEBUG modelling assessment component initializeApollonEditor disposing Apollon Editor');
// this.apollonEditor.destroy();
}

this.handleFeedback();
Expand All @@ -122,17 +125,25 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
type: this.diagramType || UMLDiagramType.ClassDiagram,
enablePopups: this.enablePopups,
});
this.apollonEditor!.subscribeToSelectionChange((selection: Selection) => {
if (this.readOnly) {
this.selectionChanged.emit(selection);

this.apollonEditor.subscribeToModelChange((state) => {
if (!this.readOnly) {
const assessmentsArray = Object.values(state.assessments);
this.referencedFeedbacks = this.generateFeedbackFromAssessment(assessmentsArray);
this.feedbackChanged.emit(this.referencedFeedbacks);
}
});
if (!this.readOnly) {
this.apollonEditor!.subscribeToAssessmentChange((assessments: Assessment[]) => {
this.referencedFeedbacks = this.generateFeedbackFromAssessment(assessments);
this.feedbackChanged.emit(this.referencedFeedbacks);
});
}
// this.apollonEditor!.subscribeToSelectionChange((selection: Selection) => {
// if (this.readOnly) {
// this.selectionChanged.emit(selection);
// }
// });
// if (!this.readOnly) {
// this.apollonEditor!.subscribeToAssessmentChange((assessments: Assessment[]) => {
// this.referencedFeedbacks = this.generateFeedbackFromAssessment(assessments);
// this.feedbackChanged.emit(this.referencedFeedbacks);
// });
// }
}

private async applyStateConfiguration() {
Expand All @@ -156,14 +167,15 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
}
feedback.credits = assessment.score;
feedback.text = assessment.feedback;
if (assessment.dropInfo && assessment.dropInfo.instruction?.id) {
feedback.gradingInstruction = assessment.dropInfo.instruction;
}
if (feedback.gradingInstruction && assessment.dropInfo == undefined) {
feedback.gradingInstruction = undefined;
}
// if (assessment.dropInfo && assessment.dropInfo.instruction?.id) {
// feedback.gradingInstruction = assessment.dropInfo.instruction;
// }
// if (feedback.gradingInstruction && assessment.dropInfo == undefined) {
// feedback.gradingInstruction = undefined;
// }
} else {
feedback = Feedback.forModeling(assessment.score, assessment.feedback, assessment.modelElementId, assessment.elementType, assessment.dropInfo);
// feedback = Feedback.forModeling(assessment.score, assessment.feedback, assessment.modelElementId, assessment.elementType, assessment.dropInfo);
feedback = Feedback.forModeling(assessment.score, assessment.feedback, assessment.modelElementId, assessment.elementType, undefined);
}
newElementFeedback.set(assessment.modelElementId, feedback);
}
Expand Down Expand Up @@ -212,15 +224,15 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
}

if (this.apollonEditor != undefined) {
await this.apollonEditor.nextRender;
const model: UMLModel = this.apollonEditor!.model;
for (const element of Object.values(model!.elements)) {
element.highlight = newElements.get(element.id);
}
for (const relationship of Object.values(model!.relationships)) {
relationship.highlight = newElements.get(relationship.id);
}
this.apollonEditor!.model = model!;
// console.log('DEBUG updateHighlightedElements', JSON.stringify(newElements));
// const model: UMLModel = this.apollonEditor!.model;
// for (const element of Object.values(model!.nodes)) {
// element.highlight = newElements.get(element.id);
// }
// for (const relationship of Object.values(model!.relationships)) {
// relationship.highlight = newElements.get(relationship.id);
// }
// this.apollonEditor!.model = model!;
}
}

Expand All @@ -239,13 +251,12 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
newElementCounts.forEach((elementCount) => elementCountMap.set(elementCount.elementId, elementCount.numberOfOtherElements));

if (this.apollonEditor != undefined) {
await this.apollonEditor.nextRender;
const model: UMLModel = this.apollonEditor.model;
for (const element of Object.values(model.elements)) {
element.assessmentNote = this.calculateNote(elementCountMap.get(element.id));
for (const node of Object.values(model.nodes)) {
node.data.assessmentNote = this.calculateNote(elementCountMap.get(node.id));
}
for (const relationship of Object.values(model.relationships)) {
relationship.assessmentNote = this.calculateNote(elementCountMap.get(relationship.id));
for (const edge of Object.values(model.edges)) {
edge.data.assessmentNote = this.calculateNote(elementCountMap.get(edge.id));
}
this.apollonEditor.model = model;
}
Expand All @@ -255,27 +266,31 @@ export class ModelingAssessmentComponent extends ModelingComponent implements Af
* Converts a given feedback list to Apollon assessments and updates the model of Apollon with the new assessments.
* @param feedbacks the feedback list to convert and pass on to Apollon
*/
private async updateApollonAssessments(feedbacks: Feedback[]) {
private updateApollonAssessments(feedbacks: Feedback[]) {
if (!feedbacks || !this.umlModel) {
return;
}

// console.log('DEBUG updateApollonAssessments feedbacks:', JSON.stringify(feedbacks));

feedbacks.forEach((feedback) => {
addOrUpdateAssessment(this.umlModel, {
const newAssessment: Assessment = {
modelElementId: feedback.referenceId!,
elementType: feedback.referenceType! as UMLElementType | UMLRelationshipType,
elementType: feedback.referenceType!,
score: feedback.credits!,
feedback: feedback.text || undefined,
label: this.calculateLabel(feedback),
labelColor: this.calculateLabelColor(feedback),
correctionStatus: this.calculateCorrectionStatusForFeedback(feedback),
dropInfo: this.calculateDropInfo(feedback),
});
};
if (this.apollonEditor) {
this.apollonEditor.addOrUpdateAssessment(newAssessment);
}
});

if (this.apollonEditor) {
await this.apollonEditor.nextRender;
this.apollonEditor.model = this.umlModel;
// this.apollonEditor.model = this.umlModel;
}
}

Expand Down
Loading
Loading