MarkUs: Scheduled Visibility (Frontend)
PR #7717 — Building the instructor-facing UI for time-based assignment visibility.
Requirements
The backend PR added visible_on / visible_until columns and query-based visibility evaluation. This PR builds the instructor interface: a visibility control with three modes (Hidden, Visible, Scheduled), datetime pickers for the scheduled mode, and a section-override table for per-section visibility windows.
UI Architecture
State Machine
The visibility control implements a three-state model:
| State | is_hidden | visible_on | visible_until | Behavior |
|---|---|---|---|---|
| Hidden | true | NULL | NULL | Not visible to students |
| Visible | false | NULL | NULL | Always visible |
| Scheduled | false | datetime | datetime (optional) | Visible within window |
State transitions clear dependent fields: switching from Scheduled to Visible nullifies both datetime fields. Switching to Hidden nullifies them and sets is_hidden = true. This prevents stale datetime values from persisting when the instructor changes their mind.
Flatpickr Integration
Datetime selection uses Flatpickr, a lightweight date picker that supports time selection, min/max constraints, and programmatic control.
Configuration handles the “midnight edge case”: an instructor setting “visible until Dec 31” expects visibility through the end of December 31, not expiration at midnight. The picker defaults to 23:59 for visible_until to match this expectation, while visible_on defaults to 00:00.
Section Override Table
A table listing all sections with per-section datetime overrides. Each row contains a section name and optional visible_on / visible_until fields that override the assessment-level defaults. Empty fields fall back to the assessment’s global settings, matching the backend’s COALESCE precedence chain.
Frontend-Backend Contract
The controller normalizes frontend data before persisting:
-
Clear stale fields. If the mode is Visible or Hidden, explicitly set
visible_onandvisible_untilto NULL regardless of what the form sends. This prevents a scenario where a previous Scheduled configuration persists in the database after the instructor switches modes. -
Parse datetimes. Flatpickr sends ISO 8601 strings. The controller parses them through
Time.zone.parseto ensure timezone-correct storage. -
Validate consistency. Reject if
visible_on >= visible_until(delegated to model validation, but the controller provides immediate feedback).
Testing Challenges
Async date pickers in system tests. Flatpickr renders asynchronously. Tests that immediately assert on date values after clicking a date fail intermittently in CI where rendering is slower. Fixed with explicit waitFor patterns that poll for the expected DOM state rather than using fixed sleep durations.
Form state transitions. Each mode transition (Hidden → Scheduled → Visible → Hidden) must be tested to verify that datetime fields appear/disappear and that submitted values are correct. This is a combinatorial testing problem: 3 modes x 2 transitions each = 6 paths, plus section overrides.
i18n. All user-facing strings routed through Rails i18n. English locale file added with keys for visibility modes, date picker labels, and validation error messages. This ensures the feature is translatable without code changes.
Design Decision
Radio buttons, not a dropdown. The three visibility modes are mutually exclusive with immediate visual consequences (showing/hiding datetime pickers). Radio buttons make the current state and available transitions visible at a glance, while a dropdown hides options behind a click. For a control with 3 options and significant dependent UI, radio buttons reduce instructor confusion.