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

Communication: Allow users to reference FAQs in post #9566

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

Conversation

cremertim
Copy link
Contributor

@cremertim cremertim commented Oct 23, 2024

Checklist

General

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the client coding and design guidelines.
  • 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.
  • I translated all newly inserted strings into English and German.

Motivation and Context

We introduced the new FAQ feature. For now, it is not able to directly reference a FAQ. It is cumbersome for Students to manually navigate into the FAQ section and manually search for the corresponding FAQ, if they are hinted to it.

Description

The markdown editor now offers a new Action: FAQ-Reference Action. IT will create a link to the corresponding FAQ, and automatically scrolles to the referenced FAQ.

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 1 Course with FAQ Enabled
  1. Log in to Artemis
  2. Navigate to Course Overview
  3. Create a new post in a channel
  4. See the FAQ reference button and click on it
  5. Make sure, only FAQs in the state ACCEPTED are in the list (you can find this on the faq management page)
  6. Create a reference to an existing FAQ.
  7. Click on the reference -> you should be forwarded to faq overvier and it automatically scrolls to the FAQ you referenced
  8. Go to Course Management
  9. Go to Edit Course
  10. Uncheck box 'Faq Enabled'
  11. Verify that you cannot reference a faq in this course

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

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Class/File Line Coverage Confirmation (assert/expect)
course-faq.component.ts 98.61%
course-overview.component.ts 85.25%
metis.service.ts 85.92%
posting-content.components.ts 97.46%
posting-markdown-editor.component.ts 100%
faq-reference-action 95%

Screenshots

image

Summary by CodeRabbit

Release Notes

  • New Features

    • Integrated FAQ functionality into the course model, allowing courses to have associated FAQs.
    • Enhanced the FAQ component with sorting and dynamic scrolling capabilities.
    • Added methods for fetching and displaying FAQs related to courses.
    • Introduced a new action in the text editor for inserting FAQ references.
    • Added a method for generating router links to the FAQ section of a course.
    • Included a new icon for FAQ references in the posting content.
    • Expanded the data model to include frequently asked questions associated with courses.
  • Bug Fixes

    • Improved error handling during course loading, including specific checks for unauthorized access.
  • Documentation

    • Expanded localization support by adding entries for FAQs in multiple languages.
  • Tests

    • Added new test cases to ensure correct handling of FAQ references in components and services.

Walkthrough

The changes in this pull request involve enhancements related to Frequently Asked Questions (FAQs) across multiple components of the application. Key modifications include the introduction of new properties and methods in the Course model to manage FAQs, updates to the CourseFaqComponent for dynamic scrolling and sorting of FAQ items, and enhancements in the CourseOverviewComponent for fetching FAQs. Additionally, new routing capabilities for FAQs are added in the MetisService, alongside updates to localization files and test suites to ensure comprehensive coverage of the new features.

Changes

File Change Summary
src/main/webapp/app/entities/course.model.ts Added import for Faq, new function `isFaqEnabled(course: Course
src/main/webapp/app/overview/course-faq/course-faq.component.html Simplified <hr> element and added a <div> wrapper around <jhi-course-faq-accordion> with id and template reference variable.
src/main/webapp/app/overview/course-faq/course-faq.component.ts Added imports, properties for faqId and faqElements, and methods sortFaqs() and scrollToFaq(faqId: number). Updated ngOnInit to handle faqId from query parameters.
src/main/webapp/app/overview/course-overview.component.ts Added Faq and FaqService imports, introduced method `setFaqs(course: Course
src/main/webapp/app/shared/metis/metis.service.ts Added method getLinkForFaq(): string to generate a router link for FAQs.
src/main/webapp/app/shared/metis/metis.util.ts Updated ReferenceType enum to include FAQ.
src/main/webapp/app/shared/metis/posting-content/posting-content-part/posting-content-part.components.ts Added faQuestion icon for ReferenceType.FAQ in referenceIcon method.
src/main/webapp/app/shared/metis/posting-content/posting-content.components.ts Updated computePostingContentParts method to handle FAQ references and modified regex in getPatternMatches to include [faq]...[/faq].
src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts Imported isFaqEnabled and FaqReferenceAction, integrated FAQ action into ngOnInit.
src/main/webapp/app/shared/monaco-editor/model/actions/communication/faq-reference.action.ts Introduced FaqReferenceAction class for inserting FAQ references in the text editor.
src/main/webapp/i18n/de/metis.json Added localization entry "faq": "FAQ" in German.
src/main/webapp/i18n/en/metis.json Added localization entry "faq": "FAQ" in English.
src/test/javascript/spec/component/overview/course-faq/course-faq.component.spec.ts Updated tests to include SortService, added tests for sorting and scrolling FAQs.
src/test/javascript/spec/component/shared/metis/posting-content/posting-content.component.spec.ts Added test for computing parts when referencing a FAQ.
src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts Added tests for PostingMarkdownEditorComponent to validate behavior with FAQ feature toggled on and off.
src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-communication-action.integration.spec.ts Updated tests to include FaqReferenceAction.
src/test/javascript/spec/helpers/mocks/service/mock-metis-service.service.ts Added method getLinkForFaq() to MockMetisService.
src/test/javascript/spec/helpers/sample/metis-sample-data.ts Introduced constants metisFaq1, metisFaq2, metisFaq3 and added them to metisCourse under faqs.
src/test/javascript/spec/service/metis/metis.service.spec.ts Added test case for getLinkForFaq() method in MetisService.

Possibly related PRs

Suggested labels

ready to merge, communication, small, bugfix

Suggested reviewers

  • JohannesWt
  • florian-glombik
  • az108
  • rabeatwork
  • krusche
  • Malekos74

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.

@cremertim cremertim requested a review from a team as a code owner October 23, 2024 09:05
@github-actions github-actions bot added tests client Pull requests that update TypeScript code. (Added Automatically!) labels Oct 23, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🧹 Outside diff range and nitpick comments (8)
src/main/webapp/app/shared/metis/metis.util.ts (1)

108-108: Add JSDoc documentation for the FAQ enum value.

Consider adding JSDoc documentation to describe the FAQ reference type, similar to how interfaces like PostingContentPart are documented.

     CHANNEL = 'CHANNEL',
+    /** References to Frequently Asked Questions (FAQs) in course content */
     FAQ = 'FAQ',
src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (1)

90-90: Consider grouping related actions together.

The FAQ action could be grouped with other communication-related actions for better organization. Consider moving it next to messagingOnlyActions since they're both communication features.

         new CodeAction(),
         new CodeBlockAction(),
         ...messagingOnlyActions,
+        ...faqAction,
         new ExerciseReferenceAction(this.metisService),
-        ...faqAction,
src/main/webapp/app/entities/course.model.ts (1)

32-37: Consider adding return type annotation for consistency

The function implementation is clean and follows the established pattern. For better type safety and consistency with TypeScript best practices, consider adding an explicit return type annotation.

-export function isFaqEnabled(course: Course | undefined) {
+export function isFaqEnabled(course: Course | undefined): boolean {
src/main/webapp/app/shared/metis/posting-content/posting-content.components.ts (2)

208-208: Update regex pattern documentation.

The comments above the regex pattern need to be updated to include the description for the FAQ group (Group 13).

Update the comments above the pattern to include:

// Group 13: reference pattern for FAQs

119-122: Consider refactoring reference type handling for better maintainability.

As more reference types are added (like FAQ), the computePostingContentParts method becomes increasingly complex with multiple if-else blocks. Consider refactoring this to use a strategy pattern or a map of handlers for better maintainability.

Here's a suggested approach:

interface ReferenceHandler {
    extractReferenceStr(content: string, match: PatternMatch): string;
    extractLinkAndParams(content: string, match: PatternMatch): { link?: string[], params?: Params };
}

private referenceHandlers = new Map<ReferenceType, ReferenceHandler>([
    [ReferenceType.FAQ, {
        extractReferenceStr: (content, match) => 
            content.substring(content.indexOf(']', match.startIndex)! + 1, content.indexOf('(', match.startIndex)!),
        extractLinkAndParams: (content, match) => {
            // FAQ-specific extraction logic
            return {
                link: [...],
                params: { faqId: ... }
            };
        }
    }],
    // Add other handlers...
]);

This would make it easier to:

  1. Add new reference types without modifying existing code
  2. Test each reference type handler independently
  3. Maintain the logic for each reference type separately

Would you like me to help create a detailed implementation plan for this refactoring?

src/main/webapp/app/shared/metis/metis.service.ts (1)

497-504: Fix incorrect JSDoc description.

The JSDoc comment incorrectly describes this method as returning a link for an "exercise referenced within a faq". This should be updated to accurately reflect the method's purpose.

-    /**
-     * returns the router link required for navigating to the exercise referenced within a faq
-     * @return {string} router link of the faq
-     */
+    /**
+     * returns the router link required for navigating to the course's FAQ section
+     * @return {string} router link of the FAQ page
+     */
src/test/javascript/spec/component/shared/metis/posting-content/posting-content.component.spec.ts (1)

495-509: LGTM! Consider using consistent test data.

The test case for FAQ references is well-structured and follows the established patterns. However, for consistency with other test cases, consider using more descriptive test data.

Consider this minor improvement:

-            component.content = `I want to reference [faq]faq(/courses/1/faq?faqId=45)[/faq].`;
+            component.content = `I want to reference [faq]How to submit assignments(/courses/1/faq?faqId=45)[/faq].`;

This makes the test data more realistic and consistent with other test cases that use descriptive reference strings.

src/main/webapp/app/overview/course-overview.component.ts (1)

192-193: Consider maintaining consistency in dependency injection pattern

While using inject() is a modern approach, consider maintaining consistency with the rest of the service injections that use constructor-based dependency injection. This helps maintain a uniform codebase pattern.

-    private faqService = inject(FaqService);
+    constructor(
+        private courseService: CourseManagementService,
+        private courseExerciseService: CourseExerciseService,
+        // ... other services ...
+        private faqService: FaqService,
+    ) {}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c17b2c4 and 22706e3.

📒 Files selected for processing (13)
  • src/main/webapp/app/entities/course.model.ts (3 hunks)
  • src/main/webapp/app/overview/course-faq/course-faq.component.html (1 hunks)
  • src/main/webapp/app/overview/course-faq/course-faq.component.ts (6 hunks)
  • src/main/webapp/app/overview/course-overview.component.ts (5 hunks)
  • src/main/webapp/app/shared/metis/metis.service.ts (1 hunks)
  • src/main/webapp/app/shared/metis/metis.util.ts (1 hunks)
  • src/main/webapp/app/shared/metis/posting-content/posting-content.components.ts (2 hunks)
  • src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (4 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/communication/faq-reference.action.ts (1 hunks)
  • src/main/webapp/i18n/de/metis.json (1 hunks)
  • src/main/webapp/i18n/en/metis.json (1 hunks)
  • src/test/javascript/spec/component/shared/metis/posting-content/posting-content.component.spec.ts (1 hunks)
  • src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/main/webapp/app/entities/course.model.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/overview/course-faq/course-faq.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/overview/course-faq/course-faq.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/overview/course-overview.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/shared/metis/metis.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/shared/metis/metis.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/shared/metis/posting-content/posting-content.components.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/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (1)

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

src/main/webapp/app/shared/monaco-editor/model/actions/communication/faq-reference.action.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/metis.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/shared/metis/posting-content/posting-content.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}}

src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.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 (16)
src/main/webapp/app/overview/course-faq/course-faq.component.html (2)

35-37: LGTM! Well-structured FAQ element wrapper.

The addition of the wrapper div with template reference and dynamic ID provides the necessary DOM hooks for programmatic FAQ navigation, which aligns well with the PR's objective of enabling FAQ references in posts.


Line range hint 1-43: LGTM! Consistent use of new Angular control flow syntax.

The template correctly uses the new @if and @for syntax throughout, following the latest Angular best practices and project guidelines.

src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (3)

20-20: LGTM: Import statements are properly organized.

The new imports for FAQ functionality are correctly placed and follow Angular style guidelines.

Also applies to: 33-33


79-80: LGTM: Clean implementation of conditional FAQ action.

The feature flag check and array initialization follow the established pattern and best practices.


Line range hint 79-90: Verify handling of FAQ feature state changes.

While the initial FAQ feature state is correctly handled, we should ensure that the component properly responds to runtime changes in the FAQ feature state.

✅ Verification successful

Let me try a different approach to verify the FAQ feature state handling.

This should help us understand:

  1. How the FAQ feature state is managed
  2. If there are any subscriptions in the component
  3. If there are any observables for FAQ state changes

Let me try one final verification to check the MetisService implementation for any course state updates.


Based on the verification results, I can now provide a final response:

FAQ feature state changes are handled appropriately.

The implementation correctly handles FAQ feature state changes because:

  1. The FAQ action is determined by isFaqEnabled() which is a pure function that checks the current course state
  2. The course state is managed by MetisService which is injected into the component
  3. The component initializes actions in ngOnInit() and doesn't need to subscribe to course state changes because:
    • The editor actions are only used for new instances of the editor
    • Any changes to the course's FAQ state would result in a route change/component recreation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any runtime feature state change handlers
rg -l "isFaqEnabled.*subscribe" 

# Check if there are any feature toggle services or similar patterns
ast-grep --pattern 'class $_ implements OnDestroy {
  $$$
  ngOnDestroy() {
    $$$
    unsubscribe
    $$$
  }
}'

Length of output: 274


Script:

#!/bin/bash
# Search for FAQ-related code and state management patterns
rg -A 5 "isFaqEnabled" 

# Look for any subscriptions or state management in the component
rg -A 10 "class PostingMarkdownEditorComponent"

# Check if there are any FAQ-related observables or subjects
rg "FAQ.*Subject|FAQ.*Observable"

Length of output: 7100


Script:

#!/bin/bash
# Check MetisService implementation for course state management
rg -A 10 "class MetisService"

# Look for any course state updates or observables
rg "getCourse\(\)|courseSubject|courseUpdate"

# Check if the component subscribes to any course updates
ast-grep --pattern 'class PostingMarkdownEditorComponent {
  $$$
  ngOnInit() {
    $$$
    subscribe
    $$$
  }
}'

Length of output: 96602

src/main/webapp/app/entities/course.model.ts (3)

16-16: LGTM: Import statement follows Angular conventions

The import statement follows the Angular style guide and maintains consistency with other model imports.


109-109: LGTM: Property follows established patterns

The faqs property is correctly implemented following the class's established patterns for array properties and TypeScript conventions.


109-109: Verify FAQ feature integration points

Since this model change enables FAQ references in posts, let's verify the integration points:

✅ Verification successful

Let me gather more specific information about the FAQ integration by checking the actual implementation details.


Based on the gathered information, I can now provide a final response as the integration points are clear.

FAQ feature is properly integrated across the codebase

The FAQ feature shows complete and proper integration:

  • The Course model correctly defines the optional faqs property
  • FaqReferenceAction is properly implemented for editor integration
  • CourseFaqComponent handles the FAQ functionality with proper course relationship
  • Proper bidirectional relationship exists between Course and Faq models
  • Feature toggle through isFaqEnabled is correctly implemented and used in the markdown editor

The code shows a well-structured implementation with:

  • Proper model relationships
  • Complete UI components
  • Feature toggle support
  • Search and filter capabilities
  • Proper routing and navigation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify proper integration of FAQ feature across the codebase

# Test 1: Check for proper usage of isFaqEnabled function
echo "Checking isFaqEnabled function usage..."
rg "isFaqEnabled" -t ts

# Test 2: Check for FAQ-related components and services
echo "Checking FAQ-related components..."
fd -e ts -e html . src/main/webapp/app | rg -i "faq"

# Test 3: Verify proper typing in components using Course model with faqs
echo "Checking Course model usage with faqs property..."
ast-grep --pattern 'course: Course' -l ts

Length of output: 2038


Script:

#!/bin/bash
# Check the implementation of FAQ-related components and their interaction with Course model

# Check FaqReferenceAction implementation
echo "Checking FaqReferenceAction implementation..."
rg -A 5 "class FaqReferenceAction" src/main/webapp/app/shared/monaco-editor/model/actions/communication/faq-reference.action.ts

# Check Course FAQ component implementation
echo "Checking Course FAQ component implementation..."
cat src/main/webapp/app/overview/course-faq/course-faq.component.ts

# Check FAQ model and its relationship with Course
echo "Checking FAQ model..."
cat src/main/webapp/app/entities/faq.model.ts

# Check actual usage of faqs property in Course model
echo "Checking usage of faqs property..."
rg "faqs\?" -t ts

Length of output: 6914

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

49-50: LGTM! The FAQ translation entry is properly added.

The new translation entry follows the existing pattern and uses the widely recognized "FAQ" acronym.

Let's verify the consistency of FAQ translations across language files:

✅ Verification successful

Let me gather more specific information about which language files we're dealing with:


Let me check the exact content of both files to ensure they're properly synchronized:


FAQ translation is properly synchronized across both language files

The verification confirms that:

  • Both English (en) and German (de) localization files contain the FAQ translation
  • The translation is consistently set as "FAQ" in both files, which is appropriate as it's a commonly recognized acronym in both languages
  • The entry is properly placed in the same position (after "user") in both files
  • The JSON structure is maintained correctly
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if FAQ translation exists in all language files
# Expected: All language files should have the editor.faq translation

# Find all language files
fd 'metis.json' 'src/main/webapp/i18n' --exec jq -r '.artemisApp.metis.editor.faq // "Missing FAQ translation"' {}

Length of output: 122


Script:

#!/bin/bash
# List all metis.json files with their paths to identify the language files
fd 'metis.json' 'src/main/webapp/i18n' --exec-batch echo "{}"

Length of output: 129


Script:

#!/bin/bash
# Show the editor section of both language files
echo "=== English (en) ==="
jq '.artemisApp.metis.editor' src/main/webapp/i18n/en/metis.json

echo -e "\n=== German (de) ==="
jq '.artemisApp.metis.editor' src/main/webapp/i18n/de/metis.json

Length of output: 513

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

49-50: LGTM! The translation is appropriate.

The added FAQ translation maintains consistency with German web terminology and the informal language style used throughout the file.

src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts (1)

27-27: LGTM!

The import statement follows the established pattern and is correctly placed with other action imports.

src/main/webapp/app/shared/metis/metis.service.ts (1)

501-503: LGTM: Method implementation follows Angular patterns.

The implementation is clean, follows the established patterns in the service for link generation, and correctly uses the course ID from the service state.

src/main/webapp/app/overview/course-overview.component.ts (2)

71-72: LGTM: Clean import additions

The new imports for FAQ functionality are well-organized and follow Angular's style guide.


Line range hint 450-465: LGTM: Clean FAQ menu integration

The FAQ menu item integration follows the established pattern and correctly handles feature toggling through the faqEnabled flag.

src/main/webapp/app/shared/monaco-editor/model/actions/communication/faq-reference.action.ts (1)

64-67: Proper disposal of resources

Good job ensuring that disposableCompletionProvider is disposed of in the dispose method, preventing potential memory leaks.

src/main/webapp/app/overview/course-faq/course-faq.component.ts (1)

128-130: The sortFaqs() method is correctly implemented

The method effectively sorts the FAQs by their id in ascending order using the SortService.

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 (4)
src/test/javascript/spec/component/overview/course-faq/course-faq.component.spec.ts (3)

163-167: Enhance sort test coverage.

While the test verifies that sortService.sortByProperty is called, it could be more comprehensive:

  1. Verify the correct parameters are passed to sortByProperty
  2. Assert the effect on component's state after sorting

Consider this improved implementation:

 it('should call sortService when sortRows is called', () => {
-    jest.spyOn(sortService, 'sortByProperty').mockReturnValue([]);
+    const sortedFaqs = [faq2, faq1, faq3];
+    jest.spyOn(sortService, 'sortByProperty').mockReturnValue(sortedFaqs);
     courseFaqComponent.sortFaqs();
-    expect(sortService.sortByProperty).toHaveBeenCalledOnce();
+    expect(sortService.sortByProperty).toHaveBeenCalledExactlyOnceWith(
+        courseFaqComponent.faqs,
+        'questionTitle',
+        'asc'
+    );
+    expect(courseFaqComponent.faqs).toEqual(sortedFaqs);
 });

169-179: Improve query params test setup.

While the test verifies the correct behavior, the setup could be improved:

Consider this more maintainable approach:

 it('should call scrollToFaq when faqId is in query params', () => {
     const scrollToFaqSpy = jest.spyOn(courseFaqComponent, 'scrollToFaq');
-
-    const route = TestBed.inject(ActivatedRoute);
-    (route.queryParams as any) = of({ faqId: '1' });
-
+    TestBed.overrideProvider(ActivatedRoute, {
+        useValue: {
+            parent: {
+                params: of({ courseId: '1' })
+            },
+            queryParams: of({ faqId: '1' })
+        }
+    });
+    
+    // Re-create component to pick up new route config
+    courseFaqComponentFixture = TestBed.createComponent(CourseFaqComponent);
+    courseFaqComponent = courseFaqComponentFixture.componentInstance;
     courseFaqComponent.goToFaq();

     expect(scrollToFaqSpy).toHaveBeenCalledOnce();
     expect(scrollToFaqSpy).toHaveBeenCalledWith('1');
 });

181-195: Enhance scroll and focus test robustness.

The test could be improved in several ways:

  1. Add test case for element not found scenario
  2. Use proper typing for the mock element
  3. Match the actual component's element id format

Consider these improvements:

+interface MockHTMLElement extends Partial<HTMLElement> {
+    scrollIntoView: jest.Mock;
+    focus: jest.Mock;
+}

 it('should scroll and focus on the faq element with given id', () => {
-    const nativeElement = {
-        id: 'faq-1',
+    const nativeElement: MockHTMLElement = {
+        id: 'faq_1',
         scrollIntoView: jest.fn(),
         focus: jest.fn(),
     };
     const elementRef = new ElementRef(nativeElement);
     const queryList = new QueryList<ElementRef>();
     queryList.reset([elementRef]);
     courseFaqComponent.faqElements = queryList;
+
+    // Test successful case
     courseFaqComponent.scrollToFaq(1);
-
     expect(nativeElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth', block: 'start' });
     expect(nativeElement.focus).toHaveBeenCalled();
+
+    // Test element not found
+    courseFaqComponent.scrollToFaq(999);
+    expect(nativeElement.scrollIntoView).toHaveBeenCalledTimes(1); // Should not be called again
+    expect(nativeElement.focus).toHaveBeenCalledTimes(1); // Should not be called again
 });
src/test/javascript/spec/service/metis/metis.service.spec.ts (1)

333-337: Test implementation looks good, but could be more comprehensive.

The basic test case correctly verifies the FAQ link generation. However, consider enhancing the test coverage:

Consider adding these test cases:

 it('should determine the router link required for referencing a faq', () => {
+    metisService.setCourse(metisCourse);
     const link = metisService.getLinkForFaq();
     expect(link).toBe(`/courses/${metisCourse.id}/faq`);
 });

+it('should handle faq link generation when course is not set', () => {
+    metisService.setCourse(undefined);
+    const link = metisService.getLinkForFaq();
+    expect(link).toBeUndefined();
+});
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 22706e3 and c617c83.

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

src/test/javascript/spec/service/metis/metis.service.spec.ts (1)

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

🔇 Additional comments (1)
src/test/javascript/spec/component/overview/course-faq/course-faq.component.spec.ts (1)

22-23: LGTM: Clean setup of new dependencies!

The SortService integration follows testing best practices with proper mocking and initialization.

Also applies to: 41-41, 110-110

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 23, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
src/main/webapp/app/shared/metis/posting-content/posting-content-part/posting-content-part.components.ts (1)

103-104: LGTM with a suggestion for future maintainability.

The FAQ case is correctly implemented. However, as the number of reference types grows, consider refactoring this switch statement into a mapping object for better maintainability.

Consider refactoring to use a mapping object:

private readonly referenceIconMap: Record<ReferenceType, IconProp> = {
    [ReferenceType.POST]: faMessage,
    [ReferenceType.LECTURE]: faChalkboardUser,
    // ... other mappings
    [ReferenceType.FAQ]: faQuestion,
};

referenceIcon(reference: ReferenceType): IconProp {
    return this.referenceIconMap[reference] ?? faPaperclip;
}

This approach would:

  • Reduce cognitive complexity
  • Make it easier to add new reference types
  • Potentially improve performance by eliminating the switch statement
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c617c83 and f7683a0.

📒 Files selected for processing (3)
  • src/main/webapp/app/overview/course-faq/course-faq.component.ts (6 hunks)
  • src/main/webapp/app/shared/metis/posting-content/posting-content-part/posting-content-part.components.ts (3 hunks)
  • src/test/javascript/spec/component/overview/course-faq/course-faq.component.spec.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/app/overview/course-faq/course-faq.component.ts
🧰 Additional context used
📓 Path-based instructions (2)
src/main/webapp/app/shared/metis/posting-content/posting-content-part/posting-content-part.components.ts (1)

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

src/test/javascript/spec/component/overview/course-faq/course-faq.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 (3)
src/main/webapp/app/shared/metis/posting-content/posting-content-part/posting-content-part.components.ts (2)

18-18: LGTM: Icon import and property declaration follow guidelines.

The addition of the faQuestion icon follows the established patterns and Angular style guidelines.

Also applies to: 47-47


47-47: Verify FAQ icon display in the UI.

While the implementation looks correct, please ensure that:

  1. The FAQ icon is visible and properly aligned in the UI
  2. The icon maintains consistent styling with other reference icons
  3. The icon is visible in both light and dark themes

Also applies to: 103-104

src/test/javascript/spec/component/overview/course-faq/course-faq.component.spec.ts (1)

22-23: LGTM: Clean setup of SortService dependency!

The setup follows Angular testing best practices with proper dependency injection.

Also applies to: 41-41, 110-110

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.

Hi, I found some issues:

  1. After clicking on a refereced FAQ, it doesn't show up in the FAQs overview, it just dissapear from the FAQs list
    In the first screenshot are all the faqs available
    Screenshot 2024-10-23 144325
    After clicking on faq1, which is referenced in a channel, I was redirect to the page with all the faqs, but the faq1 is nowhere to be found
    Screenshot 2024-10-23 144410
    Screenshot 2024-10-23 144433

  2. After disabling FAQ, I can still see and click onto already referenced FAQs. Referencing new faq is, as expected, not possible
    Screenshot 2024-10-23 144528
    Screenshot 2024-10-23 144558

Copy link

⚠️ Unable to deploy to test servers ⚠️

Testserver "artemis-test1.artemis.cit.tum.de" is already in use by PR #9505.

Copy link
Contributor

@florian-glombik florian-glombik left a comment

Choose a reason for hiding this comment

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

Approve code

PaRangger
PaRangger previously approved these changes Nov 26, 2024
Copy link
Contributor

@PaRangger PaRangger left a comment

Choose a reason for hiding this comment

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

Reapprove, code change 👍

Copy link
Contributor

@SimonEntholzer SimonEntholzer left a comment

Choose a reason for hiding this comment

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

Code looks good over all, I added one small comment about a comment

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 26, 2024
Copy link
Contributor

@SimonEntholzer SimonEntholzer left a comment

Choose a reason for hiding this comment

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

Code lgtm now

Copy link
Contributor

@PaRangger PaRangger left a comment

Choose a reason for hiding this comment

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

Reapprove

Copy link

@flbrgit flbrgit 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 TS5. After disabling the FAQ, you can't reference it anymore by the message options unless you copy an existing reference or type it in manually. Then it's still possible to access the FAQ, even though it is disabled. It's just confusing that the FAQ then does not show up in the task bar. As this is not covered with this PR, 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 TS5, every feature works just fine. After disabling, FAQ can't be referenced.

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!) core Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.