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

Modeling exercises: Inline AI feedback view #9799

Merged
merged 47 commits into from
Dec 8, 2024

Conversation

LeonWehrhahn
Copy link
Contributor

@LeonWehrhahn LeonWehrhahn commented Nov 16, 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

When students requested AI feedback for modeling exercises in Artemis, the feedback was previously only displayed as a list in a pop-up window. This made it difficult for students to correlate feedback comments with the corresponding elements in their diagrams.

The goal of this PR is to enhance the feedback experience for modeling exercises by allowing students to view AI-generated feedback directly on the diagram, similar to how tutor feedback is presented. This provides a more intuitive and interactive way for students to receive and understand feedback.

Description

A new Feedback View for modeling exercises has been introduced to enhance the way students receive and interact with AI-generated feedback.

Accessing the Feedback View:

  • From the Modeling Editor: Students can now request AI feedback directly within the modeling editor. After submitting and requesting feedback for their model, they can switch to the Feedback View by clicking on the result tag in the exercise header to see the feedback applied.
  • From the Exercise Overview: On the exercise overview page, students can select different submissions from a timeline. Clicking on a submission will navigate them to the Feedback View, displaying the selected submission along with its associated feedback.

Key Features of the Feedback View:

  1. Feedback Displayed Directly on the Diagram:

    • Referenced Feedback: Feedback linked to specific elements of the UML model is now displayed as annotations directly on those elements within the modeling editor. This visual association allows students to see exactly which parts of their model the feedback refers to.
  2. Unreferenced Feedback Listed Below the Diagram:

    • Unreferenced Feedback: Feedback that is general or not linked to specific diagram elements is displayed below the diagram, similar to how unreferenced tutor feedback is presented.
  3. Submission History and Feedback Navigation:

    • Timeline of Submissions: Students can view a history of their submissions in a timeline format. Selecting a previous submission loads the corresponding UML model and displays the associated feedback in the Feedback View.
  4. Request Feedback Directly in the Editor:

    • Feedback Button: A "Request AI Feedback" button has been added to the modeling editor page. Students can now directly request feedback in the modeling editor.

Steps for Testing

Only Deploy to TS1

Prerequisites:

  • 1 Instructor Account
  • 1 Student Account
  • A Modeling Exercise with the option to request AI feedback enabled

Testing Steps:

  1. Instructor Setup:

    • Log in as an instructor.
    • Create a new modeling exercise with AI feedback enabled.
    • Ensure that the "Allow AI Feedback" option is checked.
  2. Student Participation:

    • Log in as a student.

    • Navigate to the modeling exercise.

    • Create a model using the modeling editor.

    • Request AI Feedback:

      • Click on the "Request AI Feedback" button within the modeling editor.
      • Wait for the feedback to be generated.
    • View Feedback on Diagram:

      • Switch to the feedback view mode (accessed via a button or link).
      • Confirm that referenced feedback annotations are displayed directly on the diagram elements or unreferenced feedback is shown below
  3. Submission History:

    • Make several changes to the model and request feedback multiple times.
    • Access the submission history or timeline in the feedback view.
    • Switch between different submissions and confirm that the corresponding feedback is displayed on the diagram and below it.
    • Verify that the model displayed corresponds to the selected submission's state.
  4. Access from Exercise Overview:

    • Navigate back to the exercise overview page.
    • Access the feedback view mode from the overview.
    • Confirm that the correct model and feedback are displayed.

Exam Mode Testing

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

Screenshots

  1. AI Feedback View: For the selected element class, the corresponding feedback can be seen on the right
image
  1. Submission History: The submission history can be seen. By selecting a specific submission in the history timeline, the corresponding feedback for that particular submission is displayed
image
  1. Request AI feedback: AI Feedback can now directly be requested in the modeling exercise header
image

Summary by CodeRabbit

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a method to retrieve results based on participation ID and assessment type.
    • Added a new endpoint for fetching submissions with results for specific participations.
    • Implemented a new route for accessing submission details based on participation ID.
    • Added a new component for requesting feedback.
  • Improvements

    • Enhanced feedback representation by simplifying the data model to use a single reference string.
    • Improved user interface responsiveness for feedback and submission processes.
    • Streamlined feedback suggestion processing for better clarity and efficiency.
    • Enhanced the submission view to include detailed result history and improved filtering based on user roles.
    • Improved error handling logic during feedback generation to ensure proper state management.
    • Updated submission component to manage feedback views and submission history more effectively.
    • Enhanced logging and access control for submission retrieval based on user roles.
  • Bug Fixes

    • Refined error handling and logic for displaying results based on exercise types.
    • Enhanced testing coverage for submission retrieval functionality and component behavior.
    • Improved handling of user permissions and data filtering in the submission view.

@github-actions github-actions bot added server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) assessment Pull requests that affect the corresponding module athena Pull requests that affect the corresponding module modeling Pull requests that affect the corresponding module labels Nov 16, 2024
@LeonWehrhahn LeonWehrhahn marked this pull request as ready for review November 16, 2024 17:53
@LeonWehrhahn LeonWehrhahn requested a review from a team as a code owner November 16, 2024 17:53
@LeonWehrhahn LeonWehrhahn changed the title Feature/modeling/inline ai feedback Modeling exercises: Inline AI Feedback View Nov 16, 2024
Copy link

coderabbitai bot commented Nov 16, 2024

Walkthrough

The changes in this pull request involve multiple updates across various files, primarily focusing on enhancing feedback handling and submission management within the modeling exercise context. Key modifications include the addition of new methods for retrieving results based on participation ID and assessment type, updates to data transfer objects to streamline feedback representation, and improvements to component logic for managing submissions and feedback views. The overall structure of the application remains intact, with new functionalities introduced to improve user interaction and data processing.

Changes

File Change Summary
src/main/java/de/tum/cit/aet/artemis/assessment/repository/ResultRepository.java Added method: Optional<Result> findFirstByParticipationIdAndAssessmentTypeOrderByCompletionDateDesc(long participationId, AssessmentType assessmentType) for fetching results by participation ID and assessment type.
src/main/java/de/tum/cit/aet/artemis/athena/dto/ModelingFeedbackDTO.java Updated constructor and method signature to replace List<String> elementIds with String reference, simplifying the feedback representation.
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java Added method: private void checkLatestSubmissionHasAthenaResultOrThrow(StudentParticipation participation) for validating submissions before feedback generation. Updated error handling in generateAutomaticNonGradedFeedback.
src/main/java/de/tum/cit/aet/artemis/modeling/web/ModelingSubmissionResource.java Added method: public ResponseEntity<List<Submission>> getSubmissionsWithResultsForParticipation(@PathVariable long participationId). Updated constructor to include ResultService and ResultRepository.
src/main/webapp/app/exercises/modeling/participate/modeling-participation.module.ts Imported RequestFeedbackButtonComponent into ArtemisModelingParticipationModule.
src/main/webapp/app/exercises/modeling/participate/modeling-participation.route.ts Added new route: path: 'participate/:participationId/submission/:submissionId' for navigating to submission view.
src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html Enhanced conditional rendering logic and structure to manage visibility of buttons and feedback requests based on isFeedbackView state.
src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts Added properties for managing submission history and feedback views. Updated initialization logic with RxJS operators for better data handling. Introduced methods for fetching submissions and managing feedback views.
src/main/webapp/app/exercises/modeling/participate/modeling-submission.service.ts Added method: getSubmissionsWithResultsForParticipation(participationId: number): Observable<ModelingSubmission[]> for retrieving submissions with results.
src/main/webapp/app/exercises/shared/result/result.component.ts Updated showDetails method to handle multiple exercise types and improved initialization logic in ngOnInit.
src/main/webapp/app/exercises/shared/result/result.utils.ts Modified getUnreferencedFeedback function to include AUTOMATIC feedback elements in addition to MANUAL_UNREFERENCED.
src/main/webapp/app/assessment/athena.service.ts Updated getModelingFeedbackSuggestions method to streamline feedback suggestion processing by extracting reference details directly from the suggestion's reference property.
src/main/webapp/app/entities/feedback-suggestion.model.ts Updated constructor parameter from elementIds: string[] to `reference: string
src/test/javascript/spec/service/athena.service.spec.ts Modified test suite for AthenaService to reflect changes in ModelingFeedbackSuggestion structure and instantiation.
src/test/java/de/tum/cit/aet/artemis/modeling/ModelingSubmissionIntegrationTest.java Added several new test methods to enhance testing of submission retrieval functionality based on assessment and submission due dates, including various scenarios for result visibility and access control.
src/test/javascript/spec/service/modeling-submission.service.spec.ts Added test case to verify the functionality of getSubmissionsWithResultsForParticipation method in ModelingSubmissionService.
src/test/javascript/spec/component/modeling-submission/modeling-submission.component.spec.ts Updated test suite for ModelingSubmissionComponent to reflect changes in component behavior, including new tests for feedback view and error handling.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • JohannesStoehr
  • az108
  • florian-glombik
  • HawKhiem
  • BBesrour
  • DominikRemo
  • EneaGore

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 pmd (7.7.0)
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.


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 (21)
src/main/webapp/app/exercises/modeling/participate/modeling-participation.route.ts (1)

19-28: Consider adding a route resolver for better UX.

To prevent showing an empty/loading state while fetching submission data, consider implementing a resolver to pre-fetch the submission data before activating the route.

Example implementation:

@Injectable({ providedIn: 'root' })
export class ModelingSubmissionResolver implements Resolve<ModelingSubmission> {
    constructor(private submissionService: ModelingSubmissionService) {}

    resolve(route: ActivatedRouteSnapshot): Observable<ModelingSubmission> {
        const participationId = route.paramMap.get('participationId');
        const submissionId = route.paramMap.get('submissionId');
        return this.submissionService.getSubmission(participationId, submissionId);
    }
}

Then update the route configuration:

 {
     path: 'participate/:participationId/submission/:submissionId',
     component: ModelingSubmissionComponent,
+    resolve: {
+        submission: ModelingSubmissionResolver
+    },
     data: {
         authorities: [Authority.USER],
         pageTitle: 'artemisApp.modelingExercise.home.title',
     },
     canActivate: [UserRouteAccessService],
     canDeactivate: [PendingChangesGuard],
 },
src/main/java/de/tum/cit/aet/artemis/athena/dto/ModelingFeedbackDTO.java (1)

31-31: Consider adding parameter validation.

While the @NotNull annotation on the feedback parameter is good, consider adding validation for:

  1. exerciseId and submissionId to ensure they are positive
  2. feedback.getReference() to ensure it's not null or empty when required

Example validation:

public static ModelingFeedbackDTO of(
    @Positive long exerciseId,
    @Positive long submissionId,
    @NotNull Feedback feedback) {
    
    Objects.requireNonNull(feedback.getReference(), "Reference must not be null");
    // ... rest of the method
}
src/main/webapp/app/exercises/modeling/participate/modeling-participation.module.ts (1)

16-16: Consider moving RequestFeedbackButtonComponent to shared module

The RequestFeedbackButtonComponent is currently located in 'app/overview/exercise-details' but is being used in the modeling module. Since it's a reusable component for requesting feedback, consider:

  1. Moving it to the shared components directory (e.g., 'app/shared/components/feedback')
  2. Declaring it in ArtemisSharedComponentModule
  3. Importing ArtemisSharedComponentModule where needed

This would improve modularity and make the component's purpose and reusability more apparent.

src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts (2)

13-13: Address the TODO comment about complex type mapping.

The TODO comment indicates a known issue with complexity. Given that this PR enhances the feedback mechanism, this would be a good time to address this technical debt.

Consider these improvements:

  1. Create a dedicated type mapping configuration file
  2. Use a decorator pattern to handle different diagram types
  3. Implement a strategy pattern for type resolution

Would you like me to provide a detailed implementation proposal for any of these approaches?


Line range hint 18-95: Refactor the nested switch statements for better maintainability.

The current implementation uses nested if-else and switch statements, making it hard to maintain and extend for new diagram types. This is particularly relevant given the PR's focus on enhancing feedback visualization.

Consider this more maintainable approach:

interface ElementTypeMapping {
    [key: string]: { type: string; nameFormatter?: (element: any) => string };
}

const UML_ELEMENT_MAPPINGS: ElementTypeMapping = {
    [UMLElementType.Class]: { type: 'class' },
    [UMLElementType.Package]: { type: 'package' },
    // ... other mappings
};

const UML_RELATIONSHIP_MAPPINGS: ElementTypeMapping = {
    [UMLRelationshipType.ClassBidirectional]: { 
        type: 'association',
        nameFormatter: (rel) => `${rel.source} <-> ${rel.target}`
    },
    // ... other mappings
};

function getElementAssessmentName(element: any, mapping: ElementTypeMapping): { type: string; name: string } {
    const config = mapping[element.type] || { type: '', nameFormatter: (e) => e.name || '' };
    return {
        type: config.type,
        name: config.nameFormatter ? config.nameFormatter(element) : element.name
    };
}
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (2)

Line range hint 171-178: Consider adding input validation and documentation.

While the conversion logic is correct, consider these improvements:

  1. Add input validation for critical fields
  2. Document the purpose of the reference field
  3. Use @nonnull annotations where appropriate

Here's a suggested improvement:

    /**
     * Converts an Athena feedback suggestion to a Feedback object.
     *
     * @param feedbackItem the Athena feedback suggestion
+    * @throws IllegalArgumentException if required fields are null
     * @return the Feedback object
     */
-    private Feedback convertToFeedback(ModelingFeedbackDTO feedbackItem) {
+    private Feedback convertToFeedback(@NonNull ModelingFeedbackDTO feedbackItem) {
+        if (feedbackItem.title() == null || feedbackItem.description() == null) {
+            throw new IllegalArgumentException("Title and description are required");
+        }
         Feedback feedback = new Feedback();
         feedback.setText(feedbackItem.title());
         feedback.setDetailText(feedbackItem.description());
         feedback.setHasLongFeedbackText(false);
         feedback.setType(FeedbackType.AUTOMATIC);
         feedback.setCredits(feedbackItem.credits());
         feedback.setReference(feedbackItem.reference());
         return feedback;
     }

Line range hint 42-47: Consider operational improvements for feedback service.

The service handles core functionality well, but consider these operational enhancements:

  1. Make the rate limit (10) configurable via properties
  2. Add structured logging for better monitoring of feedback generation

Example configuration property:

artemis.modeling.feedback.max-requests=10

Example logging enhancement:

log.info("Generating AI feedback for exercise={} participation={} submission={}", 
    modelingExercise.getId(), participation.getId(), submission.getId());
src/main/webapp/app/exercises/shared/result/result.component.ts (4)

273-274: Consider using constants for exercise type paths.

The hardcoded paths could be moved to constants to improve maintainability and reduce the risk of typos.

+ private readonly EXERCISE_TYPE_PATHS = {
+   [ExerciseType.TEXT]: 'text-exercises',
+   [ExerciseType.MODELING]: 'modeling-exercises',
+ } as const;
+
- const exerciseTypePath = this.exercise?.type === ExerciseType.TEXT ? 'text-exercises' : 'modeling-exercises';
+ const exerciseTypePath = this.EXERCISE_TYPE_PATHS[this.exercise?.type!];

266-272: Enhance null safety for submission ID retrieval.

The current implementation could be more explicit about handling undefined cases.

- let submissionId = result.submission?.id;
- // In case of undefined result submission try the latest submission as this can happen before reloading the component
- if (!submissionId) {
-     submissionId = result.participation?.submissions?.last()?.id;
- }
+ const submissionId = result.submission?.id ?? result.participation?.submissions?.last()?.id;
+ if (!submissionId) {
+     console.warn('No submission ID found for result:', result);
+ }

275-277: Remove redundant return statement after navigation.

The return undefined after router.navigate is unnecessary as the navigation will end the method execution.

 this.router.navigate(['/courses', courseId, 'exercises', exerciseTypePath, this.exercise?.id, 'participate', result.participation?.id, 'submission', submissionId]);
-return undefined;

265-275: Add error handling for invalid course ID.

Consider adding validation for the courseId to provide better error feedback.

 if (this.exercise?.type === ExerciseType.TEXT || this.exercise?.type === ExerciseType.MODELING) {
     const courseId = getCourseFromExercise(this.exercise)?.id;
+    if (!courseId) {
+        console.error('Unable to navigate: Invalid course ID');
+        return;
+    }
src/main/webapp/app/exercises/shared/result/result.utils.ts (2)

119-123: Add JSDoc documentation for better maintainability.

The function implementation looks good and correctly handles both manual unreferenced and automatic feedback. Consider adding JSDoc documentation to explain the purpose and behavior.

+/**
+ * Filters and returns unreferenced feedback from an array of feedbacks.
+ * Unreferenced feedback includes both manual unreferenced feedback and automatic feedback without references.
+ *
+ * @param feedbacks - Array of feedback items to filter
+ * @returns Array of unreferenced feedback items or undefined if input is undefined
+ */
 export const getUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => {

119-123: Improve type safety with explicit return types.

Consider using a more explicit return type to improve type safety and make the function's behavior more predictable.

-export const getUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => {
+export const getUnreferencedFeedback = (feedbacks: Feedback[] | undefined): readonly Feedback[] => {
     return feedbacks
         ? feedbacks.filter(
               (feedbackElement) => !feedbackElement.reference && (feedbackElement.type === FeedbackType.MANUAL_UNREFERENCED || feedbackElement.type === FeedbackType.AUTOMATIC),
           )
-        : undefined;
+        : [];

This change:

  1. Returns an empty array instead of undefined for consistency
  2. Makes the return value readonly to prevent accidental modifications
  3. Simplifies error handling for consumers as they don't need to check for undefined
src/main/java/de/tum/cit/aet/artemis/modeling/web/ModelingSubmissionResource.java (4)

96-96: Consider breaking down the class to reduce constructor parameters.

While the constructor properly initializes all dependencies, it's getting quite large with many parameters. This might indicate that the class has too many responsibilities.

Consider:

  1. Breaking down the class into smaller, more focused components
  2. Using a builder pattern or configuration object
  3. Creating specialized service classes for different aspects of submission handling

Also applies to: 104-105


424-445: Consider simplifying the nested stream operations.

The current implementation of filtering submissions and results uses nested streams with complex conditions.

Consider extracting the filtering logic into separate methods for better readability:

-        List<Submission> submissionsWithResults = submissions.stream().filter(submission -> {
-            submission.setParticipation(participation);
-            List<Result> filteredResults = submission.getResults().stream().filter(result -> {
-                if (ExerciseDateService.isAfterAssessmentDueDate(modelingExercise)) {
-                    return true;
-                }
-                else {
-                    return result.getAssessmentType() == AssessmentType.AUTOMATIC_ATHENA;
-                }
-            }).peek(Result::filterSensitiveInformation)
-              .sorted(Comparator.comparing(Result::getCompletionDate).reversed())
-              .collect(Collectors.toList());
-            if (!filteredResults.isEmpty()) {
-                submission.setResults(filteredResults);
-                return true;
-            }
-            return false;
-        }).collect(Collectors.toList());
+        List<Submission> submissionsWithResults = submissions.stream()
+            .map(submission -> enrichSubmissionWithFilteredResults(submission, participation, modelingExercise))
+            .filter(submission -> !submission.getResults().isEmpty())
+            .collect(Collectors.toList());

Add this private method:

private Submission enrichSubmissionWithFilteredResults(Submission submission, StudentParticipation participation, ModelingExercise exercise) {
    submission.setParticipation(participation);
    
    List<Result> filteredResults = submission.getResults().stream()
        .filter(result -> shouldIncludeResult(result, exercise))
        .peek(Result::filterSensitiveInformation)
        .sorted(Comparator.comparing(Result::getCompletionDate).reversed())
        .collect(Collectors.toList());
        
    submission.setResults(filteredResults);
    return submission;
}

private boolean shouldIncludeResult(Result result, ModelingExercise exercise) {
    return ExerciseDateService.isAfterAssessmentDueDate(exercise) || 
           result.getAssessmentType() == AssessmentType.AUTOMATIC_ATHENA;
}

400-402: Consider externalizing error messages.

Error messages are currently hardcoded in the controller. Consider moving them to a resource bundle or constants file for better maintainability and internationalization support.

Also applies to: 406-408


447-448: Consider using ResponseEntity builder pattern consistently.

For better consistency with other endpoints in the class, consider using the builder pattern:

-        return ResponseEntity.ok().body(submissionsWithResults);
+        return ResponseEntity.ok(submissionsWithResults);
src/main/java/de/tum/cit/aet/artemis/assessment/repository/ResultRepository.java (1)

Line range hint 1-1000: Consider extracting business logic to a dedicated service layer.

While the implementation is functionally correct, the repository has taken on significant business logic responsibilities (e.g., point calculations, assessment submissions). Consider:

  1. Moving calculation methods like calculateTotalPoints, calculatePointsPerGradingCriterion, and submitResult to a dedicated service layer.
  2. Creating a ResultCalculationService for point-related operations.
  3. Moving assessment-related operations to an AssessmentService.

This would:

  • Improve adherence to the Single Responsibility Principle
  • Make the code more maintainable and testable
  • Keep the repository focused on data access concerns
src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html (3)

10-10: Inconsistent use of 'this' in template expressions

Variables in the template are inconsistently referenced with and without this. For example:

  • Line 10: @if (isFeedbackView)
  • Line 28: @if (modelingExercise.allowFeedbackRequests && (!this.modelingExercise.dueDate || !hasExerciseDueDatePassed(this.modelingExercise, this.participation)))
  • Line 39: @if (!this.isFeedbackView)

For consistency and to avoid confusion, please use a consistent approach when referencing component properties in the template. Preferably, omit this when accessing properties in the template.

Apply this diff to make the property references consistent:

- @if (!this.isFeedbackView) {
+ @if (!isFeedbackView) {

- @if (modelingExercise.allowFeedbackRequests && (!this.modelingExercise.dueDate || !hasExerciseDueDatePassed(this.modelingExercise, this.participation))) {
+ @if (modelingExercise.allowFeedbackRequests && (!modelingExercise.dueDate || !hasExerciseDueDatePassed(modelingExercise, participation))) {

Also applies to: 28-28, 39-39


145-145: Redundant non-null assertion operators in conditions

In the conditions on lines 145 and 148, non-null assertion operators are used unnecessarily:

  • Line 145: @if (!assessmentResult || !assessmentResult!.feedbacks || assessmentResult!.feedbacks!.length === 0)
  • Line 148: @if (assessmentResult && assessmentResult!.feedbacks && assessmentResult!.feedbacks!.length > 0)

Since you are already checking whether assessmentResult and assessmentResult.feedbacks are null or undefined, the non-null assertions (!) are redundant and can be removed.

Apply this diff to clean up the conditions:

- @if (!assessmentResult || !assessmentResult!.feedbacks || assessmentResult!.feedbacks!.length === 0) {
+ @if (!assessmentResult || !assessmentResult.feedbacks || assessmentResult.feedbacks.length === 0) {

- @if (assessmentResult && assessmentResult!.feedbacks && assessmentResult!.feedbacks!.length > 0) {
+ @if (assessmentResult && assessmentResult.feedbacks && assessmentResult.feedbacks.length > 0) {

Also applies to: 148-148


162-170: Simplify repeated conditional checks for 'feedback.reference'

In this block, you repeatedly check @if (feedback.reference) before displaying elements. To improve readability and reduce redundancy, consider wrapping the content within a single @if (feedback.reference) block.

Refactored code:

@* Combine the repeated checks into one *@
@if (feedback.reference) {
    <span>{{ assessmentsNames[feedback.referenceId!]?.type }} </span>
    <code class="text-primary">{{ assessmentsNames[feedback.referenceId!]?.name }}</code>
    <br />
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 32f6b56 and 17e99f2.

📒 Files selected for processing (12)
  • src/main/java/de/tum/cit/aet/artemis/assessment/repository/ResultRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/athena/dto/ModelingFeedbackDTO.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/modeling/web/ModelingSubmissionResource.java (5 hunks)
  • src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts (1 hunks)
  • src/main/webapp/app/exercises/modeling/participate/modeling-participation.module.ts (2 hunks)
  • src/main/webapp/app/exercises/modeling/participate/modeling-participation.route.ts (1 hunks)
  • src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html (3 hunks)
  • src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts (14 hunks)
  • src/main/webapp/app/exercises/modeling/participate/modeling-submission.service.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/result/result.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/result/result.utils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/main/java/de/tum/cit/aet/artemis/assessment/repository/ResultRepository.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/athena/dto/ModelingFeedbackDTO.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/modeling/service/ModelingExerciseFeedbackService.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/modeling/web/ModelingSubmissionResource.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/modeling/assess/modeling-assessment.util.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/modeling/participate/modeling-participation.module.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/modeling/participate/modeling-participation.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

src/main/webapp/app/exercises/modeling/participate/modeling-submission.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/exercises/modeling/participate/modeling-submission.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/modeling/participate/modeling-submission.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/main/webapp/app/exercises/shared/result/result.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/shared/result/result.utils.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

🪛 Biome
src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts

[error] 163-163: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

🔇 Additional comments (10)
src/main/webapp/app/exercises/modeling/participate/modeling-participation.route.ts (1)

19-28: LGTM! Verify component reuse strategy.

The route configuration follows Angular best practices and aligns with the PR objectives. The security guards and authorities are properly configured.

Let's verify the component handles route parameter changes correctly:

✅ Verification successful

The first search didn't find the component implementation. Let's try a broader search to locate the component and verify its subscription handling.


Route configuration is safe and component handles route parameters correctly

The ModelingSubmissionComponent implementation shows proper handling of route parameters and component lifecycle:

  1. The component implements OnDestroy and cleans up subscriptions properly
  2. Route parameters are handled safely through:
    • Initial route params subscription in ngOnInit
    • Proper cleanup of subscriptions in ngOnDestroy
    • Safe handling of submissionId and participationId parameters
  3. Component reuse is handled correctly through:
    • State reset between navigations
    • Proper cleanup of websocket subscriptions
    • Clear separation between feedback view and submission view modes

The route configuration can be safely used as is, with no risk of memory leaks or state persistence issues between route changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if ModelingSubmissionComponent implements OnDestroy and handles parameter changes

# Check for OnDestroy implementation and subscription cleanup
ast-grep --pattern 'export class ModelingSubmissionComponent implements $_ {
  $$$
  ngOnDestroy() {
    $$$
  }
  $$$
}'

# Check for route parameter subscription
ast-grep --pattern 'this.route.params.subscribe'

Length of output: 6713


Script:

#!/bin/bash
# Let's check the ModelingSubmissionComponent implementation
fd "modeling-submission.component.ts" --exec cat {}

# Also check for any route parameter handling in parent components
fd "modeling-participation.component.ts" --exec cat {}

Length of output: 60446

src/main/java/de/tum/cit/aet/artemis/athena/dto/ModelingFeedbackDTO.java (1)

14-14: LGTM! Record structure aligns with feedback enhancement goals.

The change from List<String> elementIds to String reference simplifies the feedback reference structure while maintaining the DTO's single responsibility. This aligns well with the PR objective of enhancing diagram feedback display.

src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts (1)

Line range hint 96-120: LGTM! The filterInvalidFeedback function is well-implemented.

The function correctly handles null checks and efficiently filters invalid feedback elements.

src/main/webapp/app/exercises/modeling/participate/modeling-submission.service.ts (1)

140-147: Implementation aligns well with PR objectives.

The new method effectively supports the submission history timeline feature by retrieving submissions with their associated results, which is crucial for displaying AI feedback in the new Feedback View.

src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (1)

176-176: LGTM - Change aligns with inline feedback requirements.

The addition of the reference field is essential for the new inline feedback feature, enabling the connection between feedback and specific diagram elements.

Let's verify the complete feedback mapping chain:

src/main/webapp/app/exercises/shared/result/result.component.ts (1)

265-275: LGTM! Implementation aligns with PR objectives.

The changes successfully implement the new navigation logic for TEXT and MODELING exercises, supporting the enhanced feedback mechanism.

src/main/java/de/tum/cit/aet/artemis/modeling/web/ModelingSubmissionResource.java (3)

74-75: LGTM! Field declarations follow best practices.

The new fields follow constructor injection pattern and proper encapsulation principles.

Also applies to: 91-92


381-389: LGTM! Well-documented endpoint.

The Javadoc clearly describes the endpoint's purpose and behavior under different conditions.


395-419: LGTM! Comprehensive security checks.

The implementation properly validates:

  1. Participation existence and type
  2. User permissions
  3. Exam-specific access rules
src/main/java/de/tum/cit/aet/artemis/assessment/repository/ResultRepository.java (1)

107-108: LGTM! Method signature follows repository conventions.

The new method findFirstByParticipationIdAndAssessmentTypeOrderByCompletionDateDesc is well-designed and follows Spring Data JPA naming conventions. It appropriately extends the repository's capabilities to filter results by assessment type, which aligns with the PR's objective of enhancing the feedback mechanism.

Let's verify the usage of this new method:

✅ Verification successful

Method is used appropriately in the codebase

The search results confirm that:

  1. The method follows the same pattern as other repository methods for handling assessment types with results
  2. The codebase extensively uses AssessmentType with Results in various contexts:
    • Result DTOs properly handle assessment types
    • Services like ModelingSubmissionService and ProgrammingSubmissionService use assessment types for result filtering
    • Assessment types are properly set and managed in test utilities
    • The UI components handle different assessment types appropriately
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the new method is being used appropriately in the codebase
# Test: Search for method usage and related assessment type handling

# Check for direct method usage
rg -A 3 "findFirstByParticipationIdAndAssessmentTypeOrderByCompletionDateDesc"

# Check for AssessmentType enum usage in the context of results
rg -A 3 "AssessmentType.*Result"

Length of output: 15901

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

🧹 Outside diff range and nitpick comments (2)
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (2)

120-123: Consider enhancing error handling with specific error types

The error handling correctly updates the result state and notifies clients. However, consider differentiating between different types of failures to provide more specific feedback to users.

Consider this approach:

 catch (Exception e) {
     log.error("Could not generate feedback for exercise ID: {} and participation ID: {}", modelingExercise.getId(), participation.getId(), e);
+    String errorMessage = switch (e) {
+        case NetworkingException ne -> "AI service is temporarily unavailable";
+        case IllegalArgumentException iae -> "Invalid exercise configuration";
+        default -> "AI Feedback could not be generated";
+    };
     automaticResult.setSuccessful(false);
     automaticResult.setCompletionDate(null);
+    automaticResult.setFeedbackText(errorMessage);
     participation.addResult(automaticResult);
     this.resultWebsocketService.broadcastNewResult(participation, automaticResult);
-    throw new InternalServerErrorException("Something went wrong... AI Feedback could not be generated");
+    throw new InternalServerErrorException(errorMessage);
 }

209-232: Consider optimizing the duplicate submission check

The validation logic is correct but could be more efficient by avoiding the need to load all submission results.

Consider adding a database query to check for existing Athena results:

+    @Query("""
+        SELECT COUNT(r) > 0
+        FROM Result r
+        WHERE r.submission.id = :submissionId
+        AND r.assessmentType = :assessmentType
+        """)
+    boolean hasResultWithAssessmentType(@Param("submissionId") Long submissionId, @Param("assessmentType") AssessmentType assessmentType);

     private void checkLatestSubmissionHasAthenaResultOrThrow(StudentParticipation participation) {
         Optional<Submission> submissionOptional = participationService
             .findExerciseParticipationWithLatestSubmissionAndResultElseThrow(participation.getId())
             .findLatestSubmission();

         if (submissionOptional.isEmpty()) {
             throw new BadRequestAlertException("No legal submissions found", "submission", "noSubmission");
         }

         Submission submission = submissionOptional.get();
-        Result latestResult = submission.getLatestResult();
-
-        if (latestResult != null && latestResult.getAssessmentType() == AssessmentType.AUTOMATIC_ATHENA) {
+        if (resultRepository.hasResultWithAssessmentType(submission.getId(), AssessmentType.AUTOMATIC_ATHENA)) {
             log.debug("Submission ID: {} already has an Athena result. Skipping feedback generation.", submission.getId());
             throw new BadRequestAlertException(
                 "Submission already has an Athena result",
                 "submission",
                 "submissionAlreadyHasAthenaResult",
                 true
             );
         }
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 78e1a4a and 60d87fb.

📒 Files selected for processing (1)
  • src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.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

🔇 Additional comments (2)
src/main/java/de/tum/cit/aet/artemis/modeling/service/ModelingExerciseFeedbackService.java (2)

73-73: LGTM: Good validation placement

The new validation is correctly placed before the async processing, following the fail-fast principle.


172-172: LGTM: Proper feedback reference integration

The addition of the reference field enables inline feedback display on diagrams, which aligns with the PR objectives.

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.

Thanks for the fix

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

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, re-approve.

Copy link
Member

@maximiliansoelch maximiliansoelch 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, and works as expected 👍
Minor improvements, such as preventing spamming the request feedback button and highlighting the currently viewed feedback in the timeline, will be done in a follow-up PR.

@maximiliansoelch maximiliansoelch added ready to merge maintainer-approved The feature maintainer has approved the PR and removed ready for review labels Dec 8, 2024
@maximiliansoelch maximiliansoelch added this to the 7.7.5 milestone Dec 8, 2024
@krusche krusche changed the title Modeling exercises: Inline AI Feedback View Modeling exercises: Inline AI feedback view Dec 8, 2024
@krusche krusche merged commit 390d00c into develop Dec 8, 2024
40 of 44 checks passed
@krusche krusche deleted the feature/modeling/inline-ai-feedback branch December 8, 2024 16:16
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 athena Pull requests that affect the corresponding module client Pull requests that update TypeScript code. (Added Automatically!) maintainer-approved The feature maintainer has approved the PR modeling Pull requests that affect the corresponding module ready to merge server Pull requests that update Java code. (Added Automatically!) tests
Projects
Archived in project
Status: Done
Development

Successfully merging this pull request may close these issues.