Skip to content

feat(scheduler): Clinical Scheduler audit trail + inline per-week history#236

Merged
rlorenzo merged 5 commits into
mainfrom
feature/clinical-scheduler-audit-log
Jul 17, 2026
Merged

feat(scheduler): Clinical Scheduler audit trail + inline per-week history#236
rlorenzo merged 5 commits into
mainfrom
feature/clinical-scheduler-audit-log

Conversation

@rlorenzo

@rlorenzo rlorenzo commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the legacy ColdFusion "Schedule Changes Audit log" by surfacing the ScheduleAudit data VIPER already records. Everything is gated on the legacy page's permission, SVMSecure.ClnSched.Manage; no new permission.

  • Audit Trail page: filterable grid over ScheduleAudit (grad year, term, rotation, area, modified by, person, date range) with colored action badges and a responsive layout (full table / stacked / cards) matching the Effort audit trail.
  • Inline per-week history: a manager-only clock icon on each week card in both schedule views (plus a legend entry) opens a centered dialog with that week's entries and Previous/Next week navigation.
  • Effort audit parity: same "All ..." filter defaults, search moved above the table, and a shared AuditChangeDetail component.

Audit writes are now fail-closed

Audit entries used to be written after the schedule transaction committed, inside a try/catch that reduced failures to a log warning, so a schedule change could commit with no trail. Now:

  • Add / remove / primary-evaluator audit entries are written inside the same DB transaction as the schedule change (as the legacy scheduler has done since 2016); an audit-write failure rolls the change back.
  • Notification emails moved after the commit and out of the audit path, so SMTP problems can neither block scheduling nor suppress audit rows.
  • Behavior change: if the audit insert fails in an environment (permissions, schema drift), scheduling there now fails visibly instead of succeeding silently.
  • Tests: unit tests assert a failed audit write fails all three write paths, and a SQLite-backed integration test (ScheduleEditServiceRollbackTest) asserts the schedule mutation actually rolls back.

Notes

  • The audit read methods existed but had zero callers (flagged by fallow); this PR gives them real consumers instead of deleting them.

@codecov-commenter

codecov-commenter commented Jun 27, 2026

Copy link
Copy Markdown

Bundle Report

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

Detailed changes
Bundle name Size Change
viper-frontend-esm 2.14MB 30.05kB (1.42%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: viper-frontend-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/GenericError-*.js 6 bytes 525.01kB 0.0%
assets/vendor-*.js 167 bytes 272.01kB 0.06%
assets/ManageLinkCollections-*.js 1 bytes 57.62kB 0.0%
assets/schedule-*.js 5.06kB 54.78kB 10.17% ⚠️
assets/TermManagement-*.js 3 bytes 52.38kB 0.01%
assets/CourseDetail-*.js -4 bytes 39.32kB -0.01%
assets/PhotoGallery-*.js 9 bytes 36.09kB 0.02%
assets/InstructorEdit-*.js 9 bytes 28.56kB 0.03%
assets/StaffDashboard-*.js -3 bytes 25.47kB -0.01%
assets/effort-*.js -5 bytes 23.16kB -0.02%
assets/ClinicianScheduleView-*.js -277 bytes 18.63kB -1.46%
assets/AuditList-*.js 277 bytes 17.59kB 1.6%
assets/RotationScheduleView-*.js 225 bytes 17.2kB 1.33%
assets/EmergencyContactForm-*.js 5 bytes 17.16kB 0.03%
assets/MyAssessments-*.js 5 bytes 16.47kB 0.03%
assets/CourseList-*.js -2 bytes 15.86kB -0.01%
assets/_plugin-*.js 941 bytes 14.19kB 7.1% ⚠️
assets/AuditLogPage-*.js (New) 11.26kB 11.26kB 100.0% 🚀
assets/CourseImportDialog-*.js -5 bytes 10.82kB -0.05%
assets/schedule-*.css 3.13kB 9.96kB 45.75% ⚠️
assets/permission-*.js 193 bytes 9.75kB 2.02%
assets/CourseLinkDialog-*.js -5 bytes 9.37kB -0.05%
assets/dist-*.js 2.13kB 9.13kB 30.36% ⚠️
assets/cts-*.js -5 bytes 8.33kB -0.06%
assets/AssessmentList-*.js -5 bytes 6.79kB -0.07%
assets/ManageCompetencies-*.js -7 bytes 6.61kB -0.11%
assets/UnitList-*.js -5 bytes 6.34kB -0.08%
assets/EffortRecordEditDialog-*.js 1 bytes 6.15kB 0.02%
assets/use-*.js 580 bytes 5.97kB 10.76% ⚠️
assets/use-*.js 76 bytes 739 bytes 11.46% ⚠️
assets/use-*.js (New) 663 bytes 663 bytes 100.0% 🚀
assets/use-*.js (New) 5.39kB 5.39kB 100.0% 🚀
assets/TermSelection-*.js -5 bytes 4.54kB -0.11%
assets/TeachingActivityIndividual-*.js -5 bytes 3.4kB -0.15%
assets/EmergencyContactReport-*.js 1 bytes 3.4kB 0.03%
assets/StatusBanner-*.js 1 bytes 1.73kB 0.06%
assets/clinicalscheduler-*.js 141 bytes 1.71kB 8.99% ⚠️
assets/use-*.css (New) 115 bytes 115 bytes 100.0% 🚀

Files in assets/schedule-*.js:

  • ./src/ClinicalScheduler/components/WeekHistoryBody.vue → Total Size: 252 bytes

  • ./src/ClinicalScheduler/components/WeekCell.vue → Total Size: 231 bytes

  • ./src/ClinicalScheduler/components/ScheduleLegend.vue → Total Size: 249 bytes

  • ./src/ClinicalScheduler/components/WeekHistoryButton.vue → Total Size: 258 bytes

  • ./src/ClinicalScheduler/components/WeekHistoryContent.vue → Total Size: 261 bytes

  • ./src/ClinicalScheduler/components/WeekHistoryDialog.vue → Total Size: 258 bytes

  • ./src/ClinicalScheduler/components/ScheduleView.vue → Total Size: 243 bytes

Files in assets/ClinicianScheduleView-*.js:

  • ./src/ClinicalScheduler/pages/ClinicianScheduleView.vue → Total Size: 265 bytes

Files in assets/AuditList-*.js:

  • ./src/Effort/components/AuditChangeDetail.vue → Total Size: 162 bytes

  • ./src/Effort/pages/AuditList.vue → Total Size: 218 bytes

Files in assets/RotationScheduleView-*.js:

  • ./src/ClinicalScheduler/pages/RotationScheduleView.vue → Total Size: 262 bytes

Files in assets/AuditLogPage-*.js:

  • ./src/ClinicalScheduler/pages/AuditLogPage.vue → Total Size: 153 bytes

  • ./src/ClinicalScheduler/components/AuditLogResultsTable.vue → Total Size: 182 bytes

Files in assets/permission-*.js:

  • ./src/ClinicalScheduler/constants/permission-messages.ts → Total Size: 1.62kB

Files in assets/use-*.js:

  • ./src/ClinicalScheduler/services/audit-log-service.ts → Total Size: 2.6kB

  • ./src/ClinicalScheduler/utils/audit-actions.ts → Total Size: 332 bytes

  • ./src/ClinicalScheduler/composables/use-audit-entries.ts → Total Size: 1.15kB

  • ./src/ClinicalScheduler/components/SchedulerNavigation.vue → Total Size: 264 bytes

Files in assets/clinicalscheduler-*.js:

  • ./src/ClinicalScheduler/router/routes.ts → Total Size: 1.59kB

@codecov-commenter

codecov-commenter commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 46.73748% with 351 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.31%. Comparing base (0c5ab2b) to head (215377a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...ClinicalScheduler/Services/ScheduleAuditService.cs 28.49% 137 Missing and 1 partial ⚠️
...alScheduler/Controllers/ScheduleAuditController.cs 0.00% 73 Missing ⚠️
...ueApp/src/ClinicalScheduler/pages/AuditLogPage.vue 61.71% 42 Missing and 7 partials ⚠️
...rc/ClinicalScheduler/services/audit-log-service.ts 19.04% 34 Missing ⚠️
...nicalScheduler/components/AuditLogResultsTable.vue 54.54% 17 Missing and 3 partials ⚠️
...ClinicalScheduler/composables/use-audit-entries.ts 53.12% 12 Missing and 3 partials ⚠️
...linicalScheduler/components/WeekHistoryContent.vue 76.59% 10 Missing and 1 partial ⚠️
...icalScheduler/Services/ClinicalSchedulerNavMenu.cs 0.00% 5 Missing ⚠️
...cheduler/Models/DTOs/Responses/AuditModifierDto.cs 0.00% 2 Missing ⚠️
...calScheduler/Models/DTOs/Responses/AuditTermDto.cs 0.00% 2 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #236      +/-   ##
==========================================
+ Coverage   45.29%   45.31%   +0.01%     
==========================================
  Files         897      915      +18     
  Lines       51928    52690     +762     
  Branches     4878     4992     +114     
==========================================
+ Hits        23523    23877     +354     
- Misses      27803    28186     +383     
- Partials      602      627      +25     
Flag Coverage Δ
backend 45.34% <35.94%> (-0.05%) ⬇️
frontend 44.76% <58.59%> (+1.34%) ⬆️

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

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

Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs Fixed
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs Fixed
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs Fixed
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs Fixed
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch 3 times, most recently from d936116 to 3bc2ddf Compare June 29, 2026 22:49
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an end-to-end Clinical Scheduler audit trail with backend APIs, filtered audit UI, per-week history dialogs, permission-gated navigation, and transactional schedule audit writes. Also extracts reusable audit-change rendering in the Effort module.

Changes

Clinical Scheduler Audit Trail

Layer / File(s) Summary
Backend audit contracts, queries, and API
web/Areas/ClinicalScheduler/Models/DTOs/Responses/Audit*.cs, web/Areas/ClinicalScheduler/Services/*ScheduleAudit*.cs, web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs, web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
Adds audit DTOs, filtered and per-week service queries, protected controller endpoints, and manage-permission navigation.
Frontend audit page and data loading
VueApp/src/ClinicalScheduler/types/audit-types.ts, VueApp/src/ClinicalScheduler/services/audit-log-service.ts, VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts, VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue, VueApp/src/ClinicalScheduler/components/AuditLogResultsTable.vue, VueApp/src/ClinicalScheduler/router/routes.ts
Adds typed API access, request-safe loading state, permission-gated filters, responsive results, routing, navigation, and access-control tests.
Per-week history dialog and presentation
VueApp/src/ClinicalScheduler/components/WeekHistory*.vue, VueApp/src/ClinicalScheduler/__tests__/week-history-content.test.ts
Adds history loading, navigation, keyboard controls, loading/error/empty states, and responsive week-history presentation.
Schedule history permission and context wiring
VueApp/src/ClinicalScheduler/components/WeekCell.vue, VueApp/src/ClinicalScheduler/components/ScheduleView.vue, VueApp/src/ClinicalScheduler/components/ScheduleLegend.vue, VueApp/src/ClinicalScheduler/pages/*ScheduleView.vue
Propagates access and rotation/clinician context, adds history controls and legend text, guards cell interactions, and adjusts mobile layout.

Audit Consistency

Layer / File(s) Summary
Effort audit detail rendering
VueApp/src/Effort/components/AuditChangeDetail.vue, VueApp/src/Effort/pages/AuditList.vue, VueApp/src/Effort/__tests__/audit-change-detail.test.ts
Extracts old/new value rendering, updates responsive audit details, relocates search, and clarifies null filter labels.
Transactional schedule auditing
web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs, test/ClinicalScheduler/ScheduleEditService*.cs, test/ClinicalScheduler/ScheduleAuditServiceTest.cs
Writes schedule audit entries inside transactions, sends notifications after commit, and tests rollback, failure propagation, and clinician-area filtering.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • ucdavis/VIPER#177: Both changes overlap in Clinical Scheduler public component typing and export surfaces.
  • ucdavis/VIPER#228: Both changes narrow the exported ScheduleView type surface.
  • ucdavis/VIPER#241: Both changes modify permission-based Clinical Scheduler navigation gating.

Suggested reviewers: bsedwards

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.15% 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
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.
Title check ✅ Passed The title clearly summarizes the main change: a Clinical Scheduler audit trail with inline per-week history.
Description check ✅ Passed The description is directly related to the changeset and accurately summarizes the audit trail, history UI, and audit write changes.
✨ 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 feature/clinical-scheduler-audit-log

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.

@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: 12

🤖 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/ClinicalScheduler/components/WeekHistoryButton.vue`:
- Around line 97-114: Refactor loadHistory in WeekHistoryButton.vue to satisfy
the quality gate by breaking the logic into small helpers instead of keeping the
fetch selection and result/error handling inline. Extract one helper to choose
the correct AuditLogService call based on props.viewMode and another to
normalize successful and failed responses/errors into entries.value and
error.value. Keep loadHistory focused on toggling isLoading and orchestrating
these helpers so the method stays simple and readable.

In `@VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue`:
- Around line 54-60: The AuditLogPage.vue filters expansion item is using an
inline desktop visibility style, which violates the Vue styling rules in this
repo. Update the q-expansion-item in AuditLogPage to remove the :header-style
binding and use Quasar utility classes or separate mobile/desktop filter header
containers instead, keeping the same behavior while avoiding inline styles.
- Around line 570-578: The clearFilters function in AuditLogPage.vue does not
fully reset the page because currentYear is left unchanged, so the year-scoped
data and term list remain filtered. Update clearFilters to also reset
currentYear and reuse the same refresh path as onYearChange() so the
year-specific term list and audit log state are restored consistently when
clearing filters.
- Around line 484-510: loadAuditTrail() in AuditLogPage.vue is too complex and
needs to be split up to pass the Fallow gate. Extract the
AuditLogService.getAuditLog filter construction into a helper and move the
success/error response handling into a separate helper so loadAuditTrail() stays
a simple linear fetch flow. Keep the existing behavior intact while reducing the
branching inside loadAuditTrail(), and use the current symbols like currentYear,
selectedTermCode, selectedRotationId, selectedArea, selectedModifier,
selectedPerson, fromDate, toDate, and AuditLogService.getAuditLog to organize
the refactor.
- Around line 484-515: `loadAuditTrail()` can resolve out of order and overwrite
newer filter results in `AuditLogPage.vue`. Add a request guard in
`loadAuditTrail` (for example, a monotonically increasing request id or
cancellation token) so only the latest invocation is allowed to set
`entries.value`, `error.value`, and `isLoading.value`. Make sure the debounced
loader and any other callers still invoke `loadAuditTrail`, but stale responses
are ignored before committing state.

In `@VueApp/src/Effort/components/AuditChangeDetail.vue`:
- Line 3: Remove the narration comments from AuditChangeDetail’s template
branches; they just restate the conditional rendering and add noise. Update the
Vue template around the inline reference-value and changed-value sections by
deleting the explanatory comments, while keeping the existing branch logic and
structure in place.

In `@VueApp/src/Effort/pages/AuditList.vue`:
- Around line 152-167: The search input in AuditList.vue currently relies only
on placeholder text, so it loses its visible name after typing. Update the
q-input used for filter.searchText to include a persistent label while keeping
the existing placeholder as hint text, using the existing search field markup
and v-model binding to locate it.

In `@web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs`:
- Around line 141-187: The week-history endpoints in ScheduleAuditController
return List<AuditLogEntryDto> even though
ScheduleAuditService.BuildEnrichedAuditQuery(...) does not populate required
fields such as WeekNum and Term. Update the projection used by
GetRotationWeekHistory and GetClinicianWeekHistory to fully populate
AuditLogEntryDto, or switch those actions to a narrower DTO that only includes
the fields actually returned. Ensure the response contract matches the frontend
AuditLogEntry expectations.
- Around line 15-18: The ScheduleAuditController route is using a hardcoded
nonstandard path, so update the route attribute on ScheduleAuditController to
follow the repo’s controller-based API convention. Replace the current fixed
audit route with the standard absolute /api/{area}/{controller} pattern so the
controller resolves through its name instead of a custom endpoint.
- Around line 31-41: The XML documentation for ScheduleAuditController’s
GetAuditLogAsync contract is misleading about the person filter. Update the
<param name="person"> comment so it clearly states this parameter is a MothraID
exact match, not a substring search on display name. Keep the docs aligned with
the behavior in IScheduleAuditService.GetAuditLogAsync and
ScheduleAuditService.GetAuditLogAsync, and adjust any related wording in the
controller summary if needed.

In `@web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs`:
- Around line 388-401: The week-history projection in ScheduleAuditService’s
audit query is returning AuditLogEntryDto without setting WeekNum, TermCode, or
Term, which leaves those members at default values and makes the shared DTO
inconsistent across endpoints. Update the select new AuditLogEntryDto in the
GetRotationWeekAuditAsync/GetClinicianWeekAuditAsync query to populate those
fields from the available week-related data, or introduce a separate DTO for
week history and use it there instead of reusing AuditLogEntryDto.
- Around line 237-240: Replace the filtered catch in ScheduleAuditService with
explicit typed handlers so each failure type is handled separately. Update the
exception handling around the audit retrieval logic in the relevant service
method to use distinct catch blocks for DbUpdateException, SqlException, and
InvalidOperationException instead of a single `catch (Exception) when (...)`,
and keep the existing logging/throw behavior in each branch using the same
logger message pattern and the method context around `gradYear`.
🪄 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: a18a5a59-93d9-4808-80e7-38949f8f10db

📥 Commits

Reviewing files that changed from the base of the PR and between 4564dae and 3bc2ddf.

📒 Files selected for processing (24)
  • VueApp/src/ClinicalScheduler/__tests__/audit-log-page-access.test.ts
  • VueApp/src/ClinicalScheduler/components/ScheduleLegend.vue
  • VueApp/src/ClinicalScheduler/components/ScheduleView.vue
  • VueApp/src/ClinicalScheduler/components/SchedulerNavigation.vue
  • VueApp/src/ClinicalScheduler/components/WeekCell.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryButton.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue
  • VueApp/src/ClinicalScheduler/constants/permission-messages.ts
  • VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
  • VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue
  • VueApp/src/ClinicalScheduler/pages/RotationScheduleView.vue
  • VueApp/src/ClinicalScheduler/router/routes.ts
  • VueApp/src/ClinicalScheduler/services/audit-log-service.ts
  • VueApp/src/ClinicalScheduler/types/audit-types.ts
  • VueApp/src/ClinicalScheduler/utils/audit-actions.ts
  • VueApp/src/Effort/components/AuditChangeDetail.vue
  • VueApp/src/Effort/pages/AuditList.vue
  • web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditLogEntryDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditModifierDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditTermDto.cs
  • web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
  • web/Areas/ClinicalScheduler/Services/IScheduleAuditService.cs
  • web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs

Comment thread VueApp/src/ClinicalScheduler/components/WeekHistoryButton.vue Outdated
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue Outdated
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from 3bc2ddf to b8e1cd4 Compare June 30, 2026 05:39
@rlorenzo
rlorenzo requested a review from Copilot July 3, 2026 02:35

Copilot AI 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.

Pull request overview

Surfaces and productizes existing Clinical Scheduler audit data by adding a manager-gated audit-log API + UI (full page and inline per-week history), replacing the legacy ColdFusion “Schedule Changes Audit log”.

Changes:

  • Added new Clinical Scheduler audit endpoints (/api/clinicalscheduler/audit/*) and service methods returning enriched, filterable audit DTOs.
  • Added new Vue Audit Trail page + routing/navigation, plus inline per-week history popover/dialog for managers.
  • Refactored Effort audit list change-detail rendering into a shared AuditChangeDetail component and adjusted filter UX defaults.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs Adds enriched audit-log query methods (filters, term mapping, per-week history projections).
web/Areas/ClinicalScheduler/Services/IScheduleAuditService.cs Extends the service contract to include audit-log, term, modifier/person, and per-week history methods.
web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs Adds “Audit Trail” nav item for users with Manage permission.
web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditTermDto.cs New DTO for term filter options scoped to grad year.
web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditModifierDto.cs New DTO for “Modified By” / “Person” filter options.
web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditLogEntryDto.cs New enriched audit row DTO used by page + inline week history.
web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs New API controller exposing audit-log/filter endpoints and per-week history endpoints (Manage-gated).
VueApp/src/Effort/pages/AuditList.vue Improves filter defaults/UX and uses shared change-detail component.
VueApp/src/Effort/components/AuditChangeDetail.vue New shared renderer for change-detail old/new values.
VueApp/src/ClinicalScheduler/utils/audit-actions.ts Shared mapping from schedule-audit action → Quasar color.
VueApp/src/ClinicalScheduler/types/audit-types.ts New TS types for schedule audit rows and filter option DTOs.
VueApp/src/ClinicalScheduler/services/audit-log-service.ts New frontend service for Clinical Scheduler audit endpoints.
VueApp/src/ClinicalScheduler/router/routes.ts Adds route for the new Audit Trail page.
VueApp/src/ClinicalScheduler/pages/RotationScheduleView.vue Plumbs “can view history” + context info into the schedule grid.
VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue Plumbs “can view history” + context info into the schedule grid.
VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue New Audit Trail page with responsive results display and filter controls.
VueApp/src/ClinicalScheduler/constants/permission-messages.ts Adds access-denied messaging for the new audit trail feature.
VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts Shared loader/state composable for audit entries (page + inline history).
VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue New reusable content component for per-week audit history UI.
VueApp/src/ClinicalScheduler/components/WeekHistoryButton.vue New trigger button that shows per-week history (popover on desktop, dialog on mobile).
VueApp/src/ClinicalScheduler/components/WeekCell.vue Adds per-week history icon and prevents cell actions when tapping embedded controls.
VueApp/src/ClinicalScheduler/components/ScheduleView.vue Plumbs history props through to week cells and legend; minor export cleanup + mobile layout tweak.
VueApp/src/ClinicalScheduler/components/SchedulerNavigation.vue Adds “Audit Trail” tab for managers.
VueApp/src/ClinicalScheduler/components/ScheduleLegend.vue Adds manager-only legend row describing the history icon.
VueApp/src/ClinicalScheduler/tests/audit-log-page-access.test.ts Adds access-control tests for the audit-log page behavior.

Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs Outdated
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch 2 times, most recently from 4f6cd6d to 15d53b4 Compare July 3, 2026 03:00
@rlorenzo
rlorenzo requested a review from Copilot July 3, 2026 03:44

Copilot AI 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.

Pull request overview

Copilot reviewed 29 out of 29 changed files in this pull request and generated 3 comments.

Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
Comment thread web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 29 out of 29 changed files in this pull request and generated no new comments.

@rlorenzo
rlorenzo requested a review from bsedwards July 3, 2026 05:04
@rlorenzo

rlorenzo commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@bsedwards Should be on TEST now. Adds audit trail inline on the weeks display as well as a dedicated page

bsedwards
bsedwards previously approved these changes Jul 9, 2026
@bsedwards

Copy link
Copy Markdown
Collaborator

@rlorenzo FYI I was playing with the schedule on test for year 2027, and the history button on the schedule views doesn't seem to load anything

@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from 026e8f9 to aaff6b9 Compare July 10, 2026 20:32
@rlorenzo
rlorenzo requested a review from Copilot July 15, 2026 16:48
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

Copilot AI 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.

Pull request overview

Copilot reviewed 29 out of 29 changed files in this pull request and generated 3 comments.

Comment thread VueApp/src/ClinicalScheduler/components/WeekCell.vue
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue Outdated
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from cb736e5 to 2d8d4ec Compare July 15, 2026 23:51
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

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

🤖 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/ClinicalScheduler/components/WeekCell.vue`:
- Around line 282-294: Update originatesOnControl to inspect
event.composedPath() so text-node targets inside buttons, links, inputs, and
other controls are detected reliably. Check the full path for the existing
control selectors and preserve the current false result when no event or
matching control is present; keep handleClick’s scheduling guard unchanged.

In `@VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue`:
- Around line 63-80: Update the week-history paging flow so retained entries are
not rendered under the newly selected week: either show the loading skeleton for
the entire paging interval or clear entries before updating the active week.
Ensure the existing list rendering in WeekHistoryBody and the corresponding
state/update logic preserve correct records for the selected week.

In `@VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue`:
- Around line 90-106: Update the viewport styling to remove the inline :style
height binding and define height: v-bind(bodyHeight) in the component’s scoped
stylesheet. In the progress bar markup, replace size="2px" with size="0.125rem",
preserving the existing showProgress behavior and styling.

In `@VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts`:
- Around line 41-62: Update the audit-loading flow in the composable so failed
responses and caught errors clear entries.value before setting the error,
preventing prior results from remaining visible. Update reset() to invalidate
the active request by advancing latestRequestId, then clear entries.value and
error.value so pending requests cannot repopulate stale results.

In `@VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue`:
- Around line 323-355: Update loadFilterOptions and loadTermOptions to surface
unsuccessful rotation, modifier, person, and term responses instead of silently
ignoring them, and ensure rejected service requests are propagated or reported
with actionable error details. In initialize, catch failures from the
fire-and-forget loading flow before the finally block sets ready, preserving
successful option population while preventing unhandled initialization errors.
- Around line 350-361: Update loadTermOptions to capture the requested
currentYear value before calling AuditLogService.getTerms, then commit
termOptions only if that response still matches the latest requested year.
Ensure rapid onYearChange calls cannot apply an older response over the options
for the current year.

In `@web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs`:
- Around line 307-315: Update the affected-person query in ScheduleAuditService
to exclude both null and empty MothraId values before constructing
AuditModifierDto results. Preserve the existing left join and display-name
fallback for valid identifiers, matching the modifier query’s filtering
behavior.
🪄 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: 27e54390-fcef-4e24-b101-a9a4e6121de4

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc2ddf and 2d8d4ec.

📒 Files selected for processing (35)
  • VueApp/src/ClinicalScheduler/__tests__/audit-log-page-access.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/audit-log-results-table.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/week-history-content.test.ts
  • VueApp/src/ClinicalScheduler/components/AuditLogResultsTable.vue
  • VueApp/src/ClinicalScheduler/components/ScheduleLegend.vue
  • VueApp/src/ClinicalScheduler/components/ScheduleView.vue
  • VueApp/src/ClinicalScheduler/components/SchedulerNavigation.vue
  • VueApp/src/ClinicalScheduler/components/WeekCell.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryButton.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryDialog.vue
  • VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts
  • VueApp/src/ClinicalScheduler/constants/permission-messages.ts
  • VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
  • VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue
  • VueApp/src/ClinicalScheduler/pages/RotationScheduleView.vue
  • VueApp/src/ClinicalScheduler/router/routes.ts
  • VueApp/src/ClinicalScheduler/services/audit-log-service.ts
  • VueApp/src/ClinicalScheduler/types/audit-types.ts
  • VueApp/src/ClinicalScheduler/utils/audit-actions.ts
  • VueApp/src/Effort/__tests__/audit-change-detail.test.ts
  • VueApp/src/Effort/components/AuditChangeDetail.vue
  • VueApp/src/Effort/pages/AuditList.vue
  • test/ClinicalScheduler/ScheduleAuditServiceTest.cs
  • test/ClinicalScheduler/ScheduleEditServiceRollbackTest.cs
  • test/ClinicalScheduler/ScheduleEditServiceTest.cs
  • web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditLogEntryDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditModifierDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditTermDto.cs
  • web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
  • web/Areas/ClinicalScheduler/Services/IScheduleAuditService.cs
  • web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs
  • web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs

Comment thread VueApp/src/ClinicalScheduler/components/WeekCell.vue
Comment thread VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue
Comment thread VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue Outdated
Comment thread VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
Comment thread VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue Outdated
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from 2d8d4ec to 72ca312 Compare July 16, 2026 01:03
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
VueApp/src/ClinicalScheduler/components/ScheduleView.vue (1)

70-76: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the same history gate for the legend and week buttons.

show-history uses canViewHistory, while the buttons use canShowHistory. With a missing context, the legend advertises a control that is not rendered.

Proposed fix
-            :show-history="canViewHistory"
+            :show-history="canShowHistory"
🤖 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/ClinicalScheduler/components/ScheduleView.vue` around lines 70 -
76, Update the ScheduleLegend `show-history` binding to use the same
`canShowHistory` gate as the week buttons, ensuring the legend does not
advertise history when the required context is unavailable.
🤖 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/ClinicalScheduler/__tests__/audit-log-results-table.test.ts`:
- Around line 44-54: Update the test in
VueApp/src/ClinicalScheduler/__tests__/audit-log-results-table.test.ts:44-54 to
assert the actual QTable body-row count in addition to the existing content
assertions. Update the test in
VueApp/src/ClinicalScheduler/__tests__/week-history-content.test.ts:90-96 to
assert both the week number and formatted date, preserving the existing expected
values.

In `@VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue`:
- Around line 28-48: Replace the custom error-state markup in
WeekHistoryBody.vue with the shared StatusBanner component configured with
type="error". Preserve the displayed error message and wire the existing Retry
action to emit the same retry event.

In `@VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue`:
- Around line 165-168: Replace all remaining pixel-based sizing in the listed
WeekHistory components with rem units: in
VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue lines 165-168
convert the measured offsetHeight to root-relative rem, lines 232-244 use
0.0625rem for the header border, and lines 271-276 use -0.0625rem for progress
positioning; in VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue
lines 12-16 convert skeleton width and height to rem and lines 153-156 use
0.0625rem for the item border.

In `@web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs`:
- Around line 235-238: Update the affected logging statements in the audit
retrieval and related methods to sanitize every request-derived value before
logging: pass gradYear through SanitizeYear(), rotationId and weekId through the
appropriate LogSanitizer method, and retain sanitization for mothraId. Apply the
same treatment at the referenced logging sites while preserving their existing
messages and behavior.

---

Outside diff comments:
In `@VueApp/src/ClinicalScheduler/components/ScheduleView.vue`:
- Around line 70-76: Update the ScheduleLegend `show-history` binding to use the
same `canShowHistory` gate as the week buttons, ensuring the legend does not
advertise history when the required context is unavailable.
🪄 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: 1f71d788-f711-4123-a264-2b4638ecbadf

📥 Commits

Reviewing files that changed from the base of the PR and between 2d8d4ec and 72ca312.

📒 Files selected for processing (32)
  • VueApp/src/ClinicalScheduler/__tests__/audit-log-page-access.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/audit-log-results-table.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/week-history-content.test.ts
  • VueApp/src/ClinicalScheduler/components/AuditLogResultsTable.vue
  • VueApp/src/ClinicalScheduler/components/ScheduleLegend.vue
  • VueApp/src/ClinicalScheduler/components/ScheduleView.vue
  • VueApp/src/ClinicalScheduler/components/SchedulerNavigation.vue
  • VueApp/src/ClinicalScheduler/components/WeekCell.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryButton.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue
  • VueApp/src/ClinicalScheduler/components/WeekHistoryDialog.vue
  • VueApp/src/ClinicalScheduler/composables/use-audit-entries.ts
  • VueApp/src/ClinicalScheduler/constants/permission-messages.ts
  • VueApp/src/ClinicalScheduler/pages/AuditLogPage.vue
  • VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue
  • VueApp/src/ClinicalScheduler/pages/RotationScheduleView.vue
  • VueApp/src/ClinicalScheduler/router/routes.ts
  • VueApp/src/ClinicalScheduler/services/audit-log-service.ts
  • VueApp/src/ClinicalScheduler/types/audit-types.ts
  • VueApp/src/ClinicalScheduler/utils/audit-actions.ts
  • VueApp/src/Effort/__tests__/audit-change-detail.test.ts
  • VueApp/src/Effort/components/AuditChangeDetail.vue
  • VueApp/src/Effort/pages/AuditList.vue
  • test/ClinicalScheduler/ScheduleAuditServiceTest.cs
  • web/Areas/ClinicalScheduler/Controllers/ScheduleAuditController.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditLogEntryDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditModifierDto.cs
  • web/Areas/ClinicalScheduler/Models/DTOs/Responses/AuditTermDto.cs
  • web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
  • web/Areas/ClinicalScheduler/Services/IScheduleAuditService.cs
  • web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs

Comment thread VueApp/src/ClinicalScheduler/components/WeekHistoryBody.vue
Comment thread VueApp/src/ClinicalScheduler/components/WeekHistoryContent.vue
Comment thread web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from 72ca312 to 6d22f53 Compare July 16, 2026 01:35
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

rlorenzo added 4 commits July 16, 2026 09:59
Persist schedule-change audit entries inside the same transaction as the
edit, so audit rows commit or roll back atomically with the schedule.
Add a manager-gated audit trail page for the clinical scheduler, backed
by a paged query API over schedule-change history.

- filterable, paged results table of changes by term and modifier
- REST endpoints and DTOs for querying audit history
- navigation entry and route gated by the manage permission
Surface schedule-change history directly in the grid: each week cell
opens a modal showing that week's audit entries, with week-to-week
paging and a legend icon for managers.
Match the Effort audit list's filters and change-detail presentation to
the clinical scheduler audit trail for a consistent experience.
@rlorenzo
rlorenzo force-pushed the feature/clinical-scheduler-audit-log branch from 6d22f53 to c9ec4a7 Compare July 16, 2026 17:57
@rlorenzo
rlorenzo requested a review from bniedzie July 17, 2026 00:55
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@bsedwards I synced the audit data from prod, so the 2027 entries are now showing up. Also saw log entries for student schedules were showing up. That's filtered now.

I also made the week audit history a modal instead of a pop-up for better ux and added forward and backward buttons.

bsedwards
bsedwards previously approved these changes Jul 17, 2026

@bsedwards bsedwards left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@rlorenzo This looks good and is a clear improvement on what we have. One minor improvement from a UX perspective would be to have the back and forward buttons on the week history dialog appear in the same place regardless of the height of the dialog, for quicker browsing. But I don't see that as a need for right now.

- top-anchor the dialog so the back/forward nav holds its position across weeks of differing height
- pin the scale transition so it opens/closes like the app's other centered modals
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@bsedwards I made the modal stick in one place. I was mainly using keyboard navigation, so the arrows moving didn't bother me. But this works better.

Merging in since this was a minor change from the last approval.

@rlorenzo
rlorenzo merged commit efa132b into main Jul 17, 2026
13 of 14 checks passed
@rlorenzo
rlorenzo deleted the feature/clinical-scheduler-audit-log branch July 17, 2026 19:36
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