# orca.ui.coverage

> A module of morca's API.

The Coverage card on a dated pipeline's Operate tab: its partitions' states (`orca.calendar`) as plain HTML, read-only.

A daily pipeline's card has two tabs, **Month** (a month of days) and
**Year** (twelve small months, each with how many of its days are done, and
a strip of every month of its range linking to their years). Both are in
the page; the links work without scripts (`?cov=month|year`, with `?cal=`
the month or year), and with them the tabs switch in place and the choice
is kept in `localStorage`, as the Steps tabs are. Year is the default. A
monthly pipeline's card is its year of months, as before, and an hourly
one's a day of hours (`?cal=YYYY-MM-DD`). For a sensor,
the days what it follows has but it hasn't done, failed or started are
`behind` (`orca.follow`), and `follow_html` is its Progress card's
Following line.

One calendar is read for both tabs (`year_calendar`): the month is cut out
of the year, so the card costs the same three queries as a month did.

## Functions

### `states`

```mojo
def states() -> List[String]
```

The states, in the legend's order.

### `month_name`

```mojo
def month_name(month: Int) -> String
```

### `state_words`

```mojo
def state_words(state: String) -> String
```

### `coverage_html`

```mojo
def coverage_html(mut h: Html, mut db: State, name: String, kind: String, start: String, cal: String, view: String, f: Optional[Follow] = None)
```

The pipeline page's Coverage card; `cal` is the month or year to show (`?cal=`, today's if empty) and `view` the tab (`?cov=`). With `f` (a sensor's `follow`), what it follows has but it hasn't done is `behind`.

### `coverage_href`

```mojo
def coverage_href(name: String, kind: String) -> String
```

Where a pipeline's coverage number links (`orca.coverage`): its Coverage card, a daily one's on the Year tab, or a keyed one's Keys on the Overview.

### `key_ranges`

```mojo
def key_ranges(keys: List[String], unit: String) -> String
```

Sorted day (month) keys as `orca backfill` takes them, each run of consecutive ones as `FIRST..LAST`: `2023-01-01..2023-01-31,2023-03-04`.

### `follow_html`

```mojo
def follow_html(mut h: Html, name: String, f: Follow, max_runs: Int = Int(1))
```

The Progress card's Following line: what the sensor follows, how many of its days (months) are done, and what's behind, by state, with the first of each linked, and a button that queues the ones in no run yet.

## Aliases

### `COVERAGE_STYLE`

```mojo
comptime COVERAGE_STYLE = "\n.cov__body { padding: 0.75rem 1.1rem 0.9rem; display: grid; gap: 0.6rem; }\n.cov__body[hidden] { display: none; }\n.cov__body > .cal { margin: 0; }\n.cov .cal__key { border: 1px solid var(--border-strong); }\n.cov__body > .cal__head { max-width: 22rem; }\n.cov__months { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem 1.1rem;\n  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }\n.cov__month { min-width: 0; display: grid; gap: 0.15rem; align-content: start; }\n.cov__name { font-size: 0.8125rem; font-weight: 600; color: var(--text); text-decoration: none; }\n.cov__name:hover { color: var(--lake); text-decoration: underline; }\n.cov__sum { font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; }\n.cov__grid { gap: 2px; }\n.cov__grid .cal__dow { font-size: 0.6rem; line-height: 1.2; }\n.cov__grid .cal__day { min-height: 0; aspect-ratio: 1; border-radius: 2px; font-size: 0; }\n.cov__grid .cal__day::after { content: none; }\n.cov__grid .cal--open { border-color: var(--border-strong); }\n.cov__range { display: grid; gap: 0.25rem; }\n.cov__strip { list-style: none; margin: 0; padding: 0; display: flex; gap: 1px; }\n.cov__strip li { flex: 1 1 0; min-width: 0; }\n.cov__bar { display: block; height: 1.1rem; border-radius: 1px; background: var(--surface-2);\n  border: 1px solid var(--border); }\n.cov__bar:hover, .cov__bar:focus-visible { outline: 2px solid var(--lake); outline-offset: 0; }\n.cov--0 { background: color-mix(in srgb, var(--ok) 12%, var(--surface)); }\n.cov--1 { background: color-mix(in srgb, var(--ok) 30%, var(--surface)); }\n.cov--2 { background: color-mix(in srgb, var(--ok) 50%, var(--surface)); }\n.cov--3 { background: color-mix(in srgb, var(--ok) 70%, var(--surface)); }\n.cov--all { background: var(--ok); border-color: var(--ok); }\n.cov--here { border-color: var(--ember); border-bottom-width: 3px; }\n.cal--behind { background: color-mix(in srgb, var(--warn) 18%, var(--surface)); border-color: var(--warn); }\n.cal--behind::after { content: \22\\2026\22; color: var(--warn); }\n.cov__grid .cal--behind { border-color: var(--warn); }\n.cal__key.cal--behind::after { content: none; }\n.follow__keys { display: block; font-size: 0.8125rem; color: var(--muted); }\n.follow__queue { display: block; margin-top: 0.35rem; }\n.cov__ends { display: flex; justify-content: space-between; margin: 0; font-size: 0.7rem; }\n@media (max-width: 640px) {\n  .cov__months { grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: 0.75rem; }\n  .cov__body { padding: 0.6rem 0.75rem 0.75rem; }\n}\n"
```

The Coverage card's rules, served after `orca.ui.style.STYLE`.
