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

Plagiarism checks: Same file comparison view feature #9789

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

Conversation

AjayvirS
Copy link
Contributor

@AjayvirS AjayvirS commented Nov 15, 2024

Checklist

General

  • I tested all changes and their related features with all corresponding user types on a test server.
  • This is a small issue that I tested locally and was confirmed by another developer on a test server.
  • I chose a title conforming to the naming conventions for pull requests.

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the client coding and design guidelines.
  • 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 documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.

Motivation and Context

Note: After discussing with @MarkusPaulsen, the issue was extended to improve the UI:

  • Instead of only clicked dropdown UI toggling, both dropdowns should be toggled
  • Hovering over a file in the opened dropdown should also be reflected in the other viewer
  • Handle cases if a file is selected which is named differently or missing altogther:
  • If file with this name does not exist in the other submission, do not simulate selection in other viewer (just close the dropdown)
  • If file exists in the other submission but is in a different position (index) in the dropdown, search for the index and show that file

In the majority of cases, there is no point in comparing different files in the plagiarism detection comparison viewer which can actually be misleading if different files contain similar content. This feature enables automatic selection of the file in viewer B when selecting a file from the dropown in viewer A.
(Fixes #5067)

Description

Added a fileSelectedSubject which listens on file selection changes in one instance and emits file selection changes in the other component. If the button for syncing files is enabled, the other instance triggers file selection in its own component.

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 2 Students
  • 1 Programming Exercise with multiple files
  • 2 Student submissions with identical submission to trigger plagiarism detection
  1. Log in to Artemis as Instructor
  2. Navigate to Course Management
  3. Create a programming exercise, make sure it has multiple files
  4. Log in as student 1 and submit specific lines of code (e.g. a very specific Regex pattern)
  5. Log in as student 2 and submit the same code as student 2
  6. Log in as instructor
  7. Navigate to "Exercises" tab
  8. Select the relevant exercise containing plagiarism submissions
  9. Click on "Plagiarism"
  10. Click on the plagiarism comparison
  11. Enable Syncing by clicking on "Sync Lock"
  12. In either viewer, select another file
  13. Observe the respective file in the other viewer also getting selected.

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

Class/File Line Coverage Confirmation (assert/expect)
split-pane-header.component.ts 90%

Screenshots

plagiarism_viewer_sync

Updated Functionality:
same_file_comparison_updated

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced interactivity in the plagiarism split view with new file selection and locking functionalities.
    • Added a toggle button for locking files, improving user control over file interactions.
  • Improvements

    • Introduced new input properties to various components for better data handling.
    • Updated HTML templates to support new functionalities and improve user experience through hover effects.
  • Style Updates

    • Added new CSS classes for improved visual feedback during interactions with file elements.

@github-actions github-actions bot added the client Pull requests that update TypeScript code. (Added Automatically!) label Nov 15, 2024
@github-actions github-actions bot added the tests label Nov 18, 2024
@AjayvirS AjayvirS marked this pull request as ready for review November 18, 2024 12:34
@AjayvirS AjayvirS requested a review from a team as a code owner November 18, 2024 12:34
@AjayvirS AjayvirS changed the title Feature/plagiarism checks/same file comparison view Feature/plagiarism-checks/same-file comparison-view Nov 18, 2024
@AjayvirS AjayvirS changed the title Feature/plagiarism-checks/same-file comparison-view Feature/plagiarism-checks/same-file-comparison-view Nov 18, 2024
@AjayvirS AjayvirS changed the title Feature/plagiarism-checks/same-file-comparison-view Plagiarism checks: same file comparison view Nov 18, 2024
@AjayvirS AjayvirS changed the title Plagiarism checks: same file comparison view Plagiarism checks: Same file comparison view Nov 18, 2024
Copy link

coderabbitai bot commented Nov 18, 2024

Walkthrough

The changes in this pull request involve enhancements to the plagiarism split view component in the web application. Key modifications include the addition of new input properties to various components, the introduction of subjects for managing file selection and visibility, and the implementation of lifecycle hooks for resource management. A new button for toggling file locking functionality is also added. Overall, these updates aim to improve interactivity and data handling within the plagiarism checking feature.

Changes

File Change Summary
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.html Added input properties fileSelectedSubject and isLockFilesEnabled to <jhi-text-submission-viewer>. Introduced a button for toggling lock files.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts Implemented OnDestroy, added new input property isLockFilesEnabled, and introduced subjects for handling file selection and visibility. Added toggleLockFiles method.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts Implemented OnInit and OnDestroy, added subscriptions for new subjects, and modified methods to handle file selection and visibility.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html Enhanced <jhi-split-pane-header> with new input properties: isLockFilesEnabled, fileSelectedSubject, showFilesSubject, and dropdownHoverSubject.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts Added new input properties for handling file selection and interactions.
src/main/webapp/app/exercises/shared/plagiarism/types/text/TextPlagiarismFileElement.ts Introduced a new interface TextPlagiarismFileElement with properties idx and file.
src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts Updated return type of mocked mapMatchesToElements method for type safety.
src/test/javascript/spec/component/plagiarism/plagiarism-header.component.spec.ts Added mock directive for TranslateDirective to facilitate testing.
src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts Modified tests to support parallel instances of SplitPaneHeaderComponent and added new tests for file selection and hover functionality.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.scss Added new CSS class .split-pane-header-color for styling.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.html Updated click and mouseenter event handlers for enhanced interactivity.
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.scss Added new CSS class .dropdown-item.hover for hover state styling.

Assessment against linked issues

Objective Addressed Explanation
Automatically select the same file for both submissions if it exists (5067) The changes introduce file locking, but it is unclear if they ensure automatic selection of the same file for both submissions.

Possibly related PRs

Suggested labels

small, bugfix, ready to merge

Suggested reviewers

  • HawKhiem
  • JohannesStoehr
  • SimonEntholzer
  • BBesrour
  • sachmii
  • Feras797
  • az108

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 generate docstrings to generate docstrings for this PR. (Experiment)
  • @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: 3

🧹 Outside diff range and nitpick comments (12)
src/main/webapp/app/exercises/shared/plagiarism/types/text/TextPlagiarismFileElement.ts (1)

1-1: Consider using path alias for better maintainability

The import path is quite deep. Consider adding a path alias in the tsconfig.json for the plagiarism-related components to make imports more maintainable.

Example configuration in tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "@plagiarism/*": ["app/exercises/shared/plagiarism/*"]
    }
  }
}

Then the import could be simplified to:

import { FileWithHasMatch } from '@plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component';
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.ts (1)

22-25: Consider enhancing the property declaration.

While the implementation is functionally correct, consider these improvements for better maintainability and clarity:

  1. Add an explicit access modifier
  2. Consider making it readonly if it's only modified through events
  3. Enhance the documentation to describe how this property affects child components
    /**
-     * Boolean to determine whether file locking is enabled.
+     * Controls the file locking functionality across child components.
+     * When enabled, it synchronizes file navigation between split views.
+     * Modified through isLockFilesEnabledChange events from plagiarism-header.
     */
-    isLockFilesEnabled: boolean = false;
+    public readonly isLockFilesEnabled = false;
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html (1)

1-7: Remove unnecessary 'this.' from template binding

The template binding syntax this.isLockFilesEnabled is not recommended in Angular templates as component properties are automatically bound to the component's context.

Apply this diff:

<jhi-split-pane-header
    [files]="files"
-    [isLockFilesEnabled]="this.isLockFilesEnabled"
+    [isLockFilesEnabled]="isLockFilesEnabled"
    [fileSelectedSubject]="fileSelectedSubject"
    (selectFile)="handleFileSelect($event)"
    studentLogin="{{ plagiarismSubmission?.studentLogin }}"
/>
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.html (1)

26-29: LGTM with accessibility enhancement suggestions.

The implementation looks good with proper event binding, state management, and localization. Consider these accessibility improvements:

  1. Add type="button" attribute to prevent form submission
  2. Add aria-pressed attribute to indicate toggle state

Apply this diff to enhance accessibility:

-        <button class="btn btn-outline-secondary btn-sm" (click)="toggleLockFiles()" [class.active]="isLockFilesEnabled" data-qa="lock-files-toggle-button">
+        <button 
+            type="button"
+            class="btn btn-outline-secondary btn-sm" 
+            (click)="toggleLockFiles()" 
+            [class.active]="isLockFilesEnabled"
+            [attr.aria-pressed]="isLockFilesEnabled"
+            data-qa="lock-files-toggle-button">
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (2)

19-31: Add access modifier to subscription property.

The fileSelectSubscription property should have an access modifier for better encapsulation. Also, consider initializing it as undefined to make the type more precise.

-    fileSelectSubscription: Subscription;
+    private fileSelectSubscription?: Subscription;

35-41: Enhance subscription handling with error handling and completion.

The subscription should handle potential errors and completion. Also, consider using RxJS operators to handle the file existence check more elegantly.

     ngOnInit(): void {
-        this.fileSelectSubscription = this.fileSelectedSubject.subscribe((val) => {
-            if (val.file && this.isLockFilesEnabled) {
-                this.handleFileSelectWithoutPropagation(val.file, val.idx);
-            }
-        });
+        this.fileSelectSubscription = this.fileSelectedSubject.pipe(
+            filter(val => val.file !== null && val.file !== undefined && this.isLockFilesEnabled)
+        ).subscribe({
+            next: (val) => this.handleFileSelectWithoutPropagation(val.file, val.idx),
+            error: (error) => console.error('Error in file selection:', error)
+        });
     }
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.ts (2)

23-29: Add explicit type for EventEmitter.

While the code is functionally correct, consider adding an explicit type for better type safety:

-@Output() isLockFilesEnabledChange = new EventEmitter<boolean>();
+@Output() isLockFilesEnabledChange: EventEmitter<boolean> = new EventEmitter<boolean>();

Line range hint 13-19: Add component-level documentation for the locking feature.

Consider adding a class-level JSDoc comment to explain the purpose and usage of the file locking feature in the context of plagiarism detection:

/**
 * Component that handles the header section of the plagiarism detection view.
 * Provides controls for:
 * - Confirming or denying plagiarism
 * - Expanding/resetting split panes
 * - Toggling file locking for synchronized comparison view
 */
@Component({
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts (2)

31-31: Add JSDoc documentation for the input property.

Please add JSDoc documentation to explain the purpose and behavior of the isLockFilesEnabled property. This will help other developers understand when and how to use this feature.

Example:

/** Controls whether files can be locked in the split view for comparison. */
@Input() isLockFilesEnabled = false;

Line range hint 1-180: Consider architectural improvements for maintainability.

The component could benefit from the following architectural improvements:

  1. Extract the file comparison logic into a dedicated service to improve testability and reusability
  2. Use OnDestroy interface to properly handle cleanup of subscriptions and subjects
  3. Consider using BehaviorSubject for fileSelectedSubject if initial state is important
  4. Add comprehensive documentation for the file locking feature

Would you like assistance in implementing any of these improvements?

src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts (1)

173-173: LGTM! Consider enhancing test coverage.

The change to use a strongly-typed mock return value Map<string, FromToElement[]> improves type safety. However, consider adding test cases to verify the structure and content of the mapped elements.

Add test cases to verify:

  1. The structure of the returned map matches the expected type
  2. Edge cases with empty or malformed FromToElement arrays
  3. Error handling when mapping fails

Example test case:

it('should return correctly structured map from mapMatchesToElements', () => {
    const matches = [{ start: 0, length: 2 }] as SimpleMatch[];
    const submission = {
        elements: [
            { id: 1, file: 'test.txt', column: 1, line: 1 },
            { id: 2, file: 'test.txt', column: 2, line: 2 }
        ]
    } as PlagiarismSubmission<TextSubmissionElement>;
    
    const result = comp.mapMatchesToElements(matches, submission);
    
    expect(result).toBeInstanceOf(Map);
    expect(result.get('none')).toBeInstanceOf(Array);
    expect(result.get('none')?.[0]).toBeInstanceOf(FromToElement);
    expect(result.get('none')?.[0].from).toEqual(submission.elements[0]);
    expect(result.get('none')?.[0].to).toEqual(submission.elements[1]);
});
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts (1)

31-32: LGTM! Input properties are well-defined.

The new input properties follow Angular's style guide:

  • fileSelectedSubject uses the definite assignment operator correctly
  • isLockFilesEnabled has an appropriate default value
  • Both use camelCase naming convention

However, consider adding JSDoc comments to document these properties' purposes, similar to other properties in this component.

Apply this diff to improve documentation:

+    /**
+     * Subject for broadcasting selected file changes.
+     */
     @Input() fileSelectedSubject!: Subject<TextPlagiarismFileElement>;
+    /**
+     * Flag indicating whether file locking functionality is enabled.
+     */
     @Input() isLockFilesEnabled = false;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1786886 and f02813f.

📒 Files selected for processing (13)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.ts (4 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.html (2 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts (4 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (4 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts (2 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/types/text/TextPlagiarismFileElement.ts (1 hunks)
  • src/main/webapp/i18n/de/plagiarism.json (1 hunks)
  • src/main/webapp/i18n/en/plagiarism.json (1 hunks)
  • src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.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/shared/plagiarism/plagiarism-details/plagiarism-details.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/plagiarism/plagiarism-header/plagiarism-header.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/shared/plagiarism/plagiarism-header/plagiarism-header.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/plagiarism/plagiarism-split-view/plagiarism-split-view.component.html (1)

Pattern src/main/webapp/**/*.html: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts (1)

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

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.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/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.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/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.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/plagiarism/types/text/TextPlagiarismFileElement.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/i18n/de/plagiarism.json (1)

Pattern src/main/webapp/i18n/de/**/*.json: German language translations should be informal (dutzen) and should never be formal (sietzen). So the user should always be addressed with "du/dein" and never with "sie/ihr".

src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts (1)

Pattern src/test/javascript/spec/**/*.ts: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}

🔇 Additional comments (18)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.html (3)

1-1: LGTM! Follows new Angular syntax guidelines.

The template correctly uses the new @if syntax instead of the older *ngIf.


3-4: LGTM! Event binding for file locking is properly implemented.

The jhi-plagiarism-header component correctly implements the output event binding (isLockFilesEnabledChange) to update the parent component's state.

Let's verify the event emitter declaration in the header component:

✅ Verification successful

Event binding implementation verified successfully

The isLockFilesEnabledChange is properly declared as an @Output() EventEmitter of type boolean in the PlagiarismHeaderComponent, matching the event binding usage in the template. The implementation is correct and follows Angular's best practices for component communication.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the event emitter declaration in the header component
# Expected: Should find @Output() isLockFilesEnabledChange declaration

ast-grep --pattern 'class PlagiarismHeaderComponent {
  $$$
  @Output() isLockFilesEnabledChange
  $$$
}'

Length of output: 404


Script:

#!/bin/bash
# Let's try a different approach to find the component file first
fd "plagiarism-header.component.ts" --type f

# Then we'll use ripgrep to search for the event emitter
rg "@Output\(\)\s+isLockFilesEnabledChange" -l

Length of output: 287


Script:

#!/bin/bash
# Let's examine the actual implementation to verify the event emitter type and usage
rg -A 5 "@Output\(\)\s+isLockFilesEnabledChange" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.ts

Length of output: 407


6-7: LGTM! Input property binding for file locking is properly implemented.

The jhi-plagiarism-split-view component correctly receives the isLockFilesEnabled state through input binding.

Let's verify the input property declaration in the split view component:

✅ Verification successful

Input property binding for file locking is correctly implemented and used

The isLockFilesEnabled input property is properly declared in the PlagiarismSplitViewComponent with a default value of false, confirming that the property binding in the template is valid and working as expected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the input property declaration in the split view component
# Expected: Should find @Input() isLockFilesEnabled declaration

ast-grep --pattern 'class PlagiarismSplitViewComponent {
  $$$
  @Input() isLockFilesEnabled
  $$$
}'

Length of output: 404


Script:

#!/bin/bash
# Let's try a different approach to find the component file first
fd "plagiarism-split-view.component.ts"

# Then we'll use ripgrep to search for the input property
rg "@Input\(\)\s+isLockFilesEnabled" -l

Length of output: 539


Script:

#!/bin/bash
# Let's check the actual implementation of isLockFilesEnabled in these components
rg "@Input\(\)\s+isLockFilesEnabled" -A 2 src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts

# Also check how it's being used in the component
rg "isLockFilesEnabled" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts

Length of output: 437

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.ts (1)

21-25: Verify template bindings and component integration.

Let's ensure that the template properly connects this property with the child components mentioned in the summary.

✅ Verification successful

Property is correctly integrated with template and child components

The verification confirms proper implementation:

  • Template correctly binds isLockFilesEnabled between parent and child components
  • PlagiarismHeaderComponent has matching @Output() isLockFilesEnabledChange with toggle functionality
  • isLockFilesEnabled is passed as input to PlagiarismSplitViewComponent
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify template bindings and component integration

# Check template bindings in the component's template
echo "Checking template bindings..."
rg -A 5 "isLockFilesEnabled" --glob "src/main/webapp/app/exercises/shared/plagiarism/plagiarism-details/plagiarism-details.component.html"

# Check if child components are properly typed to handle this property
echo "Checking child component interfaces..."
ast-grep --pattern 'class PlagiarismHeaderComponent {
  $$$
  @Output() isLockFilesEnabledChange
  $$$
}'

ast-grep --pattern 'class PlagiarismSplitViewComponent {
  $$$
  @Input() isLockFilesEnabled
  $$$
}'

Length of output: 12277

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html (1)

Line range hint 8-40: LGTM! Well-structured conditional blocks with proper error handling

The implementation:

  • Correctly uses the new Angular @if syntax
  • Provides clear user feedback for different states
  • Follows accessibility best practices
  • Properly implements internationalization
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.html (2)

8-15: LGTM! Correct usage of new Angular syntax and property bindings.

The component correctly uses the new @if syntax and properly implements the new input properties for file selection and locking functionality.


30-34: Verify the synchronized file selection behavior.

While the implementation is correct, both viewers share the same fileSelectedSubject. Please verify that this synchronization is intentional and properly handled in the component logic to avoid confusing user interactions.

✅ Verification successful

Based on the shell script results, I can now generate the final response as I have found clear evidence of how the fileSelectedSubject is handled in the codebase:

File selection synchronization is intentionally designed and properly handled

The synchronization between both viewers through fileSelectedSubject is a well-implemented feature:

  • The split-pane-header component handles file selection and propagates it through fileSelectedSubject with proper indexing to identify the source viewer
  • The text-submission-viewer component subscribes to these events and only reacts when isLockFilesEnabled is true
  • The implementation includes safeguards like handleFileSelectWithoutPropagation to prevent infinite loops
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how fileSelectedSubject is handled in the component

# Look for fileSelectedSubject subscription handling
ast-grep --pattern 'fileSelectedSubject.subscribe($$$)'

# Check for any methods that might handle file selection
rg -A 5 "fileSelected|handleFile|onFileSelect" 

Length of output: 30771

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.html (1)

28-28: Verify translation keys exist.

Please ensure that the translation keys artemisApp.plagiarism.unlockSync and artemisApp.plagiarism.lockSync are defined in the localization files.

✅ Verification successful

Translation keys are properly defined

Both translation keys artemisApp.plagiarism.lockSync and artemisApp.plagiarism.unlockSync are correctly defined in both English and German translation files:

  • English:
    • lockSync: "Lock Sync"
    • unlockSync: "Unlock Sync"
  • German:
    • lockSync: "Sync sperren"
    • unlockSync: "Sync entsperren"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the translation keys exist in the localization files

# Search for the translation keys in the i18n files
echo "Checking English translations..."
rg "artemisApp\.plagiarism\.(un)?lockSync" src/main/webapp/i18n/en/*.json

echo "Checking German translations..."
rg "artemisApp\.plagiarism\.(un)?lockSync" src/main/webapp/i18n/de/*.json

Length of output: 13851


Script:

#!/bin/bash
# Let's check the specific translation files for plagiarism-related keys
echo "Checking English plagiarism translations..."
cat src/main/webapp/i18n/en/plagiarism.json

echo -e "\nChecking German plagiarism translations..."
cat src/main/webapp/i18n/de/plagiarism.json

Length of output: 21082

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (3)

1-4: LGTM! Import statements and type declarations are well-organized.

The imports follow the Angular style guide and are properly organized by category (Angular core, third-party, and application imports).


Line range hint 69-90: LGTM! File handling methods are well-implemented and documented.

The methods follow single responsibility principle and have clear documentation. The separation between propagating and non-propagating file selection is well thought out.


Line range hint 19-90: Verify subscription handling in related components.

The component handles its own subscription cleanup well, but we should verify that related components using fileSelectedSubject also properly handle their subscriptions to prevent memory leaks.

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-header/plagiarism-header.component.ts (2)

1-1: LGTM! Import statements follow Angular guidelines.

The new imports are properly organized and follow Angular's style guide recommendations.

Also applies to: 11-11


86-92: 🛠️ Refactor suggestion

Consider memory leak prevention and add unit tests.

While the implementation is clean, consider these improvements:

  1. Ensure proper cleanup of the EventEmitter in the component's OnDestroy lifecycle hook
  2. Add unit tests to verify the toggle behavior and event emission

Add the following cleanup code:

export class PlagiarismHeaderComponent implements OnDestroy {
    // ... existing code ...

    ngOnDestroy() {
        this.isLockFilesEnabledChange.complete();
    }
}

Let's check for existing tests:

src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component.ts (1)

13-13: LGTM!

The import follows Angular style guide conventions and is correctly placed with other imports.

src/main/webapp/i18n/en/plagiarism.json (1)

7-8: LGTM! Please ensure German translations are added.

The new entries are clear, concise, and properly formatted. They follow the existing naming patterns and maintain consistency with other translations.

Let's verify that corresponding German translations are added:

✅ Verification successful

German translations are already in place and accurate

The German translations for both "lockSync" and "unlockSync" are properly implemented:

  • "Sync sperren" (Lock Sync)
  • "Sync entsperren" (Unlock Sync)

The translations are semantically correct and follow German language conventions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if German translations exist for the new entries

# Check for German translations
rg -A 2 '"lockSync"|"unlockSync"' src/main/webapp/i18n/de/plagiarism.json

Length of output: 565

src/main/webapp/i18n/de/plagiarism.json (1)

7-8: LGTM! The German translations are accurate and consistent.

The new translations for sync locking functionality are:

  • Grammatically correct
  • Use appropriate technical terminology
  • Follow the imperative form suitable for action buttons
  • Consistent with the existing translation style
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts (2)

15-16: LGTM! Imports are properly organized.

The new imports follow Angular style guide and are necessary for the new functionality.


31-32: Verify the usage of new input properties.

The new input properties don't have any handlers in the component's logic. Let's verify:

  1. Is fileSelectedSubject only used for output to parent components?
  2. Is isLockFilesEnabled only used for UI control in the template?
✅ Verification successful

Input properties are correctly used as template bindings only

Both properties are used appropriately as template bindings without requiring component logic handlers:

  • fileSelectedSubject is passed down to a child component via template binding
  • isLockFilesEnabled is used for UI control via template binding

No changes are needed as this is a valid pattern for input properties that only affect template rendering or are passed to child components.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of new input properties in the component and its template

# Check if fileSelectedSubject is used in component logic
echo "Checking fileSelectedSubject usage in component logic..."
rg -l "fileSelectedSubject" src/main/webapp/app/exercises/shared/plagiarism/

# Check if isLockFilesEnabled is used in component logic
echo "Checking isLockFilesEnabled usage in component logic..."
rg -l "isLockFilesEnabled" src/main/webapp/app/exercises/shared/plagiarism/

# Check template usage
echo "Checking template usage..."
fd -e html . src/main/webapp/app/exercises/shared/plagiarism/ -x rg -l "fileSelectedSubject|isLockFilesEnabled" {}

Length of output: 2594


Script:

#!/bin/bash
# Let's check the actual usage of these properties in the component and related files

# Check how fileSelectedSubject is used in the component and its template
echo "=== fileSelectedSubject usage in text-submission-viewer ==="
rg "fileSelectedSubject" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts -A 3
echo "\n=== fileSelectedSubject in template ==="
rg "fileSelectedSubject" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html

# Check how isLockFilesEnabled is used
echo "\n=== isLockFilesEnabled usage in text-submission-viewer ==="
rg "isLockFilesEnabled" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts -A 3
echo "\n=== isLockFilesEnabled in template ==="
rg "isLockFilesEnabled" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.html

# Check if component implements OnChanges and how
echo "\n=== OnChanges implementation ==="
ast-grep --pattern 'class TextSubmissionViewerComponent implements $_ {
    $$$
    ngOnChanges($_) {
        $$$
    }
    $$$
}'

Length of output: 1721

…ile-comparison-view' into feature/plagiarism-checks/same-file-comparison-view
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 (3)
src/test/javascript/spec/component/plagiarism/plagiarism-header.component.spec.ts (3)

Line range hint 48-57: Improve test specificity using recommended assertions.

The test cases for button disabled states can be improved by using the recommended assertion patterns from our coding guidelines.

Update the assertions to use the recommended patterns:

 expect(button.disabled).toBeTrue();

This assertion already follows our guidelines for boolean checks using toBeTrue(). However, consider adding more specific assertions to validate the complete state:

expect(button).toContainEntries([
    ['disabled', true],
    ['label', expect.any(String)
]);

Also applies to: 74-83


Line range hint 85-96: Improve spy assertions using recommended patterns.

The test case for modal interaction can be improved using our recommended spy assertion patterns.

Update the spy assertions to use the recommended patterns:

-expect(comp.updatePlagiarismStatus).not.toHaveBeenCalled();
-expect(modalSpy).toHaveBeenCalledOnce();
+expect(comp.updatePlagiarismStatus).not.toHaveBeenCalled();
+expect(modalSpy).toHaveBeenCalledExactlyOnceWith(expect.any(Object));

Line range hint 18-45: Add test coverage for isLockFilesEnabledChange functionality.

The AI summary indicates that the component has a new @Output property isLockFilesEnabledChange, but there are no tests covering this functionality. Please add test cases to verify:

  1. The output event emission
  2. Integration with file locking state changes

Here's a suggested test case structure:

it('should emit isLockFilesEnabledChange when toggling file lock', () => {
    const emitSpy = jest.spyOn(comp.isLockFilesEnabledChange, 'emit');
    
    comp.toggleFileLock();
    
    expect(emitSpy).toHaveBeenCalledExactlyOnceWith(expect.any(Boolean));
});
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f02813f and bbdb814.

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

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 (1)
src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts (1)

Line range hint 51-126: Add tests for fileSelectedSubject functionality

While the existing tests cover the basic component functionality well, we should add tests for the new fileSelectedSubject behavior.

Add these test cases:

it('should emit selected file through fileSelectedSubject', () => {
    // Arrange
    const selectedFile = new TextPlagiarismFileElement();
    let emittedFile: TextPlagiarismFileElement | undefined;
    comp.fileSelectedSubject.subscribe((file) => {
        emittedFile = file;
    });
    
    // Act
    comp.fileSelectedSubject.next(selectedFile);
    
    // Assert
    expect(emittedFile).toBe(selectedFile);
});

it('should handle file selection with locked files', () => {
    // Arrange
    comp.isLockFilesEnabled = true;
    const idx = 1;
    jest.spyOn(comp.fileSelectedSubject, 'next');
    
    // Act
    comp.handleFileSelect(files[idx], idx);
    
    // Assert
    expect(comp.fileSelectedSubject.next).toHaveBeenCalledExactlyOnceWith(
        expect.objectContaining({ file: files[idx].file })
    );
});
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between bbdb814 and efb80bd.

📒 Files selected for processing (1)
  • src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/javascript/spec/component/plagiarism/split-pane-header.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/plagiarism/split-pane-header.component.spec.ts (1)

13-14: LGTM: Proper setup of reactive components

The addition of TextPlagiarismFileElement type and Subject from rxjs is well integrated into the component setup.

Also applies to: 47-47

b-fein
b-fein previously requested changes Nov 18, 2024
Copy link
Contributor

@b-fein b-fein left a comment

Choose a reason for hiding this comment

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

Please fill in the motivation, description, and steps for testing in the PR description. Is/was there a related issue that is fixed by this PR?

Otherwise, it is really hard to understand if this PR is a new feature or if it fixes an issue (please adapt the PR title accordingly). Without the information I don’t really know what to look out for during a review.

@ls1intum ls1intum deleted a comment from coderabbitai bot Nov 18, 2024
kevinfischer4
kevinfischer4 previously approved these changes Dec 9, 2024
Copy link

@kevinfischer4 kevinfischer4 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. The comparison view works as expected.
Screenshot from 2024-12-09 22-26-08

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 (1)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (1)

Line range hint 1-15: Consider enhancing type safety for FileWithHasMatch

The type definition could benefit from being more strict to prevent potential runtime issues.

-export type FileWithHasMatch = {
+export interface FileWithHasMatch {
     file: string;
     hasMatch: boolean;
 };
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 442d81f and 8e9a155.

📒 Files selected for processing (2)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.scss (1 hunks)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.scss
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.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

🔇 Additional comments (4)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (4)

58-66: Improve readability of file selection logic

The conditional logic could be more readable using a more functional approach.

     private handleLockedFileSelection(file: FileWithHasMatch, idx: number): void {
-        const index = this.files[idx]?.file === file.file ? idx : this.getIndexOf(file);
-
-        if (index >= 0) {
-            this.handleFileSelect(file, index, false);
-        } else {
-            this.showFiles = false;
-        }
+        const index = this.files[idx]?.file === file.file 
+            ? idx 
+            : this.getIndexOf(file);
+
+        index >= 0
+            ? this.handleFileSelect(file, index, false)
+            : this.showFiles = false;
     }

19-39: 🛠️ Refactor suggestion

Maintain consistency in input declarations

The component mixes traditional @Input decorators with modern signal-based inputs. For better maintainability and consistency with Angular's latest practices, consider migrating all inputs to signals.

-    @Input() files: FileWithHasMatch[];
-    @Input() studentLogin: string;
+    files = input<FileWithHasMatch[]>();
+    studentLogin = input<string>();

50-56: ⚠️ Potential issue

Improve subscription error handling and null safety

The subscription lacks error handling and uses non-null assertions which could lead to runtime errors.

     private subscribeToFileSelection(): void {
-        this.fileSelectSubscription = this.fileSelectedSubject()!.subscribe((textPlagiarismElement) => {
-            if (this.isLockFilesEnabled()) {
-                this.handleLockedFileSelection(textPlagiarismElement.file, textPlagiarismElement.idx);
-            }
-        });
+        const subject = this.fileSelectedSubject();
+        if (subject) {
+            this.fileSelectSubscription = subject.subscribe({
+                next: (textPlagiarismElement) => {
+                    if (this.isLockFilesEnabled()) {
+                        this.handleLockedFileSelection(textPlagiarismElement.file, textPlagiarismElement.idx);
+                    }
+                },
+                error: (error) => {
+                    console.error('Error in file selection:', error);
+                }
+            });
+        }
     }

110-114: Verify subscription cleanup

The component properly unsubscribes from all subscriptions in ngOnDestroy, which is good practice for preventing memory leaks.

✅ Verification successful

All subscriptions are properly managed

The component correctly handles all subscriptions:

  • All three input Subjects (fileSelectedSubject, showFilesSubject, dropdownHoverSubject) have corresponding subscriptions (fileSelectSubscription, showFilesSubscription, dropdownHoverSubscription)
  • All subscriptions are properly cleaned up in the ngOnDestroy method
  • No other subscriptions or observables are found that would require cleanup
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify that all Subject declarations have corresponding cleanup
rg -A 5 "Subject.*=.*input" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts

Length of output: 503


Script:

#!/bin/bash
# Let's verify all subscriptions in the component
rg -A 2 "subscription.*=" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts

# Also check for any other Subject or Observable declarations
rg "(Subject|Observable|subscription)" src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts

Length of output: 1148

…ile-comparison-view' into feature/plagiarism-checks/same-file-comparison-view
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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8e9a155 and 9973ade.

📒 Files selected for processing (1)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.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

🔇 Additional comments (5)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (5)

1-1: Migrate remaining @input properties to signals for consistency

The component mixes traditional @Input decorators with modern signal-based inputs. For better maintainability and consistency with Angular's latest practices, consider migrating all inputs to signals.

Also applies to: 19-25


32-34: LGTM: Proper subscription management implemented

The component correctly manages subscriptions by:

  • Declaring subscription properties
  • Initializing in ngOnInit
  • Cleaning up in ngOnDestroy

Also applies to: 40-44, 110-114


130-138: LGTM: Well-documented event handlers with clear parameters

The event handlers are properly documented and have clear parameter names that indicate their purpose.

Also applies to: 149-157


141-141: LGTM: Well-implemented utility methods

The utility methods are concise and follow best practices:

  • hasFiles uses nullish coalescing for null safety
  • getIndexOf is well-documented and uses appropriate array methods

Also applies to: 168-170


159-161: ⚠️ Potential issue

Improve null safety in triggerMouseEnter

The method uses a non-null assertion which could lead to runtime errors.

Apply this diff:

 triggerMouseEnter(file: FileWithHasMatch, idx: number) {
-    this.dropdownHoverSubject()!.next({ idx: idx, file: file });
+    const subject = this.dropdownHoverSubject();
+    if (subject) {
+        subject.next({ idx, file });
+    }
 }

Likely invalid or redundant comment.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (2)

38-38: Initialize hoveredFileIndex

The hoveredFileIndex property should be initialized to prevent potential undefined behavior.

-    hoveredFileIndex: number;
+    hoveredFileIndex = -1;

141-141: Simplify boolean expression

The double negation operator can be replaced with a more straightforward expression.

-        return !!this.files?.length;
+        return Boolean(this.files?.length);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9973ade and 8aa0c0f.

📒 Files selected for processing (1)
  • src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.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

🔇 Additional comments (3)
src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts (3)

Line range hint 1-19: Consider full migration to signals and standalone component

While the component has started using signals for some inputs, it still uses traditional @Input decorators for others. For consistency and better maintainability:

  1. Migrate remaining @Input properties to signals
  2. Consider converting to standalone component in a separate PR

Apply this diff to migrate remaining inputs:

-    @Input() files: FileWithHasMatch[];
-    @Input() studentLogin: string;
+    files = input<FileWithHasMatch[]>();
+    studentLogin = input<string>();

72-78: 🛠️ Refactor suggestion

Simplify conditional logic and improve null safety

The subscription method has complex nested conditionals and uses non-null assertions which could be simplified and made safer.

     private subscribeToShowFiles(): void {
-        this.showFilesSubscription = this.showFilesSubject()?.subscribe((showFiles) => {
-            if (this.isLockFilesEnabled()! || (!this.isLockFilesEnabled()! && !showFiles)) {
-                this.toggleShowFiles(false, showFiles);
-            }
-        });
+        const subject = this.showFilesSubject();
+        if (subject) {
+            this.showFilesSubscription = subject.subscribe({
+                next: (showFiles) => {
+                    const isLocked = this.isLockFilesEnabled();
+                    if (isLocked || (!isLocked && !showFiles)) {
+                        this.toggleShowFiles(false, showFiles);
+                    }
+                },
+                error: (error) => {
+                    console.error('Error in show files subscription:', error);
+                }
+            });
+        }
     }

130-138: 🛠️ Refactor suggestion

Improve null safety in handleFileSelect

The method uses non-null assertion which could lead to runtime errors.

     handleFileSelect(file: FileWithHasMatch, idx: number, propagateChanges: boolean): void {
         if (propagateChanges) {
-            this.fileSelectedSubject()!.next({ idx: idx, file: file });
+            const subject = this.fileSelectedSubject();
+            if (subject) {
+                subject.next({ idx, file });
+                file.hasMatch = true;
+            }
-            file.hasMatch = true;
         }
         this.activeFileIndex = idx;
         this.showFiles = false;
         this.selectFile.emit(file.file);
     }

@sachmii sachmii temporarily deployed to artemis-test4.artemis.cit.tum.de December 11, 2024 12:48 — with GitHub Actions Inactive
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 TS4, reapprove

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!) lock:artemis-test4 ready for review tests
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

Plagiarism checks: Automatically select same file for both submissions in file comparison view