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

Programming exercises: Add feedback discussion feature to feedback analysis table #9810

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

Conversation

az108
Copy link
Contributor

@az108 az108 commented Nov 17, 2024

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 principle of data economy for all 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 added pre-authorization annotations according to the guidelines and checked the course groups for all new REST Calls (security).
  • 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

This is a follow-up to the feature I’m working on: #9728. The goal is to provide instructors with clearer insights into the feedback given to students. In this PR, a “Feedback Discussion” modal has been introduced. This feature allows instructors to select specific feedback and open a communication channel for it, provided the course has one. For example, during an exam review, instructors can use this functionality to send messages that clarify certain mistakes, offering students a better understanding and clearer insights.

Description

A new server-side query has been implemented, which takes a feedbackDetailText input and creates a channel based on it, automatically adding all students who encountered the corresponding error. On the client side, instructors can now create these channels via a modal accessible on the far-right side of each feedback entry. This modal provides two options: instructors can either navigate directly to the newly created channel or remain on the feedback analysis page. Additionally, the modal allows instructors to specify the channel type, name, and description.

Steps for Testing

Prerequisites:

  • 1 Instructor
  • Student Sumbissions
  • 1 Programming Exercise
  1. Log in to Artemis
  2. Navigate to a Course with Instructor rights
  3. Create a Programming Exercise or use an existing one
  4. Solve the Programming Exercise as Students, ideally with different kinds of Progress (You can use artemis test users for this)
  5. Navigate as Instructor to the Grading of an Exercise
  6. Navigate to the Feedback Analysis section
  7. Verify that the table displays data correctly, and press the icon in a feedback table entry on the far right side to see the feedback-channel modal
  8. Verify that the channel is created as specified and both creation methods work as intended. Also make sure that all affected students are added to the corresponding channel when creating it.

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

Performance Tests

  • Test 1
  • Test 2

Test Coverage

Class/File Line Coverage Confirmation (expect)
feedback-analysis 94.11%
feedback-analysis-modal 92.59%
Methods in ResultService 100%
Methods in ResultResource 100%

Screenshots

Before:
image

After:
image
image

Summary by CodeRabbit

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced functionality to count students affected by specific feedback details.
    • Added endpoints for creating feedback-specific channels and managing feedback discussions.
    • New modals for confirming feedback channel creation and managing feedback details.
  • Enhancements

    • Improved user interface with new labels and messages for feedback channels.
    • Enhanced feedback analysis component to support communication features.
    • Added success messages and confirmation modals for channel creation.
  • Bug Fixes

    • Various improvements to ensure robust error handling and user notifications.
  • Documentation

    • Updated translations and user guidance for new features.

az108 and others added 26 commits November 10, 2024 21:43
…g-exercises/add-affected-students-to-analysis-table
…d-affected-students-to-analysis-table' into feature/programming-exercises/add-affected-students-to-analysis-table
…d-affected-students-to-analysis-table' into feature/programming-exercises/add-affected-students-to-analysis-table
…g-exercises/add-communication-feature-to-analysis-table

# Conflicts:
#	src/main/java/de/tum/cit/aet/artemis/assessment/web/ResultResource.java
#	src/main/java/de/tum/cit/aet/artemis/exercise/repository/StudentParticipationRepository.java
#	src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.component.html
#	src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.component.ts
#	src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.service.ts
#	src/main/webapp/i18n/de/programmingExercise.json
#	src/main/webapp/i18n/en/programmingExercise.json
…g-exercises/add-communication-feature-to-analysis-table
@az108 az108 self-assigned this Nov 17, 2024
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) labels Nov 17, 2024
raffifasaro
raffifasaro previously approved these changes Nov 19, 2024
Copy link
Contributor

@raffifasaro raffifasaro left a comment

Choose a reason for hiding this comment

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

re-approve

Malekos74
Malekos74 previously approved these changes Nov 19, 2024
Copy link

@Malekos74 Malekos74 left a comment

Choose a reason for hiding this comment

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

Reapprove

Copy link
Contributor

@florian-glombik florian-glombik left a comment

Choose a reason for hiding this comment

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

Approve code

Copy link
Contributor

@MarkusPaulsen MarkusPaulsen left a comment

Choose a reason for hiding this comment

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

Added my feedback for the server code.

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

🧹 Outside diff range and nitpick comments (10)
src/main/java/de/tum/cit/aet/artemis/communication/dto/FeedbackChannelRequestDTO.java (1)

5-7: Consider adding documentation and validation.

Given that this DTO handles potentially sensitive feedback information:

  1. Add Javadoc to document the purpose and potential sensitive nature of the fields
  2. Consider adding validation annotations (e.g., @NotNull, @Size) for the fields
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
+/**
+ * DTO for creating feedback discussion channels.
+ * Note: The feedbackDetailText field may contain sensitive feedback information.
+ * Instructors should ensure appropriate content when creating channels.
+ */
+public record FeedbackChannelRequestDTO(
+    @NotNull ChannelDTO channel,
+    @NotNull @Size(min = 1, max = 1000) String feedbackDetailText) {
-public record FeedbackChannelRequestDTO(ChannelDTO channel, String feedbackDetailText) {
 }
src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.service.ts (1)

71-78: Add JSDoc comments for better documentation.

Consider adding JSDoc comments to the new methods to document:

  • Parameters and their purpose
  • Return value
  • Possible error cases
  • Example usage

Example improvement:

/**
 * Creates a feedback channel for discussion between instructors and students.
 * @param courseId - The ID of the course
 * @param exerciseId - The ID of the exercise
 * @param feedbackChannelRequest - The channel creation request containing channel details and feedback text
 * @returns Promise resolving to the created channel
 * @throws HttpErrorResponse if channel creation fails
 */
createChannel(courseId: number, exerciseId: number, feedbackChannelRequest: FeedbackChannelRequestDTO): Promise<ChannelDTO>
src/test/javascript/spec/component/programming-exercise/feedback-analysis/feedback-analysis.service.spec.ts (1)

Line range hint 11-33: Improve type safety of mock data.

Consider using TypeScript interfaces for the mock data to improve type safety and maintainability.

Add these type definitions at the beginning of the file:

interface FeedbackDetailMock {
    concatenatedFeedbackIds: number[];
    detailText: string;
    testCaseName: string;
    count: number;
    relativeCount: number;
    taskName: string;
    errorCategory: string;
}

interface FeedbackAnalysisResponseMock {
    feedbackDetails: {
        resultsOnPage: FeedbackDetailMock[];
        numberOfPages: number;
    };
    totalItems: number;
    taskNames: string[];
    testCaseNames: string[];
    errorCategories: string[];
}

const feedbackDetailsMock: FeedbackDetailMock[] = [...];
const feedbackAnalysisResponseMock: FeedbackAnalysisResponseMock = {...};
src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.component.ts (1)

214-217: Consider adding warning about sensitive information

Based on the PR discussion about potential exposure of sensitive information, consider adding a warning note in the modal template about avoiding sensitive information in channel names and descriptions.

This could help prevent inadvertent exposure of test case information or other sensitive data through user-provided channel names and descriptions.

src/main/java/de/tum/cit/aet/artemis/communication/web/conversation/ChannelResource.java (2)

491-494: Use 'var' for local variables to improve readability

For consistency with the codebase's style and to improve readability, use 'var' for local variable declarations.

Apply this diff:

-       User requestingUser = userRepository.getUserWithGroupsAndAuthorities();
-       Course course = courseRepository.findByIdElseThrow(courseId);
+       var requestingUser = userRepository.getUserWithGroupsAndAuthorities();
+       var course = courseRepository.findByIdElseThrow(courseId);
        checkCommunicationEnabledElseThrow(course);
-       Channel createdChannel = channelService.createFeedbackChannel(course, exerciseId, channelDTO, feedbackDetailText, requestingUser);
+       var createdChannel = channelService.createFeedbackChannel(course, exerciseId, channelDTO, feedbackDetailText, requestingUser);

471-481: Improve Javadoc conciseness

The Javadoc can be more concise while maintaining clarity.

Apply this diff to improve the documentation:

     /**
-     * POST /api/courses/:courseId/channels/: Creates a new feedback-specific channel in a course.
+     * POST /api/courses/:courseId/exercises/:exerciseId/feedback-channel: Creates a feedback-specific channel.
      *
-     * @param courseId               where the channel is being created.
-     * @param exerciseId             for which the feedback channel is being created.
-     * @param feedbackChannelRequest containing a DTO with the properties of the channel (e.g., name, description, visibility)
-     *                                   and the feedback detail text used to determine the affected students to be added to the channel.
+     * @param courseId               the course ID
+     * @param exerciseId             the exercise ID
+     * @param feedbackChannelRequest the channel properties and feedback detail text
      * @return ResponseEntity with status 201 (Created) and the body containing the details of the created channel.
      * @throws URISyntaxException       if the URI for the created resource cannot be constructed.
      * @throws BadRequestAlertException if the channel name starts with an invalid prefix (e.g., "$").
      */
src/main/java/de/tum/cit/aet/artemis/exercise/repository/StudentParticipationRepository.java (4)

1365-1371: Documentation could be more specific.

Consider enhancing the documentation:

  1. For findAffectedLoginsByFeedbackDetailText, specify the format of returned logins and any potential empty list scenarios.
  2. For countAffectedStudentsByFeedbackDetailText, mention that only negative feedback entries are considered.
     /**
      * Retrieves the logins of students affected by a specific feedback detail text in a given exercise.
      *
      * @param exerciseId The ID of the exercise for which affected students are requested.
      * @param detailText The feedback detail text to filter by.
-     * @return A list of student logins affected by the given feedback detail text in the specified exercise.
+     * @return A list of student logins (usernames) affected by the given feedback detail text. Returns an empty list if no students are affected.
      */

     /**
      * Counts the number of distinct students affected by a specific feedback detail text for a given programming exercise.
      * <p>
      * This query identifies students whose submissions were impacted by feedback entries matching the provided detail text
-     * within the specified exercise. Only students with non-test run submissions and negative feedback entries are considered.
+     * within the specified exercise. Only students with non-test run submissions and negative feedback entries (f.positive = FALSE) are considered.
      * </p>

Also applies to: 1388-1398


1372-1386: Consider performance optimizations for the query.

The current implementation might face performance issues with large datasets:

  1. The subquery for getting the latest result could be inefficient.
  2. Missing pagination could lead to memory issues with large result sets.
  3. Consider adding index hints for join conditions.

Consider these improvements:

  1. Add pagination support to limit the result set size.
  2. Use a window function instead of a subquery for better performance:
     @Query("""
                 SELECT DISTINCT p.student.login
                 FROM ProgrammingExerciseStudentParticipation p
                 INNER JOIN p.submissions s
-                INNER JOIN s.results r ON r.id = (
-                    SELECT MAX(pr.id)
-                    FROM s.results pr
-                    WHERE pr.participation.id = p.id
-                )
+                INNER JOIN s.results r ON r.id = (
+                    SELECT r2.id FROM s.results r2
+                    WHERE r2.participation.id = p.id
+                    ORDER BY r2.id DESC
+                    LIMIT 1
+                )
                 INNER JOIN r.feedbacks f
                 WHERE p.exercise.id = :exerciseId
                   AND f.detailText = :detailText
                   AND p.testRun = FALSE
             """)
+    @QueryHints(value = {
+        @QueryHint(name = "org.hibernate.comment", value = "Index hint: idx_participation_exercise"),
+        @QueryHint(name = "org.hibernate.fetchSize", value = "50")
+    })

1399-1413: Optimize the counting query for better performance.

The current implementation could be optimized for counting operations:

  1. Consider using EXISTS instead of COUNT(DISTINCT) for better performance.
  2. The subquery pattern for latest results could be inefficient.

Consider this optimization:

     @Query("""
-                SELECT COUNT(DISTINCT p.student.id)
+                SELECT COUNT(*)
+                FROM (
+                    SELECT 1
                 FROM ProgrammingExerciseStudentParticipation p
                 INNER JOIN p.submissions s
                 INNER JOIN s.results r ON r.id = (
-                    SELECT MAX(pr.id)
-                    FROM s.results pr
-                    WHERE pr.participation.id = p.id
+                    SELECT r2.id FROM s.results r2
+                    WHERE r2.participation.id = p.id
+                    ORDER BY r2.id DESC
+                    LIMIT 1
                 )
                 INNER JOIN r.feedbacks f
                 WHERE p.exercise.id = :exerciseId
                   AND f.detailText = :detailText
                   AND p.testRun = FALSE
+                GROUP BY p.student.id
+                ) AS distinct_students
             """)
+    @QueryHints(@QueryHint(name = "org.hibernate.comment", value = "Index hint: idx_participation_exercise"))

1364-1387: Enhance parameter validation and null safety.

Consider adding parameter validation and null safety annotations:

-    List<String> findAffectedLoginsByFeedbackDetailText(@Param("exerciseId") long exerciseId, @Param("detailText") String detailText);
+    List<String> findAffectedLoginsByFeedbackDetailText(
+        @Param("exerciseId") @NotNull long exerciseId,
+        @Param("detailText") @NotNull @NotEmpty String detailText);

-    long countAffectedStudentsByFeedbackDetailText(@Param("exerciseId") long exerciseId, @Param("detailText") String detailText);
+    long countAffectedStudentsByFeedbackDetailText(
+        @Param("exerciseId") @NotNull long exerciseId,
+        @Param("detailText") @NotNull @NotEmpty String detailText);

Also applies to: 1388-1413

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ffb4ded and 23988ca.

📒 Files selected for processing (7)
  • src/main/java/de/tum/cit/aet/artemis/communication/dto/FeedbackChannelRequestDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/communication/web/conversation/ChannelResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/exercise/repository/StudentParticipationRepository.java (1 hunks)
  • src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.component.ts (6 hunks)
  • src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.service.ts (3 hunks)
  • src/test/java/de/tum/cit/aet/artemis/communication/ChannelIntegrationTest.java (5 hunks)
  • src/test/javascript/spec/component/programming-exercise/feedback-analysis/feedback-analysis.service.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
src/main/java/de/tum/cit/aet/artemis/communication/dto/FeedbackChannelRequestDTO.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/java/de/tum/cit/aet/artemis/communication/web/conversation/ChannelResource.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/java/de/tum/cit/aet/artemis/exercise/repository/StudentParticipationRepository.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/programming/manage/grading/feedback-analysis/feedback-analysis.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/programming/manage/grading/feedback-analysis/feedback-analysis.service.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/java/de/tum/cit/aet/artemis/communication/ChannelIntegrationTest.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

src/test/javascript/spec/component/programming-exercise/feedback-analysis/feedback-analysis.service.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 (9)
src/main/java/de/tum/cit/aet/artemis/communication/dto/FeedbackChannelRequestDTO.java (2)

1-4: LGTM! Package and imports are well-structured.

The package naming and import statement follow best practices, avoiding star imports as required by the coding guidelines.


5-7: LGTM! Record implementation follows DTO best practices.

The use of a Java record with minimal fields aligns perfectly with the coding guidelines for DTOs.

src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.service.ts (2)

6-6: LGTM! Well-structured interface definition.

The FeedbackChannelRequestDTO interface is properly defined with appropriate naming conventions and clear property structure.

Also applies to: 32-35


71-73: Consider adding input validation for channel creation.

Given the concerns raised in PR comments about potentially exposing sensitive test case information, consider adding input validation or sanitization for the channel name and description before sending to the server.

Let's check if there are any existing input validation patterns in the codebase:

src/main/webapp/app/exercises/programming/manage/grading/feedback-analysis/feedback-analysis.component.ts (3)

2-2: LGTM: Import statements are well-organized

The new imports are correctly added and necessary for the feedback discussion feature implementation.

Also applies to: 5-5, 14-16


29-30: LGTM: Properties are well-defined and follow Angular patterns

The new properties are correctly implemented with:

  • Required inputs using Angular's new input() syntax
  • Proper type definitions
  • Modal state management to prevent multiple instances

Also applies to: 55-55, 70-71


204-238: 🛠️ Refactor suggestion

Enhance error handling and documentation

While the implementation is generally good, there are a few improvements needed:

  1. Error handling should be more specific and include the channel name in the error message
  2. The empty catch block should be better documented

Consider applying these improvements:

-                this.alertService.error(error);
+                const name = channelDto.name;
+                this.alertService.error(this.TRANSLATION_BASE + '.channelError', { name });

-        } catch {
-            // modal dismissed
+        } catch {
+            // Modal dismissed by user - no action needed as this is expected behavior

Note: This addresses similar concerns raised in previous reviews while maintaining the improved navigation approach using Angular Router.

src/main/java/de/tum/cit/aet/artemis/communication/web/conversation/ChannelResource.java (2)

38-38: LGTM: Dependencies and imports are well-structured

The new dependencies are properly integrated using constructor injection, following Spring best practices.

Also applies to: 46-46, 55-55, 57-57, 87-88, 92-93, 105-105


482-482: 🛠️ Refactor suggestion

Update endpoint path to follow REST conventions

The current path /{courseId}/{exerciseId}/feedback-channel should include 'exercises' for consistency with other endpoints and REST conventions.

Apply this diff:

-@PostMapping("{courseId}/{exerciseId}/feedback-channel")
+@PostMapping("{courseId}/exercises/{exerciseId}/feedback-channel")

Likely invalid or redundant comment.

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.

Tested on TS3, works as expected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assessment Pull requests that affect the corresponding module client Pull requests that update TypeScript code. (Added Automatically!) communication Pull requests that affect the corresponding module exercise Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Developer Approved
Status: In review
Development

Successfully merging this pull request may close these issues.