Skip to content

Conversation

@HawKhiem
Copy link
Contributor

@HawKhiem HawKhiem commented Nov 24, 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

Fixes an issue where markdown code blocks (using triple backticks ```) were not rendering correctly in quiz short answer questions. Code blocks were displaying as plain text instead of being properly formatted with syntax highlighting. This issue only affected short answer questions, while multiple choice and drag-and-drop questions rendered code blocks correctly.

Description

This PR fixes the code block rendering issue in quiz short answer questions by refactoring the markdown processing pipeline

Short notice

Spot tags and other special HTML tags don’t work inside code blocks due to how Markdown works intrinsically. In Markdown code fences:

  • Everything is treated as literal text, not real HTML.
  • So just shows up as text, not as a real form control.
  • So for this PR you might be getting errors when trying to put spot tag or hint tags inside of code blocks. This is unrelated to this PR.

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 1 Quiz Exercise with Short Answer (REQUIRED), Multiple Choice ((OPTIONAL)), and Drag-and-Drop questions (OPTIONAL)
  1. Log in to Artemis as an instructor
  2. Navigate to Course Management → Exercises → Create Quiz
  3. Create a Short Answer Question and try to add a clock block. Example (you can simply copy and paste this into the markdown editor). But do try to mess around to see if code block works in general:
Enter your long question if needed
```java
System.out.println("Hello");
System.out.println("World");
```
Select a part of the text and click on Add Spot to automatically create an input field and the corresponding mapping
You can define a input field like this: This [-spot 1] an [-spot 2] field.
To define the solution for the input fields you need to create a mapping (multiple mapping also possible):
[-option 1] is
[-option 2] input
[-option 1,2] correctInBothFields
  1. (OPTIONAL) Create a Multiple Choice Question with a code block in the question text. Example (you can simply copy and paste this into the markdown editor). But do try to mess around to see if code block works in general:
```java
System.out.println("Hello");
System.out.println("World");
```
Enter your long question if needed
	[hint] Add a hint here (visible during the quiz via ?-Button)

[correct] Enter a correct answer option here
	[hint] Add a hint here (visible during the quiz via ?-Button)
	[exp] Add an explanation here (only visible in feedback after quiz has ended)
[wrong] Enter a wrong answer option here
  1. (OPTIONAL) Create a Drag-and-Drop Question with a code block in the question text. Example (you can simply copy and paste this into the markdown editor). But do try to mess around to see if code block works in general:
```java
System.out.println("Hello");
System.out.println("World");
```
Enter your long question if needed
	[hint] Add a hint here (visible during the quiz via ?-Button)
  1. Save and start the quiz
  2. Verify as a student:
    • Code blocks render with syntax highlighting in all question types

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
  • Test 2

Test Coverage

Screenshots

Before (Code block not rendering):
image

After (Fixed):
image

Summary by CodeRabbit

  • Bug Fixes

    • Markdown code blocks in short-answer quiz questions are now preserved when splitting text, preventing code snippets from being broken across lines (including handling of unclosed blocks).
  • Style

    • Adjusted short-answer display alignment and element display rules; inputs and pre-containing elements now layout more consistently and unnecessary bottom spacing was removed.

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

@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Nov 24, 2025
@github-actions github-actions bot added client Pull requests that update TypeScript code. (Added Automatically!) quiz Pull requests that affect the corresponding module labels Nov 24, 2025
@HawKhiem HawKhiem linked an issue Nov 24, 2025 that may be closed by this pull request
@HawKhiem HawKhiem marked this pull request as ready for review November 24, 2025 19:12
@HawKhiem HawKhiem requested a review from a team as a code owner November 24, 2025 19:12
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 24, 2025

Walkthrough

Preserve Markdown fenced code blocks when splitting short-answer question text and adjust short-answer component styles: the parser now accumulates lines between triple-backtick delimiters before spot-tag processing; CSS changes modify alignment, display, and full-width behavior for elements containing pre blocks.

Changes

Cohort / File(s) Summary
Short-Answer Question Processing
src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
Updated line-splitting logic to detect and preserve fenced Markdown code blocks (```): accumulate lines inside code fences and treat each code block as a single line unit; handle unclosed code blocks by appending remaining lines. Downstream spot-tag detection and interleaving remain applied to the resulting lines.
Short-Answer Component Styles
src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
Adjusted layout: set alignment baseline, changed display from inline-flex to inline-block, added selector to make elements containing a pre child occupy full width, and removed bottom margin on the short-answer input container.

Sequence Diagram(s)

sequenceDiagram
    participant Input as questionText
    participant Parser as Line Parser
    participant PostProc as Spot Processor
    participant Output as Processed Lines

    Note over Parser: Old: split by newline only
    Input->>Parser: raw questionText
    Parser->>Parser: Scan lines for ``` delimiter
    alt entering code block
        Parser->>Parser: Accumulate lines until closing ```
        Parser->>Parser: Merge accumulated block into one line
    else no/closed blocks
        Parser->>Parser: Emit normal line
    end
    Parser->>PostProc: lines array (code-block-aware)
    PostProc->>PostProc: Detect spot tags and interleave fragments
    PostProc->>Output: final line fragments
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review code-block detection and delimiter handling (including unclosed fences).
  • Verify spot-tag processing integrates correctly with merged code-block lines.
  • Check CSS changes for layout regressions, especially elements with pre children and inline display differences.

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 pull request title directly and accurately summarizes the main change: fixing code blocks not rendering in the markdown editor for quiz exercises.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 bugfix/quiz-exercises/code-blocks-markdown-rendering

📜 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 8f039ae and 7f54493.

📒 Files selected for processing (2)
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss (1 hunks)
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.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/quiz/shared/service/short-answer-question-util.service.ts
🧠 Learnings (3)
📚 Learning: 2025-08-19T19:56:34.228Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:40-40
Timestamp: 2025-08-19T19:56:34.228Z
Learning: In the ShortAnswerQuestionComponent (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the fnOnSubmittedTextUpdate input should remain typed as "any" rather than being changed to a more specific function type like "(() => void) | undefined". This is an intentional design decision.

Applied to files:

  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
📚 Learning: 2025-08-19T20:07:18.114Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:76-78
Timestamp: 2025-08-19T20:07:18.114Z
Learning: In ShortAnswerQuestion components (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the text, hint, and explanation properties are required fields for short answer questions and do not need null safety checks when accessing them from shortAnswerQuestion().

Applied to files:

  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
📚 Learning: 2025-08-19T19:56:07.618Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/multiple-choice-question/visual-question/multiple-choice-visual-question.component.ts:84-86
Timestamp: 2025-08-19T19:56:07.618Z
Learning: In Angular signals migration for MultipleChoiceVisualQuestionComponent, when adding new answer options, it's preferred to create a copy of the answerOptions array rather than directly mutating it, maintaining immutability principles while working with signal-returned objects.

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
⏰ 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: client-style
  • GitHub Check: client-tests-selected
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: server-style
  • GitHub Check: Analyse
🔇 Additional comments (5)
src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss (2)

14-14: LGTM!

Adding align-items: baseline to the flex container ensures proper vertical alignment of text fragments and input fields, especially when mixed with code blocks.


18-23: LGTM!

Changing to inline-block and adding the :has(pre) selector ensures code blocks render at full width rather than being squeezed inline with surrounding text. The :has() pseudo-class is well-supported in modern browsers (Chrome 105+, Firefox 121+, Safari 15.4+), which is appropriate for 2025.

src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts (3)

281-300: LGTM!

The updated JSDoc clearly explains the code block preservation logic and processing steps, with a helpful example showing the spot tag interleaving behavior.


316-348: Code block preservation logic looks correct.

The implementation properly detects opening/closing delimiters, accumulates lines between them, and handles edge cases like unclosed blocks. The use of `trim().startsWith('')` appropriately handles indented code blocks.

Note: Spot tags appearing as literal text inside code blocks will still be processed by the regex split on lines 350-354. However, per the PR description, this is a documented limitation ("Spot tags... do not work inside Markdown code fences").


393-396: LGTM! Indentation fix has been correctly applied.

The method now properly passes textParts (original plain text) as the first parameter and formattedTextParts (HTML-converted) as the second parameter to addIndentationToTextParts. This resolves the critical issue flagged in the previous review where both parameters were HTML, which broke leading-space detection.

✅ Addresses the previous review comment about indentation logic.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

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/quiz/shared/service/short-answer-question-util.service.ts (1)

304-310: The indentation detection will break with HTML-wrapped content.

The concern is valid. When htmlForMarkdown converts markdown, it wraps content in HTML tags like <p>, <b>, etc. For example, plain text " some text" becomes "<p> some text</p>".

The issue: The getIndentation method looks for spaces at the string start using while (text[index] === ' '). When leading spaces are inside HTML tags, this fails. For input "<p> text</p>", it returns '' instead of detecting the 4 spaces.

The same problem affects getFirstWord, which uses text.trim().split(' ') and will incorrectly parse HTML tag content.

At line 378 in addIndentationToTextParts, the code calls getIndentation(originalTextParts[i][0]) expecting plain text, but originalTextParts now contains HTML from the modified divideQuestionTextIntoTextParts. The existing tests only cover plain text inputs, so this regression is not caught.

📜 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 466bb2c and aaa60e6.

📒 Files selected for processing (2)
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss (2 hunks)
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.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/quiz/shared/service/short-answer-question-util.service.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: magaupp
Repo: ls1intum/Artemis PR: 8802
File: src/main/resources/templates/rust/exercise/src/context.rs:1-1
Timestamp: 2024-10-08T15:35:42.972Z
Learning: Code inside the `exercise` directories in the Artemis platform is provided to students and is intended for them to implement. TODO comments in these directories are meant to guide students and should not be addressed in the PR.
Learnt from: magaupp
Repo: ls1intum/Artemis PR: 8802
File: src/main/resources/templates/rust/exercise/src/context.rs:1-1
Timestamp: 2024-08-05T00:11:50.650Z
Learning: Code inside the `exercise` directories in the Artemis platform is provided to students and is intended for them to implement. TODO comments in these directories are meant to guide students and should not be addressed in the PR.
📚 Learning: 2025-08-19T20:07:18.114Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:76-78
Timestamp: 2025-08-19T20:07:18.114Z
Learning: In ShortAnswerQuestion components (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the text, hint, and explanation properties are required fields for short answer questions and do not need null safety checks when accessing them from shortAnswerQuestion().

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
📚 Learning: 2025-08-19T19:56:34.228Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:40-40
Timestamp: 2025-08-19T19:56:34.228Z
Learning: In the ShortAnswerQuestionComponent (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the fnOnSubmittedTextUpdate input should remain typed as "any" rather than being changed to a more specific function type like "(() => void) | undefined". This is an intentional design decision.

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
📚 Learning: 2025-08-19T19:56:07.618Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/multiple-choice-question/visual-question/multiple-choice-visual-question.component.ts:84-86
Timestamp: 2025-08-19T19:56:07.618Z
Learning: In Angular signals migration for MultipleChoiceVisualQuestionComponent, when adding new answer options, it's preferred to create a copy of the answerOptions array rather than directly mutating it, maintaining immutability principles while working with signal-returned objects.

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
📚 Learning: 2025-08-21T17:30:20.530Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/drag-and-drop-question/drag-and-drop-question.component.spec.ts:34-34
Timestamp: 2025-08-21T17:30:20.530Z
Learning: FitTextDirective in src/main/webapp/app/quiz/shared/fit-text/fit-text.directive.ts is a standalone directive marked with standalone: true, so it should be imported in TestBed imports array, not declarations array.

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
🧬 Code graph analysis (1)
src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts (1)
src/main/webapp/app/shared/util/markdown.conversion.util.ts (1)
  • htmlForMarkdown (44-97)
⏰ 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). (6)
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • 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: Analyse
🔇 Additional comments (2)
src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.scss (2)

14-31: Well-designed responsive handling for code blocks.

The CSS changes properly support the new HTML structure from the service layer:

  1. align-items: baseline ensures proper alignment between text and input fields
  2. inline-block with nested inline divs allows text to flow naturally within the flex container
  3. The :has(pre) selector cleverly handles code blocks by giving them full width (flex-basis: 100%, width: 100%) and making nested divs block-level for proper formatting

This approach ensures code blocks render on their own line with proper spacing while keeping regular text inline.

Note: The :has() pseudo-class is well-supported in modern browsers as of 2025, so compatibility should not be a concern.


43-43: Better vertical alignment approach.

Changing from margin-bottom to vertical-align: middle is a more semantic way to align inline-block input fields with surrounding text content, especially given the new align-items: baseline on the parent container.

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

End-to-End (E2E) Test Results Summary

TestsPassed ✅Skipped ⚠️FailedTime ⏱
End-to-End (E2E) Test Report215 ran212 passed3 skipped0 failed1h 10m 30s 186ms
TestResultTime ⏱
No test annotations available

@helios-aet helios-aet bot temporarily deployed to artemis-test2.artemis.cit.tum.de November 24, 2025 22:55 Inactive
Copy link
Contributor

@MarcosOlivaKaczmarek MarcosOlivaKaczmarek 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 TS2. Everything worked as far as I can tell.

Image

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 24, 2025
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 (3)
src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts (2)

95-108: Hardcoded HTML expectations may be fragile.

The test at lines 104-107 expects specific HTML structure including <p> tags wrapping words like <p>This and question.</p>. This couples the test to markdown-it's specific rendering behavior. Consider using a more flexible assertion similar to what's done in later test cases:

-        const expectedTextParts = [
-            ['<p>This', 'is', 'a', '[-spot 12]', 'regarding', 'this', 'question.</p>'],
-            ['<p>Another', '[-spot 8]', 'is', 'in', 'the', 'line', 'above</p>'],
-        ];
-        expect(component.textParts).toEqual(expectedTextParts);
+        // Verify spot tags are preserved
+        const allSpots = component.textParts.flat().filter((part) => part && part.includes('[-spot'));
+        expect(allSpots).toContain('[-spot 12]');
+        expect(allSpots).toContain('[-spot 8]');
+        // Verify content is preserved
+        const allText = component.textParts.flat().join(' ');
+        expect(allText).toContain('regarding this question');
+        expect(allText).toContain('Another');

This would make the test more resilient to minor markdown rendering changes while still verifying the core functionality.


540-546: Consider flexible assertion for consistency.

Similar to the earlier comment, this test has hardcoded HTML structure expectations. While it currently works, consider using flexible assertions:

-        const splitString = ['<p>This', 'is', 'a', 'text', 'for', 'a', 'test</p>'];
-        expect(component.textParts.pop()).toEqual(splitString);
+        const lastPart = component.textParts.pop()!;
+        const joinedText = lastPart.join(' ');
+        expect(joinedText).toContain('This is a text for a test');

This is a minor suggestion for test maintainability.

src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts (1)

210-223: Tests could better verify indentation application.

The tests pass { plain, html } objects but expect the exact htmlParts arrays as output. Since addIndentationToTextParts modifies formattedTextParts in place (adding &nbsp; for indentation), these tests work by coincidence because the test data doesn't have significant indentation differences.

Consider adding a test that verifies indentation is actually applied:

it('should apply indentation from plain text to HTML', () => {
    const plainParts = [['    indented text']];
    const htmlParts = [['indented text']];
    const result = service.transformTextPartsIntoHTML({ plain: plainParts, html: htmlParts });
    expect(result[0][0]).toContain('&nbsp;');
    expect(result[0][0]).toContain('indented text');
});

This would ensure the indentation preservation logic is explicitly tested.

📜 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 aaa60e6 and b69db1a.

📒 Files selected for processing (6)
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts (9 hunks)
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts (3 hunks)
  • src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts (1 hunks)
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts (1 hunks)
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts (1 hunks)
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts (3 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/quiz/shared/service/short-answer-question-util.service.ts
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts
  • src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
🧠 Learnings (14)
📓 Common learnings
Learnt from: magaupp
Repo: ls1intum/Artemis PR: 8802
File: src/main/resources/templates/rust/exercise/src/context.rs:1-1
Timestamp: 2024-10-08T15:35:42.972Z
Learning: Code inside the `exercise` directories in the Artemis platform is provided to students and is intended for them to implement. TODO comments in these directories are meant to guide students and should not be addressed in the PR.
Learnt from: magaupp
Repo: ls1intum/Artemis PR: 8802
File: src/main/resources/templates/rust/exercise/src/context.rs:1-1
Timestamp: 2024-08-05T00:11:50.650Z
Learning: Code inside the `exercise` directories in the Artemis platform is provided to students and is intended for them to implement. TODO comments in these directories are meant to guide students and should not be addressed in the PR.
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:76-78
Timestamp: 2025-08-19T20:07:18.114Z
Learning: In ShortAnswerQuestion components (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the text, hint, and explanation properties are required fields for short answer questions and do not need null safety checks when accessing them from shortAnswerQuestion().
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:40-40
Timestamp: 2025-08-19T19:56:34.228Z
Learning: In the ShortAnswerQuestionComponent (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the fnOnSubmittedTextUpdate input should remain typed as "any" rather than being changed to a more specific function type like "(() => void) | undefined". This is an intentional design decision.
📚 Learning: 2025-08-19T19:56:34.228Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:40-40
Timestamp: 2025-08-19T19:56:34.228Z
Learning: In the ShortAnswerQuestionComponent (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the fnOnSubmittedTextUpdate input should remain typed as "any" rather than being changed to a more specific function type like "(() => void) | undefined". This is an intentional design decision.

Applied to files:

  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts
  • src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
📚 Learning: 2025-08-19T20:07:18.114Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts:76-78
Timestamp: 2025-08-19T20:07:18.114Z
Learning: In ShortAnswerQuestion components (src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts), the text, hint, and explanation properties are required fields for short answer questions and do not need null safety checks when accessing them from shortAnswerQuestion().

Applied to files:

  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts
  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts
  • src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
📚 Learning: 2025-08-19T19:56:07.618Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/multiple-choice-question/visual-question/multiple-choice-visual-question.component.ts:84-86
Timestamp: 2025-08-19T19:56:07.618Z
Learning: In Angular signals migration for MultipleChoiceVisualQuestionComponent, when adding new answer options, it's preferred to create a copy of the answerOptions array rather than directly mutating it, maintaining immutability principles while working with signal-returned objects.

Applied to files:

  • src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
📚 Learning: 2024-10-13T12:03:02.430Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9463
File: src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.service.spec.ts:50-55
Timestamp: 2024-10-13T12:03:02.430Z
Learning: In `src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.service.spec.ts`, when a function is called multiple times in a test, use `toHaveBeenCalledTimes` and `toHaveBeenNthCalledWith` assertions instead of `toHaveBeenCalledExactlyOnceWith`.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts
📚 Learning: 2024-10-10T11:42:23.069Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9443
File: src/test/javascript/spec/component/hestia/git-diff-report/git-diff-modal.component.spec.ts:55-60
Timestamp: 2024-10-10T11:42:23.069Z
Learning: In `git-diff-report-modal.component.spec.ts`, using `fakeAsync` and `tick` does not work for handling asynchronous operations in the tests; alternative methods are needed.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2025-08-21T17:30:20.530Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/drag-and-drop-question/drag-and-drop-question.component.spec.ts:34-34
Timestamp: 2025-08-21T17:30:20.530Z
Learning: FitTextDirective in src/main/webapp/app/quiz/shared/fit-text/fit-text.directive.ts is a standalone directive marked with standalone: true, so it should be imported in TestBed imports array, not declarations array.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
  • src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts
  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
📚 Learning: 2025-09-01T10:20:40.706Z
Learnt from: Michael-Breu-UIbk
Repo: ls1intum/Artemis PR: 10989
File: src/main/webapp/app/programming/manage/detail/programming-exercise-detail.component.with-sharing.spec.ts:132-149
Timestamp: 2025-09-01T10:20:40.706Z
Learning: In the Artemis codebase, Angular component test files for ProgrammingExerciseDetailComponent follow a pattern where the component is imported but not explicitly declared in TestBed.configureTestingModule(), yet TestBed.createComponent() still works successfully. This pattern is consistently used across test files like programming-exercise-detail.component.spec.ts and programming-exercise-detail.component.with-sharing.spec.ts.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2024-10-20T22:00:52.335Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9505
File: src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts:179-181
Timestamp: 2024-10-20T22:00:52.335Z
Learning: In `src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts`, `ResizeObserver` is mocked within the `beforeEach` block.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2025-02-16T16:00:38.131Z
Learnt from: iyannsch
Repo: ls1intum/Artemis PR: 10344
File: src/test/javascript/spec/component/shared/code-button.component.spec.ts:0-0
Timestamp: 2025-02-16T16:00:38.131Z
Learning: In test cases, prefer removing unnecessary type assertions over adding mock properties that aren't relevant to what's being tested. This keeps tests focused and reduces maintenance burden.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2024-10-08T15:35:52.595Z
Learnt from: pzdr7
Repo: ls1intum/Artemis PR: 9407
File: src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts:172-175
Timestamp: 2024-10-08T15:35:52.595Z
Learning: When testing components that use `MonacoEditorComponent`, it's acceptable not to test `MonacoEditorComponent` functionality within those tests, as dedicated tests already exist for it.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2024-07-09T19:09:49.666Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts:88-89
Timestamp: 2024-07-09T19:09:49.666Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting to change `expect(component.expandAll).toHaveBeenCalledOnce()` to `expect(component.expandAll).toHaveBeenCalledTimes(1)`.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2024-07-09T19:09:58.572Z
Learnt from: florian-glombik
Repo: ls1intum/Artemis PR: 8858
File: src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts:115-115
Timestamp: 2024-07-09T19:09:58.572Z
Learning: For the PR ls1intum/Artemis#8858, avoid suggesting to change `expect(component.setStoredCollapseState).toHaveBeenCalledOnce()` to `expect(component.setStoredCollapseState).toHaveBeenCalledTimes(1)`.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts
📚 Learning: 2025-08-19T19:53:56.451Z
Learnt from: MoritzSpengler
Repo: ls1intum/Artemis PR: 11297
File: src/main/webapp/app/quiz/shared/questions/multiple-choice-question/multiple-choice-question.component.ts:26-37
Timestamp: 2025-08-19T19:53:56.451Z
Learning: In the MultipleChoiceQuestionComponent (src/main/webapp/app/quiz/shared/questions/multiple-choice-question/multiple-choice-question.component.ts), the fnOnSelection input should remain typed as "any" rather than being changed to a more specific function type like "(() => void) | undefined". This is an intentional design decision.

Applied to files:

  • src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts
🧬 Code graph analysis (1)
src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts (1)
src/main/webapp/app/shared/util/markdown.conversion.util.ts (1)
  • htmlForMarkdown (44-97)
⏰ 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). (8)
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: server-style
  • GitHub Check: client-style
  • 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 (10)
src/main/webapp/app/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts (1)

60-63: LGTM!

The adaptation to the new divideQuestionTextIntoTextParts API is correct. The structured object is properly passed to transformTextPartsIntoHTML, which returns the HTML-formatted string[][] for assignment to this.textParts.

src/main/webapp/app/quiz/shared/questions/short-answer-question/short-answer-question.component.ts (1)

82-91: LGTM!

The watchCollection method correctly uses the new structured return from divideQuestionTextIntoTextParts and passes it to transformTextPartsIntoHTML. This is consistent with changes in other components. Based on learnings, the non-null assertion on text is acceptable as it's a required field for short answer questions.

src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.ts (2)

289-320: LGTM! Good fix for the code blocks rendering issue.

The refactored approach correctly separates concerns:

  1. plainTextParts preserves original whitespace for indentation detection
  2. htmlTextParts uses htmlForMarkdown to render markdown features like code blocks with syntax highlighting

This addresses the prior review feedback about indentation logic being broken when HTML was passed for both parameters.


351-361: Clean implementation with clear documentation.

The updated method properly delegates indentation detection to plain text while preserving HTML formatting in the output. The JSDoc comments accurately describe the new behavior.

src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.spec.ts (1)

379-383: LGTM!

The mock correctly returns the new structured object format expected by divideQuestionTextIntoTextParts.

src/main/webapp/app/quiz/shared/service/short-answer-question-util.service.spec.ts (1)

188-208: Good test coverage for the new API structure.

The test properly verifies:

  1. The new return structure with plain and html properties
  2. HTML conversion of markdown (e.g., **bold**<strong>bold</strong>)
  3. Spot tag preservation in the HTML output
  4. Paragraph wrapping behavior from markdown-it

The assertions correctly access textPartsData.html to verify the rendered output.

src/main/webapp/app/quiz/manage/short-answer-question/short-answer-question-edit.component.ts (4)

170-195: LGTM - Correct use of the new API for HTML rendering context.

The change correctly accesses .html[0] from the new structured return type, which is appropriate since this method parses text for visual display purposes.


431-433: LGTM - Correct use of plain text for position-based manipulation.

Using .plain here is appropriate since the subsequent substring operations (lines 432-433) require raw text positions that would be incorrect if HTML entities were present.


437-438: LGTM - Proper integration with refactored utility API.

The pattern of capturing the full data object and passing it to transformTextPartsIntoHTML correctly follows the new API design that separates plain and HTML representations.


605-606: LGTM - Consistent pattern with the other call sites.

The implementation correctly mirrors the pattern used in addSpotAtCursorVisualMode, maintaining consistency across the component. Based on learnings, the non-null assertion on text is acceptable since it's a required field.

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 422ms
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 Report215 ran210 passed3 skipped2 failed1h 14m 3s 280ms
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 31s 648ms
e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts
ts.Programming exercise participation › Programming exercise team participation › Check team participation › Instructor checks the participation❌ failure8s 851ms

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 25, 2025
@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 2m 4s 805ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts
ts.Programming exercise participation › Programming exercise team participation › Check team participation › Instructor checks the participation❌ failure8s 919ms

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 422ms
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 Report215 ran210 passed3 skipped2 failed1h 11m 55s 338ms
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 69ms
e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts
ts.Programming exercise participation › Programming exercise team participation › Check team participation › Instructor checks the participation❌ failure8s 2ms

az108
az108 previously approved these changes Nov 26, 2025
Copy link
Contributor

@az108 az108 left a comment

Choose a reason for hiding this comment

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

Code 👍 Thanks for fixing this issue

sawys777
sawys777 previously approved these changes Nov 26, 2025
Copy link

@sawys777 sawys777 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, tested on TS4, everything works as described

Copy link
Contributor

@theblobinthesky theblobinthesky left a comment

Choose a reason for hiding this comment

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

Tested locally, joins code block lines as expected. Should this code block joining maybe be documented in the method comment?

@HawKhiem HawKhiem dismissed stale reviews from sawys777, az108, and coderabbitai[bot] via 7f54493 November 27, 2025 09:11
@HawKhiem
Copy link
Contributor Author

Tested locally, joins code block lines as expected. Should this code block joining maybe be documented in the method comment?

Ahh, good catch! I just updated the comment! Thanks :D

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed1s 693ms
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 Report218 ran211 passed3 skipped4 failed1h 16m 3s 965ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exam/test-exam/TestExamParticipation.spec.ts
ts.Test exam participation › Early Hand-in › Using exercise sidebar to navigate within exam❌ failure4m 36s 535ms
ts.Test exam participation › Early Hand-in › Using exercise overview to navigate within exam❌ failure3m 36s 10ms
e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts
ts.Programming exercise participation › Programming exercise team participation › Check team participation › Instructor checks the participation❌ failure8s 148ms
e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts
ts.Static code analysis tests › Configures SCA grading and makes a successful submission with SCA errors❌ failure2m 43s 826ms

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report218 ran214 passed3 skipped1 failed1h 1m 15s 630ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts
ts.Programming exercise participation › Programming exercise team participation › Check team participation › Instructor checks the participation❌ failure8s 354ms

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

Labels

bugfix client Pull requests that update TypeScript code. (Added Automatically!) quiz Pull requests that affect the corresponding module ready for review

Projects

Status: Ready For Review

Development

Successfully merging this pull request may close these issues.

Quiz: Unable to create code block