The Rules section is one record table grouped by kind, Limit then Boolean, on fixed columns, edited in place: Edit opens a row's controls in their columns, Add rule opens a dense row above the table, and every change is staged into a tray that lists the deltas with Undo and applies them as one rule-change act. The reduction policy is a column of the rule beside its limit. History shows counts only. Group rows are a quiet heading rather than a divider, the maintainer's pick from four rounds of outside-model ideation. Dense rows align to the top and render each error under its control in every form family (design D16), replacing the below-row error block; the forms library gains the batch form (rows plus one tray) and the RowField dense and label-hidden options. Migration 00019 records the governing reduction policy on effect rows. Archive staged-rule-changes with its spec updates (entitlement-set- management, entitlement-set-history, entitlements, form-library, form-conventions, ui-quality-gate). Screens accepted 2026-09-19.
50 lines
4.7 KiB
HTML
50 lines
4.7 KiB
HTML
{{- /* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial */ -}}
|
|
{{- /* SPDX-FileCopyrightText: 2025-2026 Christian Galo */ -}}
|
|
|
|
{{/* Page anatomy: in-page section headers (docs/design-system.md §6; spec
|
|
page-anatomy "Section headers are uniform"). Pipeline:
|
|
server.SectionHeader. sectionHeader titles a section outside the box
|
|
its content sits in (h2.h5, optional muted count or one action).
|
|
sectionSummary is the same header as the <summary> of a native
|
|
<details>, for a secondary section that opens on demand; the count
|
|
rides in parentheses so the closed disclosure still says how much it
|
|
holds. */}}
|
|
{{ define "sectionHeader" }}<div class="d-flex align-items-center justify-content-between gap-3 mt-4 mb-2 app-section-header">
|
|
<h2 class="h5 mb-0">{{ .Title }}{{ if .Help }} {{ template "helpIcon" (helpIcon .Title .Help) }}{{ end }}</h2>
|
|
{{/* The action's weight follows its role (form-conventions "Button
|
|
weight follows the button's role"; design D19). An opener that
|
|
toggles a collapsed sub-record panel (Action.Toggle names the
|
|
panel's id) is tertiary: outline-secondary, with the plus glyph
|
|
that rotates into a cross while the panel is open. It carries no
|
|
pressed or filled state; the glyph is the whole open/closed signal
|
|
(maintainer, 2026-09-03: the pressed look "looks pressable as
|
|
opposed to untoggleable"). A link marked Filled is the section's
|
|
one filled call to action, which on a list page is its "New ..."
|
|
link to the record's create page (design D20); every other link
|
|
navigates and is outline-secondary. */}}
|
|
{{ if .Action }}{{ if .Action.Toggle }}<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="collapse" data-bs-target="#{{ .Action.Toggle }}" aria-controls="{{ .Action.Toggle }}" aria-expanded="{{ if .Action.Expanded }}true{{ else }}false{{ end }}">{{ template "openerIcon" }}{{ .Action.Label }}</button>{{ else if .Action.Post }}<button type="button" class="btn btn-sm btn-outline-secondary" hx-post="{{ .Action.Post }}" hx-vals='{{ .Action.Vals }}' hx-include="{{ .Action.Include }}" hx-target="{{ .Action.Target }}" hx-swap="outerHTML" hx-sync="this:replace">{{ template "openerIcon" }}{{ .Action.Label }}</button>{{ else }}<a href="{{ .Action.URL }}" class="btn btn-sm {{ if .Action.Filled }}btn-primary{{ else }}btn-outline-secondary{{ end }}">{{ .Action.Label }}</a>{{ end }}{{ else if .Count }}<span class="text-body-secondary small">{{ .Count }}</span>{{ else if .Key }}<span class="text-body-secondary small">Key <code class="text-muted small">{{ .Key }}</code></span>{{ end }}
|
|
</div>{{ end }}
|
|
{{/* openerIcon is the leading glyph of every panel opener, on this part's
|
|
Toggle actions and on the openers written out by hand (the
|
|
organization composite's Issue grant and Extend). A plus that rotates
|
|
45 degrees into a cross while its button reports aria-expanded="true"
|
|
(app.css keys the rotation on that attribute), so the control states
|
|
whether the panel it owns is open without changing weight. Adapted
|
|
from Material Design's speed-dial FAB, whose plus rotates into a
|
|
close glyph when the dial opens, and Carbon's accordion, which flips
|
|
its chevron while a section is expanded. An inline SVG for the same
|
|
reason as the external-destination marker (chrome-conventions): a
|
|
character like U+002B would take the surrounding font's own weight
|
|
and a U+00D7 cross reads as a different mark. */}}
|
|
{{ define "openerIcon" }}<svg class="app-opener-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" aria-hidden="true" focusable="false"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>{{ end }}
|
|
{{/* chevronIcon marks a linked card (page-anatomy "A linked card is marked
|
|
by a glyph and the row's hover"; overview-consistency D3, round 2): the
|
|
at-a-glance tiles are a.card links, and this glyph at the card's
|
|
trailing edge says "go into" the way a list row's disclosure chevron
|
|
does, unlike the external-destination arrow (.external-link-icon),
|
|
which says "leaves the console". An inline SVG for the same reason as
|
|
openerIcon: a character glyph would take the surrounding font's own
|
|
weight. */}}
|
|
{{ define "chevronIcon" }}<svg class="app-chevron-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><polyline points="9 6 15 12 9 18"/></svg>{{ end }}
|
|
{{ define "sectionSummary" }}<summary class="app-section-header mb-2"><h2 class="h5 d-inline mb-0">{{ .Title }}{{ if .Count }} ({{ .Count }}){{ end }}</h2></summary>{{ end }}
|