Skip to content

Commit

Permalink
Fetch and display summary in frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
ole-ve committed Aug 4, 2024
1 parent 85d2ac8 commit 0a12f62
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 3 deletions.
9 changes: 9 additions & 0 deletions src/main/webapp/app/course/manage/course-admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { map } from 'rxjs/operators';
import { Course } from 'app/entities/course.model';
import { objectToJsonBlob } from 'app/utils/blob-util';
import { CourseManagementService } from 'app/course/manage/course-management.service';
import { CourseDeletionSummaryDTO } from 'app/entities/course-deletion-summary.model';

export type EntityResponseType = HttpResponse<Course>;
export type EntityArrayResponseType = HttpResponse<Course[]>;
Expand Down Expand Up @@ -51,4 +52,12 @@ export class CourseAdminService {
delete(courseId: number): Observable<HttpResponse<void>> {
return this.http.delete<void>(`${this.resourceUrl}/${courseId}`, { observe: 'response' });
}

/**
* Returns a summary for the course providing information potentially relevant for the deletion.
* @param courseId
*/
getDeletionSummary(courseId: number): Observable<HttpResponse<CourseDeletionSummaryDTO>> {
return this.http.get<CourseDeletionSummaryDTO>(`${this.resourceUrl}/${courseId}/deletion-summary`, { observe: 'response' });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
[buttonSize]="ButtonSize.MEDIUM"
jhiDeleteButton
[entityTitle]="course.title || ''"
entitySummaryTitle="artemisApp.course.delete.summary.title"
[entitySummary]="courseSummary"
deleteQuestion="artemisApp.course.delete.question"
deleteConfirmationText="artemisApp.course.delete.typeNameToConfirm"
(delete)="deleteCourse(course.id!)"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Subject, Subscription } from 'rxjs';
import { Course, isCommunicationEnabled } from 'app/entities/course.model';
import { CourseManagementService } from 'app/course/manage/course-management.service';
Expand Down Expand Up @@ -33,6 +33,8 @@ import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { PROFILE_IRIS, PROFILE_LOCALCI, PROFILE_LTI } from 'app/app.constants';
import { CourseAccessStorageService } from 'app/course/course-access-storage.service';
import { scrollToTopOfPage } from 'app/shared/util/utils';
import { CourseDeletionSummaryDTO } from 'app/entities/course-deletion-summary.model';
import { ExerciseType } from 'app/entities/exercise.model';

@Component({
selector: 'jhi-course-management-tab-bar',
Expand Down Expand Up @@ -79,6 +81,8 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After
irisEnabled = false;
ltiEnabled = false;

courseSummary: { [key: string]: unknown } = {};

constructor(
private eventManager: EventManager,
private courseManagementService: CourseManagementService,
Expand Down Expand Up @@ -136,6 +140,9 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After
this.courseSub = this.courseManagementService.find(courseId).subscribe((courseResponse) => {
this.course = courseResponse.body!;
this.isCommunicationEnabled = isCommunicationEnabled(this.course);

this.setExistingSummaryEntries();
this.fetchAndSetCourseDeletionSummary();
});
}

Expand Down Expand Up @@ -198,4 +205,66 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After
const courseManagementRegex = /course-management\/[0-9]+(\/edit)?$/;
return courseManagementRegex.test(this.router.url);
}

private setExistingSummaryEntries() {
const numberRepositories =
this.course?.exercises
?.filter((exercise) => exercise.type === 'programming')
.map((exercise) => exercise?.numberOfParticipations ?? 0)
.reduce((a, b) => a + b, 0) ?? 0;

const numberOfExercisesPerType = new Map<ExerciseType, number>();
this.course?.exercises?.forEach((exercise) => {
if (exercise.type === undefined) {
return;
}
const oldValue = numberOfExercisesPerType.get(exercise.type) ?? 0;
numberOfExercisesPerType.set(exercise.type, oldValue + 1);
});

const numberExams = this.course?.numberOfExams ?? 0;
const numberLectures = this.course?.lectures?.length ?? 0;
const numberStudents = this.course?.numberOfStudents ?? 0;
const numberTutors = this.course?.numberOfTeachingAssistants ?? 0;
const numberEditors = this.course?.numberOfEditors ?? 0;
const numberInstructors = this.course?.numberOfInstructors ?? 0;
const isTestCourse = this.course?.testCourse;

this.courseSummary = {
...this.courseSummary,
'artemisApp.course.delete.summary.numberRepositories': numberRepositories,
'artemisApp.course.delete.summary.numberProgrammingExercises': numberOfExercisesPerType.get(ExerciseType.PROGRAMMING) ?? 0,
'artemisApp.course.delete.summary.numberModelingExercises': numberOfExercisesPerType.get(ExerciseType.MODELING) ?? 0,
'artemisApp.course.delete.summary.numberTextExercises': numberOfExercisesPerType.get(ExerciseType.TEXT) ?? 0,
'artemisApp.course.delete.summary.numberFileUploadExercises': numberOfExercisesPerType.get(ExerciseType.FILE_UPLOAD) ?? 0,
'artemisApp.course.delete.summary.numberQuizExercises': numberOfExercisesPerType.get(ExerciseType.QUIZ) ?? 0,
'artemisApp.course.delete.summary.numberExams': numberExams,
'artemisApp.course.delete.summary.numberLectures': numberLectures,
'artemisApp.course.delete.summary.numberStudents': numberStudents,
'artemisApp.course.delete.summary.numberTutors': numberTutors,
'artemisApp.course.delete.summary.numberEditors': numberEditors,
'artemisApp.course.delete.summary.numberInstructors': numberInstructors,
'artemisApp.course.delete.summary.isTestCourse': isTestCourse,
};
}

private fetchAndSetCourseDeletionSummary() {
this.courseAdminService.getDeletionSummary(this.course?.id!).subscribe({

Check warning on line 252 in src/main/webapp/app/course/manage/course-management-tab-bar/course-management-tab-bar.component.ts

View workflow job for this annotation

GitHub Actions / client-style

Optional chain expressions can return undefined by design - using a non-null assertion is unsafe and wrong
next: (res: HttpResponse<CourseDeletionSummaryDTO>) => {
const summary = res.body;

if (summary === null) {
return;
}

this.courseSummary = {
...this.courseSummary,
'artemisApp.course.delete.summary.numberBuilds': summary.numberOfBuilds,
'artemisApp.course.delete.summary.numberCommunicationPosts': summary.numberOfCommunicationPosts,
'artemisApp.course.delete.summary.numberAnswerPosts': summary.numberOfAnswerPosts,
};
},
error: (error: HttpErrorResponse) => this.dialogErrorSource.next(error.message),
});
}
}
5 changes: 5 additions & 0 deletions src/main/webapp/app/entities/course-deletion-summary.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface CourseDeletionSummaryDTO {
numberOfBuilds: number;
numberOfCommunicationPosts: number;
numberOfAnswerPosts: number;
}
21 changes: 20 additions & 1 deletion src/main/webapp/i18n/de/course.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,26 @@
"delete": {
"question": "Soll der Kurs <strong>{{ title }}</strong> wirklich dauerhaft gelöscht werden? Alle zugehörigen Elemente, inklusive der Klausuren, Aufgaben sowie Repositories und Build-Pläne werden gelöscht. Diese Aktion kann NICHT rückgängig gemacht werden!",
"typeNameToConfirm": "Bitte gib den Namen des Kurses zur Bestätigung ein.",
"icon": "Kursicon löschen"
"icon": "Kursicon löschen",
"summary": {
"title": "Kurs Zusammenfassung",
"numberExams": "Anzahl Klausuren",
"numberLectures": "Anzahl Vorlesungen",
"numberStudents": "Anzahl Studierende",
"numberTutors": "Anzahl Tutor:innen",
"numberEditors": "Anzahl Editor:innen",
"numberInstructors": "Anzahl Lehrende",
"numberProgrammingExercises": "Anzahl Programmieraufgaben",
"numberModelingExercises": "Anzahl Modellierungsaufgaben",
"numberTextExercises": "Anzahl Textaufgaben",
"numberFileUploadExercises": "Anzahl Dateiupload-Aufgaben",
"numberQuizExercises": "Anzahl Quizaufgaben",
"numberRepositories": "Anzahl Repositories",
"numberBuilds": "Anzahl Builds",
"numberCommunicationPosts": "Anzahl Kommunikationsbeiträge",
"numberAnswerPosts": "Anzahl Antwortbeiträge",
"isTestCourse": "Test Course"
}
},
"showActive": "Nur aktive Kurse anzeigen",
"totalScore": "Gesamtergebnis:",
Expand Down
21 changes: 20 additions & 1 deletion src/main/webapp/i18n/en/course.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,26 @@
"delete": {
"question": "Are you sure you want to permanently delete the course <strong>{{ title }}</strong>? All associated elements will be deleted, including exams, exercises, repositories and build plans. This action can NOT be undone!",
"typeNameToConfirm": "Please type in the name of the course to confirm.",
"icon": "Remove Icon"
"icon": "Remove Icon",
"summary": {
"title": "Course Summary",
"numberExams": "Number Exams",
"numberLectures": "Number Lectures",
"numberStudents": "Number Students",
"numberTutors": "Number Tutors",
"numberEditors": "Number Editors",
"numberInstructors": "Number Instructors",
"numberProgrammingExercises": "Number Programming Exercises",
"numberModelingExercises": "Number Modeling Exercises",
"numberTextExercises": "Number Text Exercises",
"numberFileUploadExercises": "Number File Upload Exercises",
"numberQuizExercises": "Number Quiz Exercises",
"numberRepositories": "Number Repositories",
"numberBuilds": "Number Builds",
"numberCommunicationPosts": "Number Communication Posts",
"numberAnswerPosts": "Number Answer Posts",
"isTestCourse": "Test Course"
}
},
"showActive": "Show only active courses",
"totalScore": "Total Score:",
Expand Down

0 comments on commit 0a12f62

Please sign in to comment.