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

Grading: Scroll down to complaint form after clicking on a complain button #9762

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

Conversation

badkeyy
Copy link
Contributor

@badkeyy badkeyy commented Nov 12, 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 principle of data economy for all client-server REST calls.
  • I strictly followed the client coding and design guidelines.
  • Following the theming guidelines, I specified colors only in the theming variable files and checked that the changes look consistent in both the light and the dark theme.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I added authorities to all new routes and checked the course groups for displaying navigation elements (links, buttons).
  • I documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.
  • I translated all newly inserted strings into English and German.

Motivation and Context

Fixes #9735

Description

Sometimes students were not able to see that the complaint form opened after pressing the "Complain" button. With this PR the browser windows gets scrolled down to the end of the form (To after the submit button) after pressing the button.

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 2 Students
  • 1 Programming Exercise with Complaints enabled
  1. Go to a course that has a text exercice as a student
  2. Start the exercice (type whatever)
  3. Log in as a tutor or instructor and grade the exercice
  4. Login as the original student and open your assesement
  5. Click on the complain button
  6. Find

Exam Mode Testing

Prerequisites:

  • 1 Instructor
  • 1 Students
  • 1 Graded exam with complaint functionallity
  1. Log in to Artemis
  2. Participate in the exam as a student
  3. Grade the exam (Instructor)
  4. Complain about the grading using the "Complain" button as a student

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

Performance Review

  • I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students.
  • I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Exam Mode Test

  • Test 1
  • Test 2

Performance Tests

  • Test 2
  • Test 1

Screenshots

video
video
video

Summary by CodeRabbit

  • New Features

    • Enhanced complaint submission and feedback interaction with updated button handling.
    • Added smooth scrolling to the complaint form when opened.
  • Bug Fixes

    • Improved logic for displaying complaints based on user context and permissions.
  • Tests

    • Introduced new test cases for handling complaints in different modes (Exam and Course).
    • Validated scrolling behavior and complaint type settings upon button clicks.

@github-actions github-actions bot added the client Pull requests that update TypeScript code. (Added Automatically!) label Nov 12, 2024
@github-actions github-actions bot added the tests label Nov 12, 2024
* Scrolls to the complaint form
*/
private scrollToComplaint(): void {
this.complaintScrollpoint.nativeElement.scrollIntoView({ behavior: 'smooth' });
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the element referred here is rendered conditionally, (see resp. html line 20), a suggestion would be to add the "?" construct to check whether nativeElement (or complaintScrollpoint) really exists to prevent runtime errors.

startComplaint(complainType: ComplaintType): void {
this.formComplaintType = complainType;
// Wait for the view to update
setTimeout(() => this.scrollToComplaint(), 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: for a more "Angular like" approach I would suggest using this.cdr.detectChanges(); (where cdr is ChangeDetectorRef injected through the constructor) instead of setTimeout

Copy link
Contributor

@AjayvirS AjayvirS left a comment

Choose a reason for hiding this comment

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

Suggestion for additional changes for clarity and convention.

@badkeyy badkeyy force-pushed the bugfix/scroll-down-after-clicking-complain branch from c8e3dd1 to fc3d4c8 Compare November 12, 2024 20:55
@badkeyy badkeyy marked this pull request as ready for review November 12, 2024 21:09
@badkeyy badkeyy requested a review from a team as a code owner November 12, 2024 21:09
Copy link

coderabbitai bot commented Nov 12, 2024

Walkthrough

The changes in this pull request enhance the ComplaintsStudentViewComponent in an Angular application by improving the handling of complaint submissions and user interactions. Modifications include updating event handling to use a dedicated method for opening the complaint form and adding a reference for scrolling to the complaint section. The test suite is also updated to validate these new behaviors, ensuring that the component functions correctly in various scenarios.

Changes

File Change Summary
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.html Updated event handling for complaint submission buttons and added a new div for scrolling behavior. Added ID to "more feedback" button.
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts Added imports for ChangeDetectorRef, ElementRef, and ViewChild. Introduced openComplaintForm and scrollToComplaint methods. Added @ViewChild for scrolling.
src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts Added tests for "Exam mode" and "Course mode" scenarios. Enhanced existing tests for component behavior validation. Imported necessary modules.

Assessment against linked issues

Objective Addressed Explanation
Clicking on the complain button should automatically expand the parent div (9735)

Possibly related PRs

Suggested labels

small, bugfix, ready to merge

Suggested reviewers

  • florian-glombik
  • rabeatwork
  • az108
  • JanaNF
  • krusche
  • Feras797
  • Malekos74
  • ItsaaaMeMario

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: 2

🧹 Outside diff range and nitpick comments (6)
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.html (1)

62-62: Consider adding ARIA attributes to the scroll anchor

While the scroll anchor implementation is correct, consider adding ARIA attributes to improve accessibility:

-<div #complaintScrollpoint></div>
+<div #complaintScrollpoint role="region" aria-label="Complaint form section"></div>
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts (1)

156-171: Consider adding integration tests for scroll behavior.

To ensure the scroll functionality remains reliable:

  1. Add tests verifying that openComplaintForm triggers scrolling
  2. Add tests for error cases when the scroll element isn't available

Example test structure:

describe('ComplaintsStudentViewComponent', () => {
  it('should scroll to complaint form when openComplaintForm is called', () => {
    const scrollIntoViewMock = jest.fn();
    component.complaintScrollpoint = {
      nativeElement: { scrollIntoView: scrollIntoViewMock }
    } as any;
    
    component.openComplaintForm(ComplaintType.COMPLAINT);
    
    expect(scrollIntoViewMock).toHaveBeenCalledWith({ 
      behavior: 'smooth', 
      block: 'end' 
    });
  });
});
src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (4)

161-162: Remove unnecessary comment.

The comment "Check if button is available" doesn't add value as the expectations clearly show what's being tested.

-            //Check if button is available
             expect(component.complaint).toBeUndefined();

179-180: Improve setTimeout comment.

Make the comment more specific about why we're waiting.

-            // Wait for setTimeout to execute
+            // Wait for the scroll animation timeout to complete
             tick();

261-267: Extract common mock setup.

The complaint scrollpoint mock setup is duplicated across tests. Consider extracting it into a helper method.

+    function mockScrollpoint(component: ComplaintsStudentViewComponent): jest.Mock {
+        const scrollIntoViewMock = jest.fn();
+        component.complaintScrollpoint = {
+            nativeElement: {
+                scrollIntoView: scrollIntoViewMock,
+            },
+        } as ElementRef;
+        return scrollIntoViewMock;
+    }

     it('should set complaint type MORE_FEEDBACK...', fakeAsync(() => {
         testInitWithResultStub(of());
         component.showSection = true;
         component.isCorrectUserToFileAction = true;
-        const scrollIntoViewMock = jest.fn();
-        component.complaintScrollpoint = {
-            nativeElement: {
-                scrollIntoView: scrollIntoViewMock,
-            },
-        } as ElementRef;
+        const scrollIntoViewMock = mockScrollpoint(component);

Also applies to: 289-295


286-287: Remove unnecessary comment and fix typo.

The comment has a typo and doesn't add value as the expectation is self-documenting.

-            //Check if button is available
             expect(component.complaint).toBeUndefined();
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7876792 and 09d639b.

📒 Files selected for processing (3)
  • src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.html (3 hunks)
  • src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts (4 hunks)
  • src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.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/complaints/complaints-for-students/complaints-student-view.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/complaints/complaint-student-view.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 (8)
src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.html (4)

27-27: LGTM: Improved event handling for complaint button

The change from direct variable assignment to using openComplaintForm method provides a better structure for handling the complaint form interaction, allowing for the implementation of the scrolling behavior.


39-42: LGTM: Consistent implementation for feedback button

Good improvements:

  • Added ID for better testability and accessibility
  • Consistent event handling pattern with the complaint button

Line range hint 1-71: LGTM: Excellent adherence to Angular syntax guidelines

The template consistently uses the new @if syntax throughout, following the coding guidelines perfectly.


Line range hint 1-71: Verify complete implementation of scrolling behavior

While the template changes provide the necessary structure for the scrolling functionality, we should verify the complete implementation:

src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts (3)

56-56: LGTM!

The ChangeDetectorRef injection follows Angular's dependency injection patterns and naming conventions.


156-164: LGTM!

The method implementation follows Angular best practices and achieves the PR objective of improving form visibility.


31-32: ⚠️ Potential issue

Add optional chaining for safer element access.

Since the element referred by complaintScrollpoint is rendered conditionally, add the optional chaining operator to prevent potential runtime errors.

Apply this diff:

-    @ViewChild('complaintScrollpoint') complaintScrollpoint: ElementRef;
+    @ViewChild('complaintScrollpoint') complaintScrollpoint?: ElementRef;
src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (1)

151-182: Excellent test coverage for the new scroll functionality!

The tests thoroughly verify both the complaint type setting and scroll behavior in both exam and course modes. Good use of Angular testing patterns with proper async handling and mocking.

Also applies to: 242-305

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: 0

🧹 Outside diff range and nitpick comments (2)
src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (2)

151-182: Enhance test readability and coverage.

Consider the following improvements:

  1. Make the test title more descriptive, e.g., "should set complaint type and scroll when clicking complaint button in exam mode"
  2. Extract the button selector as a constant to avoid magic strings
  3. Add explicit test for button availability instead of just the comment
+const COMPLAINT_BUTTON_SELECTOR = '#complain';
+
 it('should set complaint type COMPLAINT and scroll to complaint form when pressing complaint', fakeAsync(() => {
     component.exercise = examExercise;
     component.result = result;
     component.exam = defaultExam;
     component.showSection = true;
     component.isCorrectUserToFileAction = true;
     const complaintBySubmissionMock = jest.spyOn(complaintService, 'findBySubmissionId').mockReturnValue(of());

     fixture.detectChanges();

-    //Check if button is available
-    expect(component.complaint).toBeUndefined();
-    expect(complaintBySubmissionMock).toHaveBeenCalledOnce();
+    const button = fixture.debugElement.nativeElement.querySelector(COMPLAINT_BUTTON_SELECTOR);
+    expect(button).not.toBeNull();
+    expect(button.disabled).toBeFalse();

     // Mock complaint scrollpoint
     const scrollIntoViewMock = jest.fn();
     component.complaintScrollpoint = {
         nativeElement: {
             scrollIntoView: scrollIntoViewMock,
         },
     } as ElementRef;

-    const button = fixture.debugElement.nativeElement.querySelector('#complain');
     button.click();

     fixture.detectChanges();

     expect(component.formComplaintType).toBe(ComplaintType.COMPLAINT);
     // Wait for setTimeout to execute
     tick();
     expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth' });
 }));

279-305: Apply consistent improvements across test cases.

The same improvements suggested for the previous test cases should be applied here:

  1. Use the extracted mockScrollPoint helper
  2. Extract button selector as a constant
  3. Add explicit button availability test
+const MORE_FEEDBACK_BUTTON_SELECTOR = '#more-feedback';
+
 it('should set complaint type MORE_FEEDBACK and scroll to complaint form when pressing complaint', fakeAsync(() => {
     testInitWithResultStub(of());
     component.showSection = true;
     component.isCorrectUserToFileAction = true;

     fixture.detectChanges();

-    //Check if button is available
-    expect(component.complaint).toBeUndefined();
+    const button = fixture.debugElement.nativeElement.querySelector(MORE_FEEDBACK_BUTTON_SELECTOR);
+    expect(button).not.toBeNull();
+    expect(button.disabled).toBeFalse();

-    // Mock complaint scrollpoint
-    const scrollIntoViewMock = jest.fn();
-    component.complaintScrollpoint = {
-        nativeElement: {
-            scrollIntoView: scrollIntoViewMock,
-        },
-    } as ElementRef;
+    const scrollIntoViewMock = mockScrollPoint(component);

-    const button = fixture.debugElement.nativeElement.querySelector('#more-feedback');
     button.click();

     fixture.detectChanges();

     expect(component.formComplaintType).toBe(ComplaintType.MORE_FEEDBACK);
     tick(); // Wait for setTimeout to execute
     expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth' });
 }));
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 09d639b and 3ca663e.

📒 Files selected for processing (1)
  • src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/javascript/spec/component/complaints/complaint-student-view.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 (2)
src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts (2)

28-29: LGTM!

The new imports are correctly added and necessary for the new test cases.


242-277: 🛠️ Refactor suggestion

Refactor test to improve maintainability.

  1. Extract common scrolling mock setup into a helper function
  2. Standardize comment style with exam mode test
  3. The Course object creation pattern was previously flagged as problematic
+function mockScrollPoint(component: ComplaintsStudentViewComponent): jest.Mock {
+    const scrollIntoViewMock = jest.fn();
+    component.complaintScrollpoint = {
+        nativeElement: {
+            scrollIntoView: scrollIntoViewMock,
+        },
+    } as ElementRef;
+    return scrollIntoViewMock;
+}

 it('should set complaint type COMPLAINT and scroll to complaint form when pressing complaint', fakeAsync(() => {
     testInitWithResultStub(of());
-    const courseWithMaxComplaints: Course = {
-        ...course,
-        maxComplaints: 3,
-    };
-    const exerciseWithMaxComplaints: Exercise = {
-        ...courseExercise,
-        course: courseWithMaxComplaints,
-    };
+    const courseWithMaxComplaints = { id: 1, maxComplaints: 3 } as Course;
+    const exerciseWithMaxComplaints = { id: 1, course: courseWithMaxComplaints } as Exercise;
     component.course = courseWithMaxComplaints;
     component.exercise = exerciseWithMaxComplaints;

     component.showSection = true;
     component.isCorrectUserToFileAction = true;
     component.remainingNumberOfComplaints = 1;

     fixture.detectChanges();

-    // Mock complaint scrollpoint
-    const scrollIntoViewMock = jest.fn();
-    component.complaintScrollpoint = {
-        nativeElement: {
-            scrollIntoView: scrollIntoViewMock,
-        },
-    } as ElementRef;
+    const scrollIntoViewMock = mockScrollPoint(component);

     const button = fixture.debugElement.nativeElement.querySelector('#complain');
     button.click();

     fixture.detectChanges();

     expect(component.formComplaintType).toBe(ComplaintType.COMPLAINT);
-    tick(); // Wait for update to happen
+    tick(); // Wait for setTimeout to execute
     expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth' });
 }));

This issue with Course object creation was previously flagged. Using type assertion is preferred over spread operator with types.

@Malekos74
Copy link

Could not deploy for some reason :((

@badkeyy
Copy link
Contributor Author

badkeyy commented Nov 18, 2024

Any idea why the deployment does not work?

Copy link

github-actions bot commented Dec 5, 2024

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@badkeyy
Copy link
Contributor Author

badkeyy commented Dec 5, 2024

Not stale

@badkeyy badkeyy changed the title Usability: Scroll down to complaint form after clicking on a complain button Grading: Scroll down to complaint form after clicking on a complain button Dec 5, 2024
Copy link

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@github-actions github-actions bot added the stale label Dec 21, 2024
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!) stale tests
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

Clicking on the Complain button appears to do Nothing
10 participants