Skip to main content

Schedule channel context + auto-watch requester design

Summary

Two Lab scheduling UX fixes:
  1. Enriched Schedule channel dropdown — each option shows live availability state and electrical ratings (A / V) so schedulers do not bounce to the Lab wall to judge fit.
  2. Auto-watch requester on start — when a scheduled planned measurement links to a started cell_measurement, the backend silently watches that measurement for requested_by only.
No protocol auto-filter, mismatch badges, toasts, or auto-watch for scheduled_by / operators.

Problem

  • The Schedule dialog (SchedulePlannedMeasurementDialog) Autocomplete lists only cycler / channel (and disables out-of-commission). Availability and ratings already exist on the Lab wall via GET .../lab/status, but not in the picker, so schedulers context-switch to Lab view.
  • Watching is manual. When a requested test finally starts, the requester does not appear on “My Channels” until they find the channel and click Watch.

Current state (references)

  • Schedule dialog: frontend/src/sections/lab/schedule-planned-measurement-dialog.tsx
  • Lab status types + query: frontend/src/redux/api/lab-api.ts (LabChannel.state, max_amps, min_volts, max_volts)
  • Lab wall tiles already format ratings: frontend/src/sections/lab/channel-tile.tsx, wall-scope.ts (formatRatingRange)
  • Planned measurements overview: dev-docs/planned-measurements.md
  • Link on measurement create: CellMeasurementServicePlannedMeasurementRepository.link_started_measurement (backend/src/services/cell_measurements.py ~2107)
  • Alternate path: PATCH planned measurement to in_progress + started_measurement_id via PlannedMeasurementService
  • Watches: UserWatchedMeasurementService.watch(user_id, measurement_id) (idempotent) in backend/src/services/user_watched_measurements.py
  • Planned row fields: requested_by, scheduled_by

Design

1. Enriched channel Autocomplete (frontend only)

File: schedule-planned-measurement-dialog.tsx When flattening labStatus.sites → cyclers → channels, keep:
  • id, label (${cycler.name} / ${channel.name})
  • outOfCommission (still disables the option)
  • state (free | occupied | stale | out_of_commission)
  • max_amps, min_volts, max_volts
Option rendering:
  • Primary: cycler / channel
  • Secondary: ratings via existing formatRatingRange (same string shape as Lab tiles, e.g. 40 A · 0–5 V; omit empty parts)
  • Trailing / muted: human state label (free, occupied, stale; out of commission already in the disabled label today)
Behavior unchanged:
  • All non–out-of-commission channels remain selectable (including occupied / stale).
  • Selecting a channel still fetches next available start and prefills / shows the existing helper text.
  • No comparison against protocol voltage/current; no sorting or filtering by “fit”.
API: reuse useGetProjectLabStatusQuery — no backend change. Tests: lightweight unit/render test that option content includes state + ratings when lab status fixture supplies them (follow existing lab section test patterns).

2. Auto-watch requester when plan becomes in progress (backend)

Trigger (both paths):
  1. Primary: after a successful link_started_measurement (returns a linked plan, not None) in CellMeasurementService’s planned-measurement link helper.
  2. Secondary: when PlannedMeasurementService update transitions a row to in_progress with a new started_measurement_id (logger PATCH path).
Action:
  • Resolve requested_by from the linked/updated planned measurement.
  • Call UserWatchedMeasurementService.watch(requested_by, started_measurement_id) (or equivalent repo call with org resolved as today).
  • Idempotent: already-watching is a no-op.
Failure policy:
  • Watch errors must not fail measurement create or plan update.
  • Log at warning/exception level and continue (same spirit as today’s “created measurement but failed to link plan” handling).
Not in this change:
  • Auto-watch scheduled_by
  • Client-side watch after polling status
  • Toast / email / push notification
  • Unwatch previous measurements for the requester
Dependency wiring: inject UserWatchedMeasurementService (or its repository) into CellMeasurementService / PlannedMeasurementService as needed; prefer the service so org resolution and idempotency stay centralized. Tests:
  • Link scheduled plan → measurement: assert a user_watched_measurements row for (requested_by, measurement_id).
  • Second link/watch is idempotent (no error).
  • Forced watch failure still leaves measurement created / plan in_progress.
  • PATCH-to-in_progress path also creates the watch.

Out of scope

  • Protocol envelope vs channel rating auto-check or disable
  • Embedding Lab wall / mini channel grid in the Schedule dialog
  • Auto-watch for anyone other than requested_by
  • Realtime push to open Lab wall clients (cache invalidation remains as today when the requester next loads lab status)
  • Changing next-available slot UX beyond current helper text

Success criteria

  • Scheduler can see free/occupied/stale and A/V ratings in the Schedule channel list without opening the Lab wall.
  • When a scheduled test starts and links to a measurement, that measurement is watched for the requester so it can show under “My Channels” on their next Lab status fetch.