Skip to content

Add internal notes feature and improve chat UX - #32

Merged
addee1 merged 6 commits into
mainfrom
feature/internal-message
Apr 21, 2026
Merged

Add internal notes feature and improve chat UX#32
addee1 merged 6 commits into
mainfrom
feature/internal-message

Conversation

@addee1

@addee1 addee1 commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Adds support for internal notes in ticket conversations and improves the chat UI.

  • Staff (ADMIN, INVESTIGATOR) can mark messages as internal
  • Internal notes are hidden from reporters and anonymous users
  • Chat now displays message timestamps
  • Improved send button behavior (disabled when empty, correct cursor state)

Summary by CodeRabbit

  • New Features

    • Comments show readable formatted timestamps and an “internal” badge for internal notes.
    • Admin/Investigator users can mark comments as internal when posting.
    • Ticket description now appears at the top of the chat area.
  • UI Improvements

    • Dedicated scrollable chat container with custom scrollbar styling, auto-scroll-to-bottom on load, and a scroll-to-top button.
    • Comment send control updates cursor/disabled styling for clearer interaction feedback.

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@addee1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 34 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 55 minutes and 34 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e1d43606-d868-48cb-8db8-7e3c7cdfbe20

📥 Commits

Reviewing files that changed from the base of the PR and between 773f446 and a76b911.

📒 Files selected for processing (1)
  • src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java
📝 Walkthrough

Walkthrough

Adds an internalNote boolean to comment view data, formats comment creation timestamps for display, maps the new field from entities to DTOs, updates the chat UI to show formatted timestamps and an internal badge, provides a role-gated internal-note checkbox, customizes scrollbar styling, and adds scroll/top controls.

Changes

Cohort / File(s) Summary
DTO
src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java
Added private boolean internalNote and public String getFormattedCreatedAt() which returns "" when createdAt is null or formats it as dd MMM HH:mm.
Mapper
src/main/java/org/example/alfs/mapper/TicketCommentMapper.java
entityToViewDTO now sets internalNote on CommentViewDTO using comment.isInternalNote().
UI Template
src/main/jte/view.jte
Wrapped messages in a scroll container, added ticket-description block, displays each comment's formatted created-at, conditionally shows an “internal” badge, added role-gated internalNote checkbox for ADMIN/INVESTIGATOR, scroll-to-top button, auto-scroll-on-load, and updated toggleSendButton() to manage cursor classes.
Styles
src/main/resources/static/css/style.css
Added custom scrollbar styling for #chatContainer (WebKit and Firefox rules).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Feature/dto #3: Adds/extends CommentViewDTO changes (internalNote and formatted timestamp) that overlap with this PR.
  • Feature/non editable ticket #6: Related edits to the TicketComment internal-note field and mapping semantics.

Poem

🐇✧ I nibble through comments, a tiny internal clue,
Timestamps all tidy in dd MMM HH:mm view,
Admins can mark secrets with a gentle check,
Scrolls glide like carrots down the chat deck,
Hooray—soft badges and gold bars for our queue!

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add internal notes feature and improve chat UX' directly and accurately summarizes the main changes: introducing the internal notes feature (visible in DTO, mapper, and template changes) and improving the chat user experience (timestamps, scroll-to-top, scrollbar styling, send button behavior).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/internal-message

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/main/jte/view.jte (1)

276-291: Initial cursor state is set via static classes only — consider calling toggleSendButton() on load.

The button is initially rendered with cursor-not-allowed hardcoded (line 236), which is correct for the empty-textarea starting state, but if the form is ever re-rendered with preserved textarea content (e.g., validation error round-trip), the cursor/style will be stale until the user types. Low-impact; a one-liner toggleSendButton(); at the end of the script (or on DOMContentLoaded) would keep UI and state in sync.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/jte/view.jte` around lines 276 - 291, The toggleSendButton function
updates the send button state but isn't invoked on load, so initial classes
(e.g., cursor-not-allowed) can become out of sync if the textarea already has
content; call toggleSendButton() after the function definition or register it on
DOMContentLoaded (e.g., document.addEventListener('DOMContentLoaded', () =>
toggleSendButton())) so the textarea selector ('textarea[name="message"]') and
button id ("sendBtn") are checked and the correct classes/disabled state are
applied immediately.
src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java (1)

29-32: Consider including the year and deduplicating the formatter.

The pattern "dd MMM HH:mm" drops the year, which will be ambiguous/misleading for comments older than a year (e.g., a comment from 2024 and one from 2026 will look identical). TicketViewDTO.getFormattedCreatedAt() already uses "dd MMM yyyy HH:mm" — consider reusing the same pattern here for consistency, and extracting a shared DateTimeFormatter constant (e.g., in a util class) to avoid duplicating the pattern string across DTOs. Also, prefer a top-level import java.time.format.DateTimeFormatter; over the inline FQN to match TicketViewDTO's style.

♻️ Proposed change
 import lombok.Data;
 
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
@@
     public String getFormattedCreatedAt() {
         if (createdAt == null) return "";
-        return createdAt.format(java.time.format.DateTimeFormatter.ofPattern("dd MMM HH:mm"));
+        return createdAt.format(DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm"));
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java` around lines
29 - 32, Update CommentViewDTO.getFormattedCreatedAt to include the year and
reuse a shared DateTimeFormatter constant instead of an inline pattern: change
the pattern to match TicketViewDTO (e.g., "dd MMM yyyy HH:mm"), stop using the
fully-qualified java.time.format.DateTimeFormatter in this method, and reference
a single DateTimeFormatter constant (for example a public static final
DateTimeFormatter COMMENT_DATE_FORMAT in a common util or dto utility class) so
both CommentViewDTO.getFormattedCreatedAt and TicketViewDTO use the same
formatter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java`:
- Around line 29-32: Update CommentViewDTO.getFormattedCreatedAt to include the
year and reuse a shared DateTimeFormatter constant instead of an inline pattern:
change the pattern to match TicketViewDTO (e.g., "dd MMM yyyy HH:mm"), stop
using the fully-qualified java.time.format.DateTimeFormatter in this method, and
reference a single DateTimeFormatter constant (for example a public static final
DateTimeFormatter COMMENT_DATE_FORMAT in a common util or dto utility class) so
both CommentViewDTO.getFormattedCreatedAt and TicketViewDTO use the same
formatter.

In `@src/main/jte/view.jte`:
- Around line 276-291: The toggleSendButton function updates the send button
state but isn't invoked on load, so initial classes (e.g., cursor-not-allowed)
can become out of sync if the textarea already has content; call
toggleSendButton() after the function definition or register it on
DOMContentLoaded (e.g., document.addEventListener('DOMContentLoaded', () =>
toggleSendButton())) so the textarea selector ('textarea[name="message"]') and
button id ("sendBtn") are checked and the correct classes/disabled state are
applied immediately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a38939f5-1b02-422d-92e1-0dc81cb86436

📥 Commits

Reviewing files that changed from the base of the PR and between 735bdb2 and 3e35130.

📒 Files selected for processing (3)
  • src/main/java/org/example/alfs/dto/comment/CommentViewDTO.java
  • src/main/java/org/example/alfs/mapper/TicketCommentMapper.java
  • src/main/jte/view.jte

@addee1 addee1 self-assigned this Apr 20, 2026

@simonforsberg simonforsberg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good to me! Albeit a nitpick comment, maybe consider adding the year to the timestamp!

@FionaSprinkles FionaSprinkles left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good ✨

Comment thread src/main/jte/view.jte
${c.getAuthor()}
</div>

${c.getMessage()}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There is a risk that an admin or investigator might mistake an internal comment for a public one, leading to communication errors. Maybe add some sort of indicator so there is no confusion 😊 Maybe a different color or badge or something. 🌈

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, i've already added an "internal" note in the message, if the message is "internal" :)

@addee1
addee1 merged commit c7c26cf into main Apr 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants