> For the complete documentation index, see [llms.txt](https://help.resouris.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.resouris.com/run-the-roster/roster-grid-actions.md).

# Roster grid actions

Everything you can do on a cell of `/ui/rosters/{roster_id}/spaces` — added / consolidated across v1.6.8.2, v1.6.8.3, and v1.6.8.4.

**Who can do this**: any role holding `roster.update` (default: `rostering_manager`, `platform_admin`, `tenant_admin`).

***

## The grid at a glance

* **Rows** = rooms in the current tier (Primary or Working from home tabs).
* **Columns per day** = **AM / PM / OOH** (three sub-columns).
  * AM = 09:00–13:00 UTC
  * PM = 13:00–17:00 UTC
  * **OOH = 18:00 UTC of the day → 09:00 UTC of the next day** (renders in the START day's OOH column; the band spans midnight but doesn't stretch into a second cell). Added v1.6.8.4 (enhancement #57).
* **Tabs** — Primary roster + Working from home. The Secondary tab was dropped in v1.6.8.4 (OOH work moved into the Primary tab).

## The `⋯` button + right-click

Every cell has a small `⋯` menu button in its top-right corner (subtle at rest; darkens to brand-teal on hover). It replaces the old `+` add-only button from v1.6.7. **Right-click anywhere in a cell** opens the same menu — pick your affordance.

The menu contents adapt to the cell state:

### Empty cell

```
+ Add manually…
⊗ Cancel this session…
```

### Filled cell (1 or more staff)

```
+ Add another person…
⊗ Cancel this session…
──────────────
Replace a person
  ↺ Replace {name}…            (one per person)
──────────────
Change service line
  ⇄ Change SL for {name}…  coming  (enhancement #48; placeholder)
```

### Cancelled cell

```
↺ Un-cancel this session
```

(All other actions are locked out until the operator reverses the cancellation.)

## Add manually — the intelligent picker

The Add-manually modal (opened from any cell) uses a **competency-filtered staff picker**:

1. **Service line** dropdown — active service lines in the tenant's department. *Changed in v1.8.3: there was a **Clinic** dropdown above this one, and this list was filtered to the lines wired to whichever clinic you picked. Clinics are gone; choose the line directly.* Auto-selects when there's only one.
2. **Staff** dropdown — filtered to staff who hold the SL's equipment-derived skills at the required level. Shows a "N of M eligible" count.
3. **Override checkbox** — "Allow any active staff member (emergency override)". Ticked = every active staff shows regardless of skills. The override choice lands in the audit payload.

Save → assignment row lands with `origin='manual'`. See [the origin marker](#the-manual-origin-marker) below.

## Replace staff — also intelligent

The Replace-staff modal (opened via **Replace {name}…** on a filled cell) uses the same competency filter, keyed on the CURRENT assignment's service line:

* Shows only staff who hold the equipment-required skills for that SL.
* Shows a "N of M eligible" count so operators know the pool depth.
* **Override checkbox** widens the list to every active staff. Ticking it live-rebuilds the dropdown.

Replaced assignment retains its `origin` field (a solver-produced row stays `solver`; a manual-added row stays `manual`).

## The manual `origin` marker

Every assignment row carries an `origin` field (MIG-172, added v1.6.8.2):

* **`solver`** (default) — produced by the CP-SAT solver on a published roster.
* **`manual`** — added or force-swapped by an operator via any of the manual paths (Add manually, Replace).

Manual rows render with:

* A **2px dashed indigo left border** on the `.rg-assignment` div.
* A tiny **"M" corner badge** (top-right).

Why care? Two operator questions this answers:

* *"What % of the published roster did I hand-author?"* — a single SQL group-by. Feeds workload + business-case conversations.
* *"Did last night's re-solve preserve every manual override I made?"* — grep the audit + count.

## Cancel a session

See the dedicated [Cancel a session](/run-the-roster/cancel-a-session.md) guide.

## OOH (out-of-hours) column

Added v1.6.8.4. The OOH column appears alongside AM/PM on every day of the Primary tab.

* Any assignment starting at 18:00 UTC or later renders in that day's OOH column.
* The band conceptually extends to 09:00 UTC the NEXT day, but the cell stays in the START day.
* Currently populated **manually** via the ⋯ menu → Add manually flow. The solver auto-emit is a planned follow-up (enhancement #57, PR 2 — extends `application.rostering.on_call_planner` to produce OOH assignments for service lines with `has_on_call=true`).
* Empty OOH cells have a subtle violet accent so operators can scan the column at a glance.
* Cancellations work identically on OOH cells (MIG-174 admits `half='ooh'`).

## Working from home tab

Currently uses the same Rooms × Days grid shape as Primary but filtered to `rooms.target_roster_tier='tertiary'`. Enhancement #58 (planned) reworks this to a **Staff × Days** grid driven by a new `assignments.work_location` column so WFH is modelled as "the person's work mode" rather than "a physical room". See enhancement #58 in the `enhancements.md` tracker for the migration plan.

## Keyboard + right-click parity

* **Right-click any cell** → opens the same ⋯ menu at the cursor position (power-user shortcut).
* **Escape** closes any open menu.
* **Click outside the menu** closes it.
* No keyboard shortcut binds the ⋯ button directly — use right-click for the fast path.

## What the audit trail captures

Every cell action emits at least one event. Highlights:

| Action       | Event                      | Payload notes                                                                            |
| ------------ | -------------------------- | ---------------------------------------------------------------------------------------- |
| Add manually | `roster.manual_assign`     | via='ui', room\_id, iso\_date, half, service\_line\_id, staff\_id, override\_eligibility |
| Replace      | `staff.shift_changed`      | assignment\_id, old\_staff\_id, new\_staff\_id, override\_eligibility, missing\_skills   |
| Cancel       | `roster.slot.cancelled`    | revision\_id, room\_id, iso\_date, half, reason, release\_staff, notes                   |
| Un-cancel    | `roster.slot.un_cancelled` | cancellation\_id                                                                         |

## Related surfaces

* **Availability view** (`/ui/admin/availability`) — orthogonal read surface. Doesn't render `origin` markers or cancellations (yet). Shows staff-side status only.
* **My Team calendar** (`/ui/my-team`) — line manager's view over their subordinates. Same as availability view — doesn't render `origin` markers or cancellations.
* **Trust Admin** (`/ui/trust-admin/upcoming-clinics`) — sits alongside on the same page family; unaffected by these changes.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://help.resouris.com/run-the-roster/roster-grid-actions.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
