Skip to content
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

General: Migrate exercise group module to signals, inject and standalone #9891

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cbaaf2d
migrate exercise-group.service
coolchock Nov 27, 2024
e13c7a3
migrate exercise-group-update.component
coolchock Nov 27, 2024
e4fac27
migrate exercise-groups.component
coolchock Nov 27, 2024
e582529
migrate quiz-exercise-group-cell.component
coolchock Nov 27, 2024
cea2cf3
migrate modeling-exercise-group-cell.component
coolchock Nov 27, 2024
4cd8cea
migrate file-exercise-group-cell.component
coolchock Nov 27, 2024
361b4cc
fix file-upload-exercise-group-cell.component
coolchock Nov 27, 2024
159069d
migrate programming-exercise-group-cell.component
coolchock Nov 27, 2024
342e800
fix file-upload-exercise-group-cell.component.spec.ts
coolchock Nov 28, 2024
255172a
fix modeling-exercise-group-cell.component.spec.ts
coolchock Nov 28, 2024
ee5c569
rename variable for file-upload
coolchock Nov 28, 2024
8322b8b
fix quiz-exercise-group-cell.component.spec.ts
coolchock Nov 28, 2024
65b0e6b
fix programming-exercise-group-cell.component.spec.ts
coolchock Nov 28, 2024
e9a561c
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Nov 30, 2024
f6a99b6
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Dec 3, 2024
662d5db
standalone imports
coolchock Dec 3, 2024
2333679
fix exercise-group-update.component.ts
coolchock Dec 3, 2024
2ba092f
fix cell tests
coolchock Dec 3, 2024
144b991
fix exercise-group-update.component.spec.ts
coolchock Dec 3, 2024
9fb875e
Merge remote-tracking branch 'origin/develop' into chore/exercise-gro…
coolchock Dec 10, 2024
31b3233
fix exercise groups tests
coolchock Dec 10, 2024
8f5ead4
fix test
coolchock Dec 12, 2024
00e3db1
export shared components
coolchock Dec 20, 2024
2c23cbd
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 2, 2025
5d48e0c
revert changes to test runs module
coolchock Jan 2, 2025
9d5f0a8
fix tests
coolchock Jan 2, 2025
0dc158e
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 2, 2025
f3cf6fa
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 3, 2025
7e121d9
remove redundant export
coolchock Jan 3, 2025
0126a3a
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 24, 2025
40ec9c9
resolve conflict
coolchock Jan 24, 2025
13c4f32
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 26, 2025
f58e5f9
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Jan 31, 2025
533bf72
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Feb 12, 2025
d44c7ff
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Feb 12, 2025
c99f095
Merge branch 'develop' into chore/exercise-groups-client-migration
coolchock Feb 13, 2025
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { AlertService } from 'app/core/util/alert.service';
Expand All @@ -14,6 +14,11 @@ import { faBan, faSave } from '@fortawesome/free-solid-svg-icons';
templateUrl: './exercise-group-update.component.html',
})
export class ExerciseGroupUpdateComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
private exerciseGroupService = inject(ExerciseGroupService);
private alertService = inject(AlertService);

readonly alertType = 'info';
courseId: number;
exam: Exam;
Expand All @@ -23,13 +28,6 @@ export class ExerciseGroupUpdateComponent implements OnInit {
faBan = faBan;
faSave = faSave;

constructor(
private route: ActivatedRoute,
private router: Router,
private exerciseGroupService: ExerciseGroupService,
private alertService: AlertService,
) {}

/**
* Initialize the courseId and exerciseGroup
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ExerciseGroup } from 'app/entities/exercise-group.model';
Expand All @@ -9,12 +8,9 @@ type EntityArrayResponseType = HttpResponse<ExerciseGroup[]>;

@Injectable({ providedIn: 'root' })
export class ExerciseGroupService {
public resourceUrl = 'api/courses';
private http = inject(HttpClient);

constructor(
private router: Router,
private http: HttpClient,
) {}
public resourceUrl = 'api/courses';

/**
* Create an exercise group on the server using a POST request.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject, forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
Expand All @@ -13,7 +13,6 @@ import { Course } from 'app/entities/course.model';
import { Exam } from 'app/entities/exam/exam.model';
import dayjs from 'dayjs/esm';
import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service';
import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { AlertService } from 'app/core/util/alert.service';
import { EventManager } from 'app/core/util/event-manager.service';
Expand Down Expand Up @@ -41,7 +40,16 @@ import { PROFILE_LOCALCI, PROFILE_LOCALVC } from 'app/app.constants';
styleUrls: ['./exercise-groups.component.scss'],
})
export class ExerciseGroupsComponent implements OnInit {
participationType = ProgrammingExerciseParticipationType;
private route = inject(ActivatedRoute);
private exerciseGroupService = inject(ExerciseGroupService);
exerciseService = inject(ExerciseService);
private examManagementService = inject(ExamManagementService);
private eventManager = inject(EventManager);
private alertService = inject(AlertService);
private modalService = inject(NgbModal);
private router = inject(Router);
private profileService = inject(ProfileService);

courseId: number;
course: Course;
examId: number;
Expand Down Expand Up @@ -69,18 +77,6 @@ export class ExerciseGroupsComponent implements OnInit {
faAngleDown = faAngleDown;
faFileImport = faFileImport;

constructor(
private route: ActivatedRoute,
private exerciseGroupService: ExerciseGroupService,
public exerciseService: ExerciseService,
private examManagementService: ExamManagementService,
private eventManager: EventManager,
private alertService: AlertService,
private modalService: NgbModal,
private router: Router,
private profileService: ProfileService,
) {}

/**
* Initialize the courseId and examId. Get all exercise groups for the exam. Setup dictionary for exercise groups which contain programming exercises.
* See {@link setupExerciseGroupToExerciseTypesDict}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@if (fileUploadExercise.type === exerciseType.FILE_UPLOAD) {
{{ fileUploadExercise.filePattern || '' }}
@if (exercise().type === exerciseType.FILE_UPLOAD) {
{{ exercise().filePattern || '' }}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core';
import { Component, input } from '@angular/core';
import { ExerciseType } from 'app/entities/exercise.model';
import { FileUploadExercise } from 'app/entities/file-upload-exercise.model';
import { Exercise, ExerciseType } from 'app/entities/exercise.model';

@Component({
selector: 'jhi-file-upload-exercise-group-cell',
Expand All @@ -9,11 +9,5 @@ import { Exercise, ExerciseType } from 'app/entities/exercise.model';
})
export class FileUploadExerciseGroupCellComponent {
exerciseType = ExerciseType;

fileUploadExercise: FileUploadExercise;

@Input()
set exercise(exercise: Exercise) {
this.fileUploadExercise = exercise as FileUploadExercise;
}
exercise = input.required<FileUploadExercise>();
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@if (modelingExercise.type === exerciseType.MODELING) {
{{ 'artemisApp.DiagramType.' + modelingExercise.diagramType | artemisTranslate }}
@if (exercise().type === exerciseType.MODELING) {
{{ 'artemisApp.DiagramType.' + exercise().diagramType | artemisTranslate }}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core';
import { Exercise, ExerciseType } from 'app/entities/exercise.model';
import { Component, input } from '@angular/core';
import { ExerciseType } from 'app/entities/exercise.model';
import { ModelingExercise } from 'app/entities/modeling-exercise.model';

@Component({
Expand All @@ -9,10 +9,5 @@ import { ModelingExercise } from 'app/entities/modeling-exercise.model';
})
export class ModelingExerciseGroupCellComponent {
exerciseType = ExerciseType;
modelingExercise: ModelingExercise;

@Input()
set exercise(exercise: Exercise) {
this.modelingExercise = exercise as ModelingExercise;
}
exercise = input.required<ModelingExercise>();
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,54 @@
@if (programmingExercise) {
@if (displayShortName) {
@if (exercise()) {
@if (displayShortName()) {
<div>
{{ programmingExercise.shortName || '' }}
{{ exercise().shortName || '' }}
</div>
}
@if (displayRepositoryUri) {
@if (displayRepositoryUri()) {
<div>
<div>
@if (programmingExercise.templateParticipation?.repositoryUri) {
@if (exercise().templateParticipation?.repositoryUri) {
<!--Checks if the programming exercise has a setup with VCS and CI, if this not the case
the links/clone-buttons are disabled--->
@if (!localVCEnabled) {
<span>
<a href="{{ programmingExercise.templateParticipation?.repositoryUri || '' }}" target="_blank">Template</a>
<a href="{{ exercise().templateParticipation?.repositoryUri || '' }}" target="_blank">Template</a>
</span>
} @else {
<a [routerLink]="" (click)="downloadRepository('TEMPLATE')"> <fa-icon [icon]="faDownload" /> Template </a>
}
}
@if (programmingExercise.templateParticipation?.results?.length) {
@if (exercise().templateParticipation?.results?.length) {
<jhi-programming-exercise-instructor-status
[participationType]="participationType.TEMPLATE"
[participation]="programmingExercise.templateParticipation!"
[exercise]="programmingExercise"
[participation]="exercise().templateParticipation!"
[exercise]="exercise()"
/>
}
</div>
<div>
@if (programmingExercise.solutionParticipation?.repositoryUri) {
@if (exercise().solutionParticipation?.repositoryUri) {
@if (!localVCEnabled) {
<span>
<a href="{{ programmingExercise.solutionParticipation?.repositoryUri || '' }}" target="_blank">Solution</a>
<a href="{{ exercise().solutionParticipation?.repositoryUri || '' }}" target="_blank">Solution</a>
</span>
} @else {
<a [routerLink]="" (click)="downloadRepository('SOLUTION')"> <fa-icon [icon]="faDownload" /> Solution </a>
}
}
@if (programmingExercise.solutionParticipation?.results?.length) {
@if (exercise().solutionParticipation?.results?.length) {
<jhi-programming-exercise-instructor-status
[participationType]="participationType.SOLUTION"
[participation]="programmingExercise.solutionParticipation!"
[exercise]="programmingExercise"
[participation]="exercise().solutionParticipation!"
[exercise]="exercise()"
/>
}
</div>
<div>
@if (programmingExercise.testRepositoryUri) {
@if (exercise().testRepositoryUri) {
@if (!localVCEnabled) {
<span>
<a href="{{ programmingExercise.testRepositoryUri }}" target="_blank">Test</a>
<a href="{{ exercise().testRepositoryUri }}" target="_blank">Test</a>
</span>
} @else {
<a [routerLink]="" (click)="downloadRepository('TESTS')"> <fa-icon [icon]="faDownload" /> Test </a>
Expand All @@ -57,44 +57,44 @@
</div>
</div>
}
@if (displayTemplateUrls) {
@if (displayTemplateUrls()) {
<div>
@if (programmingExercise.templateParticipation?.buildPlanId) {
@if (exercise().templateParticipation?.buildPlanId) {
<span>
@if (!localVCEnabled) {
<a target="_blank" rel="noreferrer" href="{{ programmingExercise.templateParticipation!.buildPlanUrl }}">Template</a>
<a target="_blank" rel="noreferrer" href="{{ exercise().templateParticipation!.buildPlanUrl }}">Template</a>
} @else {
{{ programmingExercise.templateParticipation!.buildPlanId }}
{{ exercise().templateParticipation!.buildPlanId }}
}
</span>
}
<br />
@if (programmingExercise.solutionParticipation?.buildPlanId) {
@if (exercise().solutionParticipation?.buildPlanId) {
<span>
@if (!localVCEnabled) {
<a target="_blank" rel="noreferrer" href="{{ programmingExercise.solutionParticipation!.buildPlanUrl }}">Solution</a>
<a target="_blank" rel="noreferrer" href="{{ exercise().solutionParticipation!.buildPlanUrl }}">Solution</a>
} @else {
{{ programmingExercise.solutionParticipation!.buildPlanId }}
{{ exercise().solutionParticipation!.buildPlanId }}
}
</span>
}
<br />
</div>
}
@if (displayEditorModus) {
coolchock marked this conversation as resolved.
Show resolved Hide resolved
@if (displayEditorModus()) {
<div>
<div class="d-flex justify-content-between">
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.offlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOfflineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
<span [jhiTranslate]="exercise().allowOfflineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
<div class="d-flex justify-content-between">
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineEditor'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineEditor ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
<span [jhiTranslate]="exercise().allowOnlineEditor ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
@if (onlineIdeEnabled) {
<div class="d-flex justify-content-between">
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
<span [jhiTranslate]="exercise().allowOnlineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, OnInit, inject, input } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model';
import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model';
import { Exercise } from 'app/entities/exercise.model';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { createBuildPlanUrl } from 'app/exercises/programming/shared/utils/programming-exercise.utils';
import { ProgrammingExerciseInstructorRepositoryType, ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service';
Expand All @@ -17,53 +16,38 @@ import { PROFILE_LOCALVC, PROFILE_THEIA } from 'app/app.constants';
styles: [':host{display: contents}'],
})
export class ProgrammingExerciseGroupCellComponent implements OnInit {
participationType = ProgrammingExerciseParticipationType;
private profileService = inject(ProfileService);
private programmingExerciseService = inject(ProgrammingExerciseService);
private alertService = inject(AlertService);

programmingExercise: ProgrammingExercise;
participationType = ProgrammingExerciseParticipationType;

localVCEnabled = false;
onlineIdeEnabled = false;

@Input()
displayShortName = false;
@Input()
displayRepositoryUri = false;
@Input()
displayTemplateUrls = false;
@Input()
displayEditorModus = false;

@Input()
set exercise(exercise: Exercise) {
this.programmingExercise = exercise as ProgrammingExercise;
}
displayShortName = input(false);
displayRepositoryUri = input(false);
displayTemplateUrls = input(false);
displayEditorModus = input(false);
exercise = input.required<ProgrammingExercise>();

faDownload = faDownload;

constructor(
private profileService: ProfileService,
private programmingExerciseService: ProgrammingExerciseService,
private alertService: AlertService,
) {}

ngOnInit(): void {
this.profileService.getProfileInfo().subscribe((profileInfo) => {
this.localVCEnabled = profileInfo.activeProfiles.includes(PROFILE_LOCALVC);
this.onlineIdeEnabled = profileInfo.activeProfiles.includes(PROFILE_THEIA);
if (this.programmingExercise.projectKey) {
if (this.programmingExercise.solutionParticipation?.buildPlanId) {
this.programmingExercise.solutionParticipation!.buildPlanUrl = createBuildPlanUrl(
profileInfo.buildPlanURLTemplate,
this.programmingExercise.projectKey,
this.programmingExercise.solutionParticipation.buildPlanId,
);

const projectKey = this.exercise()?.projectKey;
if (projectKey) {
const solutionParticipation = this.exercise()?.solutionParticipation;
if (solutionParticipation?.buildPlanId) {
solutionParticipation.buildPlanUrl = createBuildPlanUrl(profileInfo.buildPlanURLTemplate, projectKey, solutionParticipation.buildPlanId);
}
if (this.programmingExercise.templateParticipation?.buildPlanId) {
this.programmingExercise.templateParticipation!.buildPlanUrl = createBuildPlanUrl(
profileInfo.buildPlanURLTemplate,
this.programmingExercise.projectKey,
this.programmingExercise.templateParticipation.buildPlanId,
);

const templateParticipation = this.exercise()?.templateParticipation;
if (templateParticipation?.buildPlanId) {
templateParticipation.buildPlanUrl = createBuildPlanUrl(profileInfo.buildPlanURLTemplate, projectKey, templateParticipation.buildPlanId);
}
}
});
Expand All @@ -76,10 +60,11 @@ export class ProgrammingExerciseGroupCellComponent implements OnInit {
*
* @param repositoryType
*/
downloadRepository(repositoryType: ProgrammingExerciseInstructorRepositoryType) {
if (this.programmingExercise.id) {
downloadRepository(repositoryType: ProgrammingExerciseInstructorRepositoryType): void {
const programmingExerciseId = this.exercise()?.id;
if (programmingExerciseId) {
// Repository type cannot be 'AUXILIARY' as auxiliary repositories are currently not supported for the local VCS.
this.programmingExerciseService.exportInstructorRepository(this.programmingExercise.id, repositoryType, undefined).subscribe((response: HttpResponse<Blob>) => {
this.programmingExerciseService.exportInstructorRepository(programmingExerciseId, repositoryType, undefined).subscribe((response: HttpResponse<Blob>) => {
downloadZipFileFromResponse(response);
this.alertService.success('artemisApp.programmingExercise.export.successMessageRepos');
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@if (quizExercise.type === exerciseType.QUIZ) {
{{ quizExercise.quizQuestions?.length || 0 }}
@if (exercise().type === exerciseType.QUIZ) {
{{ exercise().quizQuestions?.length || 0 }}
}
Loading
Loading