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

Adaptive learning: Refactor competencies management page to signals #9629

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

JohannesWt
Copy link
Contributor

@JohannesWt JohannesWt commented Oct 29, 2024

Checklist

General

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the client coding and design guidelines.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I documented the TypeScript code using JSDoc style.

Motivation and Context

According to the new client coding guidelines Artemis should move to using signals step by step. This PR refactors the competency management page to using signals.

Description

This PR changes the current competency management page to use signals. Visually nothing changed.

Steps for Testing

Prerequisites:

  • 1 Instructor
  1. Log in to Artemis
  2. Navigate to course competency management
  3. verify that a competency and prerequisite can be created and that they are shown in the table
  4. verify that a competency/prerequiste can be deleted
  5. verify that the generate competencies button is visible (on TS3 as Iris is required)

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

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Client

Class/File Line Coverage Confirmation (assert/expect)
competency-management.component.ts 92.04% ✅ ❌

Screenshots

unchanged

Summary by CodeRabbit

  • New Features

    • Enhanced reactivity in the Competency Management component, improving data handling and state management.
    • Updated loading indicators and competency retrieval methods for better user experience.
  • Bug Fixes

    • Improved error handling and alert notifications for data fetching issues.
  • Tests

    • Refined test suite for better coverage and reliability, including new tests for loading states and error handling.

@JohannesWt JohannesWt self-assigned this Oct 29, 2024
@github-actions github-actions bot added tests client Pull requests that update TypeScript code. (Added Automatically!) labels Oct 29, 2024
@JohannesWt JohannesWt changed the title Adaptive Learning: Refactor competencies management page to signals Adaptive learning: Refactor competencies management page to signals Oct 29, 2024
@JohannesWt JohannesWt temporarily deployed to artemis-test3.artemis.cit.tum.de October 29, 2024 15:26 — with GitHub Actions Inactive
@JohannesWt JohannesWt marked this pull request as ready for review October 29, 2024 17:10
@JohannesWt JohannesWt requested a review from a team as a code owner October 29, 2024 17:10
Copy link

coderabbitai bot commented Oct 29, 2024

Walkthrough

This pull request introduces significant updates to the CompetencyManagementComponent in both the HTML and TypeScript files. The changes primarily involve converting property accesses to function calls for various data bindings, enhancing the component's reactivity by utilizing Angular's reactive programming features. The lifecycle management has been simplified by removing the OnDestroy hook, and the test suite has been refactored to improve dependency management and test robustness.

Changes

File Change Summary
src/main/webapp/app/course/competencies/competency-management/competency-management.component.html Converted property accesses to function calls for irisCompetencyGenerationEnabled, courseId, isLoading, courseCompetencies, and standardizedCompetenciesEnabled.
src/main/webapp/app/course/competencies/competency-management/competency-management.component.ts Updated component to use reactive signals for state management, removed OnDestroy, and refactored methods for loading data.
src/test/javascript/spec/component/competencies/competency-management/competency-management.component.spec.ts Enhanced test suite with mock services, refactored beforeEach, and added new tests for loading state and error handling.

Possibly related PRs

Suggested labels

enhancement, ready to merge, component:AdaptiveLearning

Suggested reviewers

  • JohannesStoehr
  • MaximilianAnzinger
  • Jan-Thurner
  • pzdr7
  • az108
  • coolchock

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a 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

🧹 Outside diff range and nitpick comments (3)
src/main/webapp/app/course/competencies/competency-management/competency-management.component.html (1)

42-43: LGTM! Proper signal-based input bindings for prerequisites table.

All input properties correctly use function calls for signal-based reactivity.

Consider extracting the common table configuration into a reusable interface or type to reduce duplication:

interface CompetencyTableConfig {
  courseId: () => number;
  courseCompetencies: () => CourseCompetency[];
  competencyType: CourseCompetencyType;
  standardizedCompetenciesEnabled: () => boolean;
}

Then in the template, you could use a structural directive or component property to render tables based on configurations:

readonly tableConfigs: CompetencyTableConfig[] = [
  {
    courseId: this.courseId,
    courseCompetencies: this.competencies,
    competencyType: CourseCompetencyType.COMPETENCY,
    standardizedCompetenciesEnabled: this.standardizedCompetenciesEnabled
  },
  {
    courseId: this.courseId,
    courseCompetencies: this.prerequisites,
    competencyType: CourseCompetencyType.PREREQUISITE,
    standardizedCompetenciesEnabled: this.standardizedCompetenciesEnabled
  }
];

Also applies to: 45-45

src/test/javascript/spec/component/competencies/competency-management/competency-management.component.spec.ts (1)

176-194: Enhance error handling tests with message verification

While the error handling tests are good, they could be more specific by verifying the error message content:

 it('should show alert when loading iris settings fails', async () => {
     const errorSpy = jest.spyOn(alertService, 'error');
-    getIrisSettingsSpy.mockRejectedValueOnce({});
+    const errorMessage = 'Failed to load IRIS settings';
+    getIrisSettingsSpy.mockRejectedValueOnce(new Error(errorMessage));

     fixture.detectChanges();
     await fixture.whenStable();

-    expect(errorSpy).toHaveBeenCalledOnce();
+    expect(errorSpy).toHaveBeenCalledExactlyOnceWith('artemis.competencyManagement.error.loadIrisSettings');
 });
src/main/webapp/app/course/competencies/competency-management/competency-management.component.ts (1)

117-118: Avoid unnecessary wrapping of values in new signals

Creating new signals with signal<number>(this.courseId()) when passing data to child components may be redundant since courseId is already a signal. Passing the existing signal or the value directly can simplify the code and avoid unnecessary nesting.

Adjust the code as follows:

-modalRef.componentInstance.courseId = signal<number>(this.courseId());
+modalRef.componentInstance.courseId = this.courseId;

-modalRef.componentInstance.courseCompetencies = signal<CourseCompetency[]>(this.courseCompetencies());
+modalRef.componentInstance.courseCompetencies = this.courseCompetencies;

This ensures that the child components receive the current signals without creating additional layers.

Also applies to: 129-129

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7503f9c and 47cd904.

📒 Files selected for processing (3)
  • src/main/webapp/app/course/competencies/competency-management/competency-management.component.html (2 hunks)
  • src/main/webapp/app/course/competencies/competency-management/competency-management.component.ts (7 hunks)
  • src/test/javascript/spec/component/competencies/competency-management/competency-management.component.spec.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/webapp/app/course/competencies/competency-management/competency-management.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/main/webapp/app/course/competencies/competency-management/competency-management.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/test/javascript/spec/component/competencies/competency-management/competency-management.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}}

🔇 Additional comments (6)
src/main/webapp/app/course/competencies/competency-management/competency-management.component.html (3)

11-12: LGTM! Proper usage of new Angular control flow syntax.

The @if directive is correctly used here, replacing the older *ngIf syntax as per guidelines. The function calls indicate proper signal usage.


27-33: LGTM! Proper loading state handling with accessibility support.

The loading spinner is correctly implemented with:

  • New @if syntax
  • Proper ARIA attributes for accessibility
  • Signal-based loading state

35-36: LGTM! Proper signal-based input bindings for competency table.

All input properties correctly use function calls for signal-based reactivity.

Also applies to: 38-38

src/test/javascript/spec/component/competencies/competency-management/competency-management.component.spec.ts (3)

34-35: LGTM: Proper mock service imports

The imports follow the best practices by using specific mock services instead of full module imports.


95-130: LGTM: Well-structured test setup

The test setup follows best practices with:

  • Proper service injection
  • Well-configured spies
  • Clear test data structure

228-239: LGTM: Well-structured modal test

The test properly verifies the modal interaction and competency updates using signals. The assertions follow the coding guidelines for checking array length.

Comment on lines +166 to +174
it('should set isLoading correctly', async () => {
const isLoadingSpy = jest.spyOn(component.isLoading, 'set');

fixture.detectChanges();
await fixture.whenStable();

expect(isLoadingSpy).toHaveBeenNthCalledWith(1, true);
expect(isLoadingSpy).toHaveBeenNthCalledWith(2, false);
});
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 testing observable state instead of setter

The test is tightly coupled to implementation details by spying on the isLoading setter. Consider testing the observable state directly:

-it('should set isLoading correctly', async () => {
-    const isLoadingSpy = jest.spyOn(component.isLoading, 'set');
+it('should handle loading state correctly', async () => {
+    const loadingStates: boolean[] = [];
+    component.isLoading().subscribe((state) => loadingStates.push(state));

     fixture.detectChanges();
     await fixture.whenStable();

-    expect(isLoadingSpy).toHaveBeenNthCalledWith(1, true);
-    expect(isLoadingSpy).toHaveBeenNthCalledWith(2, false);
+    expect(loadingStates).toEqual([true, false]);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should set isLoading correctly', async () => {
const isLoadingSpy = jest.spyOn(component.isLoading, 'set');
fixture.detectChanges();
await fixture.whenStable();
expect(isLoadingSpy).toHaveBeenNthCalledWith(1, true);
expect(isLoadingSpy).toHaveBeenNthCalledWith(2, false);
});
it('should handle loading state correctly', async () => {
const loadingStates: boolean[] = [];
component.isLoading().subscribe((state) => loadingStates.push(state));
fixture.detectChanges();
await fixture.whenStable();
expect(loadingStates).toEqual([true, false]);
});

const combinedCourseSettings = await firstValueFrom(this.irisSettingsService.getCombinedCourseSettings(this.courseId()));
this.irisCompetencyGenerationEnabled.set(combinedCourseSettings?.irisCompetencyGenerationSettings?.enabled ?? false);
} catch (error) {
this.alertService.error(error);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Provide user-friendly error messages in alerts

Passing the error object directly to this.alertService.error may not display meaningful information to the user. It could show as [object Object]. Extract a user-friendly message from the error object or provide a custom error message to enhance the user's understanding.

Update the error handling as follows:

-this.alertService.error(error);
+const errorMessage = error.message ?? 'An unexpected error occurred';
+this.alertService.error(errorMessage);

Or use the AlertService's capability to handle error objects if available.

Also applies to: 105-105

Copy link

@Cathy0123456789 Cathy0123456789 left a comment

Choose a reason for hiding this comment

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

Tested on TS3. Creating, editing and deleting competencies / prerequisites still works, as well as linking and unlinking lecture units. Also the "Generate Competencies" button is shown.

flbrgit
flbrgit previously approved these changes Oct 29, 2024
Copy link

@flbrgit flbrgit left a comment

Choose a reason for hiding this comment

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

Tested on TS3. Functionality works as described and the button to generate competencies is also shown. Linking to units, deleting and creating as well as editing works without noticable bugs

ItsaaaMeMario
ItsaaaMeMario previously approved these changes Oct 29, 2024
Copy link

@ItsaaaMeMario ItsaaaMeMario left a comment

Choose a reason for hiding this comment

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

I tested on TS3 with artemis_test_user_20, I was flawlessly able to create/delete/edit prerequisites/competencies. The "generate Competencies" button is also visible.

JohannesStoehr
JohannesStoehr previously approved these changes Oct 29, 2024
Copy link
Contributor

@JohannesStoehr JohannesStoehr left a comment

Choose a reason for hiding this comment

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

Code looks good apart from one small issue:

HawKhiem
HawKhiem previously approved these changes Oct 29, 2024
Copy link

@HawKhiem HawKhiem left a comment

Choose a reason for hiding this comment

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

Competencies and prerequesites can be added and deleted as described. The generate competencies button is also visible. But when I click on it it takes really long to load

image

Copy link

@zagemello zagemello left a comment

Choose a reason for hiding this comment

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

image
Works as expected, tested on TS3

Copy link

@SindiBuklaji SindiBuklaji left a comment

Choose a reason for hiding this comment

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

Tested on TS3. Everything works as expected.👍

Copy link
Contributor

@EneaGore EneaGore left a comment

Choose a reason for hiding this comment

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

code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client Pull requests that update TypeScript code. (Added Automatically!) ready for review refactoring small tests
Projects
Status: Ready For Review
Status: In review
Development

Successfully merging this pull request may close these issues.

10 participants