Skip to content

feat(clinsched): permission-gated scheduler views for own-schedule & rotation-specific users#241

Merged
bsedwards merged 6 commits into
mainfrom
patch/clinicial-rotations
Jul 2, 2026
Merged

feat(clinsched): permission-gated scheduler views for own-schedule & rotation-specific users#241
bsedwards merged 6 commits into
mainfrom
patch/clinicial-rotations

Conversation

@rlorenzo

@rlorenzo rlorenzo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Permission-gates the Clinical Scheduler so the UI only surfaces the views a user can actually use, and lets EditOwnSchedule users manage their own rotations.

  • Own-schedule users see a single "Edit My Schedule" card; the clinician selector is read-only, pre-populated with themselves; the clinicians API returns only them.
  • Rotation-specific users see only "Schedule by Rotation" limited to their permitted rotations; the clinician view is hard-denied.
  • Nav and home cards only advertise views the user can open (server-side checks mirror the client getters), with a dynamic "Edit My Schedule" label.

Commits

  1. add view-access and own-schedule permission checks - new permission-service methods + unit tests.
  2. gate nav and home cards by scheduler permissions - nav menu + home cards + async left-nav.
  3. let own-schedule users self-schedule all rotations - rotations API bypass for self-scheduling (fixes the empty "Add Rotation" dropdown). The bypass is DRY'd into one shared helper covering both the plain and with-scheduled-weeks endpoints, each with a regression test so the empty-dropdown cannot return on either path.
  4. make clinician selector read-only in own-schedule mode - read-only single-clinician display + auto-select.

Testing

  • Backend + frontend unit tests pass (pre-commit gate green on every commit).
  • Manually smoke-tested via user emulation: own-schedule and rotation-specific flows.

Add CanAccessRotationViewAsync, CanAccessClinicianViewAsync and
GetClinicianViewLabelAsync so server-side callers can mirror the client's
view-gating getters, plus a public HasEditOwnSchedulePermissionAsync used
by rotation self-scheduling checks.
@rlorenzo

rlorenzo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@codecov-commenter

codecov-commenter commented Jul 1, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 799 bytes (0.04%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
viper-frontend-esm 2.12MB 799 bytes (0.04%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: viper-frontend-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/schedule-*.js 671 bytes 49.72kB 1.37%
assets/ClinicianScheduleView-*.js 42 bytes 18.91kB 0.22%
assets/ClinicalSchedulerHome-*.js 86 bytes 3.47kB 2.54%

Files in assets/schedule-*.js:

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

  • ./src/ClinicalScheduler/components/RotationSelector.vue → Total Size: 255 bytes

  • ./src/ClinicalScheduler/services/rotation-service.ts → Total Size: 2.19kB

Files in assets/ClinicianScheduleView-*.js:

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

Files in assets/ClinicalSchedulerHome-*.js:

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

@rlorenzo rlorenzo requested a review from Copilot July 1, 2026 22:28
@codecov-commenter

codecov-commenter commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.76471% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.65%. Comparing base (ae61c44) to head (9002337).

Files with missing lines Patch % Lines
...icalScheduler/Services/ClinicalSchedulerNavMenu.cs 0.00% 12 Missing ⚠️
...calScheduler/Services/SchedulePermissionService.cs 80.00% 5 Missing and 1 partial ⚠️
web/Controllers/LayoutController.cs 0.00% 3 Missing ⚠️
...ClinicalScheduler/components/ClinicianSelector.vue 90.00% 0 Missing and 1 partial ⚠️
.../ClinicalScheduler/components/RotationSelector.vue 88.88% 1 Missing ⚠️
...inicalScheduler/Controllers/RotationsController.cs 93.75% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #241      +/-   ##
==========================================
+ Coverage   44.58%   44.65%   +0.06%     
==========================================
  Files         896      897       +1     
  Lines       51733    51890     +157     
  Branches     4834     4868      +34     
==========================================
+ Hits        23063    23169     +106     
- Misses      28098    28141      +43     
- Partials      572      580       +8     
Flag Coverage Δ
backend 44.71% <63.93%> (+0.02%) ⬆️
frontend 43.41% <91.66%> (+1.05%) ⬆️

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.

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

Adds permission-aware gating across the Clinical Scheduler so users only see (and can call) the scheduler views they’re authorized for, with explicit support for “EditOwnSchedule”-only users to self-schedule rotations without the rotation dropdown silently emptying.

Changes:

  • Introduces server-side “can access rotation/clinician view” + dynamic clinician-view label checks in SchedulePermissionService (with unit tests) and uses them to gate the left-nav scheduler subitems.
  • Updates rotations endpoints + Vue rotation fetches to support an own-schedule self-scheduling bypass (only when the caller supplies their own MothraId), covering both the plain and with-scheduled-weeks paths with regression tests.
  • Improves the own-schedule UX by making the clinician selector effectively read-only when appropriate (including auto-select when only one clinician is returned) and updates home-card copy accordingly.

Reviewed changes

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

Show a summary per file
File Description
web/Controllers/LayoutController.cs Makes left-nav loading async and injects permission service to build permission-gated scheduler nav.
web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs Adds view-access checks, clinician-view label helper, and an exposed EditOwnSchedule permission check.
web/Areas/ClinicalScheduler/Services/ISchedulePermissionService.cs Extends the permission service contract with new view-access/label methods.
web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs Gates scheduler sub-nav items based on server-side permission checks and dynamic label.
web/Areas/ClinicalScheduler/Controllers/RotationsController.cs Adds self-scheduling bypass logic (based on matching mothraId + EditOwnSchedule) shared across both rotation endpoints.
VueApp/src/ClinicalScheduler/services/rotation-service.ts Adds optional clinicianMothraId query parameter support for rotation endpoints.
VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue Passes selected clinician mothraId down to the rotation selector so own-schedule users get the bypass behavior.
VueApp/src/ClinicalScheduler/pages/ClinicalSchedulerHome.vue Updates clinician-card description copy to reflect own-schedule vs general clinician scheduling.
VueApp/src/ClinicalScheduler/components/RotationSelector.vue Threads clinicianMothraId into rotation API calls for both rotations endpoints.
VueApp/src/ClinicalScheduler/components/ClinicianSelector.vue Adds read-only behavior + auto-select when a single clinician is returned and adjusts UI affordances accordingly.
VueApp/src/ClinicalScheduler/tests/clinician-selector-permissions.test.ts Adds coverage for read-only locking when only own-schedule permission + single clinician result.
VueApp/src/ClinicalScheduler/tests/clinician-selector-basic.test.ts Adds coverage for auto-select behavior when only one clinician is returned and tightens fetch expectations.
VueApp/src/ClinicalScheduler/tests/clinical-scheduler-home-display.test.ts Updates/extends assertions for the new clinician-card description behavior.
test/ClinicalScheduler/SchedulePermissionServiceTest.cs Adds unit tests for new view-access checks and clinician-view label behavior.
test/ClinicalScheduler/RotationsControllerTest.cs Adds regression tests ensuring own-schedule self-scheduling returns all rotations on both endpoints.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds clinician-scoped rotation access, own-schedule view labeling, single-clinician selector behavior, and permission-based navigation and home text updates across the Clinical Scheduler flow.

Changes

Clinician rotation scheduling and permission gating

Layer / File(s) Summary
Schedule permission service contract and implementation
web/Areas/ClinicalScheduler/Services/ISchedulePermissionService.cs, web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs, test/ClinicalScheduler/SchedulePermissionServiceTest.cs
Adds access-check and label methods for rotation and clinician views, plus own-schedule permission checks and test coverage for the supported permission combinations.
Nav menu and layout wiring
web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs, web/Controllers/LayoutController.cs
Makes the clinical scheduler nav async, injects the permission service, and conditionally adds nav items based on view access and label lookup.
RotationsController clinician filtering
web/Areas/ClinicalScheduler/Controllers/RotationsController.cs, test/ClinicalScheduler/RotationsControllerTest.cs
Adds optional clinicianMothraId handling to rotation endpoints, routes filtering through a shared helper, and covers self-scheduling and fallback behavior in controller tests.
RotationService and selector prop flow
VueApp/src/ClinicalScheduler/services/rotation-service.ts, VueApp/src/ClinicalScheduler/components/RotationSelector.vue, VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue
Carries clinicianMothraId from the clinician schedule view into both rotation-fetching API calls.
ClinicianSelector single-clinician mode
VueApp/src/ClinicalScheduler/components/ClinicianSelector.vue, VueApp/src/ClinicalScheduler/__tests__/clinician-selector-basic.test.ts, VueApp/src/ClinicalScheduler/__tests__/clinician-selector-permissions.test.ts
Derives a single-clinician read-only state, updates select/affiliates rendering, auto-selects the sole clinician, and updates tests for the new rendering and permission cases.
Home description text
VueApp/src/ClinicalScheduler/pages/ClinicalSchedulerHome.vue, VueApp/src/ClinicalScheduler/__tests__/clinical-scheduler-home-display.test.ts
Switches the clinician card description to computed text based on own-schedule state and updates the display assertions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LayoutController
  participant ClinicalSchedulerNavMenu
  participant SchedulePermissionService
  LayoutController->>ClinicalSchedulerNavMenu: Nav(HttpContext.RequestAborted)
  ClinicalSchedulerNavMenu->>SchedulePermissionService: CanAccessRotationViewAsync()
  ClinicalSchedulerNavMenu->>SchedulePermissionService: CanAccessClinicianViewAsync()
  ClinicalSchedulerNavMenu->>SchedulePermissionService: GetClinicianViewLabelAsync()
  ClinicalSchedulerNavMenu-->>LayoutController: NavMenu
Loading
sequenceDiagram
  participant ClinicianScheduleView
  participant RotationSelector
  participant RotationService
  participant RotationsController
  ClinicianScheduleView->>RotationSelector: clinician-mothra-id = selected clinician
  RotationSelector->>RotationService: loadRotations(clinicianMothraId)
  RotationService->>RotationsController: GET rotations with clinicianMothraId
  RotationsController-->>RotationService: filtered rotations
  RotationService-->>RotationSelector: rotation data
Loading

Suggested reviewers: bsedwards

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: permission-gated scheduler views for own-schedule and rotation-specific users.
Description check ✅ Passed The description is on-topic and matches the implemented Clinical Scheduler permission-gating, self-scheduling, and UI updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 patch/clinicial-rotations

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.

@bsedwards bsedwards self-requested a review July 1, 2026 22:44
rlorenzo added 3 commits July 1, 2026 15:52
Only advertise the sub-views a user can actually open: the left-nav now
lists Schedule by Rotation and/or the clinician view based on the new
permission checks, and shows "Edit My Schedule" instead of "Schedule by
Clinician" for own-schedule users. The home card copy matches. GetLeftNav
becomes async to resolve these checks.
Own-schedule users have no service edit permissions, so the rotation list
was filtered to empty and their "Add Rotation" dropdown showed nothing. The
rotations endpoints now accept clinicianMothraId; when it matches the current
user and they hold EditOwnSchedule, permission filtering is bypassed so they
see every rotation for their own schedule. A shared helper applies this on
both the plain and with-scheduled-weeks endpoints, each covered by tests so
the empty-dropdown regression cannot return on either path.
When an own-schedule user's list resolves to a single clinician (themselves),
the selector renders as a read-only display - person icon, no search, clear,
or affiliates toggle - and auto-selects that clinician instead of an editable
combobox. Also types the vitest mocks and de-nests a conditional expect in the
selector tests so they satisfy the lint gate.
@rlorenzo rlorenzo force-pushed the patch/clinicial-rotations branch from f55eaeb to 3620c8f Compare July 1, 2026 22:57
@rlorenzo

rlorenzo commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

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

Caution

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

⚠️ Outside diff range comments (1)
web/Controllers/LayoutController.cs (1)

82-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the async leftnav clinical-scheduler branch.

Codecov flagged uncovered lines in this file. Consider a controller test exercising the "clinicalscheduler" nav case now that it awaits ISchedulePermissionService-gated results.

🤖 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 `@web/Controllers/LayoutController.cs` around lines 82 - 97, Add controller
test coverage for the async left-nav clinical-scheduler path in GetLeftNav by
exercising the "clinicalscheduler" (and/or "viper-clinical-scheduler") switch
case and verifying the awaited Nav(HttpContext.RequestAborted) result from
ClinicalSchedulerNavMenu. Use LayoutController as the entry point and mock
ISchedulePermissionService so the branch executes and is asserted, ensuring the
uncovered async branch is hit.
🤖 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 `@test/ClinicalScheduler/SchedulePermissionServiceTest.cs`:
- Around line 490-540: Add missing Admin-permission test coverage for the
clinician view paths in SchedulePermissionServiceTest. The current
CanAccessClinicianViewAsync and GetClinicianViewLabelAsync tests cover
Manage/EditClnSchedules but not the Admin branch used by
HasFullAccessPermission, so add cases using
SetupUserWithAdminPermission(TestUserMothraId) to verify
CanAccessClinicianViewAsync returns true and GetClinicianViewLabelAsync returns
the clinician schedule label. Keep the new tests alongside the existing
CanAccessClinicianViewAsync and GetClinicianViewLabelAsync cases so the
full-access OR paths are covered.

In
`@VueApp/src/ClinicalScheduler/__tests__/clinical-scheduler-home-display.test.ts`:
- Around line 58-71: Add a test case in ClinicalSchedulerHome’s display spec to
cover the hybrid hasClinicianViewReadOnly path used by isPersonalClinicianView.
Reuse the existing own-schedule assertion pattern in the ClinicalSchedulerHome
wrapper setup, but set hasClinicianViewReadOnly instead of
hasOnlyOwnSchedulePermission and verify the same “Schedule your own rotations”
copy and banner are shown for this branch.

In `@VueApp/src/ClinicalScheduler/components/RotationSelector.vue`:
- Around line 84-85: The RotationSelector component is missing reactivity for
the clinicianMothraId prop, so changes from the parent won’t trigger a refresh.
Add clinicianMothraId to the existing watcher setup in RotationSelector.vue
alongside serviceFilter, year, and onlyWithScheduledWeeks so loadRotations()
runs whenever the clinician selection changes. Make sure the update is wired in
the same place as the current watchers/getters that drive rotation loading.

In `@web/Areas/ClinicalScheduler/Controllers/RotationsController.cs`:
- Around line 362-386: `FilterRotationsByPermissionAsync` currently mixes
identity lookup with permission filtering by calling
`_userHelper.GetCurrentUser()` and comparing `currentUser.MothraId` to
`clinicianMothraId`. Move this self-identification logic into
`ISchedulePermissionService`, either by extending
`HasEditOwnSchedulePermissionAsync` or adding a dedicated
`IsSelfSchedulingAsync(clinicianMothraId)`-style method, and have
`RotationsController` rely on that service instead of direct user-helper access.
Keep the controller focused on filtering rotations and service ownership checks,
with the authenticated-user comparison encapsulated in the permission layer.

In `@web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs`:
- Around line 32-46: Add unit test coverage for ClinicalSchedulerNavMenu to lock
in the new permission-gated branching. Create tests around the
ClinicalSchedulerNavMenu build logic that exercise the
CanAccessRotationViewAsync, CanAccessClinicianViewAsync, and
GetClinicianViewLabelAsync paths, covering base-permission-denied,
rotation-only, clinician-only, own-schedule label, and full-access cases. Verify
the generated NavMenuItem entries and MenuItemText/MenuItemURL/IndentLevel
values for each scenario so the new nav behavior stays covered.
- Around line 32-46: The scheduler nav permission checks in
ClinicalSchedulerNavMenu are not protected against service failures, so a thrown
exception can break LayoutController.GetLeftNav() instead of simply omitting
those sub-items. Update the menu-building logic around
CanAccessRotationViewAsync, CanAccessClinicianViewAsync, and
GetClinicianViewLabelAsync to catch failures and fall back to adding no
scheduler-specific items, keeping the nav render resilient.

In `@web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs`:
- Around line 175-186: CanAccessRotationViewAsync currently triggers a full
Services load through GetUserEditableServicesAsync on every nav render for
non-full-access users, which is wasteful. Update the permission check to avoid
re-querying the entire table on each call, preferably by reusing a cheaper
access check or introducing per-request/short-TTL caching around the
editable-services lookup. Keep the behavior of HasFullAccessPermission and the
current access decision intact, but change the data access path used by
CanAccessRotationViewAsync.
- Around line 175-186: Wrap the remaining permission checks in the same
database-exception guard so these methods fail closed instead of throwing:
`CanAccessRotationViewAsync`, `CanAccessClinicianViewAsync`,
`GetClinicianViewLabelAsync`, and `HasEditOwnSchedulePermissionAsync` in
`SchedulePermissionService`. `HasFullAccessPermission()` and
`HasEditOwnSchedulePermission()` both call into `UserHelper.HasPermission()` via
RAPS-backed queries, so catch the same DB-related exceptions around those checks
and return false (or the existing safe fallback) when they occur. Keep the guard
logic consistent with the existing exception handling already used in the
service.

---

Outside diff comments:
In `@web/Controllers/LayoutController.cs`:
- Around line 82-97: Add controller test coverage for the async left-nav
clinical-scheduler path in GetLeftNav by exercising the "clinicalscheduler"
(and/or "viper-clinical-scheduler") switch case and verifying the awaited
Nav(HttpContext.RequestAborted) result from ClinicalSchedulerNavMenu. Use
LayoutController as the entry point and mock ISchedulePermissionService so the
branch executes and is asserted, ensuring the uncovered async branch is hit.
🪄 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: b305a5ac-bc7d-43ed-a92a-94cfb330181e

📥 Commits

Reviewing files that changed from the base of the PR and between ae61c44 and 3620c8f.

📒 Files selected for processing (15)
  • VueApp/src/ClinicalScheduler/__tests__/clinical-scheduler-home-display.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/clinician-selector-basic.test.ts
  • VueApp/src/ClinicalScheduler/__tests__/clinician-selector-permissions.test.ts
  • VueApp/src/ClinicalScheduler/components/ClinicianSelector.vue
  • VueApp/src/ClinicalScheduler/components/RotationSelector.vue
  • VueApp/src/ClinicalScheduler/pages/ClinicalSchedulerHome.vue
  • VueApp/src/ClinicalScheduler/pages/ClinicianScheduleView.vue
  • VueApp/src/ClinicalScheduler/services/rotation-service.ts
  • test/ClinicalScheduler/RotationsControllerTest.cs
  • test/ClinicalScheduler/SchedulePermissionServiceTest.cs
  • web/Areas/ClinicalScheduler/Controllers/RotationsController.cs
  • web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
  • web/Areas/ClinicalScheduler/Services/ISchedulePermissionService.cs
  • web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs
  • web/Controllers/LayoutController.cs

Comment thread test/ClinicalScheduler/SchedulePermissionServiceTest.cs
Comment thread VueApp/src/ClinicalScheduler/components/RotationSelector.vue
Comment thread web/Areas/ClinicalScheduler/Controllers/RotationsController.cs
Comment thread web/Areas/ClinicalScheduler/Services/ClinicalSchedulerNavMenu.cs
Comment thread web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs
The Add-Rotation picker used the with-scheduled-weeks endpoint, so it only
listed rotations that already had instructor schedules in the selected year -
showing progressively fewer (and eventually zero) rotations for future years.
The legacy scheduler always listed every active rotation (getRotations
active=1); switch the own-schedule picker to the all-active list to match.

Also add a watcher on RotationSelector's clinicianMothraId prop so the list
refetches when the target clinician changes (it previously reacted only to
serviceFilter/year/onlyWithScheduledWeeks), with tests covering the prop
forwarding and the refetch.

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 16 out of 16 changed files in this pull request and generated 2 comments.

Comment thread VueApp/src/ClinicalScheduler/components/ClinicianSelector.vue Outdated
Comment thread web/Controllers/LayoutController.cs
- Auto-select of a sole clinician now fires only in own-schedule
  contexts; the rotation view's add-clinician picker previously staged
  a clinician for scheduling without user action whenever the list had
  one entry, re-firing on every refetch
- Emit update:modelValue/change at most once per clinician fetch;
  own-schedule loads previously emitted duplicates
- Ignore stale out-of-order rotation-list responses in RotationSelector
- Prove the clinicianMothraId bypass negatives: a mismatched ID or
  missing EditOwnSchedule keeps normal service filtering
- Require IUserHelper injection in RotationsController; drop the dead
  new UserHelper() fallback
@rlorenzo

rlorenzo commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@bsedwards Ready for review/merging

@bsedwards bsedwards merged commit da4c356 into main Jul 2, 2026
13 checks passed
@bsedwards bsedwards deleted the patch/clinicial-rotations branch July 2, 2026 03:24
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