Add the Home Assistant REST calendar client and the idempotent sync that writes important school events to Sam's Home Assistant calendar (FR-8). The school stays read-only; the only write is to the calendar (rule 7). - internal/calendar: HA REST client (states, create_event, get_events, delete_event) and the sync that selects important future events, adopts an existing event by its description marker, records the HA event id on the item, and records every attempt. - internal/store: migration 003 (items.ha_event_uid, items.ha_pushed_at and the append-only calendar_pushes table), candidates, mark-synced and the push log. - internal/parse: a school event is important; a routine class period is not. - cmd/school: `school calendar entities|status|push|events`. - web: an "Add to calendar" item action and a fail-loud calendar banner, so a failed write is never swallowed (FR-12). - scripts/calendar-push.sh, Makefile target, env example, docs and tests. The target is configurable (SCHOOL_HA_CALENDAR_ENTITY). Home Assistant has no non-Google writable calendar today, so the entity is asked on AUD-110. Co-Authored-By: Paperclip <noreply@paperclip.ing>
20 lines
901 B
HTML
20 lines
901 B
HTML
{{define "calendar-status.html"}}
|
|
{{/* Fail-loudly calendar banner (FR-8, FR-12). A missing target or a failed
|
|
write is never hidden: the family must not assume an event was written. */}}
|
|
<section class="scan scan--{{.Level}}" aria-labelledby="calendar-title">
|
|
<div class="scan__head">
|
|
<h2 id="calendar-title" class="heading-2">Calendar</h2>
|
|
<span class="category-pill scan__pill">
|
|
{{if eq .Level "ok"}}healthy
|
|
{{else if eq .Level "error"}}failed
|
|
{{else if eq .Level "warn"}}attention
|
|
{{else}}off{{end}}
|
|
</span>
|
|
</div>
|
|
<p class="scan__message">{{.Message}}</p>
|
|
{{if .Entity}}<p class="scan__meta">{{.Entity}}{{if .LastAt}} · last write {{.LastAt}}{{end}}
|
|
{{if gt .Written 0}}· {{.Written}} event(s) written{{end}}</p>{{end}}
|
|
{{if gt .Failed 0}}<p class="scan__meta">{{.Failed}} failed calendar write(s) on record.</p>{{end}}
|
|
</section>
|
|
{{end}}
|