Skip to content

Commit

Permalink
Development: Improve client code quality for learning paths (#9654)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohannesWt authored Nov 16, 2024
1 parent e3f1c92 commit 0db5cc1
Show file tree
Hide file tree
Showing 17 changed files with 148 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import { Component, effect, inject, input, signal } from '@angular/core';
import { FontAwesomeModule, IconDefinition } from '@fortawesome/angular-fontawesome';
import { ChangeDetectionStrategy, Component, effect, inject, input, signal, untracked } from '@angular/core';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { CompetencyGraphComponent } from 'app/course/learning-paths/components/competency-graph/competency-graph.component';
import { ArtemisSharedModule } from 'app/shared/shared.module';
import { LearningPathApiService } from 'app/course/learning-paths/services/learning-path-api.service';
import { AlertService } from 'app/core/util/alert.service';
import { CompetencyGraphDTO } from 'app/entities/competency/learning-path.model';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-competency-graph-modal',
standalone: true,
imports: [FontAwesomeModule, CompetencyGraphComponent, ArtemisSharedModule],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FontAwesomeModule, CompetencyGraphComponent, TranslateDirective],
templateUrl: './competency-graph-modal.component.html',
styleUrl: './competency-graph-modal.component.scss',
})
export class CompetencyGraphModalComponent {
protected readonly closeIcon: IconDefinition = faXmark;
protected readonly closeIcon = faXmark;

private readonly learningPathApiService: LearningPathApiService = inject(LearningPathApiService);
private readonly alertService: AlertService = inject(AlertService);
private readonly learningPathApiService = inject(LearningPathApiService);
private readonly alertService = inject(AlertService);

readonly learningPathId = input.required<number>();

Expand All @@ -28,7 +29,13 @@ export class CompetencyGraphModalComponent {
private readonly activeModal: NgbActiveModal = inject(NgbActiveModal);

constructor() {
effect(() => this.loadCompetencyGraph(this.learningPathId()), { allowSignalWrites: true });
effect(
() => {
const learningPathId = this.learningPathId();
untracked(() => this.loadCompetencyGraph(learningPathId));
},
{ allowSignalWrites: true },
);
}

private async loadCompetencyGraph(learningPathId: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { Component, computed, effect, input, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, effect, input, signal } from '@angular/core';
import { NgxGraphModule, NgxGraphZoomOptions } from '@swimlane/ngx-graph';
import { Subject } from 'rxjs';
import { CompetencyGraphDTO, NodeType } from 'app/entities/competency/learning-path.model';
import { CompetencyGraphDTO } from 'app/entities/competency/learning-path.model';
import { CompetencyNodeComponent, SizeUpdate } from 'app/course/learning-paths/components/competency-node/competency-node.component';
import { ArtemisSharedModule } from 'app/shared/shared.module';

@Component({
selector: 'jhi-competency-graph',
standalone: true,
imports: [CompetencyNodeComponent, NgxGraphModule, ArtemisSharedModule],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CompetencyNodeComponent, NgxGraphModule],
templateUrl: './competency-graph.component.html',
styleUrl: './competency-graph.component.scss',
})
export class CompetencyGraphComponent {
protected readonly NodeType = NodeType;

readonly competencyGraph = input.required<CompetencyGraphDTO>();

private readonly internalCompetencyGraph = signal<CompetencyGraphDTO>({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { AfterViewInit, Component, ElementRef, computed, inject, input, output } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, computed, inject, input, output } from '@angular/core';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { NgbAccordionModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NodeDimension } from '@swimlane/ngx-graph';
Expand All @@ -13,6 +13,7 @@ export interface SizeUpdate {
@Component({
selector: 'jhi-learning-path-competency-node',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgbDropdownModule, FontAwesomeModule, NgbAccordionModule, CommonModule],
templateUrl: './competency-node.component.html',
styleUrl: './competency-node.component.scss',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { Component, InputSignal, ViewContainerRef, effect, inject, input } from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewContainerRef, effect, inject, input } from '@angular/core';
import { CourseExerciseDetailsComponent } from 'app/overview/exercise-details/course-exercise-details.component';
import { CourseExerciseDetailsModule } from 'app/overview/exercise-details/course-exercise-details.module';

@Component({
selector: 'jhi-learning-path-exercise',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CourseExerciseDetailsModule],
templateUrl: './learning-path-exercise.component.html',
})
export class LearningPathExerciseComponent {
public readonly courseId: InputSignal<number> = input.required<number>();
public readonly exerciseId: InputSignal<number> = input.required<number>();
public readonly courseId = input.required<number>();
public readonly exerciseId = input.required<number>();

private readonly viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
private readonly viewContainerRef = inject(ViewContainerRef);

constructor() {
effect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { Component, computed, effect, inject, input, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, signal, untracked } from '@angular/core';
import { LectureUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/lectureUnit.service';
import { AlertService } from 'app/core/util/alert.service';
import { LectureUnit, LectureUnitType } from 'app/entities/lecture-unit/lectureUnit.model';
import { ArtemisLectureUnitsModule } from 'app/overview/course-lectures/lecture-units.module';
import { LectureUnitCompletionEvent } from 'app/overview/course-lectures/course-lecture-details.component';
import { LearningPathNavigationService } from 'app/course/learning-paths/services/learning-path-navigation.service';
import { lastValueFrom } from 'rxjs';
import { ArtemisSharedModule } from 'app/shared/shared.module';
import { VideoUnitComponent } from 'app/overview/course-lectures/video-unit/video-unit.component';
import { TextUnitComponent } from 'app/overview/course-lectures/text-unit/text-unit.component';
import { AttachmentUnitComponent } from 'app/overview/course-lectures/attachment-unit/attachment-unit.component';
import { OnlineUnitComponent } from 'app/overview/course-lectures/online-unit/online-unit.component';
import { isCommunicationEnabled } from 'app/entities/course.model';
import { DiscussionSectionComponent } from 'app/overview/discussion-section/discussion-section.component';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-learning-path-lecture-unit',
standalone: true,
imports: [ArtemisLectureUnitsModule, ArtemisSharedModule, VideoUnitComponent, TextUnitComponent, AttachmentUnitComponent, OnlineUnitComponent, DiscussionSectionComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ArtemisLectureUnitsModule, VideoUnitComponent, TextUnitComponent, AttachmentUnitComponent, OnlineUnitComponent, DiscussionSectionComponent, TranslateDirective],
templateUrl: './learning-path-lecture-unit.component.html',
})
export class LearningPathLectureUnitComponent {
Expand All @@ -36,7 +37,13 @@ export class LearningPathLectureUnitComponent {
readonly isCommunicationEnabled = computed(() => isCommunicationEnabled(this.lecture()?.course));

constructor() {
effect(() => this.loadLectureUnit(this.lectureUnitId()), { allowSignalWrites: true });
effect(
() => {
const lectureUnitId = this.lectureUnitId();
untracked(() => this.loadLectureUnit(lectureUnitId));
},
{ allowSignalWrites: true },
);
}

async loadLectureUnit(lectureUnitId: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
import { Component, InputSignal, OutputEmitterRef, Signal, WritableSignal, computed, effect, inject, input, output, signal, untracked } from '@angular/core';
import { ArtemisSharedModule } from 'app/shared/shared.module';
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, output, signal, untracked } from '@angular/core';
import { AlertService } from 'app/core/util/alert.service';
import { LearningPathApiService } from 'app/course/learning-paths/services/learning-path-api.service';
import { LearningPathNavigationService } from 'app/course/learning-paths/services/learning-path-navigation.service';
import { LearningPathNavigationObjectDTO } from 'app/entities/competency/learning-path.model';
import { IconDefinition, faCheckCircle, faLock } from '@fortawesome/free-solid-svg-icons';
import { faCheckCircle, faLock } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { CommonModule } from '@angular/common';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-learning-path-nav-overview-learning-objects',
standalone: true,
imports: [NgbAccordionModule, FontAwesomeModule, ArtemisSharedModule],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgbAccordionModule, FontAwesomeModule, CommonModule, TranslateDirective],
templateUrl: './learning-path-nav-overview-learning-objects.component.html',
styleUrl: './learning-path-nav-overview-learning-objects.component.scss',
})
export class LearningPathNavOverviewLearningObjectsComponent {
protected readonly faCheckCircle: IconDefinition = faCheckCircle;
protected readonly faLock: IconDefinition = faLock;
protected readonly faCheckCircle = faCheckCircle;
protected readonly faLock = faLock;

private readonly alertService: AlertService = inject(AlertService);
private readonly learningPathApiService: LearningPathApiService = inject(LearningPathApiService);
private readonly alertService = inject(AlertService);
private readonly learningPathApiService = inject(LearningPathApiService);
private readonly learningPathNavigationService = inject(LearningPathNavigationService);

readonly learningPathId: InputSignal<number> = input.required();
readonly competencyId: InputSignal<number> = input.required();
readonly learningPathId = input.required<number>();
readonly competencyId = input.required<number>();
// competency id of current competency of learning path (not the one of the selected learning object)
readonly currentCompetencyIdOnPath: InputSignal<number | undefined> = input.required();
readonly currentLearningObject: Signal<LearningPathNavigationObjectDTO | undefined> = this.learningPathNavigationService.currentLearningObject;
readonly currentCompetencyIdOnPath = input.required();
readonly currentLearningObject = this.learningPathNavigationService.currentLearningObject;

readonly isLoading: WritableSignal<boolean> = signal(false);
readonly learningObjects: WritableSignal<LearningPathNavigationObjectDTO[] | undefined> = signal(undefined);
readonly isLoading = signal<boolean>(false);
readonly learningObjects = signal<LearningPathNavigationObjectDTO[] | undefined>(undefined);

readonly nextLearningObjectOnPath: Signal<LearningPathNavigationObjectDTO | undefined> = computed(() =>
readonly nextLearningObjectOnPath = computed(() =>
this.competencyId() === this.currentCompetencyIdOnPath() ? this.learningObjects()?.find((learningObject) => !learningObject.completed) : undefined,
);

readonly onLearningObjectSelected: OutputEmitterRef<void> = output();
readonly onLearningObjectSelected = output<void>();

constructor() {
effect(
() => {
untracked(async () => await this.loadLearningObjects());
untracked(() => this.loadLearningObjects());
},
{ allowSignalWrites: true },
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
import { Component, InputSignal, OutputEmitterRef, Signal, WritableSignal, computed, effect, inject, input, output, signal, viewChild } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, output, signal, untracked, viewChild } from '@angular/core';
import { NgbAccordionDirective, NgbAccordionModule, NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { CommonModule } from '@angular/common';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { IconDefinition, faCheckCircle } from '@fortawesome/free-solid-svg-icons';
import { faCheckCircle } from '@fortawesome/free-solid-svg-icons';
import { AlertService } from 'app/core/util/alert.service';
import { LearningPathCompetencyDTO } from 'app/entities/competency/learning-path.model';
import { ArtemisSharedModule } from 'app/shared/shared.module';
import { LearningPathApiService } from 'app/course/learning-paths/services/learning-path-api.service';
import { CompetencyGraphModalComponent } from 'app/course/learning-paths/components/competency-graph-modal/competency-graph-modal.component';
import { LearningPathNavOverviewLearningObjectsComponent } from 'app/course/learning-paths/components/learning-path-nav-overview-learning-objects/learning-path-nav-overview-learning-objects.component';
import { LearningPathNavigationService } from 'app/course/learning-paths/services/learning-path-navigation.service';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-learning-path-nav-overview',
standalone: true,
imports: [FontAwesomeModule, CommonModule, NgbDropdownModule, NgbAccordionModule, ArtemisSharedModule, LearningPathNavOverviewLearningObjectsComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FontAwesomeModule, CommonModule, NgbDropdownModule, NgbAccordionModule, LearningPathNavOverviewLearningObjectsComponent, TranslateDirective],
templateUrl: './learning-path-nav-overview.component.html',
styleUrl: './learning-path-nav-overview.component.scss',
})
export class LearningPathNavOverviewComponent {
protected readonly faCheckCircle: IconDefinition = faCheckCircle;
protected readonly faCheckCircle = faCheckCircle;

private readonly alertService: AlertService = inject(AlertService);
private readonly modalService: NgbModal = inject(NgbModal);
private readonly learningPathApiService: LearningPathApiService = inject(LearningPathApiService);
private readonly alertService = inject(AlertService);
private readonly modalService = inject(NgbModal);
private readonly learningPathApiService = inject(LearningPathApiService);
private readonly learningPathNavigationService = inject(LearningPathNavigationService);

readonly learningPathId: InputSignal<number> = input.required();
readonly learningPathId = input.required<number>();

readonly competencyAccordion: Signal<NgbAccordionDirective> = viewChild.required(NgbAccordionDirective);
readonly competencyAccordion = viewChild.required(NgbAccordionDirective);

readonly onLearningObjectSelected: OutputEmitterRef<void> = output();
readonly isLoading: WritableSignal<boolean> = signal(false);
readonly onLearningObjectSelected = output<void>();
readonly isLoading = signal(false);
readonly competencies = signal<LearningPathCompetencyDTO[]>([]);

// competency id of currently selected learning object
readonly currentCompetencyId: Signal<number | undefined> = computed(() => this.learningPathNavigationService.currentLearningObject()?.competencyId);
readonly currentCompetencyId = computed(() => this.learningPathNavigationService.currentLearningObject()?.competencyId);
// current competency of learning path (not the one of the selected learning object)
readonly currentCompetencyOnPath: Signal<LearningPathCompetencyDTO | undefined> = computed(() => this.competencies()?.find((competency) => competency.masteryProgress < 1));
readonly currentCompetencyOnPath = computed(() => this.competencies()?.find((competency) => competency.masteryProgress < 1));

constructor() {
effect(async () => await this.loadCompetencies(this.learningPathId()), { allowSignalWrites: true });
effect(
() => {
const learningPathId = this.learningPathId();
untracked(() => this.loadCompetencies(learningPathId));
},
{ allowSignalWrites: true },
);
}

async loadCompetencies(learningPathId: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Component, computed, effect, inject, input, signal, untracked } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, signal, untracked } from '@angular/core';
import { LearningPathNavigationObjectDTO } from 'app/entities/competency/learning-path.model';
import { CommonModule } from '@angular/common';
import { NgbAccordionModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faCheckCircle, faChevronDown, faChevronLeft, faChevronRight, faFlag, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { LearningPathNavOverviewComponent } from 'app/course/learning-paths/components/learning-path-nav-overview/learning-path-nav-overview.component';
import { ArtemisSharedModule } from 'app/shared/shared.module';
import { LearningPathNavigationService } from 'app/course/learning-paths/services/learning-path-navigation.service';
import { TranslateDirective } from 'app/shared/language/translate.directive';

@Component({
selector: 'jhi-learning-path-student-nav',
standalone: true,
imports: [CommonModule, NgbDropdownModule, NgbAccordionModule, FontAwesomeModule, LearningPathNavOverviewComponent, ArtemisSharedModule],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, NgbDropdownModule, NgbAccordionModule, FontAwesomeModule, LearningPathNavOverviewComponent, TranslateDirective],
templateUrl: './learning-path-student-nav.component.html',
styleUrl: './learning-path-student-nav.component.scss',
})
Expand Down
Loading

0 comments on commit 0db5cc1

Please sign in to comment.