Summary
Sort Students A→Z; sort Assignments by Title or Due date; filter Assignments by type
3Questions
0Links
0Comments
0PRs
Open questions
- 1 **URL-persistence of sort/filter state.** `?sort=name-asc&type=daily-pages,thesis` makes a filtered view shareable and back-button-friendly, at the cost of router plumbing. In-memory only is the simpler ship. Bryant picks.
- 2 **Filter UX shape.** Multi-select dropdown vs. a row of toggleable chips above the table. Dropdown scales better when the type list is long; chips are faster to scan when it's short. Bryant picks.
- 3 **Rollout flag.** Default expectation is this rides the existing `course-view` feature flag (see [course-view.md](course-view.md)) rather than introducing a second flag. Bryant to confirm.
Spec body
# My Classes sorting and filtering
Give teachers in the course view a way to sort the Students roster alphabetically, sort the Assignments table by title or due date, and filter the Assignments table by assignment type (Daily Pages, Thesis-Driven Essay, etc.) so they can find a student or assignment without scanning the whole list.
## Problem
In the redesigned course view ([course-view.md](course-view.md)) the Students tab is a flat roster and the Assignments tab is a flat table. For the pilot UA professor (150+ students across multiple sections) and any teacher with more than a handful of assignment types active in a course, "find Ada in this class" or "show me only the Daily Pages assignments" today means eyeballing the list top-to-bottom. There's no ordering guarantee (current order is whatever the loader returns) and no filter affordance at all.
The workaround is Cmd-F in the browser, which doesn't help when the teacher knows the *kind* of thing they want but not the exact name ("show me everything Daily Pages").
## Goals
- Students tab can be sorted alphabetically (A→Z and Z→A) by student name.
- Assignments tab can be sorted alphabetically (A→Z and Z→A) by assignment title.
- Assignments tab can be sorted by due date (soonest-first and latest-first).
- Assignments tab can be filtered to one or more assignment types.
- Default order is stable and predictable so teachers don't have to re-sort every time they land.
## Non-goals
- Sorting by other Students columns (submission counts, last activity, etc.). One sort axis on this page; revisit if teachers ask.
- Sorting Assignments by status counts (In Progress / Submitted / Graded / Paste). Keep the sort axes to Title and Due date for v1.
- Sorting/filtering on the top-level `/app/my-classes` class grid. That page is a small set of class cards; no scaling problem there yet.
- Saving sort/filter preferences across sessions. State is per-page-load.
- Full-text search inside a class. Filtering is by structured field (assignment type) only.
- Filtering Students by enrollment state, section, or any roster attribute beyond name sort.
## Domain notes
- **Course** — both controls scope to a single Course (the course view at `/app/my-classes/:courseId`).
- **Students tab** — sort is over the course's enrolled student list (the same roster the loader builds today).
- **Assignments tab** — sort is over the per-row assignment entries shown in the table. Filter is over the row's AssignmentType. Today each row corresponds to an AssignmentType active in the course; once [assignments-unification](assignments-unification.md) lands, the row identity may shift, but the filter axis (assignment type) stays the same.
- No state transitions; this is presentation-layer only.
## UX sketch
Controls live above each tab's table, left-aligned, not in a separate filter drawer.
**Students tab**
A single sort control (the `Name` column header acts as the toggle, with a small ↑/↓ indicator). Default is A→Z. Clicking flips to Z→A; clicking again returns to A→Z.
```
+------------------------------------------------------------------+
| [ Students ] [ Assignments ] |
+------------------------------------------------------------------+
| Name ↑ |
+------------------------------------------------------------------+
| Ada Lovelace 3 docs [View Details] |
| Alan Turing 1 doc [View Details] |
| Grace Hopper 2 docs [View Details] |
| Linus Torvalds 0 docs [View Details] |
+------------------------------------------------------------------+
```
**Assignments tab**
Three controls above and within the table:
1. **Type filter** — a multi-select dropdown labeled "Type" listing the assignment types this teacher can normally assign (per [AssignmentType visibility](assignment-type-visibility.md)) that also appear in this course's assignments. So the dropdown only shows types both (a) within the teacher's normal scope and (b) actually present in the table — no empty options, no types the teacher can't see elsewhere. Default: all selected (no filter applied). A small chip count appears on the trigger when the filter is narrowed: `Type (2)`.
2. **Title sort** — the `Assignment` column header toggles A→Z / Z→A. Default A→Z.
3. **Due date sort** — the `Due` column header toggles soonest-first / latest-first.
Only one sort column is active at a time; clicking a different column header takes over as the active sort. The inactive sortable headers show a faint hint indicator that they're sortable.
```
+------------------------------------------------------------------+
| [ + Create New Assignment ] |
+------------------------------------------------------------------+
| [ Students ] [ Assignments ] |
+------------------------------------------------------------------+
| [ Type ▾ ] |
+------------------------------------------------------------------+
| Assignment ↑ Due ⇅ In Prog Submitted Graded Paste |
| Daily Pages — Wk 3 May 14 8 [2] [0] [0] |
| Macbeth essay May 10 11 [3] [1] [0] |
| Reading reflection May 5 0 0 0 0 |
+------------------------------------------------------------------+
Type filter open:
+-----------------------------+
| [x] Daily Pages |
| [x] Thesis-Driven Essay |
| [x] 5-Paragraph Essay |
| [ ] DBQ |
| [ ] LEQ |
| |
| [ Clear ] [ Apply ] |
+-----------------------------+
```
**Empty / edge states**
- Type filter applied, no rows match: empty state with "No assignments match this filter. [Clear filter]"
- Course has zero assignments: existing empty state from `course-view.md` wins; no filter control rendered.
- Course has zero students: existing empty state wins; no sort control rendered.
**Locale-aware sort**
Use the browser's locale-aware comparator (`Intl.Collator`) so "Ángela" sorts where a Spanish-speaking teacher expects, not at the end after "Z".
## Data model implications
None. All three controls are presentation-layer over data the loaders already return.
- Sort can happen client-side after the loader returns; the lists in question are bounded (hundreds of students max, dozens of assignments) and don't need a server round-trip.
- Filter can also happen client-side. A future move to URL-param-driven state (so a filtered view is shareable) is plausible but out of scope here.
No migrations, no new fields, no indexes.
## File paths in `yawp-2.0` likely to change
- `services/web-app/app/routes/app.my-classes.$courseId/components/students-table.tsx` — add sort toggle on Name header
- `services/web-app/app/routes/app.my-classes.$courseId/components/assignments-table.tsx` — add Type filter dropdown and sort toggle on Assignment header
- `services/web-app/app/routes/app.my-classes.$courseId/route.tsx` — loader unchanged; route may need to surface the list of types active in the course (or compute it client-side from the assignments list)
- Possibly a shared sort/filter component (`services/web-app/app/components/...`) if the column-header-sort pattern is reusable
## Open questions (Bryant's call before building)
These are engineering judgement calls — product is fine with whichever way Bryant lands.
- [ ] **URL-persistence of sort/filter state.** `?sort=name-asc&type=daily-pages,thesis` makes a filtered view shareable and back-button-friendly, at the cost of router plumbing. In-memory only is the simpler ship. Bryant picks.
- [ ] **Filter UX shape.** Multi-select dropdown vs. a row of toggleable chips above the table. Dropdown scales better when the type list is long; chips are faster to scan when it's short. Bryant picks.
- [ ] **Rollout flag.** Default expectation is this rides the existing `course-view` feature flag (see [course-view.md](course-view.md)) rather than introducing a second flag. Bryant to confirm.
Scope note (not an open question, recorded so it doesn't get re-litigated): "My Classes view" in the original ask refers to the inside-a-class course view (`/app/my-classes/:courseId`), not the top-level `/app/my-classes` class grid.
## Edge cases
- Two students with the same first name: secondary sort on last name (or full display name) to keep order stable.
- Two assignments with identical titles: secondary sort on due date (ascending) so the order is deterministic. When the active sort *is* due date, secondary sort on title.
- Assignments with no due date set: group them at the end of the due-date sort regardless of direction (so the "no due date" pile doesn't bounce to the top when the teacher flips to latest-first). Show the cell as `—` rather than blank.
- Two assignments with the same due date: secondary sort on title.
- Assignment type names with accented characters or non-Latin scripts: use locale-aware comparison.
- Teacher narrows the Type filter to a single type, then creates a new assignment of a different type: the new assignment is hidden by the filter. Consider showing a one-time inline notice ("New assignment created — not shown by current filter. [Clear filter]") rather than silently hiding it.
- Re-sorting while a drilldown is open: drilldown is unaffected (it's a separate view); when the teacher returns, the sort state is preserved.
- Mobile / narrow viewport: sort toggles in column headers must remain tappable; the Type filter dropdown should stack below the tab bar rather than overflow horizontally.
## Test plan
Unit:
- Sort comparator: locale-aware, case-insensitive, stable secondary sort on tiebreakers (last name for students; due date for title-sorted assignments; title for due-date-sorted assignments).
- Due-date comparator: assignments with no due date sink to the bottom for both directions.
- Filter predicate: empty selection treated as "all" (not "none"); narrowing the selection returns only rows whose assignment type matches.
Integration:
- Students tab renders Name header with sort indicator; clicking flips order; clicking again restores.
- Assignments tab renders Type dropdown listing only types active in this course; selecting a subset filters the table; clearing restores the full list.
- Assignments title sort works independently of the type filter (sort + filter compose correctly).
- Empty-state rendering when a filter excludes all rows.
Manual QA:
- UA professor account (or a seeded test course with 150+ students and 10+ assignment types): roster sort is snappy, dropdown lists all active types in alphabetical order.
- Default landing on the Students tab shows A→Z order without the teacher clicking anything.
- Default landing on the Assignments tab shows A→Z by title with all types selected.
- Clicking the Due column header switches the active sort to due date soonest-first; clicking again flips to latest-first.
- Assignments with no due date appear at the bottom of both due-date orderings.
- Filter + sort compose: select two types, sort Z→A by title, confirm only those two types are shown in reverse alphabetical order. Repeat with the due-date sort.
- Locale check: a student named "Ángela Ruiz" sorts before "Beatriz", not after "Zoe".
## Rollout
Small UI-only change with no data model risk. Default plan: piggyback on the existing `course-view` feature flag rather than introducing a second one, and ship to the same pilot order (UA → Washington → Birmingham City → broader). Bryant confirms the flag plumbing in the open-questions section above.
## Engineering handoff checklist
- [x] Domain context covered
- [x] File paths in `yawp-2.0` listed
- [x] Data model implications spelled out, including backward-compat plan
- [x] UX sketch in prose
- [x] Edge cases enumerated
- [x] Test plan written
- [x] Rollout plan decided (ride `course-view` flag; Bryant confirms plumbing)Repo sync
No repo sync metadata recorded yet.