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

Text exercises: Replace feedback modal with inline feedback view #9395

Merged

Conversation

EneaGore
Copy link
Contributor

@EneaGore EneaGore commented Oct 1, 2024

Deploy only to TS1

Reopened from: #9310

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the server coding and design guidelines.
  • I added multiple integration tests (Spring) related to the features (with a high test coverage).
  • I documented the Java code using JavaDoc style.

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

The previous PR in Athena Feedback for Text Exercises added the option to enable preliminary AI Feedback for students. This PR improves the way the feedback is viewed by adding a new route. Enhanced error handling, integration tests and some minor bug fixes are also included.

Description

Create new route to view the (preliminary) results inline on the text submission. Add the timeline to that view and make results not show the modal but use that route for text exercises.

Steps for Testing

Prerequisites:

  • 1 Student
  • 1 Text Exercise
  1. Open a text exercise with athena feedback requests avilable
  2. Request feedback from inside the editor and from the overview
  3. Click on results and check that the correct submission is shown
  4. Assessment should continue working as usual

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

Test Coverage

✅ ❌

Client

Class/File Line Coverage Confirmation (assert/expect)
header-participation-page.component.ts 100%
exercise-scores.component.ts 95.59% ✅ ❌
feedback.component.ts 95% ✅ ❌
rating.component.ts 91.66% ✅ ❌
result.component.ts 88.81% ✅ ❌
result.service.ts 90.75% ✅ ❌
result.utils.ts 89.94% ✅ ❌
text-editor.component.ts 84.4% ✅ ❌
text-editor.route.ts 100%
course-exercise-details.component.ts 88.47% ✅ ❌
exercise-details-student-actions.component.ts 91.3% ✅ ❌
request-feedback-button.component.ts 90.47% ✅ ❌

Screenshots

newAIButton
view
Flow

H01E01.Coupling.and.Cohesion.WS24._.Test.Course.Enea.Gore.-.Google.Chrome.2024-09-14.06-37-35.mp4

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced feedback request handling with new user messages for pending changes.
    • Improved exercise participation management with better error handling and access control.
    • New buttons for "Continue Submission" and "Request Feedback" in the text editor.
    • Added support for localized action labels in both German and English.
    • Dynamic filtering for exercise scores based on user input.
    • New functionality for viewing and hiding the timeline of submissions.
    • Introduction of a new feedback button component to streamline feedback requests.
    • New route configuration for accessing specific submissions in the text editor.
  • Bug Fixes

    • Refined filtering logic for exercise scores and participation results.
    • Improved navigation handling for text exercises.
    • Adjusted success alert messages based on feedback generation results.
  • Documentation

    • Updated localization strings for improved clarity and accuracy.
  • Chores

    • General code refactoring for improved maintainability and readability.

@github-actions github-actions bot added deployment-error Added by deployment workflows if an error occured and removed deploy:artemis-test1 labels Oct 27, 2024
coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 27, 2024
@EneaGore EneaGore added deploy:artemis-test1 and removed deployment-error Added by deployment workflows if an error occured labels Oct 27, 2024
@EneaGore EneaGore temporarily deployed to artemis-test1.artemis.cit.tum.de October 27, 2024 14:31 — with GitHub Actions Inactive
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/overview/exercise-details/request-feedback-button/request-feedback-button.component.spec.ts (2)

218-219: Enhance test specificity with additional assertions.

While the test correctly verifies the button state, consider adding assertions to explicitly verify that both conditions influence the button's enabled state:

expect(component.isSubmitted).toBeTrue();
expect(component.isGeneratingFeedback).toBeFalse();

This makes it clearer which conditions are being tested and helps with debugging if the test fails.


Line range hint 1-230: Add test coverage for missing scenarios.

The test suite is missing coverage for:

  1. The pendingChanges input property's effect on the button state
  2. The case when isGeneratingFeedback is true but isSubmitted is also true

Consider adding these test cases:

it('should disable the button when there are pending changes', fakeAsync(() => {
    setAthenaEnabled(true);
    const participation = {
        id: 1,
        submissions: [{ id: 1, submitted: true }],
        testRun: false,
    } as StudentParticipation;
    const exercise = { id: 1, type: ExerciseType.TEXT, studentParticipations: [participation], course: {}, allowFeedbackRequests: true } as Exercise;
    fixture.componentRef.setInput('exercise', exercise);
    fixture.componentRef.setInput('isSubmitted', true);
    fixture.componentRef.setInput('isGeneratingFeedback', false);
    fixture.componentRef.setInput('pendingChanges', true);
    mockExerciseDetails(exercise);

    component.ngOnInit();
    tick();
    fixture.detectChanges();

    const button = debugElement.query(By.css('button'));
    expect(button.nativeElement.disabled).toBeTrue();
    expect(component.pendingChanges).toBeTrue();
}));

it('should disable the button when feedback is being generated regardless of submission state', fakeAsync(() => {
    setAthenaEnabled(true);
    const participation = {
        id: 1,
        submissions: [{ id: 1, submitted: true }],
        testRun: false,
    } as StudentParticipation;
    const exercise = { id: 1, type: ExerciseType.TEXT, studentParticipations: [participation], course: {}, allowFeedbackRequests: true } as Exercise;
    fixture.componentRef.setInput('exercise', exercise);
    fixture.componentRef.setInput('isSubmitted', true);
    fixture.componentRef.setInput('isGeneratingFeedback', true);
    mockExerciseDetails(exercise);

    component.ngOnInit();
    tick();
    fixture.detectChanges();

    const button = debugElement.query(By.css('button'));
    expect(button.nativeElement.disabled).toBeTrue();
    expect(component.isGeneratingFeedback).toBeTrue();
}));
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7c466a4 and ba65dc0.

📒 Files selected for processing (1)
  • src/test/javascript/spec/component/overview/exercise-details/request-feedback-button/request-feedback-button.component.spec.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/javascript/spec/component/overview/exercise-details/request-feedback-button/request-feedback-button.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 (1)
src/test/javascript/spec/component/overview/exercise-details/request-feedback-button/request-feedback-button.component.spec.ts (1)

196-197: Past review comment is still applicable.

The existing review comment about splitting this test case into multiple test cases for better coverage is still valid.

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.

Tested on TS1. Reapprove

image

@krusche krusche modified the milestones: 7.6.4, 7.6.5 Oct 27, 2024
Copy link

@sachmii sachmii 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 TS1, still works fine. Re-approve

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 TS1. Re-approved 👍

Copy link
Contributor

@dmytropolityka dmytropolityka left a comment

Choose a reason for hiding this comment

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

code- latest changes look good to me

@ls1intum ls1intum deleted a comment from github-actions bot Oct 28, 2024
Copy link
Contributor

@FelixTJDietrich FelixTJDietrich 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 TS1 again to verify that everything is still working. Works really well, great job 🎉

@FelixTJDietrich FelixTJDietrich added maintainer-approved The feature maintainer has approved the PR ready to merge labels Oct 28, 2024
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 (1)
src/main/webapp/app/exercises/text/participate/text-editor.component.ts (1)

Line range hint 385-388: Enhance error handling in submission.

The current error handling only displays the error message. Consider adding proper error recovery and state reset.

Apply this diff:

 error: (err: HttpErrorResponse) => {
-    this.alertService.error(err.error.message);
+    const errorMessage = err.error?.message || this.translateService.instant('artemisApp.textExercise.error.submission');
+    this.alertService.error(errorMessage);
+    // Reset states
+    this.hasAthenaResultForLatestSubmission = false;
     this.isSaving = false;
 },
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ba65dc0 and e6fae3a.

📒 Files selected for processing (4)
  • src/main/java/de/tum/cit/aet/artemis/text/web/TextExerciseResource.java (2 hunks)
  • src/main/webapp/app/exercises/text/participate/text-editor.component.ts (10 hunks)
  • src/main/webapp/app/exercises/text/participate/text-editor.route.ts (1 hunks)
  • src/main/webapp/i18n/de/programmingExercise.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/i18n/de/programmingExercise.json
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/text/web/TextExerciseResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/webapp/app/exercises/text/participate/text-editor.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/main/webapp/app/exercises/text/participate/text-editor.route.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

📓 Learnings (1)
src/main/webapp/app/exercises/text/participate/text-editor.component.ts (2)
Learnt from: iyannsch
PR: ls1intum/Artemis#9379
File: src/main/webapp/app/shared/components/code-button/code-button.component.ts:143-170
Timestamp: 2024-10-08T15:35:42.972Z
Learning: In `code-button.component.ts`, `this.exercise.id` is checked before use, so it's acceptable to use the non-null assertion operator `!` on `this.exercise.id!`.
Learnt from: iyannsch
PR: ls1intum/Artemis#9379
File: src/main/webapp/app/shared/components/code-button/code-button.component.ts:143-170
Timestamp: 2024-09-30T08:34:49.363Z
Learning: In `code-button.component.ts`, `this.exercise.id` is checked before use, so it's acceptable to use the non-null assertion operator `!` on `this.exercise.id!`.
🪛 ast-grep
src/main/java/de/tum/cit/aet/artemis/text/web/TextExerciseResource.java

[warning] 432-432: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (new HashSet<>())
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 432-432: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (new HashSet<>())
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration

🔇 Additional comments (4)
src/main/webapp/app/exercises/text/participate/text-editor.component.ts (1)

144-158: 🛠️ Refactor suggestion

Improve readability of WebSocket subscription conditions.

The nested conditions make the code hard to read. Consider extracting the conditions into well-named variables.

Apply this diff:

+const hasNewResults = changedParticipation.results?.length > (this.participation?.results?.length || 0);
+const hasUncompletedResult = changedParticipation.results?.last()?.completionDate === undefined;
+const isAthenaResult = changedParticipation.results?.last()?.assessmentType === AssessmentType.AUTOMATIC_ATHENA;
+const hasSuccessStatus = changedParticipation.results?.last()?.successful !== undefined;

-if (
-    changedParticipation.results &&
-    ((changedParticipation.results?.length || 0) > (this.participation?.results?.length || 0) ||
-        changedParticipation.results?.last()?.completionDate === undefined) &&
-    changedParticipation.results?.last()?.assessmentType === AssessmentType.AUTOMATIC_ATHENA &&
-    changedParticipation.results.last()?.successful !== undefined
-) {
+if (changedParticipation.results && (hasNewResults || hasUncompletedResult) && isAthenaResult && hasSuccessStatus) {

Likely invalid or redundant comment.

src/main/java/de/tum/cit/aet/artemis/text/web/TextExerciseResource.java (3)

425-430: LGTM! Clear and correct implementation of result filtering.

The code correctly filters results to show only AUTOMATIC_ATHENA assessments before the assessment due date, which aligns with the PR objective of displaying preliminary feedback.


435-437: ⚠️ Potential issue

Add type checking before casting submission.

The current implementation directly casts Submission to TextSubmission without type verification, which could lead to ClassCastException.

Apply this fix:

-            TextSubmission textSubmission = (TextSubmission) submission;
+            if (!(submission instanceof TextSubmission textSubmission)) {
+                continue;
+            }

Likely invalid or redundant comment.


444-445: ⚠️ Potential issue

Use consistent collection type for results.

The code uses Set<Result> at line 427 but List<Result> here. For consistency and to prevent potential issues, use the same collection type.

Apply this fix:

-                    List<Result> athenaResults = submission.getResults().stream()
+                    Set<Result> athenaResults = submission.getResults().stream()
                         .filter(result -> result.getAssessmentType() == AssessmentType.AUTOMATIC_ATHENA)
-                        .toList();
+                        .collect(Collectors.toSet());

Likely invalid or redundant comment.

@krusche krusche merged commit a9d3399 into develop Oct 28, 2024
45 of 57 checks passed
@krusche krusche deleted the feature/text-exercises/replace-modal-with-inline-feedback branch October 28, 2024 20:56
muradium added a commit that referenced this pull request Nov 1, 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!) exercise Pull requests that affect the corresponding module maintainer-approved The feature maintainer has approved the PR playwright ready to merge server Pull requests that update Java code. (Added Automatically!) tests text Pull requests that affect the corresponding module
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.