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:

Stateis_hiddenvisible_onvisible_untilBehavior
HiddentrueNULLNULLNot visible to students
VisiblefalseNULLNULLAlways visible
Scheduledfalsedatetimedatetime (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:

  1. Clear stale fields. If the mode is Visible or Hidden, explicitly set visible_on and visible_until to 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.

  2. Parse datetimes. Flatpickr sends ISO 8601 strings. The controller parses them through Time.zone.parse to ensure timezone-correct storage.

  3. 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.