Skip to content

Add comment count badge and title updates - #272

Open
cass-clearly wants to merge 1 commit into
mainfrom
feature/comment-count-267
Open

Add comment count badge and title updates#272
cass-clearly wants to merge 1 commit into
mainfrom
feature/comment-count-267

Conversation

@cass-clearly

Copy link
Copy Markdown
Owner

What changed

  • added comment count helpers and updated sidebar to show unresolved badge + title suffixes
  • added client tests for comment count formatting
  • fixed pre-commit hook to stage the built feedback-layer bundle

Why

Closes #267.

How to verify

remarq@2.3.0 test:client
c8 --check-coverage --lines 80 --include=feedback-layer/src/utils/** --include=feedback-layer/src/prompt-builder.js node --test feedback-layer/test/test.mjs feedback-layer/test/markdown.test.mjs

▶ renderMarkdown
✔ returns empty string for falsy input (0.92521ms)
✔ returns plain text unchanged (0.229837ms)
✔ renders bold text (0.095081ms)
✔ renders italic text (0.808559ms)
✔ renders bold text with underscores (0.117754ms)
✔ renders italic text with underscores (0.073831ms)
✔ matches underscore italic mid-word (known limitation) (0.079942ms)
✔ renders inline code (0.117063ms)
✔ renders links (0.243243ms)
✔ renders bold inside italic (0.14208ms)
✔ renders multiple markdown elements in one string (0.104829ms)
✔ does not apply bold/italic inside code spans (0.072217ms)
✔ handles adjacent bold and italic (0.063771ms)
✔ handles unclosed markers as plain text (0.067689ms)
✔ handles empty markers (0.059774ms)
✔ handles links with parentheses in URL (0.100922ms)
✔ converts line breaks to
tags (0.073429ms)
✔ preserves paragraph breaks (double newlines) (0.076546ms)
✔ renders markdown with line breaks correctly (0.077808ms)
✔ renderMarkdown (4.785484ms)
▶ renderMarkdown XSS prevention
✔ escapes HTML tags in input (0.124978ms)
✔ escapes HTML within bold markers (0.065194ms)
✔ blocks javascript: URLs in links (0.072057ms)
✔ blocks JavaScript: URLs case-insensitively (0.063831ms)
✔ blocks data: URLs in links (0.069332ms)
✔ blocks vbscript: URLs in links (0.065124ms)
✔ allows https links (0.0736ms)
✔ allows http links (0.073299ms)
✔ allows mailto links (0.080433ms)
✔ escapes HTML attributes in link text (0.070985ms)
✔ prevents injection via link URL with quotes (0.070404ms)
✔ renderMarkdown XSS prevention (1.031863ms)
▶ isSafeUrl
✔ allows https URLs (0.121391ms)
✔ allows http URLs (0.109308ms)
✔ allows mailto URLs (0.070114ms)
✔ allows relative URLs (0.071776ms)
✔ allows fragment URLs (0.073189ms)
✔ blocks javascript: scheme (0.070033ms)
✔ blocks JAVASCRIPT: scheme (case insensitive) (0.083018ms)
✔ blocks data: scheme (0.062509ms)
✔ blocks vbscript: scheme (0.054193ms)
✔ blocks javascript: with leading whitespace (0.053201ms)
✔ blocks javascript: with embedded tabs (0.054303ms)
✔ blocks javascript: with embedded newlines (0.071747ms)
✔ blocks javascript: with embedded carriage returns (0.071256ms)
✔ isSafeUrl (1.26648ms)
▶ renderMarkdown – line breaks
✔ converts newlines to
tags (0.100752ms)
✔ preserves multiple newlines (0.061336ms)
✔ renderMarkdown – line breaks (0.22597ms)
▶ escapeHtml
✔ escapes ampersands (0.835499ms)
✔ escapes less-than (0.132883ms)
✔ escapes greater-than (0.087216ms)
✔ escapes double quotes (0.086324ms)
✔ escapes single quotes (0.093308ms)
✔ handles all special chars together (0.095231ms)
✔ returns empty string unchanged (0.110009ms)
✔ escapeHtml (2.727669ms)
▶ formatComments
✔ formats a single comment (0.468952ms)
✔ formats multiple comments with numbering (0.11067ms)
✔ threads replies under parent (0.10008ms)
✔ returns placeholder for empty list (0.08391ms)
✔ handles comment without quote (0.08945ms)
✔ formatComments (1.04083ms)
▶ buildPrompt
✔ includes document HTML (0.16306ms)
✔ includes top-level comment count (0.121952ms)
✔ includes instructions section (0.18886ms)
✔ includes formatted comments (0.134135ms)
✔ buildPrompt (0.76239ms)
▶ threadComments
✔ separates top-level and reply comments (0.788389ms)
✔ handles empty array (0.082627ms)
✔ handles all top-level (no replies) (0.081916ms)
✔ groups multiple replies under same parent (0.098087ms)
✔ preserves order within top-level and replies (0.093949ms)
✔ threadComments (1.294733ms)
▶ truncate
✔ returns short strings unchanged (0.157099ms)
✔ truncates long strings with ellipsis (0.076165ms)
✔ handles exact length (0.077858ms)
✔ handles empty string (0.061607ms)
✔ truncate (0.494481ms)
▶ timeAgo
✔ returns 'just now' for recent timestamps (0.427202ms)
✔ returns minutes ago (0.15225ms)
✔ returns hours ago (0.15257ms)
✔ returns days ago (0.092857ms)
✔ timeAgo (0.994852ms)
▶ getFocusableElements
✔ returns empty array for null container (0.438634ms)
✔ getFocusableElements (0.498639ms)
▶ wrapIndex
✔ wraps negative index to end (0.131761ms)
✔ wraps index past end to beginning (0.06273ms)
✔ returns 0 for zero length (0.065795ms)
✔ returns index unchanged when within bounds (0.05791ms)
✔ wraps large negative index (0.059153ms)
✔ wraps large positive index (0.074021ms)
✔ returns 0 for index 0 and length 1 (0.063812ms)
✔ wrapIndex (0.70399ms)
▶ color utils
✔ resolves preset names to hex codes (0.169312ms)
✔ resolves preset names case-insensitively (0.075513ms)
✔ passes through valid hex codes (0.132011ms)
✔ returns null for invalid values (0.088027ms)
✔ converts hex to rgba (0.126671ms)
✔ exports expected presets (0.086775ms)
✔ has a default color matching yellow preset (0.078489ms)
✔ color utils (0.958574ms)
▶ injectPrintHideStyles
✔ creates a style element with print media rule (0.224006ms)
✔ injectPrintHideStyles (0.28378ms)
▶ commentCounts
✔ returns zeros for empty array (0.280583ms)
✔ counts top-level comments only (excludes replies) (0.161517ms)
✔ counts all as unresolved when none are closed (0.112985ms)
✔ commentCounts (0.660677ms)
▶ titleSuffix
✔ returns empty string for zero comments (0.156628ms)
✔ uses singular 'comment' for exactly 1 (0.069823ms)
✔ uses plural 'comments' for 2+ (0.065575ms)
✔ includes resolved count when some are resolved (0.069563ms)
✔ uses singular label when 1 resolved (0.684793ms)
✔ includes Remarq suffix (0.070544ms)
✔ titleSuffix (1.288822ms)
▶ api
✔ setBaseUrl strips trailing slashes (0.141069ms)
✔ api (0.188499ms)
ℹ tests 100
ℹ suites 17
ℹ pass 100
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 106.116979
---------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files | 99.69 | 98.63 | 100 | 99.69 |
src | 100 | 100 | 100 | 100 |
prompt-builder.js | 100 | 100 | 100 | 100 |
src/utils | 99.64 | 98.57 | 100 | 99.64 |
color.js | 100 | 100 | 100 | 100 |
comment-counts.js | 100 | 100 | 100 | 100 |
escape-html.js | 100 | 100 | 100 | 100 |
format-comments.js | 100 | 100 | 100 | 100 |
keyboard-nav.js | 96.66 | 83.33 | 100 | 96.66 | 16
markdown.js | 100 | 100 | 100 | 100 |
print-hide.js | 100 | 100 | 100 | 100 |
thread-comments.js | 100 | 100 | 100 | 100 |
time-ago.js | 100 | 100 | 100 | 100 |
truncate.js | 100 | 100 | 100 | 100 |
---------------------|---------|----------|---------|---------|-------------------

Manual testing checklist

  • Client tests pass (

remarq@2.3.0 test:client
c8 --check-coverage --lines 80 --include=feedback-layer/src/utils/** --include=feedback-layer/src/prompt-builder.js node --test feedback-layer/test/test.mjs feedback-layer/test/markdown.test.mjs

▶ renderMarkdown
✔ returns empty string for falsy input (2.04492ms)
✔ returns plain text unchanged (0.241259ms)
✔ renders bold text (0.096003ms)
✔ renders italic text (0.882599ms)
✔ renders bold text with underscores (0.110721ms)
✔ renders italic text with underscores (0.081124ms)
✔ matches underscore italic mid-word (known limitation) (0.074311ms)
✔ renders inline code (0.115981ms)
✔ renders links (0.284722ms)
✔ renders bold inside italic (0.205271ms)
✔ renders multiple markdown elements in one string (0.105741ms)
✔ does not apply bold/italic inside code spans (0.076115ms)
✔ handles adjacent bold and italic (0.065084ms)
✔ handles unclosed markers as plain text (0.06833ms)
✔ handles empty markers (0.061366ms)
✔ handles links with parentheses in URL (0.107414ms)
✔ converts line breaks to
tags (0.07335ms)
✔ preserves paragraph breaks (double newlines) (0.071216ms)
✔ renders markdown with line breaks correctly (0.107745ms)
✔ renderMarkdown (6.263014ms)
▶ renderMarkdown XSS prevention
✔ escapes HTML tags in input (0.129186ms)
✔ escapes HTML within bold markers (0.067469ms)
✔ blocks javascript: URLs in links (0.067328ms)
✔ blocks JavaScript: URLs case-insensitively (0.061837ms)
✔ blocks data: URLs in links (0.076496ms)
✔ blocks vbscript: URLs in links (0.069052ms)
✔ allows https links (0.06333ms)
✔ allows http links (0.072969ms)
✔ allows mailto links (0.076225ms)
✔ escapes HTML attributes in link text (0.066687ms)
✔ prevents injection via link URL with quotes (0.065564ms)
✔ renderMarkdown XSS prevention (1.022215ms)
▶ isSafeUrl
✔ allows https URLs (0.123445ms)
✔ allows http URLs (0.109879ms)
✔ allows mailto URLs (0.069702ms)
✔ allows relative URLs (0.086595ms)
✔ allows fragment URLs (0.112244ms)
✔ blocks javascript: scheme (0.063711ms)
✔ blocks JAVASCRIPT: scheme (case insensitive) (0.060094ms)
✔ blocks data: scheme (0.059092ms)
✔ blocks vbscript: scheme (0.056858ms)
✔ blocks javascript: with leading whitespace (0.054273ms)
✔ blocks javascript: with embedded tabs (0.053462ms)
✔ blocks javascript: with embedded newlines (0.053792ms)
✔ blocks javascript: with embedded carriage returns (0.055295ms)
✔ isSafeUrl (1.247343ms)
▶ renderMarkdown – line breaks
✔ converts newlines to
tags (0.112083ms)
✔ preserves multiple newlines (0.065915ms)
✔ renderMarkdown – line breaks (0.249635ms)
▶ escapeHtml
✔ escapes ampersands (0.705813ms)
✔ escapes less-than (0.086875ms)
✔ escapes greater-than (0.079131ms)
✔ escapes double quotes (0.074472ms)
✔ escapes single quotes (0.077438ms)
✔ handles all special chars together (0.073099ms)
✔ returns empty string unchanged (0.075523ms)
✔ escapeHtml (2.235323ms)
▶ formatComments
✔ formats a single comment (0.298267ms)
✔ formats multiple comments with numbering (0.098508ms)
✔ threads replies under parent (0.096063ms)
✔ returns placeholder for empty list (0.084621ms)
✔ handles comment without quote (0.085302ms)
✔ formatComments (0.817616ms)
▶ buildPrompt
✔ includes document HTML (0.156928ms)
✔ includes top-level comment count (0.121952ms)
✔ includes instructions section (0.115219ms)
✔ includes formatted comments (0.086925ms)
✔ buildPrompt (0.612285ms)
▶ threadComments
✔ separates top-level and reply comments (0.461608ms)
✔ handles empty array (0.087958ms)
✔ handles all top-level (no replies) (0.082978ms)
✔ groups multiple replies under same parent (0.098969ms)
✔ preserves order within top-level and replies (0.086585ms)
✔ threadComments (0.956279ms)
▶ truncate
✔ returns short strings unchanged (0.129767ms)
✔ truncates long strings with ellipsis (0.065685ms)
✔ handles exact length (0.06312ms)
✔ handles empty string (0.061297ms)
✔ truncate (0.444926ms)
▶ timeAgo
✔ returns 'just now' for recent timestamps (0.400001ms)
✔ returns minutes ago (0.080293ms)
✔ returns hours ago (0.074412ms)
✔ returns days ago (0.076636ms)
✔ timeAgo (0.743414ms)
▶ getFocusableElements
✔ returns empty array for null container (0.389641ms)
✔ getFocusableElements (0.445718ms)
▶ wrapIndex
✔ wraps negative index to end (0.12585ms)
✔ wraps index past end to beginning (0.059173ms)
✔ returns 0 for zero length (0.055976ms)
✔ returns index unchanged when within bounds (0.056688ms)
✔ wraps large negative index (0.058ms)
✔ wraps large positive index (0.060224ms)
✔ returns 0 for index 0 and length 1 (0.066597ms)
✔ wrapIndex (0.652882ms)
▶ color utils
✔ resolves preset names to hex codes (0.165775ms)
✔ resolves preset names case-insensitively (0.073059ms)
✔ passes through valid hex codes (0.129065ms)
✔ returns null for invalid values (0.079942ms)
✔ converts hex to rgba (0.128455ms)
✔ exports expected presets (0.107745ms)
✔ has a default color matching yellow preset (0.078299ms)
✔ color utils (0.953043ms)
▶ injectPrintHideStyles
✔ creates a style element with print media rule (0.213837ms)
✔ injectPrintHideStyles (0.270835ms)
▶ commentCounts
✔ returns zeros for empty array (0.230058ms)
✔ counts top-level comments only (excludes replies) (0.133504ms)
✔ counts all as unresolved when none are closed (0.096885ms)
✔ commentCounts (0.555196ms)
▶ titleSuffix
✔ returns empty string for zero comments (0.158341ms)
✔ uses singular 'comment' for exactly 1 (0.063801ms)
✔ uses plural 'comments' for 2+ (0.058652ms)
✔ includes resolved count when some are resolved (0.756159ms)
✔ uses singular label when 1 resolved (0.070123ms)
✔ includes Remarq suffix (0.055546ms)
✔ titleSuffix (1.302688ms)
▶ api
✔ setBaseUrl strips trailing slashes (0.14194ms)
✔ api (0.188689ms)
ℹ tests 100
ℹ suites 17
ℹ pass 100
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 98.825579
---------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files | 99.69 | 98.63 | 100 | 99.69 |
src | 100 | 100 | 100 | 100 |
prompt-builder.js | 100 | 100 | 100 | 100 |
src/utils | 99.64 | 98.57 | 100 | 99.64 |
color.js | 100 | 100 | 100 | 100 |
comment-counts.js | 100 | 100 | 100 | 100 |
escape-html.js | 100 | 100 | 100 | 100 |
format-comments.js | 100 | 100 | 100 | 100 |
keyboard-nav.js | 96.66 | 83.33 | 100 | 96.66 | 16
markdown.js | 100 | 100 | 100 | 100 |
print-hide.js | 100 | 100 | 100 | 100 |
thread-comments.js | 100 | 100 | 100 | 100 |
time-ago.js | 100 | 100 | 100 | 100 |
truncate.js | 100 | 100 | 100 | 100 |
---------------------|---------|----------|---------|---------|-------------------)

  • Tested in browser (annotations, sidebar, highlights work)
  • No console errors in browser DevTools

@cass-clearly

Copy link
Copy Markdown
Owner Author

Cass pipeline review: APPROVE. Spot-check passed against issue #267 acceptance criteria, and the implementation reports npm run test:client passing. Since this PR is authored by Cass, GitHub will not allow a formal self-approval review, so I am marking the board item Ready for Review for human review.

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.

Add comment count and resolved count to document header / page title

1 participant