Skip to content

Conversation

@HawKhiem
Copy link
Contributor

@HawKhiem HawKhiem commented Nov 11, 2025

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 principle of data economy for all client-server REST calls.
  • I strictly followed the client coding guidelines.
  • I strictly followed the AET UI-UX 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

Closes issue #9952

Currently, when users want to add a hyperlink to selected text in the markdown editor, they need to:

  1. Unselect the text (otherwise it gets deleted when clicking the hyperlink button)
  2. Click the hyperlink button
  3. Manually paste the text into the brackets [text here]
  4. Add the URL

This workflow is cumbersome and doesn't match the behavior of modern markdown editors. Many applications (like Notion, Discord, Slack, etc.) allow users to simply select text and click the hyperlink button to wrap it with link syntax.

Description

This PR improves the user experience of adding hyperlinks in the markdown editor by automatically wrapping selected text with the link syntax when the hyperlink button is clicked.

Steps for Testing

Prerequisites:

  • Access to any feature with markdown editor (e.g., Communication posts, Exercise descriptions, Lectures)

Test 1: Wrap selected text with hyperlink

  1. Log in to Artemis
  2. Navigate to any markdown editor (e.g., create a new post in Communication)
  3. Type some text: "Click here to learn more"
  4. Select the text "Click here"
  5. Click the Link button (🔗) or the Attachment button in the editor toolbar
  6. Expected: The text becomes [Click here](https://)
  7. Type or paste a URL after https://
  8. Expected: The link is properly formatted: [Click here](https://example.com)

Test 2: Insert default text when no selection

  1. In the markdown editor, place cursor at an empty position (no text selected)
  2. Click the hyperlink button (🔗)
  3. Expected: Default text [🔗 Link](https://) is inserted
  4. Expected: Behavior is unchanged from before (backward compatibility)

Test 3: Wrap text with special characters

  1. Type text with special characters: "Bold and italic text"
  2. Select the entire text
  3. Click the hyperlink button
  4. Expected: Text is properly sanitized and wrapped: [**Bold** and *italic* text](https://)

Testserver States

You can manage test servers using Helios. Check environment statuses in the environment list. To deploy to a test server, go to the CI/CD page, find your PR or branch, and trigger the deployment.

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.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1: Wrap selected text with hyperlink
  • Test 2: Insert default text when no selection
  • Test 3: Wrap text with special characters

Screenshots

Before: User must unselect text, click button, then manually type [text](url)

old.mp4

After: User selects text, clicks button, and only needs to add the URL

test.mp4

Summary by CodeRabbit

  • New Features

    • Markdown editor now wraps selected text when inserting links or attachments without explicit parameters, sanitizing the selection into proper markdown and falling back to a default placeholder when no selection exists.
  • Documentation

    • In-editor docs updated to describe the conditional wrapping behavior and the fallback to default insertion.

@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Nov 11, 2025
@github-actions github-actions bot added the client Pull requests that update TypeScript code. (Added Automatically!) label Nov 11, 2025
@HawKhiem HawKhiem added the communication Pull requests that affect the corresponding module label Nov 11, 2025
@HawKhiem HawKhiem marked this pull request as ready for review November 11, 2025 18:15
@HawKhiem HawKhiem requested a review from krusche as a code owner November 11, 2025 18:15
@github-actions github-actions bot removed the communication Pull requests that affect the corresponding module label Nov 11, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

Walkthrough

Adds a protected helper to TextEditorAction that conditionally wraps selected text via a provided wrapper (sanitizing the selection) or inserts a default placeholder when no selection exists. attachment and url actions now use this helper when invoked without arguments; argument-driven insertion behavior is unchanged.

Changes

Cohort / File(s) Summary
Text editor helper
src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
Added protected wrapSelectionOrInsertDefault(editor, wrapperFn, defaultText): void which checks for a non-empty selection, calls wrapperFn(selectedText) and replaces the selection if the wrapper returns a non-empty string; otherwise inserts defaultText at the cursor. Added relevant imports and JSDoc.
Attachment action
src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
Replaced direct default-insert logic with wrapSelectionOrInsertDefault(...). When called with no args and a selection exists, wraps selection as ![selectedText](https://) (sanitizing selection via wrapper); otherwise inserts the default placeholder. Existing behavior when args are provided and editor.focus() remain. Documentation updated.
URL action
src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts
Replaced direct default-insert logic with wrapSelectionOrInsertDefault(...). When called with no args and a selection exists, wraps selection as [selectedText](https://) (sanitizing selection via wrapper); otherwise inserts the default placeholder. Existing behavior when both text and url args are provided and editor.focus() remain. Documentation updated.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Editor
    participant TextEditorAction
    participant SpecificAction

    User->>SpecificAction: run() (no args)
    SpecificAction->>TextEditorAction: wrapSelectionOrInsertDefault(editor, wrapperFn, defaultText)
    alt selection exists
        TextEditorAction->>Editor: getSelectedText()
        Editor-->>TextEditorAction: selectedText
        TextEditorAction->>TextEditorAction: sanitize selectedText
        TextEditorAction->>Editor: replace selection with wrapperFn(sanitizedText)
        Editor-->>TextEditorAction: selection replaced
    else no selection
        TextEditorAction->>Editor: replaceTextAtCurrentSelection(defaultText)
        Editor-->>TextEditorAction: default inserted
    end
    SpecificAction->>Editor: editor.focus()
    Editor-->>User: focused
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify wrapSelectionOrInsertDefault correctly trims/sanitizes selection handling and treats whitespace-only selection as empty.
  • Confirm wrapper functions passed from attachment.action.ts and url.action.ts produce expected markdown and that argument-provided insertion paths remain unchanged.
  • Check selection range replacement logic and that editor.focus() is preserved.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding the ability to wrap selected text with hyperlink syntax in the markdown editor.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/communication/add-hyperlink-to-selected-text

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa39ad6 and cbceecc.

📒 Files selected for processing (3)
  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (1 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts (1 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/**/*.ts

⚙️ CodeRabbit configuration file

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

Files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
🧠 Learnings (2)
📚 Learning: 2024-10-25T07:52:32.513Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9580
File: src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts:475-491
Timestamp: 2024-10-25T07:52:32.513Z
Learning: In `src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts`, `useCommunicationForFileUpload` is a Signal, so it should be called as a function when used.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
📚 Learning: 2024-07-10T08:47:07.884Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/main/webapp/app/shared/range-slider/range-slider.component.ts:16-16
Timestamp: 2024-07-10T08:47:07.884Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting the removal of trivially inferred type annotations for the `step` property in `range-slider.component.ts`.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Build and Push Docker Image / Build linux/arm64 Docker Image for ls1intum/artemis
  • GitHub Check: Build and Push Docker Image / Build linux/amd64 Docker Image for ls1intum/artemis
  • GitHub Check: Build .war artifact
  • GitHub Check: server-tests
  • GitHub Check: client-tests-selected
  • GitHub Check: server-style
  • GitHub Check: client-style
  • GitHub Check: client-tests
  • GitHub Check: Analyse
🔇 Additional comments (2)
src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (2)

82-82: LGTM! Wrapping behavior correctly implemented.

The use of wrapSelectionOrInsertDefault properly wraps selected text with attachment syntax or inserts the default text when no selection exists, matching the PR objectives.


83-85: Attachment insertion fails silently when args are provided but no selection exists.

The concern in the review is valid. When args.text and args.url are provided (e.g., from the file upload callback at line 642 in markdown-editor-monaco.component.ts), the code calls replaceTextAtCurrentSelection, which only inserts text if an active selection with content exists. If the user deselects or clicks elsewhere during the async upload operation, nothing is inserted.

The JSDoc comment suggests insertion "at the current selection," but doesn't clarify the failure case. Comparing with UrlAction, the same pattern exists there—both rely on selection presence when args are provided.

Consider inserting at the cursor position (or end of document) when args are explicitly provided but no selection exists, rather than silently failing.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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

♻️ Duplicate comments (1)
src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts (1)

42-46: Trim inconsistency (duplicate of issue in attachment.action.ts).

The same trim inconsistency exists here as in attachment.action.ts lines 84-88. If the suggested refactoring is implemented, this issue will be resolved.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36dcefc and 44efba6.

📒 Files selected for processing (2)
  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (1 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/**/*.ts

⚙️ CodeRabbit configuration file

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

Files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 8832
File: src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts:344-345
Timestamp: 2024-06-20T21:25:36.138Z
Learning: The Monaco editor uses 1-based line numbering, and this should be considered when handling line numbers in code related to this editor.
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 8832
File: src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts:344-345
Timestamp: 2024-10-08T15:35:42.972Z
Learning: The Monaco editor uses 1-based line numbering, and this should be considered when handling line numbers in code related to this editor.
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9463
File: src/main/webapp/app/shared/monaco-editor/model/themes/monaco-editor-theme.model.ts:51-51
Timestamp: 2024-10-13T12:01:14.787Z
Learning: In the Monaco editor TypeScript code, prefer simple string concatenation over nested template strings when nesting adds unnecessary complexity.
📚 Learning: 2024-10-25T07:52:32.513Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9580
File: src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts:475-491
Timestamp: 2024-10-25T07:52:32.513Z
Learning: In `src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts`, `useCommunicationForFileUpload` is a Signal, so it should be called as a function when used.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: client-tests-selected
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: server-style
  • GitHub Check: client-style
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Build and Push Docker Image / Build linux/arm64 Docker Image for ls1intum/artemis
  • GitHub Check: Build and Push Docker Image / Build linux/amd64 Docker Image for ls1intum/artemis
  • GitHub Check: Build .war artifact
  • GitHub Check: Analyse
🔇 Additional comments (1)
src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (1)

83-88: Helper methods are properly defined in the parent class—no issues found.

Both getSelectedText() (line 172) and replaceTextAtRange() (line 193) are correctly defined as public methods in the parent class TextEditorAction within text-editor-action.model.ts. The method calls in the code snippet are valid.

Comment on lines 37 to 51
if (!args?.text || !args?.url) {
this.replaceTextAtCurrentSelection(editor, UrlAction.DEFAULT_INSERT_TEXT);
// Check if there's selected text
const selectedText = this.getSelectedText(editor);
if (selectedText && selectedText.trim()) {
// Wrap selected text with link syntax
const selection = editor.getSelection();
if (selection) {
this.replaceTextAtRange(editor, selection, `[${sanitizeStringForMarkdownEditor(selectedText)}](https://)`);
}
} else {
// No selection, insert default text
this.replaceTextAtCurrentSelection(editor, UrlAction.DEFAULT_INSERT_TEXT);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract duplicated wrapping logic to parent class.

The text-wrapping logic in lines 39-51 is nearly identical to lines 81-93 in attachment.action.ts. The only difference is the markdown syntax format ([text](url) vs ![text](url)).

Consider extracting this shared logic to the parent TextEditorAction class with a method like:

protected wrapSelectionOrInsertDefault(
    editor: TextEditor,
    wrapFormat: (text: string) => string,
    defaultText: string
): void {
    const selectedText = this.getSelectedText(editor)?.trim();
    if (selectedText) {
        const selection = editor.getSelection();
        if (selection) {
            this.replaceTextAtRange(editor, selection, wrapFormat(sanitizeStringForMarkdownEditor(selectedText)));
        }
    } else {
        this.replaceTextAtCurrentSelection(editor, defaultText);
    }
}

Then both classes can call:

// In UrlAction:
this.wrapSelectionOrInsertDefault(editor, (text) => `[${text}](https://)`, UrlAction.DEFAULT_INSERT_TEXT);

// In AttachmentAction:
this.wrapSelectionOrInsertDefault(editor, (text) => `![${text}](https://)`, AttachmentAction.DEFAULT_INSERT_TEXT);
🤖 Prompt for AI Agents
src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts lines
39-51: the selection-wrapping logic here duplicates logic in
attachment.action.ts (lines ~81-93) differing only by the wrapper syntax; move
that shared behavior into the parent TextEditorAction by adding a protected
helper (e.g., wrapSelectionOrInsertDefault) that accepts the editor, a function
to produce the wrapped string from sanitized text, and the default insert text,
and then replace the duplicated blocks in UrlAction and AttachmentAction with
calls to that helper using the appropriate wrapper-producing function for
`[text](https://)` and `![text](https://)` respectively.

@github-project-automation github-project-automation bot moved this from Work In Progress to Ready For Review in Artemis Development Nov 11, 2025
@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 519ms
TestResultTime ⏱
No test annotations available

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran201 passed3 skipped1 failed1h 21m 7s 3ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exercise/quiz-exercise/QuizExerciseDropLocation.spec.ts
ts.Quiz Exercise Drop Location Spec › DnD Quiz drop locations › Checks drop locations❌ failure2m 3s 972ms

@HawKhiem HawKhiem linked an issue Nov 12, 2025 that may be closed by this pull request
@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran201 passed3 skipped1 failed1h 12m 59s 144ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exercise/quiz-exercise/QuizExerciseDropLocation.spec.ts
ts.Quiz Exercise Drop Location Spec › DnD Quiz drop locations › Checks drop locations❌ failure2m 3s 322ms

Copy link
Contributor

@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

🧹 Nitpick comments (1)
src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts (1)

184-184: Tighten the wrapperFn parameter type.

The wrapperFn parameter is typed as (sanitizedText: string | undefined) => string, but at line 190 it's only ever invoked with a string (the result of sanitizeStringForMarkdownEditor at line 189, called within the if (selectedText && selection) block where selectedText is guaranteed to be truthy). The | undefined is unnecessary and may cause callers to add unneeded null checks.

Apply this diff to correct the type signature:

-    protected wrapSelectionOrInsertDefault(editor: TextEditor, wrapperFn: (sanitizedText: string | undefined) => string, defaultText: string): void {
+    protected wrapSelectionOrInsertDefault(editor: TextEditor, wrapperFn: (sanitizedText: string) => string, defaultText: string): void {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44efba6 and ef72343.

📒 Files selected for processing (3)
  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (1 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts (2 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/**/*.ts

⚙️ CodeRabbit configuration file

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

Files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts
🧠 Learnings (8)
📚 Learning: 2024-10-25T07:52:32.513Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9580
File: src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts:475-491
Timestamp: 2024-10-25T07:52:32.513Z
Learning: In `src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts`, `useCommunicationForFileUpload` is a Signal, so it should be called as a function when used.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
📚 Learning: 2024-07-10T08:47:07.884Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/main/webapp/app/shared/range-slider/range-slider.component.ts:16-16
Timestamp: 2024-07-10T08:47:07.884Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting the removal of trivially inferred type annotations for the `step` property in `range-slider.component.ts`.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
📚 Learning: 2024-10-13T12:01:14.787Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9463
File: src/main/webapp/app/shared/monaco-editor/model/themes/monaco-editor-theme.model.ts:51-51
Timestamp: 2024-10-13T12:01:14.787Z
Learning: In the Monaco editor TypeScript code, prefer simple string concatenation over nested template strings when nesting adds unnecessary complexity.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
  • src/main/webapp/app/shared/monaco-editor/model/actions/url.action.ts
📚 Learning: 2024-10-08T15:35:42.972Z
Learnt from: BaumiCoder
Repo: ls1intum/Artemis PR: 8552
File: src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores.component.html:0-0
Timestamp: 2024-10-08T15:35:42.972Z
Learning: When rendering icons conditionally based on the presence of text, ensure that the text is not empty or whitespace to avoid displaying icons without popups.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
📚 Learning: 2024-07-10T08:46:02.595Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/main/webapp/app/shared/range-slider/range-slider.component.ts:60-63
Timestamp: 2024-07-10T08:46:02.595Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting changing the type for the `event` parameter in the `onSelectedMinValueChanged` and `onSelectedMaxValueChanged` methods in `range-slider.component.ts`.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
📚 Learning: 2024-07-10T08:46:07.854Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/main/webapp/app/shared/range-slider/range-slider.component.ts:55-58
Timestamp: 2024-07-10T08:46:07.854Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting changing the type of the `event` parameter in the `onSelectedMinValueChanged` method in `range-slider.component.ts`.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts
📚 Learning: 2024-10-20T21:59:11.630Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9505
File: src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html:9-9
Timestamp: 2024-10-20T21:59:11.630Z
Learning: In Angular templates within the Artemis project (e.g., `src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html`), properties like `selectedFile()`, `readOnlyManualFeedback()`, `highlightDifferences()`, and `course()` are signals. It is appropriate to call these signals directly in the template.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
📚 Learning: 2024-10-20T22:04:46.906Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9505
File: src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html:36-36
Timestamp: 2024-10-20T22:04:46.906Z
Learning: In Angular templates, methods that return Signals (e.g., `feedbackSuggestionsForSelectedFile()` in `code-editor-monaco.component.ts`) can be used directly without performance issues because Signals are optimized for efficient change detection.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Build and Push Docker Image / Build linux/amd64 Docker Image for ls1intum/artemis
  • GitHub Check: Build and Push Docker Image / Build linux/arm64 Docker Image for ls1intum/artemis
  • GitHub Check: Build .war artifact
  • GitHub Check: client-tests-selected
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: client-style
  • GitHub Check: server-style
  • GitHub Check: Analyse
🔇 Additional comments (3)
src/main/webapp/app/shared/monaco-editor/model/actions/attachment.action.ts (1)

81-82: LGTM! Refactoring addresses previous trim concern.

The refactoring to use wrapSelectionOrInsertDefault resolves the earlier concern about trimming inconsistency. The helper now properly trims the selected text (line 185 in text-editor-action.model.ts) and uses the trimmed/sanitized result, avoiding markdown like ![ text ](https://) with surrounding whitespace.

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

39-40: LGTM! Duplication successfully eliminated.

The extraction of the wrapping logic to the parent class's wrapSelectionOrInsertDefault method successfully addresses the previous concern about code duplication between UrlAction and AttachmentAction. Both now share the same core logic while providing their specific markdown syntax via the wrapper function.

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

177-195: LGTM! Helper method correctly handles all selection cases.

The implementation correctly handles three scenarios:

  1. Non-empty selection: Trims, sanitizes, and wraps with the provided syntax
  2. Whitespace-only selection: Inserts default text (avoids empty links like [](https://))
  3. No selection (cursor only): Inserts default text at cursor position

The logic aligns well with the PR objectives and provides a clean, reusable solution for both UrlAction and AttachmentAction.

Copy link
Contributor

@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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef72343 and 270a03c.

📒 Files selected for processing (1)
  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/**/*.ts

⚙️ CodeRabbit configuration file

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

Files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
🧠 Learnings (3)
📚 Learning: 2024-10-25T07:52:32.513Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9580
File: src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts:475-491
Timestamp: 2024-10-25T07:52:32.513Z
Learning: In `src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts`, `useCommunicationForFileUpload` is a Signal, so it should be called as a function when used.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
📚 Learning: 2024-10-20T21:59:11.630Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9505
File: src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html:9-9
Timestamp: 2024-10-20T21:59:11.630Z
Learning: In Angular templates within the Artemis project (e.g., `src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html`), properties like `selectedFile()`, `readOnlyManualFeedback()`, `highlightDifferences()`, and `course()` are signals. It is appropriate to call these signals directly in the template.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
📚 Learning: 2024-10-20T22:04:46.906Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9505
File: src/main/webapp/app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component.html:36-36
Timestamp: 2024-10-20T22:04:46.906Z
Learning: In Angular templates, methods that return Signals (e.g., `feedbackSuggestionsForSelectedFile()` in `code-editor-monaco.component.ts`) can be used directly without performance issues because Signals are optimized for efficient change detection.

Applied to files:

  • src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Build and Push Docker Image / Build linux/amd64 Docker Image for ls1intum/artemis
  • GitHub Check: Build and Push Docker Image / Build linux/arm64 Docker Image for ls1intum/artemis
  • GitHub Check: Build .war artifact
  • GitHub Check: Analyse
  • GitHub Check: client-tests
  • GitHub Check: server-style
  • GitHub Check: client-tests-selected
  • GitHub Check: server-tests
  • GitHub Check: client-style
🔇 Additional comments (1)
src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts (1)

14-14: LGTM!

The import is correctly added and used in the new helper method for sanitizing selected text.

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 417ms
TestResultTime ⏱
No test annotations available

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 833ms
TestResultTime ⏱
No test annotations available

@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de November 12, 2025 21:11 Inactive
@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 410ms
TestResultTime ⏱
No test annotations available

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran200 passed3 skipped2 failed1h 11m 3s 642ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exam/ExamDateVerification.spec.ts
ts.Exam date verification › Exam timing › Student can start after start Date❌ failure2m 5s 305ms
e2e/exercise/quiz-exercise/QuizExerciseDropLocation.spec.ts
ts.Quiz Exercise Drop Location Spec › DnD Quiz drop locations › Checks drop locations❌ failure2m 3s 57ms

@Gavlitskii Gavlitskii temporarily deployed to artemis-test2.artemis.cit.tum.de November 18, 2025 16:31 — with GitHub Actions Inactive
Copy link

@Gavlitskii Gavlitskii left a comment

Choose a reason for hiding this comment

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

I have tested the hyperlink issue on a Test Server 2. Everything works as expected.

I followed the steps:

  • I put example text and clicked the URL button. The text was appropriately formatted and converted into a link.
  • It works with Bold or Italic as well.
  • Even without any text the link is created as expected.
Screenshot 2025-11-18 at 5 37 10 PM Screenshot 2025-11-18 at 5 35 27 PM

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran200 passed3 skipped2 failed1h 19m 27s 636ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exam/ExamDateVerification.spec.ts
ts.Exam date verification › Exam timing › Student can start after start Date❌ failure2m 4s 842ms
e2e/exam/test-exam/TestExamStudentExams.spec.ts
ts.Test Exam - student exams › Check exam participants and their submissions › Open the list of exam students❌ failure6m 10s 621ms

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran200 passed3 skipped2 failed1h 16m 28s 297ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exam/test-exam/TestExamStudentExams.spec.ts
ts.Test Exam - student exams › Check exam participants and their submissions › Open the list of exam students❌ failure6m 5s 435ms
e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts
ts.Static code analysis tests › Configures SCA grading and makes a successful submission with SCA errors❌ failure2m 36s 376ms

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report215 ran211 passed3 skipped1 failed1h 19m 59s 119ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exam/test-exam/TestExamParticipation.spec.ts
ts.Test exam participation › Early Hand-in › Using exercise overview to navigate within exam❌ failure3m 42s 361ms

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!) ready for review

Projects

Status: Ready For Review

Development

Successfully merging this pull request may close these issues.

Communication: Add possibility to add hyperlink to selected text

3 participants