Skip to content

CTS - MyAssessment UI changes#155

Open
rlorenzo wants to merge 2 commits into
mainfrom
VPR-104-accessibility-audit-CTS-myassessments
Open

CTS - MyAssessment UI changes#155
rlorenzo wants to merge 2 commits into
mainfrom
VPR-104-accessibility-audit-CTS-myassessments

Conversation

@rlorenzo
Copy link
Copy Markdown
Contributor

@rlorenzo rlorenzo commented Apr 20, 2026

Summary

Final piece of the CTS accessibility audit for MyAssessments — collapses the page down to two settled designs (Compact + Timeline), keeps the privacy-preserving AssessmentBubble redesign, and adds the Timeline narrative view as the default for students viewing their own page.

Two display modes

A q-tabs at the top of the page switches between Compact and Timeline. The default depends on the viewer:

  • Timeline — when the student opens /CTS/MyAssessments for themselves (no ?student= query). Renders the new narrative EpaVoiceThread cards.
  • Compact — when a non-student (faculty/admin) opens /CTS/MyAssessments?student=X. Renders the compact bubble grid; expanding an EPA reveals the same voice-card style used in Timeline (quote + name·service·date·supervision-dot byline).

The toggle wrapper carries role="group" + aria-label="Assessment display mode" so screen readers announce it as a single grouped control.

Compact mode (AssessmentBubble.vue)

  • Privacy-preserving aria-label — the rating dot reads the descriptive level name (e.g. "Trust with indirect supervision"), never the numeric value. Prevents screen readers from announcing a low rating aloud in shared spaces. (4.1.2 Name, Role, Value)
  • Contrast & target size — buttons use a stepped UC Davis blue palette (rgba(62,127,238,0.3)rgba(11,3,139,1)), 1.5rem diameter, blue (Quasar primary) focus-visible ring, 0.25rem horizontal spacing. (1.4.1 Use of Color, 1.4.11 Non-text Contrast)
  • Single variant — the legacy/abbreviation display variants and the supervision-blend bar view are removed; the component now has one styling path.

Timeline mode (new components)

  • EpaVoiceThread.vue — renders each EPA as a card with a left-gutter SVG spline (decorative, aria-hidden) connecting hover/focus-synchronized "voice" cards. Each voice shows the comment as a pull-quote and a byline with the assessor, service, date, and a colored supervision dot. Threshold-gated "show earlier" button, with a chart-expand dialog at the side.
  • EpaProgressionChart.vue — compact + large SVG chart plotting supervision level vs. date, with same-day duplicate spread, smooth spline, and synced hover halo. Marked aria-hidden so the voice list remains the canonical keyboard surface.

Page structure (MyAssessments.vue)

  • <h1> for the page title; <h2> for "Entrustable Professional Activities". (1.3.1 Info and Relationships)
  • Compact mode keeps the global expand-all button and per-EPA expand buttons with aria-label + aria-expanded. (4.1.2)
  • Assessment Details dialog has aria-labelledby + a close q-btn with aria-label="Close dialog". (2.1.1 Keyboard)

Accessibility audit (axe-core, WCAG 2.1 A + AA + best-practice)

Run via Playwright MCP on https://localhost:7159/CTS/MyAssessments, scoped to <main>:

Scenario Violations
Timeline, own page (empty data) 0
Compact, own page (empty data) 0
Compact, other student (data, EPA expanded) 0
Timeline, other student (data) 0
Assessment Details dialog (open) 0

Reported "incomplete" items were either positional (fixed footer overlapping a heading at a specific scroll position) or chart axis labels inside the aria-hidden SVG — pre-existing decorative styling, not introduced here.

Tests

  • assessment-bubble.test.ts — 15 cases covering the privacy contract (aria-label must never contain the numeric rating), the value → class mapping, click emission, and the non-interactive span variant.

Test plan

  • /CTS/MyAssessments (own page) defaults to Timeline
  • /CTS/MyAssessments?student=<id> (as faculty/admin) defaults to Compact
  • Toggle switches cleanly between Compact and Timeline in both contexts
  • In Compact mode, expanding an EPA shows voice-card comments with the supervision-dot byline
  • Clicking a bubble opens the Assessment Details dialog; close button works with mouse + keyboard
  • Screen reader announces level names (not numeric scores) for bubbles
  • npm run test:frontendassessment-bubble.test.ts passes (15/15)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added progression chart visualization showing assessment timelines
    • Added timeline view with voice thread interface for detailed assessment browsing
  • Improvements

    • Enhanced accessibility for assessment bubbles with improved aria labels
    • Redesigned assessment details dialog layout and styling
    • Improved expand/collapse all controls for better navigation

Review Change Stack

Copilot AI review requested due to automatic review settings April 20, 2026 18:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

@rlorenzo rlorenzo closed this Apr 20, 2026
@rlorenzo rlorenzo reopened this Apr 20, 2026
Base automatically changed from VPR-104-accessibility-audit-CTS to main April 22, 2026 22:45
@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from 9db50f7 to daef548 Compare April 28, 2026 02:52
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 42.97%. Comparing base (8227e33) to head (2a0e2cf).

Files with missing lines Patch % Lines
VueApp/src/CTS/components/AssessmentBubble.vue 77.77% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #155      +/-   ##
==========================================
+ Coverage   42.96%   42.97%   +0.01%     
==========================================
  Files         877      878       +1     
  Lines       51468    51483      +15     
  Branches     4802     4807       +5     
==========================================
+ Hits        22113    22125      +12     
- Misses      28831    28832       +1     
- Partials      524      526       +2     
Flag Coverage Δ
backend 43.04% <ø> (ø)
frontend 41.58% <77.77%> (+0.24%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 28, 2026

Bundle Report

Changes will increase total bundle size by 16.95kB (0.79%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
viper-frontend-esm 2.16MB 16.95kB (0.79%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: viper-frontend-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/quasar.client-*.js -5 bytes 480.22kB -0.0%
assets/vendor-*.js 107 bytes 271.68kB 0.04%
assets/ManageLinkCollections-*.js 1 bytes 57.7kB 0.0%
assets/schedule-*.js 5 bytes 51.47kB 0.01%
assets/PhotoGallery-*.js 5 bytes 36.15kB 0.01%
assets/InstructorEdit-*.js -5 bytes 32.21kB -0.02%
assets/StaffDashboard-*.js 2 bytes 25.6kB 0.01%
assets/CrossListedCoursesSection-*.js 5 bytes 23.7kB 0.02%
assets/EmergencyContactForm-*.js -5 bytes 17.57kB -0.03%
assets/MyAssessments-*.js 10.87kB 16.54kB 191.75% ⚠️
assets/runtime-*.esm-bundler-eQtUIWRV.js (New) 12.44kB 12.44kB 100.0% 🚀
assets/CourseImportDialog-*.js -1 bytes 10.88kB -0.01%
assets/ManageSessionCompetencies-*.js 5 bytes 6.87kB 0.07%
assets/UnitList-*.js 1 bytes 6.34kB 0.02%
assets/cts-*.css 5.35kB 5.8kB 1184.07% ⚠️
assets/MyAssessments-*.css (New) 605 bytes 605 bytes 100.0% 🚀
assets/runtime-*.esm-bundler-B55_r9pp.js (Deleted) -12.44kB 0 bytes -100.0% 🗑️

Files in assets/MyAssessments-*.js:

  • ./src/CTS/components/AssessmentBubble.vue → Total Size: 156 bytes

  • ./src/CTS/pages/MyAssessments.vue → Total Size: 142 bytes

  • ./src/CTS/components/EpaProgressionChart.vue → Total Size: 252 bytes

  • ./src/CTS/components/EpaVoiceThread.vue → Total Size: 150 bytes

@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from daef548 to 6057b7e Compare May 5, 2026 20:13
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

📝 Walkthrough

Walkthrough

AssessmentBubble switched to computed-driven state and a conditional button/span template; CSS adds bubble and level chip styles. MyAssessments gains displayMode/timeline support and uses level chips. New EpaProgressionChart and EpaVoiceThread components render interactive timelines and gutters. Tests and a Vitest lint override were added.

Changes

AssessmentBubble Component & Integration

Layer / File(s) Summary
Component props, computed state, template
VueApp/src/CTS/components/AssessmentBubble.vue
Replaced ref/watch logic with computed isValidValue, bubbleClasses, added levelName prop, and conditional template rendering button (clickable) or decorative/non-clickable span.
Styling for bubbles & level chips
VueApp/src/CTS/assets/cts.css
Added .expandToggleCol, .assessmentBubble/trigger/focus styles, updated .assessmentBubble5_* to set background and text color, added .levelChip and .levelChip--1--5 variants plus thread/chart related CSS.
MyAssessments page integration
VueApp/src/CTS/pages/MyAssessments.vue
Added displayMode/isTimelineView, assessmentsByEpaId bucketing, anyExpanded computed, updated toggleExpandAll(), replaced rating rendering with levelChip, and wired timeline rendering through EpaVoiceThread.
Tests for AssessmentBubble
VueApp/src/CTS/__tests__/assessment-bubble.test.ts
Adds tests verifying aria-label privacy/fallbacks, class-name contract mapping for assessmentBubble5_{1..5}, click emission only when id present, and empty bubble content.
New components: progression & voice thread
VueApp/src/CTS/components/EpaProgressionChart.vue, VueApp/src/CTS/components/EpaVoiceThread.vue
EpaProgressionChart renders SVG spline/dots, groups same-day assessments, emits hover/leave and highlights active encounter. EpaVoiceThread renders voice cards, computes a DOM-measured gutter spline, manages active hover/focus, and provides an expanded dialog using EpaProgressionChart.
Lint rule override
.oxlintrc.json
Disable vitest/prefer-importing-vitest-globals inside test-file overrides.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~23 minutes

Suggested reviewers

  • bsedwards
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title "CTS - MyAssessment UI changes" is vague and overly broad—it refers to component styling and accessibility improvements across multiple new files but doesn't capture the main purpose (accessibility audit, bubble/timeline mode toggle, or voice thread feature). Use a more specific title such as "CTS: Add accessibility audit fixes and timeline view with voice thread" or "CTS: Implement bubble/timeline toggle and improve assessment bubble accessibility".
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
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
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch VPR-104-accessibility-audit-CTS-myassessments

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
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@VueApp/src/CTS/__tests__/assessment-bubble.test.ts`:
- Around line 44-54: Add a new test in assessment-bubble.test.ts that covers the
accessibility edge case where levelName is empty or omitted: use createWrapper
with maxValue and value (e.g., maxValue: 5, value: 2) and set levelName: "" (and
optionally another case with levelName undefined) and assert that the
span[role="img"] aria-label is not an empty string and instead contains the
numeric fallback (match /\b2 of 5\b/i); name the test to describe the edge case
(e.g., "falls back to numeric label when levelName is empty") and mirror the
style of the existing tests so it fails if component produces aria-label="".

In `@VueApp/src/CTS/assets/cts.css`:
- Around line 96-119: Duplicate color definitions exist between
.assessmentBubble5_1–5 and .levelChip--1–5; consolidate by extracting the five
color pairs into CSS custom properties (e.g. --level-bg-1..5 and
--level-fg-1..5) and create shared modifier classes (e.g. .levelPalette--1..5)
that set background-color and color via those vars, then update
.assessmentBubble5_1..5 and .levelChip--1..5 to simply include the corresponding
shared modifier class (or reference the variables) so palette changes are
managed in one place; modify references in the stylesheet for the selectors
assessmentBubble5_* and levelChip--* accordingly.

In `@VueApp/src/CTS/components/AssessmentBubble.vue`:
- Line 27: The emit definition is untyped so TypeScript won't enforce that
"bubble-click" carries a numeric id; replace the untyped defineEmits in
AssessmentBubble.vue with a typed signature (e.g. use defineEmits<{ (e:
'bubble-click', id: number): void }>() or defineEmits<{ 'bubble-click': (id:
number) => void }>() ) so emitting "bubble-click" requires a number, and ensure
places that call emit("bubble-click", ...) still pass a number (matching
MyAssessments.vue's handleAssessmentClick(id: number)).
- Around line 64-69: The span with role="img" in AssessmentBubble.vue uses the
prop levelName which defaults to "" and thus renders aria-label="" (invalid per
WCAG); change the template so aria-label is only bound when levelName is
non-empty and set aria-hidden to true when levelName is falsy (e.g.
:aria-label="levelName || undefined" and :aria-hidden="!levelName") so the
element is treated as decorative when no name is provided; update bindings on
the <span> that uses role="img" and the levelName prop accordingly.
- Around line 48-63: Replace the raw <button> with a Quasar q-btn: keep the
v-if="id", type="button" (if desired), :aria-label using the same levelName
expression, `@click`="clickBubble", and add flat, padding="none", round so it
matches the reset; render the visual bubble inside q-btn (e.g., as the default
slot using the existing <span :class="['assessmentBubble', bubbleClass]"
aria-hidden="true" />) and keep the q-tooltip with its content and {{ props.text
}}; after changing to q-btn, remove the custom .assessmentBubbleTrigger reset
rule and the :focus-visible override from cts.css so Quasar’s built-in
focus/hover/ripple behavior is used instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ca3eb28b-1ab4-462c-b6dd-1d6df9777221

📥 Commits

Reviewing files that changed from the base of the PR and between bfe8cfa and 6057b7e.

📒 Files selected for processing (4)
  • VueApp/src/CTS/__tests__/assessment-bubble.test.ts
  • VueApp/src/CTS/assets/cts.css
  • VueApp/src/CTS/components/AssessmentBubble.vue
  • VueApp/src/CTS/pages/MyAssessments.vue

Comment thread VueApp/src/CTS/__tests__/assessment-bubble.test.ts
Comment thread VueApp/src/CTS/components/AssessmentBubble.vue Outdated
Comment thread VueApp/src/CTS/components/AssessmentBubble.vue
Comment thread VueApp/src/CTS/components/AssessmentBubble.vue
@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from 6057b7e to 43056bc Compare May 7, 2026 02:31
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Controllers/UserInfoController.cs Fixed
@rlorenzo
Copy link
Copy Markdown
Contributor Author

rlorenzo commented May 7, 2026

@bsedwards New changes to the timeline display. Example: https://secure-test.vetmed.ucdavis.edu/2/CTS/MyAssessments?student=19774

  1. Bigger graph, will expand if the screen is wide enough
  2. Adding "click to expand" reminder text on the graph
  3. If you hover over the review, it will highlight the dot on the graph and vice versa
  4. If a review is on the same day, show dots side by side
  5. Added a colored circle next to the rating

@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from b96e286 to e2bc753 Compare May 12, 2026 15:56
@rlorenzo rlorenzo requested a review from Copilot May 12, 2026 16:45
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comment thread VueApp/src/CTS/components/EpaVoiceThread.vue
Comment thread VueApp/src/CTS/components/AssessmentBubble.vue Outdated
Comment thread VueApp/src/CTS/pages/MyAssessments.vue
Comment thread VueApp/src/CTS/pages/MyAssessments.vue
Comment thread VueApp/src/CTS/components/EpaVoiceThread.vue
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread VueApp/src/CTS/components/EpaVoiceThread.vue
Comment thread VueApp/src/CTS/assets/cts.css
@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from f0393ce to 556a9f0 Compare May 12, 2026 20:08
@rlorenzo
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
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: 6

♻️ Duplicate comments (1)
VueApp/src/CTS/components/AssessmentBubble.vue (1)

52-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Raw <button> violates the guideline; replace with q-btn.

The template uses a plain <button> element. As per coding guidelines, Quasar components must be used instead of HTML elements.

♻️ Replace with q-btn
-    <button
+    <q-btn
         v-if="id !== undefined"
-        type="button"
-        class="assessmentBubbleTrigger"
+        flat
+        round
+        dense
+        padding="none"
         :aria-label="levelName ? `${levelName}, open assessment details` : 'Open assessment details'"
         `@click`="clickBubble"
     >
         <span
             :class="bubbleClasses"
             aria-hidden="true"
         />
         <q-tooltip class="text-body2">
             <div><strong>Click to open details</strong></div>
             <div class="assessmentBubbleTooltipText">{{ props.text }}</div>
         </q-tooltip>
-    </button>
+    </q-btn>

With q-btn, the .assessmentBubbleTrigger reset rule in cts.css (lines 60–68) and the :focus-visible override (lines 78–82) can be removed.

As per coding guidelines: "Use Quasar components (q-btn, q-dialog, q-banner, etc.) instead of HTML elements."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@VueApp/src/CTS/components/AssessmentBubble.vue` around lines 52 - 67, Replace
the raw <button> in AssessmentBubble.vue with a Quasar q-btn while preserving
behavior: use v-if="id !== undefined", set flat/fab/round/size or attributes to
match the visual reset previously provided by .assessmentBubbleTrigger, bind
:aria-label="levelName ? `${levelName}, open assessment details` : 'Open
assessment details'", attach `@click`="clickBubble", and render the same inner
visual element by placing the span with :class="bubbleClasses" and
aria-hidden="true" inside the q-btn (or use q-btn's default slot); keep the
q-tooltip as the q-btn child. After replacing the element, remove the
.assessmentBubbleTrigger reset rule and the :focus-visible override from cts.css
as noted. Ensure props.text is still used inside the tooltip and that
clickBubble and bubbleClasses remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@VueApp/src/CTS/assets/cts.css`:
- Around line 96-119: Extract the repeated color palette into CSS custom
properties and reference them from the three class families so updates are
centralized: define variables (e.g., --palette-1-bg, --palette-1-fg ... through
palette-5) at a root or component scope, then replace the background-color/color
declarations in .assessmentBubble5_1..5, .levelChip--* and .cts-dot-* to use
those variables (e.g., background-color: var(--palette-1-bg); color:
var(--palette-1-fg)). Update any selectors that map to the same palette entries
to reference the appropriate variable names so one change to the variables
updates all three families. Ensure variable names are unique and descriptive and
scoped where needed ( :root or .cts ) to avoid collisions.

In `@VueApp/src/CTS/components/EpaProgressionChart.vue`:
- Around line 72-79: Replace the inline literals in the chart padding logic with
named constants to make intent clear: extract 86_400_000 into a constant like
DAY_MS, the 7 into PAD_DAYS (or DAYS_PADDING), and 0.05 into PAD_RATIO (or
PADDING_RATIO), then use those constants in the block that sets min/max and the
else branch; update the code around the function that adjusts min/max (the block
using min, max, and dayMs) so it references DAY_MS, PAD_DAYS, and PAD_RATIO
instead of the raw numbers.
- Line 129: Extract the magic number 2.4 into a clearly named constant (e.g.,
DOT_SPREAD_FACTOR or DOT_SPREAD_MULTIPLIER) and use it in the calculation for
step (const step = dotRadius.value * DOT_SPREAD_FACTOR) so the layout tuning
parameter is explicit and easily adjustable; add the new constant near the other
layout constants or component setup and update any related comments or usages
referencing step/dotRadius to reflect the extracted constant.
- Line 162: Extract the magic number 0.3 used to compute bulge into a named
constant (e.g., QUADRATIC_BULGE or BULGE_SCALE) and replace the literal in the
computation of bulge (currently const bulge = geometry.value.LANE_H * 0.3) with
that constant (const bulge = geometry.value.LANE_H * QUADRATIC_BULGE); declare
the constant near the component setup or top of the script so its purpose is
clear and document its role in one short comment; ensure references to
geometry.value.LANE_H and the bulge variable remain unchanged.

In `@VueApp/src/CTS/components/EpaVoiceThread.vue`:
- Around line 54-56: The magic numbers in lvX should be replaced with named
constants to clarify the gutter layout: extract the values 6 and 5 into
descriptively named constants (e.g., GUTTER_BASE and GUTTER_STEP or
GUTTER_OFFSET and GUTTER_INCREMENT) and update function lvX(lv: number): number
{ return GUTTER_BASE + (lv - 1) * GUTTER_STEP } so callers of lvX and future
maintainers see the layout intent; declare the constants near the top of the
component/file so lvX and related SVG coordinate logic reference the named
values.
- Line 77: Extract the magic number 18 used in y: el.getBoundingClientRect().top
- gutterTop + 18 into a named constant (e.g., GUTTER_DOT_VERTICAL_OFFSET = 18)
declared near the top of the component script (or in the constants section) and
replace the literal in the expression with that constant to document the layout
contract; update any other occurrences that align gutter dots with card centers
to use the same constant to keep behavior consistent.

---

Duplicate comments:
In `@VueApp/src/CTS/components/AssessmentBubble.vue`:
- Around line 52-67: Replace the raw <button> in AssessmentBubble.vue with a
Quasar q-btn while preserving behavior: use v-if="id !== undefined", set
flat/fab/round/size or attributes to match the visual reset previously provided
by .assessmentBubbleTrigger, bind :aria-label="levelName ? `${levelName}, open
assessment details` : 'Open assessment details'", attach `@click`="clickBubble",
and render the same inner visual element by placing the span with
:class="bubbleClasses" and aria-hidden="true" inside the q-btn (or use q-btn's
default slot); keep the q-tooltip as the q-btn child. After replacing the
element, remove the .assessmentBubbleTrigger reset rule and the :focus-visible
override from cts.css as noted. Ensure props.text is still used inside the
tooltip and that clickBubble and bubbleClasses remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2e987c16-3c02-4637-b0ab-d1e75bc43d50

📥 Commits

Reviewing files that changed from the base of the PR and between 6057b7e and 556a9f0.

📒 Files selected for processing (7)
  • .oxlintrc.json
  • VueApp/src/CTS/__tests__/assessment-bubble.test.ts
  • VueApp/src/CTS/assets/cts.css
  • VueApp/src/CTS/components/AssessmentBubble.vue
  • VueApp/src/CTS/components/EpaProgressionChart.vue
  • VueApp/src/CTS/components/EpaVoiceThread.vue
  • VueApp/src/CTS/pages/MyAssessments.vue

Comment thread VueApp/src/CTS/assets/cts.css
Comment thread VueApp/src/CTS/components/EpaProgressionChart.vue Outdated
Comment thread VueApp/src/CTS/components/EpaProgressionChart.vue Outdated
Comment thread VueApp/src/CTS/components/EpaProgressionChart.vue Outdated
Comment thread VueApp/src/CTS/components/EpaVoiceThread.vue
Comment thread VueApp/src/CTS/components/EpaVoiceThread.vue Outdated
@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from 556a9f0 to f5161e4 Compare May 12, 2026 21:37
rlorenzo added 2 commits May 12, 2026 18:03
- Two display modes via q-tabs: Timeline (default when a student views
  their own page) and Compact (default when a non-student opens
  ?student=X). q-tabs gives us role="tablist" + arrow-key navigation.
- New Timeline view (EpaVoiceThread + EpaProgressionChart) renders each
  EPA as voice-card comments with a gutter spline connecting them and a
  chart-expand dialog. Compact mode's expanded comments use the same
  voice-card style so the two modes feel consistent.
- AssessmentBubble: typed defineProps/defineEmits; aria-label surfaces
  the descriptive level name (never the numeric score); the decorative
  span falls back to aria-hidden when levelName is empty so role="img"
  never lands with an empty label.
- EpaVoiceThread: ResizeObserver keeps the gutter spline aligned after
  window resize or font load; useId() prevents collisions on
  aria-labelledby when multiple instances render with null epaIds.
- MyAssessments: bucket assessments by epaId in a computed Map so the
  template's repeated lookups don't refilter the full list per render.
- Drop the unused legacy/abbreviation/blend display variants along with
  their supporting components, props, and CSS.
- Lock the AssessmentBubble contract with 16 unit tests covering the
  aria-label privacy paths, value→class mapping, and click emission.
vitest plugin ships both prefer-importing-vitest-globals (wants explicit
imports) and no-importing-vitest-globals (wants globals) enabled by
default, so oxlint --fix flips test files between the two warnings on
every run. vitest.config sets globals: true and every test file in
VueApp/src uses the globals form, so disable the prefer- rule to match
the established convention.
@rlorenzo rlorenzo force-pushed the VPR-104-accessibility-audit-CTS-myassessments branch from f5161e4 to 2a0e2cf Compare May 13, 2026 01:03
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.

4 participants