Skip to content

Ref: Improve course exam results accessibility#294

Merged
Marty-Byrde merged 8 commits into
canaryfrom
ref/improve-course-exam-results-accessibility
Mar 28, 2026
Merged

Ref: Improve course exam results accessibility#294
Marty-Byrde merged 8 commits into
canaryfrom
ref/improve-course-exam-results-accessibility

Conversation

@Marty-Byrde

@Marty-Byrde Marty-Byrde commented Mar 28, 2026

Copy link
Copy Markdown
Member

Summary

  • New Features

    • “Show Exam Results” added to course action menu (visible to owners/contributors; shows tooltip when disabled).
    • Breadcrumb navigation added to exam results and attempt result pages for clearer context.
    • Added English and German translations for new navigation labels and UI text.
  • Refactors

    • Moved the examination results pages and components into app/results/[courseId]/examination directory
      This way users are able to view said results even when a course no longer has a share-key.

The reason for this change is that this way the `/courses` route directory is less cluttered is less cluttered but also viewing said results does not require share-token. Hence, users can view the results of a given check even after the respective share-token has been deleted.
This commits moves the exam results component into the same hierarchical structure as the exam-results page (`results/[courseId]/examination`) are so that they are easier to locate.
This way users can now view examination results by clicking on the newly introduced menu-item within the `CourseActionMenu`.
This way custom breadcrumbs are shown for both the examination results overview page and the individual attempt results page. The reason for this is that the `GenericBreadcrumbs` show dynamic route parameters like `courseId` in its Breadcrumbs, which is not necessarily good from a user perspective.
@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Marty-Byrde has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 56 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 0 minutes and 56 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4cd2d985-cd73-4b5d-bc92-a443a9a0f0a6

📥 Commits

Reviewing files that changed from the base of the PR and between 58e3274 and 9514611.

📒 Files selected for processing (5)
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/de.ts
  • src/i18n/locales/en.json
  • src/i18n/locales/en.ts

Walkthrough

Server pages and components were updated to use courseId route params instead of share_token, course lookups now use getCourseById(), breadcrumb components for exam results were added, a "Show exam results" menu item was introduced, import paths for exam result components were reorganized, and i18n strings for breadcrumbs and the new menu label were added.

Changes

Cohort / File(s) Summary
Route Parameter Migration
src/app/[locale]/results/[courseId]/exam/page.tsx, src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx
Page signatures and param types changed to accept courseId instead of share_token; calls to getCourseByShareToken() replaced with getCourseById(); params passed into child components updated accordingly.
Breadcrumb Navigation
src/components/results/examination/ExamResultsBreadcrumbs.tsx
New server-side breadcrumb components: ExamResultsBreadcrumbs and ExamResultAttemptResultsBreadcrumbs that fetch course data and render hierarchical breadcrumb links including course edit and exam-results routes.
UI Menu & Action Updates
src/components/courses/(hamburger-menu)/CourseActionMenu.tsx, src/components/courses/[share_token]/ExaminationAttemptTable.tsx
Added "Show exam results" menu item (conditional on owner/contributor) and changed attempt action links from results/{attemptId} to exam/{attemptId}.
Component Import Reorganization
src/components/results/examination/ExamQuestionResultTable.tsx, src/components/results/examination/ExamQuestionTable_ActionMenu.tsx, src/components/results/examination/PreviewQuestionResultDrawer.tsx, src/app/[locale]/results/[courseId]/practice/page.tsx
Updated import paths to move exam-result-related components into src/components/results/examination/* namespace.
Internationalization
src/i18n/locales/en.json, src/i18n/locales/en.ts, src/i18n/locales/de.json, src/i18n/locales/de.ts
Added Shared.Breadcrumbs translation keys and Components.CourseActionMenu.show_exam_results.label for English and German locales.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Browser
participant ServerPage as ExamPage
participant CourseService as CourseAPI
participant Breadcrumbs as BreadcrumbComponent
Browser->>ExamPage: Request /results/{courseId}/exam or /exam/{attemptId}
ExamPage->>CourseService: getCourseById(courseId)
CourseService-->>ExamPage: course data (or null)
ExamPage->>Breadcrumbs: render(courseId, userName?)
Breadcrumbs-->>ExamPage: breadcrumb HTML
ExamPage-->>Browser: Rendered page with breadcrumbs and exam results

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

Code Improvements, Visual Improvements

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: refactoring exam results pages to use courseId routing instead of share tokens, adding breadcrumbs for improved navigation, and exposing exam results through the course action menu—all of which enhance accessibility and discoverability of exam results.

✏️ 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 ref/improve-course-exam-results-accessibility

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
src/components/courses/[share_token]/ExaminationAttemptTable.tsx (1)

160-165: ⚠️ Potential issue | 🔴 Critical

Incorrect relative URL path causes navigation to wrong route.

The link exam/${row.original.id} will resolve incorrectly when the table is rendered on /results/{courseId}/exam. The resulting URL would be /results/{courseId}/exam/exam/{attemptId} instead of the intended /results/{courseId}/exam/{attemptId}.

Since this table is rendered on the exam results page at /results/{courseId}/exam, the relative link should simply be the attempt ID.

🐛 Proposed fix
-              <Link href={`exam/${row.original.id}`}>
+              <Link href={`${row.original.id}`}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/courses/`[share_token]/ExaminationAttemptTable.tsx around
lines 160 - 165, The Link currently uses a relative path
"exam/${row.original.id}" which appends "exam" again and produces the wrong URL;
update the Link href to just "${row.original.id}" so it navigates to the attempt
ID relative to the current "/results/{courseId}/exam" route (modify the Link
wrapping DropdownMenuItem in ExaminationAttemptTable.tsx where Link,
row.original.id, DropdownMenuItem and ChartColumnIcon are used).
🧹 Nitpick comments (3)
src/components/results/examination/PreviewQuestionResultDrawer.tsx (1)

6-6: Switch this to import type for the table item type.

This symbol is type-only and currently creates an unnecessary module edge back to ExamQuestionResultTable.

Proposed fix
-import { PreviewQuestionResult_QuestionItem } from '@/src/components/results/examination/ExamQuestionResultTable'
+import type { PreviewQuestionResult_QuestionItem } from '@/src/components/results/examination/ExamQuestionResultTable'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/results/examination/PreviewQuestionResultDrawer.tsx` at line
6, The import of PreviewQuestionResult_QuestionItem in
PreviewQuestionResultDrawer.tsx is type-only and should be converted to a
TypeScript type-only import to avoid a runtime module dependency; replace the
current import statement that brings in PreviewQuestionResult_QuestionItem from
ExamQuestionResultTable with an "import type {
PreviewQuestionResult_QuestionItem } ..." so the compiler treats it as a
type-only import and removes the module edge.
src/i18n/locales/de.ts (1)

1-1: Note: Auto-generated file header may be outdated.

The file header states it is auto-generated and changes will be replaced. If this is still true, these manual changes could be lost. Consider either removing this comment if the file is now manually maintained, or updating the generation process to include these new keys.

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

In `@src/i18n/locales/de.ts` at line 1, The file header comment "//! Auto
generated file, changes to this file will get replaced on next update" is
misleading; either remove or update it if this locale file is now maintained
manually, or modify the generation process to emit an accurate header that
includes the new keys. Locate the header string in src/i18n/locales/de.ts and
either (a) replace the auto-generated notice with a current maintenance note (or
remove it) when making manual edits, or (b) update the i18n generation script so
it regenerates this file with the correct header and includes the added keys.
src/i18n/locales/en.ts (1)

1-1: Note: Same auto-generated file concern as the German locale.

Same as de.ts - if this file is still auto-generated, manual changes may be overwritten.

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

In `@src/i18n/locales/en.ts` at line 1, This en.ts file is auto-generated and
manual edits will be lost; stop editing it directly and instead either (a) add
your manual translations/overrides into the generator's source data (the
canonical translations source used to produce en.ts), or (b) create a separate
override module (e.g., en.overrides.ts) that imports the generated en.ts and
applies your changes, or (c) update the generation config to preserve custom
sections; locate the generated header line ("//! Auto generated file, changes to
this file will get replaced on next update") in en.ts to identify the file and
implement one of these approaches so manual changes aren’t overwritten.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/courses/`(hamburger-menu)/CourseActionMenu.tsx:
- Around line 145-151: The tooltip for the "Show Examination Results" menu item
is using t('edit_course.tooltip') which is misleading; add a new locale key
(e.g. Components.CourseActionMenu.show_exam_results.tooltip) with copy like "You
are not allowed to view exam results for this course!" and update the
DropdownMenuItem's tooltipOptions to use that new key instead of
t('edit_course.tooltip') while keeping the label using
t('show_exam_results.label'); change the call inside the component (around
DropdownMenuItem and tooltipOptions) to reference the new translation key so the
disabled tooltip matches the action.

In `@src/components/results/examination/ExamQuestionTable_ActionMenu.tsx`:
- Line 5: The import of PreviewQuestionResult_QuestionItem in
ExamQuestionTable_ActionMenu.tsx is creating a circular runtime dependency even
though it's only used as a type in function signatures; change the import to a
type-only import (use "import type { PreviewQuestionResult_QuestionItem }") so
the symbol remains available for typing but is erased at runtime, preventing the
circular module dependency with ExamQuestionResultTable which imports
ExamQuestionTable_ActionMenu at runtime.

In `@src/components/results/examination/ExamResultsBreadcrumbs.tsx`:
- Line 46: The breadcrumb component calls getCourseById causing a duplicate DB
fetch; either wrap the database helper getCourseById (in
database/course/select.ts) with React's cache() to dedupe within the same render
pass, i.e., export a cached version of getCourseById, or remove the call from
ExamResultsBreadcrumbs.tsx and accept the already-fetched course as a prop from
the page component (update the ExamResultsBreadcrumbs props and callers to pass
course) so no redundant query runs.
- Line 74: In ExamResultsBreadcrumbs.tsx the JSX currently contains the literal
HTML entity "&apos;" which will render as text; replace {userName}&apos;s
{t('results')} with a real apostrophe (e.g. {userName}'s {t('results')}) or the
Unicode escape (\u2019) to produce a proper apostrophe so the breadcrumb reads
correctly; update the JSX where userName and t('results') are combined.
- Line 1: Remove the top-level "'use server'" directive from
ExamResultsBreadcrumbs.tsx — this file exports React components (e.g., the
ExamResultsBreadcrumbs component) and is a Server Component by default; the
"'use server'" directive is only valid for Server Actions (functions invoked
from the client). Open the file, delete the "'use server'" line, and ensure no
server-action-specific syntax remains; if you intended to define a server
action, move the "'use server'" directive to the specific function instead.

---

Outside diff comments:
In `@src/components/courses/`[share_token]/ExaminationAttemptTable.tsx:
- Around line 160-165: The Link currently uses a relative path
"exam/${row.original.id}" which appends "exam" again and produces the wrong URL;
update the Link href to just "${row.original.id}" so it navigates to the attempt
ID relative to the current "/results/{courseId}/exam" route (modify the Link
wrapping DropdownMenuItem in ExaminationAttemptTable.tsx where Link,
row.original.id, DropdownMenuItem and ChartColumnIcon are used).

---

Nitpick comments:
In `@src/components/results/examination/PreviewQuestionResultDrawer.tsx`:
- Line 6: The import of PreviewQuestionResult_QuestionItem in
PreviewQuestionResultDrawer.tsx is type-only and should be converted to a
TypeScript type-only import to avoid a runtime module dependency; replace the
current import statement that brings in PreviewQuestionResult_QuestionItem from
ExamQuestionResultTable with an "import type {
PreviewQuestionResult_QuestionItem } ..." so the compiler treats it as a
type-only import and removes the module edge.

In `@src/i18n/locales/de.ts`:
- Line 1: The file header comment "//! Auto generated file, changes to this file
will get replaced on next update" is misleading; either remove or update it if
this locale file is now maintained manually, or modify the generation process to
emit an accurate header that includes the new keys. Locate the header string in
src/i18n/locales/de.ts and either (a) replace the auto-generated notice with a
current maintenance note (or remove it) when making manual edits, or (b) update
the i18n generation script so it regenerates this file with the correct header
and includes the added keys.

In `@src/i18n/locales/en.ts`:
- Line 1: This en.ts file is auto-generated and manual edits will be lost; stop
editing it directly and instead either (a) add your manual
translations/overrides into the generator's source data (the canonical
translations source used to produce en.ts), or (b) create a separate override
module (e.g., en.overrides.ts) that imports the generated en.ts and applies your
changes, or (c) update the generation config to preserve custom sections; locate
the generated header line ("//! Auto generated file, changes to this file will
get replaced on next update") in en.ts to identify the file and implement one of
these approaches so manual changes aren’t overwritten.
🪄 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: CHILL

Plan: Pro

Run ID: 6cb9c373-6bf3-4331-9eb7-7256a9a06d92

📥 Commits

Reviewing files that changed from the base of the PR and between a9501ef and 286e654.

📒 Files selected for processing (12)
  • src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx
  • src/app/[locale]/results/[courseId]/exam/page.tsx
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/components/courses/[share_token]/ExaminationAttemptTable.tsx
  • src/components/results/examination/ExamQuestionResultTable.tsx
  • src/components/results/examination/ExamQuestionTable_ActionMenu.tsx
  • src/components/results/examination/ExamResultsBreadcrumbs.tsx
  • src/components/results/examination/PreviewQuestionResultDrawer.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/de.ts
  • src/i18n/locales/en.json
  • src/i18n/locales/en.ts

Comment thread src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
Comment thread src/components/results/examination/ExamQuestionTable_ActionMenu.tsx
Comment thread src/components/results/examination/ExamResultsBreadcrumbs.tsx
Comment thread src/components/results/examination/ExamResultsBreadcrumbs.tsx
Comment thread src/components/results/examination/ExamResultsBreadcrumbs.tsx
@codecov

codecov Bot commented Mar 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 7.69231% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...nts/results/examination/ExamResultsBreadcrumbs.tsx 0.00% 10 Missing ⚠️
src/app/[locale]/results/[courseId]/exam/page.tsx 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Marty-Byrde Marty-Byrde moved this to In review in KnowledgeCheckr Project Mar 28, 2026
@Marty-Byrde Marty-Byrde merged commit b84e8fb into canary Mar 28, 2026
29 checks passed
@Marty-Byrde Marty-Byrde deleted the ref/improve-course-exam-results-accessibility branch March 28, 2026 07:10
@github-project-automation github-project-automation Bot moved this from In review to Done in KnowledgeCheckr Project Mar 28, 2026
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 4.0.0-canary.3 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant