Files
internet_use_control/internal/web/templates/schedule-editor.html
Paperclip 9af543c394 Phase 6: schedules, blocklists, allowlists (editors + effective state)
- Weekly schedule editor per device: a Monday-Sunday grid of blocking
  windows, including windows that cross midnight.
- Blocklist/allowlist editor per device: app (Android package / Windows
  process) and site (hostname) entries, tagged by the device platform.
- Effective desired state: a manual lock, an active schedule window, or
  neither. While blocked the allowlist is honoured (Spotify stays while
  other apps are blocked). Published retained with reason schedule/manual.
- Boundary-aware republish loop so a window turns on and off on time,
  and manual lock expiry is cleared promptly.
- CONTROL_TIMEZONE (default Australia/Sydney) with embedded tzdata, so
  wall-clock windows are evaluated in the family zone, not the container.
- Every change is written to the append-only audit log (FR-15).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 16:12:02 +11:00

92 lines
3.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "schedule-editor.html"}}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>{{.Title}} — Internet Use Control</title>
<link rel="stylesheet" href="/static/tokens.css">
<link rel="stylesheet" href="/static/app.css">
</head>
<body class="app">
<nav class="nav-bar">
<a class="nav-bar__brand" href="/">
<span class="nav-bar__mark" aria-hidden="true"></span>
Internet Use Control
</a>
<div class="nav-bar__right">
<span class="nav-bar__user">{{.Username}}</span>
</div>
</nav>
<main class="container">
<header class="page-head">
<p class="page-head__eyebrow"><a href="/">← Dashboard</a></p>
<h1 class="heading-1">{{.Heading}}</h1>
<p class="page-head__sub">{{.Sub}}</p>
</header>
{{if .Flash}}<p class="flash flash--ok" role="status">{{.Flash}}</p>{{end}}
{{if .Error}}<p class="flash flash--error" role="alert">{{.Error}}</p>{{end}}
<section class="schedule-note">
{{if .ActiveNow}}
<p class="schedule-note__now"><span class="dot dot--off"></span> A window is active now{{if .ActiveUntil}} until {{.ActiveUntil}}{{end}}.</p>
{{else}}
<p class="schedule-note__now"><span class="dot dot--faint"></span> No window is active now.</p>
{{end}}
{{if .NextBoundary}}<p class="schedule-note__next">Next change: {{.NextBoundary}}.</p>{{end}}
<p class="schedule-note__hint">Each row is a day. A window means restrictions are ON during that time.
Leave both boxes empty to remove a window. An end time earlier than the start crosses midnight.</p>
</section>
<section class="card-panel">
<form method="post" action="/devices/{{.DeviceID}}/schedule" class="stack-form">
<input type="hidden" name="csrf" value="{{.CSRF}}">
<div class="schedule-scroll">
<table class="schedule-grid">
<caption class="visually-hidden">Weekly blocking windows for {{.DeviceName}}</caption>
<thead>
<tr>
<th scope="col">Day</th>
{{range index .Rows 0}}{{range .Slots}}<th scope="col">Window</th>{{end}}{{end}}
</tr>
</thead>
<tbody>
{{range $row := .Rows}}
<tr>
<th scope="row">{{$row.Name}}</th>
{{range $i, $slot := $row.Slots}}
<td class="schedule-grid__slot">
<input class="text-input time-input" type="time" name="start_{{$row.Weekday}}_{{$i}}"
value="{{$slot.Start}}" aria-label="{{$row.Name}} window {{$i}} start">
<span class="schedule-grid__dash" aria-hidden="true">–</span>
<input class="text-input time-input" type="time" name="end_{{$row.Weekday}}_{{$i}}"
value="{{$slot.End}}" aria-label="{{$row.Name}} window {{$i}} end">
</td>
{{end}}
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="form-actions">
<button class="button-primary" type="submit">Save schedule</button>
<button class="button-utility" type="submit" name="clear" value="1" formnovalidate>Clear all</button>
<a class="button-utility" href="/devices/{{.DeviceID}}/lists">Blocklist / allowlist</a>
<a class="button-utility" href="/">Done</a>
</div>
</form>
</section>
</main>
<footer class="app-foot">
<span>Control Service · {{.Version}} · {{.AppEnv}}</span>
<span class="app-foot__sep">·</span>
<span>{{year}} Family Home Lab</span>
</footer>
</body>
</html>{{end}}