Skip to content

Conversation

@thynguyentumde
Copy link

@thynguyentumde thynguyentumde commented Jan 27, 2026

Summary

Checklist

General

Server

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 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 authorities to all new routes and checked the course groups for displaying navigation elements (links, buttons).
  • I added multiple screenshots/screencasts of my UI changes.
  • I translated all newly inserted strings into English and German.

Motivation and Context

Improved the Iris UI layout and behavior in course and widget contexts, ensuring consistent sizing, alignment, and usability across different pages and view modes. Ensured the color contrast for the Iris client and chatbot interface. Added a dedicated sidebar entry point for the Iris so that students can easily find Iris from the global sidebar.

Description

  • Updated the Iris UI layout and styling for better alignment, sizing, and responsiveness across course and widget views.
  • Tuned chat widget resizing constraints and aligned button/input presentation.
  • Miscellaneous visual tweaks to chat history, message bubbles, and layout.
  • Simplified the color variables for Iris across light/dark themes.
  • Added telemetry iris_entrypoint_impression and iris_opened to track the open rate students click on "Iris" from the global sidebar.

Steps for Testing

  1. Log in to Artemis
  2. Navigate to a course and open the Iris page (/courses/:id/iris).
  3. Verify the sidebar toggle appears.
  4. Send messages and confirm chat bubbles, input, and disclaimer render correctly.
  5. Confirm that empty messages cannot be sent in the text area.
  6. Navigate through different chat session items on the chat sidebar.
  7. Open the exercise chatbot widget and confirm default size, resize limits (max width), and drag behavior.
  8. Switch to dark mode and confirm chat body/background and bubbles use correct colors.
  9. Use the developer tool to inspect elements and ensure color contrast are compliant.

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.
  • I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Performance Tests

  • Test 1
  • Test 2

Test Coverage

Warning: Client tests failed. Coverage could not be fully measured. Please check the workflow logs.

Server

Class/File Line Coverage Lines
ScienceEventType.java 100.00% 5

Last updated: 2026-01-27 14:07:45 UTC

Screenshots

image image image image

FIX IRIS-80, IRIS-51, IRIS-9

Summary by CodeRabbit

  • New Features

    • IRIS course integration with sidebar entry, chat UI, and session management
    • Chat history grouping and "new chat" handling
    • Message copy with visual feedback
    • Analytics events for IRIS entrypoint and sidebar opens
  • Improvements

    • Consolidated Iris theme variables and refreshed UI styling
    • Redesigned chat layout, controls, and widget sizing
    • Status bar now closes immediately when idle
  • Tests

    • Added/updated tests covering IRIS access, sidebar items, and chat sessions
  • Translations

    • Added German and English IRIS translations

✏️ Tip: You can customize this high-level summary in your review settings.

@thynguyentumde thynguyentumde requested review from a team and krusche as code owners January 27, 2026 13:13
@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Jan 27, 2026
@github-actions github-actions bot added server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) atlas Pull requests that affect the corresponding module communication Pull requests that affect the corresponding module core Pull requests that affect the corresponding module iris Pull requests that affect the corresponding module labels Jan 27, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Walkthrough

Adds Iris (chat) to course overview: new IRIS route and component, sidebar integration with analytics, chat UI/UX enhancements (copy, new-session handling, history grouping), theme variable consolidation, and new ScienceEventType values for Iris analytics.

Changes

Cohort / File(s) Summary
Routing & Access Control
src/main/webapp/app/core/course/overview/courses.route.ts, src/main/webapp/app/core/course/overview/course-overview-guard.ts, src/main/webapp/app/core/course/overview/course-overview-guard.spec.ts
Added IRIS route path, lazy-loads CourseIrisComponent, and enforces access via irisEnabledInCourse; added test for IRIS access.
Science Event Types (Backend & Frontend model)
src/main/java/de/tum/cit/aet/artemis/atlas/domain/science/ScienceEventType.java, src/main/webapp/app/shared/science/science.model.ts
Added IRIS__ENTRYPOINT_IMPRESSION and IRIS__OPENED_SIDEBAR enum values.
Course Iris Component
src/main/webapp/app/iris/overview/course-iris/course-iris.component.ts, src/main/webapp/app/iris/overview/course-iris/course-iris.component.html, src/main/webapp/app/iris/overview/course-iris/course-iris.component.scss
New CourseIrisComponent: parses courseId from route, exposes toggle for sidebar/chat history, and provides responsive container styles.
Course Overview Integration & Sidebar
src/main/webapp/app/core/course/overview/course-overview/course-overview.component.ts, src/main/webapp/app/core/course/shared/course-sidebar/course-sidebar.component.ts, src/main/webapp/app/core/course/shared/course-sidebar/course-sidebar.component.html, src/main/webapp/app/core/course/shared/course-sidebar/course-sidebar.component.spec.ts, src/main/webapp/app/core/course/shared/services/sidebar-item.service.ts, src/main/webapp/app/core/course/shared/services/sidebar-item.service.spec.ts
Injected Iris into activatable components and sidebar items (getIrisItem()), added onSidebarItemClick handler and ScienceService usage to log impressions and sidebar-open events; tests updated to mock ScienceService.
Base Chatbot — Template & Logic
src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html, src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.ts, src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.spec.ts
Major template restructure (history grouping, messages area, suggestions, input), added copy-to-clipboard, copied-state tracking, new-chat detection, message filtering, textarea enhancements, and tests for new-session behavior.
Base Chatbot — Styling
src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.scss
Large stylesheet refactor: new layout, updated color tokens to new Iris theme variables, redesigned bubbles, history sidebar, inputs, and rate UI.
Chat History Item
src/main/webapp/app/iris/overview/base-chatbot/chat-history-item/chat-history-item.component.ts, src/main/webapp/app/iris/overview/base-chatbot/chat-history-item/chat-history-item.component.html, src/main/webapp/app/iris/overview/base-chatbot/chat-history-item/chat-history-item.component.scss, src/main/webapp/app/iris/overview/base-chatbot/chat-history-item/chat-history-item.component.spec.ts
Added NEW_CHAT_TITLES and isNewChat signal, conditional plus icon for new chats, repositioned related-entity icon, styling adjustments, and test selector updates.
Chat Status Bar
src/main/webapp/app/iris/overview/base-chatbot/chat-status-bar/chat-status-bar.component.ts, src/main/webapp/app/iris/overview/base-chatbot/chat-status-bar/chat-status-bar.component.scss
Removed delayed close timeout (now closes synchronously), updated styling and layout tokens.
Course Chatbot Wrapper
src/main/webapp/app/iris/overview/course-chatbot/course-chatbot.component.ts, src/main/webapp/app/iris/overview/course-chatbot/course-chatbot.component.scss
Added viewChild reference and toggleChatHistory() to delegate history toggling to base chatbot; minor style adjustments.
Exercise Chatbot Button & Widget
src/main/webapp/app/iris/overview/exercise-chatbot/exercise-chatbot-button.component.ts, src/main/webapp/app/iris/overview/exercise-chatbot/exercise-chatbot-button.component.html, src/main/webapp/app/iris/overview/exercise-chatbot/exercise-chatbot-button.component.scss, src/main/webapp/app/iris/overview/exercise-chatbot/widget/chatbot-widget.component.ts, src/main/webapp/app/iris/overview/exercise-chatbot/widget/chatbot-widget.component.scss
UI and icon changes (faAngleDoubleDown → faArrowRight), inner text container .bubble-text, overflow detection update, increased default widget width (400→450), added maxWidth/maxHeight and dynamic resize bounds.
Agent Chat Modal & Tutor Suggestion Styling
src/main/webapp/app/atlas/manage/agent-chat-modal/agent-chat-modal.component.scss, src/main/webapp/app/communication/course-conversations/tutor-suggestion/tutor-suggestion.component.scss
Updated background token usages to new Iris theme variables; small formatting comments.
Theme Variables — Consolidation
src/main/webapp/content/scss/themes/_dark-variables.scss, src/main/webapp/content/scss/themes/_default-variables.scss
Removed legacy iris-chat-specific variables and introduced consolidated Iris theme variables (iris-primary/secondary/tertiary-background, iris-accent-background, iris-btn-primary, iris-label-color, iris-accent-border-color) plus several new feature tokens.
I18n
src/main/webapp/i18n/de/global.json, src/main/webapp/i18n/de/iris.json, src/main/webapp/i18n/de/student-dashboard.json, src/main/webapp/i18n/en/global.json, src/main/webapp/i18n/en/iris.json, src/main/webapp/i18n/en/student-dashboard.json
Added translations for iris menu label and chatHistory.newChat entries (EN/DE).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant Sidebar as CourseSidebarComponent
participant Science as ScienceService
participant Router
participant Chat as CourseChatbotComponent

User->>Sidebar: click Iris sidebar item
Sidebar->>Science: log IRIS__OPENED_SIDEBAR (courseId)
Sidebar->>Router: navigate to /course/:id/iris
Router->>Chat: instantiate CourseIrisComponent / CourseChatbot
Note right of Chat: Chat rendered with courseId
Sidebar->>Science: (on visibility) log IRIS__ENTRYPOINT_IMPRESSION (once per course)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Iris: Improved general UI changes for Iris' is directly related to the changeset, which comprises extensive UI updates, layout refinements, color variable simplifications, and styling improvements across Iris components in course and widget contexts.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 chore/iris/general-ui-fixes

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/webapp/app/core/course/overview/course-overview/course-overview.component.ts (1)

299-308: Fix dashboard flag logic to prevent unintended dashboard activation.

When studentCourseAnalyticsDashboardEnabled is false but irisEnabledInCourse is true, the OR condition passes true to getStudentDefaultItems, causing the dashboard item to be added even though analytics are disabled. Pass only studentCourseAnalyticsDashboardEnabled as the first parameter:

Fix
         const defaultItems = this.sidebarItemService.getStudentDefaultItems(
-            currentCourse?.studentCourseAnalyticsDashboardEnabled || currentCourse?.irisEnabledInCourse,
+            currentCourse?.studentCourseAnalyticsDashboardEnabled,
             currentCourse?.trainingEnabled,
         );
🤖 Fix all issues with AI agents
In
`@src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html`:
- Around line 200-205: The ngFor track uses the loop variable "line" which can
produce duplicate keys; update the ngFor in the iris-base-chatbot template that
iterates over (content | as: IrisTextMessageContent).textContent.split('\n') to
use a unique index key (track $index) instead of track line so each rendered
line has a stable unique key and avoids DOM reuse/NG0955 warnings.
- Around line 216-239: The three icon-only buttons for copy, thumbs-up, and
thumbs-down in iris-base-chatbot.component.html (the buttons invoking
copyMessage(message, i), rateMessage(message, true) and rateMessage(message,
false)) need accessible labels: add both aria-label and title attributes to each
button using the artemisTranslate pipe with keys `artemisApp.iris.chat.copy`,
`artemisApp.iris.chat.thumbsUp`, and `artemisApp.iris.chat.thumbsDown`
respectively so screen readers and tooltips receive the translated text.

In `@src/main/webapp/app/iris/overview/course-iris/course-iris.component.scss`:
- Around line 1-8: The :host selector contains two conflicting min-height
declarations (min-height: 100% and min-height: 0); remove the incorrect/unused
one so only the intended value remains (likely keep min-height: 0 for flex
behavior) by editing the :host block in course-iris.component.scss to delete the
duplicate min-height declaration.

In `@src/main/webapp/content/scss/themes/_dark-variables.scss`:
- Around line 633-640: The iris theme variables in _dark-variables.scss (e.g.,
$iris-primary-background, $iris-secondary-background, $iris-tertiary-background,
$iris-accent-background, $iris-btn-primary, $iris-label-color,
$iris-accent-border-color) incorrectly reference non-existent CSS custom
properties via var(--...), causing runtime styling failures; fix this by either
(preferred) replacing each var(...) usage with the corresponding SCSS variable
(for example use $neutral-dark, $neutral-dark-l-5, $neutral-dark-l-10,
$neutral-dark-l-15, $primary, $gray-500) or alternatively ensure those CSS
custom properties are defined in the theme :root; update the lines that assign
the $iris-* variables accordingly so they reference existing symbols in the SCSS
variable set.

In `@src/main/webapp/content/scss/themes/_default-variables.scss`:
- Around line 568-574: The SCSS variables $iris-secondary-background,
$iris-tertiary-background, $iris-accent-background, $iris-accent-border-color,
$iris-label-color and $iris-btn-primary are referencing undefined CSS custom
properties; update them to use the existing SCSS tokens instead (e.g. replace
var(--gray-100)/var(--gray-200)/var(--gray-300)/var(--gray-500)/var(--gray-600)
with the corresponding $gray-100/$gray-200/$gray-300/$gray-500/$gray-600 tokens
and replace var(--primary) with the existing $primary token) so the variables
resolve correctly in _default-variables.scss.
🧹 Nitpick comments (7)
src/main/webapp/app/iris/overview/exercise-chatbot/exercise-chatbot-button.component.html (1)

12-13: Remove commented-out code or restore functionality.

The commented-out translation span appears to be dead code. If the "see full" translation is no longer needed, remove the comment entirely. If it's intended to be restored, consider creating a tracking issue.

♻️ Proposed fix
             `@if` (isOverflowing()) {
                 <div class="read-more">
-                    <!-- <span jhiTranslate="artemisApp.iris.chatBubble.seeFull"></span> -->
                     <fa-icon [icon]="faArrowRight" class="read-more-icon" />
                 </div>
             }
src/main/webapp/app/iris/overview/course-chatbot/course-chatbot.component.scss (1)

8-9: Remove commented-out code.

The commented border line should be removed rather than left as dead code. If this was an intentional design change for the Iris UI update, keeping the comment adds noise without value.

♻️ Proposed fix
-    // border: 1px solid var(--border-color);
     border-radius: 8px;
src/main/webapp/app/iris/overview/base-chatbot/chat-status-bar/chat-status-bar.component.ts (1)

30-31: Remove unused openTimeout variable.

The openTimeout variable is declared and cleared in cleanup (line 80) but never assigned. Since the immediate closure behavior removed its usage, this is now dead code.

♻️ Proposed fix
     // Timeouts are not signals since they're not used in the template
-    private openTimeout: ReturnType<typeof setTimeout> | undefined;
     private styleTimeout: ReturnType<typeof setTimeout> | undefined;

Also update the cleanup:

             onCleanup(() => {
-                clearTimeout(this.openTimeout);
                 clearTimeout(this.styleTimeout);
             });

And remove the now-unnecessary clear at line 54:

             if (firstUnfinished) {
-                clearTimeout(this.openTimeout);
                 clearTimeout(this.styleTimeout);
src/main/webapp/app/iris/overview/base-chatbot/chat-history-item/chat-history-item.component.ts (1)

20-20: Consider maintainability for additional language support.

The hardcoded NEW_CHAT_TITLES set couples this component to specific translation strings. If additional languages are added (beyond English and German), this set will require updates. Consider documenting this coupling or extracting these values to a shared constant if they're used elsewhere.

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

19-28: Prefer undefined over null for courseIdParam.

Line 19 sets initialValue: null; map the param to undefined to keep the signal type consistent and avoid null. As per coding guidelines, prefer undefined over null.

🔧 Suggested update
-    private readonly courseIdParam = toSignal((this.route.parent?.paramMap ?? of(convertToParamMap({}))).pipe(map((params) => params.get('courseId'))), { initialValue: null });
+    private readonly courseIdParam = toSignal(
+        (this.route.parent?.paramMap ?? of(convertToParamMap({}))).pipe(map((params) => params.get('courseId') ?? undefined)),
+        { initialValue: undefined },
+    );
src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html (1)

16-75: Precompute session buckets instead of calling helpers repeatedly in the template.

Lines 26–66 call getSessionsBetween(...) multiple times per change detection; consider computed signals (e.g., todaySessions, yesterdaySessions, etc.) to avoid repeated filtering/date math.

src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.ts (1)

71-71: Avoid relying on localized titles for “new chat” detection.

Line 71 and Lines 533–575 hard-code EN/DE titles; other locales or backend title changes will misclassify sessions. Prefer a stable flag/enum on IrisSessionDTO (or a backend-provided marker).

Also applies to: 533-575

@github-project-automation github-project-automation bot moved this from Work In Progress to Ready For Review in Artemis Development Jan 27, 2026
@github-actions
Copy link

@thynguyentumde Test coverage could not be fully measured because some tests failed. Please check the workflow logs for details.

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

🤖 Fix all issues with AI agents
In
`@src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html`:
- Around line 201-205: The template renders user-provided text lines via
[innerHTML]="line" (in the iris-base-chatbot component loop over (content | as:
IrisTextMessageContent).textContent.split('\n')), which risks XSS; change it to
use safe text interpolation (replace [innerHTML]="line" with {{ line }} so
Angular escapes user text) or, if you intend to allow HTML from user messages,
apply the same sanitization pipe used for LLM messages (e.g., [innerHTML]="line
| htmlForMarkdown") to keep treatment consistent with LLM outputs.
🧹 Nitpick comments (4)
src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html (4)

96-114: Remove commented-out code before merging.

This block contains ~20 lines of commented HTML that clutters the template. If this functionality may be needed later, consider tracking it in an issue rather than leaving it in the codebase.


178-186: Use track $index for suggestion strings to avoid potential duplicate key warnings.

Line 178 uses track suggestion where suggestion is a string value. If two suggestions happen to have identical text, Angular will produce NG0955 warnings due to duplicate track keys.

🔧 Suggested fix
-                                `@for` (suggestion of suggestions(); track suggestion) {
+                                `@for` (suggestion of suggestions(); track $index) {

301-324: Extract duplicated disabled logic to a computed property.

The same complex disabled condition appears in both the textarea (lines 301-306) and send button (lines 318-324). This duplication makes maintenance error-prone.

Consider extracting to a computed signal in the component:

readonly isInputDisabled = computed(() => 
    this.isLoading() || 
    !this.active() || 
    (this.rateLimitInfo()?.rateLimit && this.rateLimitInfo()?.currentMessageCount === this.rateLimitInfo()?.rateLimit) ||
    this.hasActiveStage()
);

Then in template:

[disabled]="isInputDisabled()"

16-74: Convert session grouping methods to computed signals to avoid repeated evaluation on every change detection cycle.

The template calls getNewChatSessions() and getSessionsBetween() multiple times. While @let prevents repetition within a single template execution, it does not cache results across change detection cycles—these methods re-execute on every update. Converting to computed signals will memoize results until the underlying data (chatSessions() or searchValue()) actually changes.

Example:

readonly newChatSessions = computed(() => this.getNewChatSessions());
readonly todaySessions = computed(() => this.getSessionsBetween(0, 0));
readonly yesterdaySessions = computed(() => this.getSessionsBetween(1, 1));
// ... etc

Then use these computed signals directly in the template instead of calling the methods.

Comment on lines +201 to +205
<span class="bubble-right">
@for (line of (content | as: IrisTextMessageContent).textContent.split('\n'); track $index) {
<div [innerHTML]="line"></div>
}
</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for textContent usage in iris directory
rg -n "textContent" "src/main/webapp/app/iris/" -A 2 -B 2 | head -100

Repository: ls1intum/Artemis

Length of output: 11371


🏁 Script executed:

# Also check the component TypeScript file
fd "iris-base-chatbot.component.ts" "src/main/webapp/app/iris/"

Repository: ls1intum/Artemis

Length of output: 137


🏁 Script executed:

# Look at the surrounding context in the HTML file around line 203
sed -n '195,215p' "src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html" | cat -n

Repository: ls1intum/Artemis

Length of output: 1806


🏁 Script executed:

# Find the htmlForMarkdown pipe definition
fd "htmlForMarkdown" "src/main/webapp/"

Repository: ls1intum/Artemis

Length of output: 42


🏁 Script executed:

# Search for the pipe implementation
rg -n "htmlForMarkdown" "src/main/webapp/app/iris/" -B 5 -A 10 | head -80

Repository: ls1intum/Artemis

Length of output: 5077


🏁 Script executed:

# Check if there are any comments or documentation about security considerations
rg -n "innerHTML|sanitize|XSS" "src/main/webapp/app/iris/overview/base-chatbot/" -B 2 -A 2

Repository: ls1intum/Artemis

Length of output: 2494


🏁 Script executed:

# Find htmlForMarkdown pipe in shared pipes or common locations
find "src/main/webapp" -name "*.ts" -type f | xargs grep -l "htmlForMarkdown" | grep -i pipe

Repository: ls1intum/Artemis

Length of output: 118


🏁 Script executed:

# Search for the pipe declaration or export
rg -n "htmlForMarkdown|HtmlForMarkdown" "src/main/webapp" -t ts -B 3 -A 15 | head -120

Repository: ls1intum/Artemis

Length of output: 12855


🏁 Script executed:

# Read the htmlForMarkdown pipe implementation
cat -n "src/main/webapp/app/shared/pipes/html-for-markdown.pipe.ts"

Repository: ls1intum/Artemis

Length of output: 1531


🏁 Script executed:

# Find the ArtemisMarkdownService to understand what safeHtmlForMarkdown does
rg -n "safeHtmlForMarkdown" "src/main/webapp/app/shared/service/markdown.service.ts" -A 20 | head -60

Repository: ls1intum/Artemis

Length of output: 1232


🏁 Script executed:

# Also check if there's any documentation or comments about user input handling
cat -n "src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.ts" | sed -n '265,280p'

Repository: ls1intum/Artemis

Length of output: 972


🏁 Script executed:

# Check if user messages ever need HTML rendering or if they should be plain text
rg -n "IrisTextMessageContent|textContent" "src/main/webapp/app/iris/" -B 3 -A 3 | grep -A 5 -B 5 "USER"

Repository: ls1intum/Artemis

Length of output: 998


🏁 Script executed:

# Check the component imports to see if htmlForMarkdown is available
sed -n '1,50p' "src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.ts" | cat -n

Repository: ls1intum/Artemis

Length of output: 2990


🏁 Script executed:

# Check if the user can input arbitrary HTML or if it's controlled
rg -n "textContent|IrisUserMessage" "src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.ts" -B 2 -A 5 | grep -A 8 -B 8 "sendMessage"

Repository: ls1intum/Artemis

Length of output: 860


🏁 Script executed:

# Check how messages are sent from the client
fd "iris-chat.service.ts" "src/main/webapp/app/iris/" -exec cat -n {} \; | sed -n '1,100p'

Repository: ls1intum/Artemis

Length of output: 290


🏁 Script executed:

# Check the iris-chat.service.ts file
cat "src/main/webapp/app/iris/overview/services/iris-chat.service.ts" | head -150

Repository: ls1intum/Artemis

Length of output: 6895


🏁 Script executed:

# Check if there's any HTML sanitization on the client side when processing user input
rg -n "DomSanitizer|sanitize" "src/main/webapp/app/iris/" -B 2 -A 2

Repository: ls1intum/Artemis

Length of output: 42


Apply sanitization or text interpolation for user message content on line 203.

User-provided textContent is rendered directly via [innerHTML] without the htmlForMarkdown sanitization pipe applied to LLM messages (line 213). This creates an inconsistency in security treatment and exposes user input to potential XSS if malicious HTML is injected.

Since user messages are plain text, use text interpolation instead:

-                                                            <div [innerHTML]="line"></div>
+                                                            <div>{{ line }}</div>

Alternatively, if HTML formatting is intentional, apply the same htmlForMarkdown pipe used for LLM messages.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span class="bubble-right">
@for (line of (content | as: IrisTextMessageContent).textContent.split('\n'); track $index) {
<div [innerHTML]="line"></div>
}
</span>
<span class="bubble-right">
`@for` (line of (content | as: IrisTextMessageContent).textContent.split('\n'); track $index) {
<div>{{ line }}</div>
}
</span>
🤖 Prompt for AI Agents
In
`@src/main/webapp/app/iris/overview/base-chatbot/iris-base-chatbot.component.html`
around lines 201 - 205, The template renders user-provided text lines via
[innerHTML]="line" (in the iris-base-chatbot component loop over (content | as:
IrisTextMessageContent).textContent.split('\n')), which risks XSS; change it to
use safe text interpolation (replace [innerHTML]="line" with {{ line }} so
Angular escapes user text) or, if you intend to allow HTML from user messages,
apply the same sanitization pipe used for LLM messages (e.g., [innerHTML]="line
| htmlForMarkdown") to keep treatment consistent with LLM outputs.

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

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

@github-actions
Copy link

@thynguyentumde Test coverage could not be fully measured because some tests failed. Please check the workflow logs for details.

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report223 ran221 passed1 skipped1 failed1h 46m 32s 102ms
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❌ failure4m 45s 599ms

@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de January 28, 2026 09:30 Inactive
Copy link
Collaborator

@MaximilianAnzinger MaximilianAnzinger left a comment

Choose a reason for hiding this comment

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

science endpoint related changes look good. Minor remarks by Codacy should be considered.

flex: 1;
min-height: 0; /* allow child to shrink inside flex container */
min-height: 0;
/* allow child to shrink inside flex container */
Copy link
Collaborator

Choose a reason for hiding this comment

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

Codacy comment

.messages-container {
max-height: calc(90vh - 11.25rem); /* account for header and footer on mobile */
max-height: calc(90vh - 11.25rem);
/* account for header and footer on mobile */
Copy link
Collaborator

Choose a reason for hiding this comment

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

codacy comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

atlas Pull requests that affect the corresponding module client Pull requests that update TypeScript code. (Added Automatically!) communication Pull requests that affect the corresponding module core Pull requests that affect the corresponding module iris Pull requests that affect the corresponding module server Pull requests that update Java code. (Added Automatically!)

Projects

Status: Ready For Review
Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants