-
Notifications
You must be signed in to change notification settings - Fork 291
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
: Implement Course Archive to see old courses from previous semesters
#9343
base: develop
Are you sure you want to change the base?
Conversation
Pull latest changes
Pull latest changes
Pull latest changes
pull latest changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
📒 Files selected for processing (5)
- src/main/webapp/app/overview/course-archive/course-archive.component.ts (1 hunks)
- src/main/webapp/app/overview/course-overview.component.ts (2 hunks)
- src/main/webapp/app/overview/courses.module.ts (1 hunks)
- src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java (1 hunks)
- src/test/javascript/spec/component/course/course-overview.component.spec.ts (0 hunks)
💤 Files with no reviewable changes (1)
- src/test/javascript/spec/component/course/course-overview.component.spec.ts
🧰 Additional context used
📓 Path-based instructions (4)
src/main/webapp/app/overview/course-archive/course-archive.component.ts (1)
src/main/webapp/app/overview/course-overview.component.ts (1)
src/main/webapp/app/overview/courses.module.ts (1)
src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java (1)
Pattern
src/test/java/**/*.java
: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true
🪛 Biome
src/main/webapp/app/overview/course-archive/course-archive.component.ts
[error] 142-142: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
[error] 142-142: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
🔇 Additional comments (18)
src/main/webapp/app/overview/courses.module.ts (1)
Line range hint
1-46
: Summary: Minor adjustments needed for course archive implementationThe changes in this file contribute to the implementation of the course archive feature mentioned in the PR objectives. The addition of
SearchFilterComponent
aligns with the search functionality requirement for the course archive.However, there are two minor issues that need to be addressed:
- Moving
SearchFilterComponent
to the correct array (declarations instead of imports).- Reverting the declarations array to a multi-line format for better readability.
Once these adjustments are made, the module will be properly set up to support the new course archive feature, including the search functionality.
src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java (2)
1070-1074
: LGTM! Well-structured test for an important edge case.This test method is well-implemented and follows the established patterns in the file. It correctly uses the @WithMockUser annotation to simulate a student user and delegates the testing logic to the courseTestService. Testing the scenario for an unenrolled student is an important edge case to cover.
1063-1074
: Great addition of test cases for course archive functionality!These new test methods enhance the test coverage for the course archive feature, including an important edge case for unenrolled students. The implementation is consistent with the existing code structure and testing patterns in this file.
src/main/webapp/app/overview/course-archive/course-archive.component.ts (15)
1-14
: Well-Organized Imports and Dependency InjectionThe imports are well-organized, grouping Angular core modules, third-party libraries, and application-specific modules effectively. The use of the modern
inject()
function for dependency injection enhances code readability and aligns with Angular best practices.
15-21
: Correct Component Configuration with Standalone ComponentThe
@Component
decorator is correctly configured. Settingstandalone: true
modernizes the component, and the necessary modules are imported explicitly. This approach promotes encapsulation and reusability.
22-35
: Proper Declaration and Initialization of Class PropertiesClass properties are appropriately declared and initialized, ensuring that they are ready for use within the component. The initialization of arrays and objects prevents potential
undefined
errors during runtime. The use ofreadonly
for icon declarations enhances code safety by preventing unintended mutations.
43-46
: Effective Initialization inngOnInit
Lifecycle HookThe
ngOnInit()
method effectively initializes the component by loading archived courses and enabling the course overview background. This ensures that the component is ready for user interaction upon rendering.
51-63
: Efficient Data Loading inloadArchivedCourses
MethodThe
loadArchivedCourses()
method efficiently fetches archived courses, handles the response correctly, and processes the data by sorting and mapping it into semesters. Error handling is appropriately managed using theonError
utility.
65-75
: Accurate Mapping of Courses into SemestersThe
mapCoursesIntoSemesters()
method accurately organizes courses by their respective semesters and initializes the collapse states. This enhances the user's ability to navigate through archived courses effectively.
77-80
: Proper Cleanup inngOnDestroy
Lifecycle HookThe
ngOnDestroy()
method unsubscribes from subscriptions and disables the course overview background, ensuring that resources are released appropriately and preventing potential memory leaks.
82-89
: Responsive Search Functionality insetSearchValue
MethodThe
setSearchValue()
method effectively updates the search text and adjusts the display of semesters based on the search input, enhancing the user experience through responsive filtering.
91-96
: Intuitive Sorting Mechanism inonSort
MethodThe
onSort()
method provides an intuitive mechanism for users to sort semesters in ascending or descending order, improving the navigability of the course archive.
97-105
: Dynamic Expansion and Collapse Based on Search InputThe
expandOrCollapseBasedOnSearchValue()
method dynamically adjusts the visibility of semesters based on whether courses match the search criteria, enhancing usability by showing relevant content.
107-111
: Consistent Retrieval of Collapse StatesThe
getCollapseStateForSemesters()
method retrieves the collapse states for semesters consistently, ensuring that the user interface reflects the user's previous interactions and preferences.
113-116
: Toggle Functionality for Semester VisibilityThe
toggleCollapseState()
method allows users to expand or collapse semesters interactively, providing control over the displayed content.
118-120
: Efficient Course Search Within SemestersThe
isCourseFoundInSemester()
method efficiently determines if a course matching the search text exists within a semester, aiding in the accurate display of search results.
122-124
: Proper Sorting of Courses by TitleThe
sortCoursesByTitle()
method correctly sorts courses alphabetically by their titles, improving the organization and findability of courses within semesters.
126-157
: Robust Sorting Logic for SemestersThe
getUniqueSemesterNamesSorted()
method implements a robust sorting algorithm to order semesters logically, accounting for both the year and semester type (WS
orSS
). This ensures that semesters are presented in a meaningful sequence.🧰 Tools
🪛 Biome
[error] 142-142: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
[error] 142-142: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
📒 Files selected for processing (2)
- src/main/webapp/app/overview/course-archive/course-archive.component.html (1 hunks)
- src/test/javascript/spec/component/course/course-archive.component.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/webapp/app/overview/course-archive/course-archive.component.html (1)
Pattern
src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.src/test/javascript/spec/component/course/course-archive.component.spec.ts (1)
Pattern
src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
📓 Learnings (1)
src/test/javascript/spec/component/course/course-archive.component.spec.ts (1)
Learnt from: pzdr7 PR: ls1intum/Artemis#9463 File: src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.service.spec.ts:50-55 Timestamp: 2024-10-13T12:03:02.430Z Learning: In `src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.service.spec.ts`, when a function is called multiple times in a test, use `toHaveBeenCalledTimes` and `toHaveBeenNthCalledWith` assertions instead of `toHaveBeenCalledExactlyOnceWith`.
🔇 Additional comments (7)
src/main/webapp/app/overview/course-archive/course-archive.component.html (1)
1-70
: Well-structured Implementation of Course Archive ComponentThe template is well-organized and effectively utilizes the new
@if
and@for
Angular directives as per the coding guidelines. The code is clean, readable, and follows best practices. Great job!src/test/javascript/spec/component/course/course-archive.component.spec.ts (6)
198-205
: 🧹 Nitpick (assertive)Remove unnecessary use of
fakeAsync
andtick()
In this test, there are no asynchronous operations that require
fakeAsync
ortick()
. Simplifying the test improves readability without affecting functionality.Apply this diff to simplify the test:
-it('should toggle sort order and update the icon accordingly', fakeAsync(() => { +it('should toggle sort order and update the icon accordingly', () => { // ... fixture.detectChanges(); - tick(); // ... }));Likely invalid or redundant comment.
129-135
: 🧹 Nitpick (assertive)Prefer
.toEqual()
over.toStrictEqual()
for object comparisonUsing
.toStrictEqual()
enforces strict equality, which can make tests brittle if objects have additional properties or different prototypes..toEqual()
performs a deep equality check and is more appropriate here.Apply this diff to adjust the assertions:
expect(component.coursesBySemester).toStrictEqual({ +expect(component.coursesBySemester).toEqual({ // ... }); expect(component.semesterCollapsed).toStrictEqual({ +expect(component.semesterCollapsed).toEqual({ // ... }); expect(component.fullFormOfSemesterStrings).toStrictEqual({ +expect(component.fullFormOfSemesterStrings).toEqual({ // ... });Likely invalid or redundant comment.
70-70
: 🧹 Nitpick (assertive)Unnecessary call to
component.ngOnDestroy()
inafterEach
Calling
component.ngOnDestroy()
in theafterEach
block is unnecessary because the Angular testing environment automatically handles component destruction after each test. Removing this call simplifies the test code without affecting functionality.Apply this diff to remove the unnecessary call:
afterEach(() => { - component.ngOnDestroy(); jest.restoreAllMocks(); });
Likely invalid or redundant comment.
102-102
: 🧹 Nitpick (assertive)Prefer
.toEqual()
over.toStrictEqual()
for array comparisonUsing
.toStrictEqual()
for array comparison can be unnecessarily strict and may cause tests to fail if there are prototype differences..toEqual()
is sufficient for comparing arrays deeply.Apply this diff to adjust the assertion:
expect(component.courses).toStrictEqual(emptyCourses); +expect(component.courses).toEqual(emptyCourses);
Likely invalid or redundant comment.
218-218
: 🧹 Nitpick (assertive)Specify the number of times
onSort
is calledInstead of checking if
onSort
was called, assert that it was called exactly once to make the test more precise.Apply this diff to clarify the expectation:
-expect(onSortSpy).toHaveBeenCalled(); +expect(onSortSpy).toHaveBeenCalledTimes(1);Likely invalid or redundant comment.
184-185
: 🧹 Nitpick (assertive)Avoid spying on internal component methods
Spying on
expandOrCollapseBasedOnSearchValue
, an internal method, couples your test to implementation details, making it fragile. Instead, assert the observable outcomes to ensure the component behaves as expected.Consider removing the spy and verifying the expected state:
-const expandOrCollapseBasedOnSearchValueSpy = jest.spyOn(component, 'expandOrCollapseBasedOnSearchValue'); component.setSearchValue('iPraktikum'); -expect(expandOrCollapseBasedOnSearchValueSpy).toHaveBeenCalledOnce(); +expect(component.searchValue).toBe('iPraktikum'); +expect(component.semesterCollapsed['WS21/22']).toBeFalse(); +// Add assertions for other semesters as neededLikely invalid or redundant comment.
src/test/javascript/spec/component/course/course-archive.component.spec.ts
Show resolved
Hide resolved
src/test/javascript/spec/component/course/course-archive.component.spec.ts
Show resolved
Hide resolved
src/test/javascript/spec/component/course/course-archive.component.spec.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
📒 Files selected for processing (3)
- src/main/webapp/app/overview/course-archive/course-archive.component.ts (1 hunks)
- src/main/webapp/app/overview/courses.component.html (2 hunks)
- src/test/javascript/spec/component/course/course.component.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/webapp/app/overview/course-archive/course-archive.component.ts (1)
src/main/webapp/app/overview/courses.component.html (1)
Pattern
src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.src/test/javascript/spec/component/course/course.component.spec.ts (1)
Pattern
src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
🪛 Biome
src/main/webapp/app/overview/course-archive/course-archive.component.ts
[error] 134-134: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
[error] 134-134: Use Number.parseInt instead of the equivalent global.
ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.(lint/style/useNumberNamespace)
🔇 Additional comments (5)
src/main/webapp/app/overview/courses.component.html (2)
27-27
: LGTM: Added id for testing purposes.The addition of the
id="test-sort"
attribute to the sort link is appropriate. This change likely facilitates easier targeting of the element for testing purposes, which is a good practice for improving testability.
65-71
: 🧹 Nitpick (assertive)LGTM! Consider improving HTML structure for better semantics.
The implementation successfully adds the course archive feature as described in the PR objectives. It correctly uses the @if directive and jhiTranslate for internationalization, addressing previous review comments.
However, the HTML structure could be improved for better semantics and consistency with the rest of the file. Consider the following changes:
@if (coursesLoaded) { - <div class="d-flex justify-content-center mt-3"> - <div jhiTranslate="artemisApp.studentDashboard.archive.oldCourses"></div> - <div> </div> - <a [routerLink]="['/courses/archive']" jhiTranslate="artemisApp.studentDashboard.archive.here"></a> + <div class="text-center mt-3"> + <span jhiTranslate="artemisApp.studentDashboard.archive.oldCourses"></span> + <a [routerLink]="['/courses/archive']" class="ms-1" jhiTranslate="artemisApp.studentDashboard.archive.here"></a> </div> }These changes:
- Replace
d-flex justify-content-center
withtext-center
for simpler centering.- Use a
<span>
instead of a<div>
for inline text.- Remove the unnecessary
<div> </div>
and addms-1
class to the link for spacing.- Maintain the use of jhiTranslate and the correct routing.
This structure is more semantic and consistent with modern HTML practices while maintaining the intended functionality.
Likely invalid or redundant comment.
src/test/javascript/spec/component/course/course.component.spec.ts (1)
Line range hint
1-298
: Overall assessment: Good additions with minor improvements needed.The new test cases for search functionality and sorting behavior enhance the coverage of the CoursesComponent. They focus on important aspects of the component's functionality. While there are minor issues in the implementation of these tests, they can be easily addressed with the suggested changes. Once these improvements are made, the test suite will provide more robust coverage of the component's behavior.
src/main/webapp/app/overview/course-archive/course-archive.component.ts (2)
28-28
:⚠️ Potential issueInitialize 'semesters' to avoid potential undefined issues
The
semesters
array is declared but not initialized. Initializing it to an empty array ensures that it doesn't causeundefined
errors when accessed before being populated.Apply this diff to initialize
semesters
:- semesters: string[]; + semesters: string[] = [];Likely invalid or redundant comment.
31-31
:⚠️ Potential issueCorrect the type of 'coursesBySemester' to match assigned data
The
coursesBySemester
property is typed as{ [key: string]: Course[] }
, but it is assigned arrays ofCourseForArchiveDTO[]
. To ensure type safety and prevent potential runtime errors, update the type to match the assigned data.Apply this diff to fix the type:
- coursesBySemester: { [key: string]: Course[] } = {}; + coursesBySemester: { [key: string]: CourseForArchiveDTO[] } = {};Likely invalid or redundant comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested again on Ts4, reapprove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-approve after merge conflicts were resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-approve after fixing coverage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-approve, tested on TS3
|
Checklist
General
Server
Client
authorities
to all new routes and checked the course groups for displaying navigation elements (links, buttons).Motivation and Context
Students often want access to old or completed courses on Artemis from previous semesters in which they were enrolled. While they can technically access these courses if they remember the course link, relying on memory and attempting to access the course via the link is not practical. This PR closes #9129.
Description
Steps for Testing
Prerequisites:
(I already created some old courses on TS3, and test users 1-5 are enrolled in these courses. Other test users are not enrolled. You can test that only users 1-5 can see these additional tests courses, where other test users can not. )
Testserver States
Note
These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.
Review Progress
Code Review
Manual Tests
Screenshots
Summary by CodeRabbit
Release Notes
New Features
User Interface Improvements
Localization Enhancements
Bug Fixes
Tests