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

Learning paths: Redesign learning path instructor view #9144

Merged
merged 61 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6557bfb
initial setup
JohannesWt Jul 22, 2024
74093a5
table
JohannesWt Jul 22, 2024
ce4d57a
Add endpoint for instructor graph
JohannesStoehr Jul 22, 2024
3f6f4ee
initial instructor view setup
JohannesWt Jul 24, 2024
ce68ec4
improve styles of config and table
JohannesWt Jul 25, 2024
42f53c3
small style improvements
JohannesWt Jul 25, 2024
61b8d78
refactor competency graph to get data from outside of component
JohannesWt Jul 26, 2024
c51bd46
test setup
JohannesWt Jul 28, 2024
ed604b4
add client tests
JohannesWt Jul 28, 2024
b6e27b2
fetch course details
JohannesWt Jul 29, 2024
0727b08
generalize competency-node.component.ts
JohannesWt Jul 29, 2024
748e701
fix tests and formatting
JohannesWt Jul 29, 2024
6e24fd3
fix server error and implement code review
JohannesWt Jul 29, 2024
d38de02
Update src/main/java/de/tum/in/www1/artemis/service/learningpath/Lear…
JohannesWt Jul 29, 2024
e9acb9e
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Jul 30, 2024
487ad36
Merge branch 'develop' into feature/learning-paths/refactor-competenc…
JohannesWt Jul 30, 2024
168070c
Merge branch 'feature/learning-paths/refactor-competency-graph' into …
JohannesWt Jul 30, 2024
f73e021
fix model
JohannesWt Jul 30, 2024
cfdcf8f
add competency graph modal to table rows
JohannesWt Jul 30, 2024
82dd171
remove OK health status
JohannesWt Jul 30, 2024
6a87251
add competency graph to analytics section
JohannesWt Jul 31, 2024
451bcde
add translations
JohannesWt Jul 31, 2024
b25ede5
add empty state and final translations
JohannesWt Jul 31, 2024
408b34d
fix height of table to prevent layout jumps
JohannesWt Jul 31, 2024
8bf9f64
add static modal method and add tests
JohannesWt Aug 4, 2024
a98a156
learning-paths-table.component.spec.ts tests
JohannesWt Aug 5, 2024
0da10a7
remove margin to prevent vertical scroll
JohannesWt Aug 5, 2024
fd3d83b
add test ids
JohannesWt Aug 5, 2024
6576e7b
simplify learning-paths-state.component.ts and remove legacy enum types
JohannesWt Aug 5, 2024
68df4ae
add more tests for learning-paths-state.component.ts
JohannesWt Aug 6, 2024
41a4a84
simplify learning-paths-state.component.spec.ts tests
JohannesWt Aug 6, 2024
f1bcbe3
add success alert to learning path generation and tests for analytics
JohannesWt Aug 6, 2024
52dcaa7
add learning-path-instructor-page.component.spec.ts tests
JohannesWt Aug 6, 2024
22b2df7
reformat
JohannesWt Aug 6, 2024
c1b927e
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Aug 6, 2024
7fe32c7
java doc
JohannesWt Aug 6, 2024
0ca2f03
add missing brace
JohannesWt Aug 6, 2024
4844d40
revert currentLearningObject to be optional
JohannesWt Aug 6, 2024
11c6649
align legacy code
JohannesWt Aug 6, 2024
23c5ba7
remove unused import
JohannesWt Aug 6, 2024
d6e5f8b
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesStoehr Sep 23, 2024
8f0b2b2
Merge
JohannesStoehr Sep 23, 2024
bc613ce
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 6, 2024
1f3725f
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 6, 2024
b1ff6b5
fix merge conflicts
JohannesWt Oct 6, 2024
5a4e142
add debounce and refactor client tests
JohannesWt Oct 6, 2024
2ded01c
remove init tests
JohannesWt Oct 6, 2024
b93d129
remove init tests and fix translations
JohannesWt Oct 6, 2024
2898a31
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 6, 2024
6656f14
code review feedback client
JohannesWt Oct 6, 2024
cff42c9
Compute average in query
JohannesStoehr Oct 6, 2024
fb380b5
Remove disabled
JohannesStoehr Oct 7, 2024
fd6c569
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 7, 2024
130abaa
Actually remove disabled
JohannesStoehr Oct 8, 2024
94c1016
fix translation
JohannesWt Oct 8, 2024
b732707
fix pagination
JohannesWt Oct 8, 2024
7fb8a9b
fix client tests and increase page size
JohannesWt Oct 8, 2024
1935c2f
fix last page of pagination
JohannesWt Oct 8, 2024
59e21d7
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 12, 2024
1fd81fb
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
krusche Oct 13, 2024
6d9cd7d
Merge branch 'develop' into feature/learning-paths/refactor-instructo…
JohannesWt Oct 15, 2024
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
Expand Up @@ -12,7 +12,7 @@
public record CompetencyGraphNodeDTO(String id, String label, ZonedDateTime softDueDate, Double value, CompetencyNodeValueType valueType) {

public enum CompetencyNodeValueType {
MASTERY_PROGRESS
MASTERY_PROGRESS, AVERAGE_MASTERY_PROGRESS,
}

public static CompetencyGraphNodeDTO of(@NotNull CourseCompetency competency, Double value, CompetencyNodeValueType valueType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ public LearningPathHealthDTO(Set<HealthStatus> status) {
}

public enum HealthStatus {
OK, DISABLED, MISSING, NO_COMPETENCIES, NO_RELATIONS
MISSING, NO_COMPETENCIES, NO_RELATIONS
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

💡 Codebase verification

Inconsistency Detected in HealthStatus Enum Modifications

  • The DISABLED value is still referenced in LearningPathServiceTest.java and LearningPathService.java but has been removed from the HealthStatus enum.
🔗 Analysis chain

Verify the consistency of enum values across the codebase

The HealthStatus enum has been modified to remove the OK status. This change aligns with the PR objectives of providing more specific health statuses for learning paths. However, there's a discrepancy noted in a previous review comment about the removal of a DISABLED status in the client code.

To ensure consistency across the codebase, please run the following script:

This script will help identify any inconsistencies in the usage of HealthStatus across the codebase.

Consider adding a comment above the enum to explain the purpose of each status, which would improve code documentation and maintainability.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to removed HealthStatus values

# Search for 'OK' or 'DISABLED' HealthStatus references
echo "Searching for references to removed HealthStatus values:"
rg --type java "HealthStatus\.(OK|DISABLED)" -g '!LearningPathHealthDTO.java'

# Search for HealthStatus enum definitions
echo "Searching for HealthStatus enum definitions:"
rg --type java "enum\s+HealthStatus" -A 5

Length of output: 1103

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,16 @@ SELECT COUNT(cp)
AND c = :competency
""")
Set<CompetencyProgress> findAllPriorByCompetencyId(@Param("competency") CourseCompetency competency, @Param("user") User userId);

@Query("""
SELECT COALESCE(GREATEST(0.0, LEAST(1.0, AVG(cp.progress * cp.confidence / com.masteryThreshold))), 0.0)
FROM CompetencyProgress cp
LEFT JOIN cp.competency com
LEFT JOIN com.course c
LEFT JOIN cp.user u
WHERE com.id = :competencyId
AND cp.progress > 0
pzdr7 marked this conversation as resolved.
Show resolved Hide resolved
AND c.studentGroupName MEMBER OF u.groups
""")
double findAverageOfAllNonZeroStudentProgressByCompetencyId(@Param("competencyId") long competencyId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import de.tum.cit.aet.artemis.atlas.repository.CompetencyProgressRepository;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRelationRepository;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository;
import de.tum.cit.aet.artemis.atlas.repository.CourseCompetencyRepository;
import de.tum.cit.aet.artemis.atlas.repository.LearningPathRepository;
import de.tum.cit.aet.artemis.atlas.service.competency.CompetencyProgressService;
import de.tum.cit.aet.artemis.core.domain.Course;
Expand Down Expand Up @@ -89,10 +90,13 @@ public class LearningPathService {

private final StudentParticipationRepository studentParticipationRepository;

private final CourseCompetencyRepository courseCompetencyRepository;

public LearningPathService(UserRepository userRepository, LearningPathRepository learningPathRepository, CompetencyProgressRepository competencyProgressRepository,
LearningPathNavigationService learningPathNavigationService, CourseRepository courseRepository, CompetencyRepository competencyRepository,
CompetencyRelationRepository competencyRelationRepository, LearningPathNgxService learningPathNgxService,
LectureUnitCompletionRepository lectureUnitCompletionRepository, StudentParticipationRepository studentParticipationRepository) {
LectureUnitCompletionRepository lectureUnitCompletionRepository, StudentParticipationRepository studentParticipationRepository,
CourseCompetencyRepository courseCompetencyRepository) {
Comment on lines +93 to +99
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider reducing constructor dependencies to improve maintainability

The LearningPathService constructor now has a large number of dependencies, including the newly added CourseCompetencyRepository. Having many constructor arguments can indicate that the class is handling too many responsibilities, which can make it harder to maintain and test.

Consider refactoring the class to adhere to the Single Responsibility Principle by delegating some functionality to other services or components. This can reduce the number of dependencies and improve code modularity.

this.userRepository = userRepository;
this.learningPathRepository = learningPathRepository;
this.competencyProgressRepository = competencyProgressRepository;
Expand All @@ -103,6 +107,7 @@ public LearningPathService(UserRepository userRepository, LearningPathRepository
this.learningPathNgxService = learningPathNgxService;
this.lectureUnitCompletionRepository = lectureUnitCompletionRepository;
this.studentParticipationRepository = studentParticipationRepository;
this.courseCompetencyRepository = courseCompetencyRepository;
}

/**
Expand Down Expand Up @@ -298,20 +303,11 @@ else if (learningPath.isStartedByStudent()) {
* @return dto containing the health status and additional information (missing learning paths) if needed
*/
public LearningPathHealthDTO getHealthStatusForCourse(@NotNull Course course) {
if (!course.getLearningPathsEnabled()) {
return new LearningPathHealthDTO(Set.of(LearningPathHealthDTO.HealthStatus.DISABLED));
}

Set<LearningPathHealthDTO.HealthStatus> status = new HashSet<>();
Long numberOfMissingLearningPaths = checkMissingLearningPaths(course, status);
checkNoCompetencies(course, status);
checkNoRelations(course, status);

// if no issues where found, add OK status
if (status.isEmpty()) {
status.add(LearningPathHealthDTO.HealthStatus.OK);
}

return new LearningPathHealthDTO(status, numberOfMissingLearningPaths);
}

Expand Down Expand Up @@ -366,6 +362,25 @@ public LearningPathCompetencyGraphDTO generateLearningPathCompetencyGraph(@NotNu
return new LearningPathCompetencyGraphDTO(progressDTOs, relationDTOs);
}

/**
* Generates the graph of competencies with the student's progress for the given learning path.
*
* @param courseId the id of the course for which the graph should be generated
* @return dto containing the competencies and relations of the learning path
*/
JohannesWt marked this conversation as resolved.
Show resolved Hide resolved
public LearningPathCompetencyGraphDTO generateLearningPathCompetencyInstructorGraph(long courseId) {
List<CourseCompetency> competencies = courseCompetencyRepository.findByCourseIdOrderById(courseId);
Set<CompetencyGraphNodeDTO> progressDTOs = competencies.stream().map(competency -> {
double averageMasteryProgress = competencyProgressRepository.findAverageOfAllNonZeroStudentProgressByCompetencyId(competency.getId());
return CompetencyGraphNodeDTO.of(competency, averageMasteryProgress, CompetencyGraphNodeDTO.CompetencyNodeValueType.AVERAGE_MASTERY_PROGRESS);
}).collect(Collectors.toSet());
Comment on lines +373 to +376
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Optimize database queries to prevent N+1 query issue

The method generateLearningPathCompetencyInstructorGraph executes a database query for each competency within the loop:

double averageMasteryProgress = competencyProgressRepository.findAverageOfAllNonZeroStudentProgressByCompetencyId(competency.getId());

This can lead to performance issues due to the N+1 query problem, especially when dealing with a large number of competencies.

Consider modifying the repository method to fetch the average mastery progress for all competencies in a single query. This can be achieved by adding a method that retrieves averages grouped by competency IDs.

Here's an example of how you might adjust the code:

// In the repository:
Map<Long, Double> averageMasteryProgresses = competencyProgressRepository.findAverageProgressByCompetencyIds(competencyIds);

// In the service method:
Set<CompetencyGraphNodeDTO> progressDTOs = competencies.stream().map(competency -> {
    double averageMasteryProgress = averageMasteryProgresses.getOrDefault(competency.getId(), 0.0);
    return CompetencyGraphNodeDTO.of(competency, averageMasteryProgress, CompetencyGraphNodeDTO.CompetencyNodeValueType.AVERAGE_MASTERY_PROGRESS);
}).collect(Collectors.toSet());

This approach reduces the number of database queries and improves performance.


🧹 Nitpick (assertive)

Consider preserving the order of competencies

The progressDTOs are collected into a Set using Collectors.toSet(). If the order of competencies is significant for the graph presentation or user experience, using a Set may lose the ordering as sets do not guarantee order.

Consider collecting into a List to preserve the order provided by competencies, which is ordered by ID.

You can modify the collection to:

List<CompetencyGraphNodeDTO> progressDTOs = competencies.stream().map(competency -> {
    // existing mapping logic
}).collect(Collectors.toList());


Set<CompetencyRelation> relations = competencyRelationRepository.findAllWithHeadAndTailByCourseId(courseId);
Set<CompetencyGraphEdgeDTO> relationDTOs = relations.stream().map(CompetencyGraphEdgeDTO::of).collect(Collectors.toSet());

return new LearningPathCompetencyGraphDTO(progressDTOs, relationDTOs);
}
Comment on lines +372 to +382
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to eliminate code duplication with generateLearningPathCompetencyGraph.

The method generateLearningPathCompetencyInstructorGraph shares similar logic with generateLearningPathCompetencyGraph, such as fetching competencies, computing progress DTOs, and mapping relations. To adhere to the DRY principle and improve maintainability, consider extracting the shared logic into a private helper method.

Here's how you can refactor:

  • Extract the common code that processes competencies and relations into a private method.
  • Customize the behavior for each method by passing parameters or using functional interfaces (e.g., supplier functions for progress calculation).

Comment on lines +371 to +382
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

⚠️ Potential issue

Add unit tests for generateLearningPathCompetencyInstructorGraph

To ensure the new method works as intended and to prevent future regressions, please add unit tests for generateLearningPathCompetencyInstructorGraph. This will help verify the correctness of the logic and maintain high code quality.

Would you like assistance in creating unit tests for this method?


/**
* Generates Ngx graph representation of the learning path graph.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,21 @@ public ResponseEntity<LearningPathCompetencyGraphDTO> getLearningPathCompetencyG
return ResponseEntity.ok(learningPathService.generateLearningPathCompetencyGraph(learningPath, user));
}

/**
* GET courses/{courseId}/learning-path/competency-instructor-graph : Gets the competency instructor graph
*
* @param courseId the id of the course for which the graph should be fetched
* @return the ResponseEntity with status 200 (OK) and with body the graph
*/
@GetMapping("courses/{courseId}/learning-path/competency-instructor-graph")
@FeatureToggle(Feature.LearningPaths)
@EnforceAtLeastInstructorInCourse
public ResponseEntity<LearningPathCompetencyGraphDTO> getLearningPathCompetencyInstructorGraph(@PathVariable long courseId) {
log.debug("REST request to get competency instructor graph for learning path with id: {}", courseId);

return ResponseEntity.ok(learningPathService.generateLearningPathCompetencyInstructorGraph(courseId));
}
JohannesWt marked this conversation as resolved.
Show resolved Hide resolved

/**
* GET learning-path/:learningPathId/graph : Gets the ngx representation of the learning path as a graph.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,14 @@ GROUP BY SUBSTRING(CAST(s.submissionDate AS string), 1, 10), p.student.login
""")
List<Course> findAllNotEndedCoursesByManagementGroupNames(@Param("now") ZonedDateTime now, @Param("userGroups") List<String> userGroups);

@Query("""
SELECT COUNT(DISTINCT ug.userId)
FROM Course c
JOIN UserGroup ug ON c.studentGroupName = ug.group
WHERE c.id = :courseId
""")
int countCourseStudents(@Param("courseId") long courseId);

/**
* Counts the number of members of a course, i.e. users that are a member of the course's student, tutor, editor or instructor group.
* Users that are part of multiple groups are NOT counted multiple times.
Expand Down
1 change: 1 addition & 0 deletions src/main/webapp/app/admin/metrics/metrics.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export interface Services {
export enum HttpMethod {
Post = 'POST',
Get = 'GET',
Put = 'PUT',
Delete = 'DELETE',
Patch = 'PATCH',
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, effect, inject, input, signal } from '@angular/core';
import { FontAwesomeModule, IconDefinition } from '@fortawesome/angular-fontawesome';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
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';
Expand Down Expand Up @@ -46,4 +46,13 @@ export class CompetencyGraphModalComponent {
closeModal(): void {
this.activeModal.close();
}

static openCompetencyGraphModal(modalService: NgbModal, learningPathId: number): void {
const modalRef = modalService.open(CompetencyGraphModalComponent, {
size: 'xl',
backdrop: 'static',
windowClass: 'competency-graph-modal',
});
modalRef.componentInstance.learningPathId = signal<number>(learningPathId);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<div class="d-inline-block competency-node">
<div class="progress-container d-inline-block" [ngClass]="{ 'green-competency': isGreen(), 'yellow-competency': isYellow(), 'gray-competency': isGray() }">
<small class="font-bold"
<small
><strong>
@if (valueType() === CompetencyGraphNodeValueType.MASTERY_PROGRESS) {
@if (valueType() === CompetencyGraphNodeValueType.MASTERY_PROGRESS || valueType() === CompetencyGraphNodeValueType.AVERAGE_MASTERY_PROGRESS) {
{{ value() }} %
} @else {
{{ value() }}
}
</strong></small
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class CompetencyNodeComponent implements AfterViewInit {
isYellow(): boolean {
switch (this.valueType()) {
case CompetencyGraphNodeValueType.MASTERY_PROGRESS:
case CompetencyGraphNodeValueType.AVERAGE_MASTERY_PROGRESS:
return this.value() > 0 && this.value() < 100;
default:
return false;
Expand All @@ -55,6 +56,7 @@ export class CompetencyNodeComponent implements AfterViewInit {
isGray(): boolean {
switch (this.valueType()) {
case CompetencyGraphNodeValueType.MASTERY_PROGRESS:
case CompetencyGraphNodeValueType.AVERAGE_MASTERY_PROGRESS:
return this.value() === 0;
default:
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ export class LearningPathNavOverviewComponent {
}

openCompetencyGraph(): void {
const modalRef = this.modalService.open(CompetencyGraphModalComponent, {
size: 'xl',
backdrop: 'static',
windowClass: 'competency-graph-modal',
});
modalRef.componentInstance.learningPathId = this.learningPathId;
CompetencyGraphModalComponent.openCompetencyGraphModal(this.modalService, this.learningPathId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div class="learning-paths-analytics-container">
<h5 class="m-0" jhiTranslate="artemisApp.learningPathManagement.learningPathsAnalytics.title"></h5>
<hr class="my-2" />
<div class="row h-100 m-0 gap-3">
<div class="col-2 p-0 learning-paths-analytics-graph-selection-container">
<ng-container [ngTemplateOutlet]="radioTemplate" [ngTemplateOutletContext]="{ $implicit: CompetencyGraphNodeValueType.AVERAGE_MASTERY_PROGRESS }"></ng-container>
</div>
<div class="col p-0">
@if (isLoading()) {
<div class="row justify-content-center p-2">
<div class="spinner-border text-primary" role="status">
<span class="sr-only" jhiTranslate="loading"></span>
</div>
</div>
} @else if (instructorCompetencyGraph()) {
<jhi-competency-graph [competencyGraph]="instructorCompetencyGraph()!" />
}
</div>
</div>
</div>

<ng-template #radioTemplate let-competencyNodeValueType>
<div class="row m-0 align-items-center">
<input type="radio" class="col-md-auto" [checked]="valueSelection() === competencyNodeValueType" />
<label class="col-md-auto pe-0 text-break" [jhiTranslate]="'artemisApp.learningPathManagement.learningPathsAnalytics.graphSelection.' + competencyNodeValueType"></label>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.learning-paths-analytics-container {
height: 500px;

.learning-paths-analytics-graph-selection-container {
border-right: var(--bs-border-width) solid var(--border-color);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Component, effect, inject, input, signal } from '@angular/core';
import { LearningPathApiService } from 'app/course/learning-paths/services/learning-path-api.service';
import { CompetencyGraphDTO, CompetencyGraphNodeValueType } from 'app/entities/competency/learning-path.model';
import { AlertService } from 'app/core/util/alert.service';
import { ArtemisSharedCommonModule } from 'app/shared/shared-common.module';
import { CompetencyGraphComponent } from 'app/course/learning-paths/components/competency-graph/competency-graph.component';
import { onError } from 'app/shared/util/global.utils';

@Component({
selector: 'jhi-learning-paths-analytics',
standalone: true,
imports: [ArtemisSharedCommonModule, CompetencyGraphComponent],
templateUrl: './learning-paths-analytics.component.html',
styleUrl: './learning-paths-analytics.component.scss',
})
export class LearningPathsAnalyticsComponent {
protected readonly CompetencyGraphNodeValueType = CompetencyGraphNodeValueType;

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

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

readonly isLoading = signal<boolean>(false);
readonly instructorCompetencyGraph = signal<CompetencyGraphDTO | undefined>(undefined);

readonly valueSelection = signal<CompetencyGraphNodeValueType>(CompetencyGraphNodeValueType.AVERAGE_MASTERY_PROGRESS);

constructor() {
effect(() => this.loadInstructionCompetencyGraph(this.courseId()), { allowSignalWrites: true });
}

private async loadInstructionCompetencyGraph(courseId: number): Promise<void> {
try {
this.isLoading.set(true);
const instructorCompetencyGraph = await this.learningPathApiService.getLearningPathInstructorCompetencyGraph(courseId);
this.instructorCompetencyGraph.set(instructorCompetencyGraph);
} catch (error) {
onError(this.alertService, error);
} finally {
this.isLoading.set(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<div>
<div class="row m-0 align-items-center justify-content-between">
<h5 class="m-0 col-md-auto p-0" jhiTranslate="artemisApp.learningPathManagement.learningPathsConfiguration.title"></h5>
@if (isEditMode()) {
<button id="save-learning-paths-configuration-button" class="btn btn-primary btn-sm col-md-auto" (click)="saveLearningPathsConfiguration()">
@if (isSaving()) {
<fa-icon [icon]="faSpinner" animation="spin" />
}
<span jhiTranslate="artemisApp.learningPathManagement.learningPathsConfiguration.saveButtonLabel"></span>
</button>
} @else {
<button
id="edit-learning-paths-configuration-button"
class="btn btn-secondary btn-sm col-md-auto"
(click)="enableEditMode()"
jhiTranslate="artemisApp.learningPathManagement.learningPathsConfiguration.editButtonLabel"
></button>
}
</div>
<hr class="my-2" />
<div class="row align-items-center m-0 learning-paths-management-container">
@if (isConfigLoading()) {
<div class="row justify-content-center p-2">
<div class="spinner-border text-primary" role="status">
<span class="sr-only" jhiTranslate="loading"></span>
</div>
</div>
} @else {
<input
id="include-all-graded-exercises-checkbox"
type="checkbox"
class="col-md-auto"
(change)="toggleIncludeAllGradedExercises()"
[checked]="includeAllGradedExercisesEnabled()"
[disabled]="!isEditMode()"
/>
<label class="col-md-auto" jhiTranslate="artemisApp.learningPathManagement.learningPathsConfiguration.configuration.includeAllGradedExercises"></label>
<jhi-help-icon class="col-md-auto p-0" text="artemisApp.learningPathManagement.learningPathsConfiguration.configuration.includeAllGradedExercisesToolTip" />
}
</div>
</div>
Loading
Loading