Spread the Rules table's treatment to every table that carries verbs (record-table-actions, archived 2026-09-19): the table is align-middle, the Actions header and cells are text-end, every button in an Actions cell carries ms-1, and the header's word is for assistive technology only (a visually-hidden span; Primer: row actions do not require a visible column header). The two integrations tables and the member domains list, which headed their controls with an empty cell, take the hidden word too. A new anatomy-lint rule, actions-column, refuses a table that drifts from any of it. Decisions on the way: a row tint marks the row in play (the current workspace, a staged change), never a record's status; the member catalog lists only what can be bought, so a Listed product without an active, synced, recurring price is left out instead of shown with "Not available for purchase"; two Actions cells that carried text in a verb's place are empty (the Placements column and the pending panel already say why); and four record tables gain their width floor. Specs: page-anatomy "Tables share one density" modified, ui-quality-gate gains "Lint refuses an Actions column without its treatment", member-product-discovery's Extras bucket and truthful-copy requirements modified. docs/design-system.md §6 states the treatment and its reasons.
101 lines
5.4 KiB
HTML
101 lines
5.4 KiB
HTML
{{- /* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial */ -}}
|
|
{{- /* SPDX-FileCopyrightText: 2025-2026 Christian Galo */ -}}
|
|
|
|
<!-- Integrations landing — registry-driven list of every registered
|
|
integration (all provider kinds, so payments integrations appear
|
|
alongside provisioning ones). Adding a conforming integration
|
|
populates this with no edit here. Browse-only except the
|
|
unrecognized-override cleanup, which is confirm-modal-gated. Built
|
|
from the page-anatomy parts (docs/design-system.md §6): the header,
|
|
badges, section header, and empty state come from ui_*.html; the
|
|
values from IntegrationsData's methods. -->
|
|
{{ template "pageHeader" .Header }}
|
|
|
|
{{ if .Error }}
|
|
<div class="alert alert-danger" role="alert"><strong>Error:</strong> {{ .Error }}</div>
|
|
{{ else if eq (len .Integrations) 0 }}
|
|
{{ template "emptyState" .Empty }}
|
|
{{ else }}
|
|
<div class="table-responsive">
|
|
{{/* list-scale exempt: curated configuration list, one row per registered integration, bounded by compiled-in providers not deployment data */}}
|
|
<table class="table table-hover table-sm align-middle table-record">
|
|
<thead>
|
|
<tr>
|
|
<th>Integration</th>
|
|
<th>Status</th>
|
|
<th>Kind {{ template "helpIcon" (helpIcon "Kind" "What the integration does for members: a provisioning integration creates and manages member resources; a payment integration handles billing.") }}</th>
|
|
<th>Operations</th>
|
|
<th>Resource keys</th>
|
|
<th class="text-end"><span class="visually-hidden">Actions</span></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{ range .Integrations }}
|
|
<tr>
|
|
{{/* Row navigation is the primary column's link (chrome-conventions,
|
|
ACC-6/ACC-2 sheet pass): the display name links to the
|
|
provider's own page, its admin surface when it declares
|
|
one, otherwise its settings page. A provider with
|
|
neither stays plain text. */}}
|
|
<th scope="row">
|
|
{{ if .LinkPath }}<a href="{{ .LinkPath }}">{{ .DisplayName }}</a>{{ else }}{{ .DisplayName }}{{ end }}
|
|
<span class="text-muted small ms-1 text-nowrap">{{ .Key }}</span>
|
|
</th>
|
|
<td>{{ template "statusBadge" .StatusBadge }}</td>
|
|
<td><span class="text-capitalize">{{ .Kind }}</span></td>
|
|
<td class="text-nowrap">
|
|
<!-- Operation names are identifiers, not states: muted code, like
|
|
the resource keys beside them. -->
|
|
{{ range .Operations }}<code class="small me-1">{{ . }}</code>{{ end }}
|
|
{{ if eq (len .Operations) 0 }}<span class="text-muted small">—</span>{{ end }}
|
|
</td>
|
|
<td>
|
|
{{ range .ResourceKeys }}<span class="d-block text-nowrap">{{ if .DisplayName }}{{ .DisplayName }} <span class="text-muted small">({{ .ResourceKey }})</span>{{ else }}<code class="small">{{ .ResourceKey }}</code>{{ end }}</span>{{ end }}
|
|
{{ if eq (len .ResourceKeys) 0 }}<span class="text-muted small">—</span>{{ end }}
|
|
</td>
|
|
<td class="text-end text-nowrap">
|
|
{{ if .SettingsPath }}
|
|
<a href="{{ .SettingsPath }}" class="btn btn-sm btn-outline-secondary">Settings</a>
|
|
{{ else }}
|
|
<span class="text-muted small">—</span>
|
|
{{ end }}
|
|
</td>
|
|
</tr>
|
|
{{ end }}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{ end }}
|
|
|
|
{{ if .Orphans }}
|
|
{{ template "sectionHeader" .OrphansHeader }}
|
|
<p class="text-muted small">Stored configuration overrides whose key matches no installed integration, left behind by a removed integration or a retired key. They have no effect; remove them when convenient.</p>
|
|
<div class="table-responsive">
|
|
{{/* list-scale exempt: curated configuration list, orphaned integration config overrides left by a removed integration */}}
|
|
<table class="table table-hover table-sm table-record-sm align-middle">
|
|
<thead><tr><th>Key</th><th>Value</th><th class="text-end"><span class="visually-hidden">Actions</span></th></tr></thead>
|
|
<tbody>
|
|
{{ range .Orphans }}
|
|
<tr>
|
|
<td><code>{{ .Key }}</code></td>
|
|
<td><code>{{ .Value }}</code></td>
|
|
<td class="text-end">
|
|
<button type="button" class="btn btn-sm btn-outline-danger ms-1"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#confirmActionModal"
|
|
data-action-url="{{ routeURL "/operator/integrations/config-orphans/{key}" .Key }}"
|
|
data-action-method="delete"
|
|
data-action-target="#operator-body"
|
|
data-action-title="Delete stored override"
|
|
data-action-body="Delete the stored override for {{ .Key }}? It has no effect; this only removes the leftover row."
|
|
data-action-confirm-label="Delete override">
|
|
Delete
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{{ end }}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{ end }}
|