Implement the ux-first-run change: a state-derived setup checklist on /operator/setup with a landing region that recedes once required steps are done, and empty states that distinguish blocked from empty across operator and member surfaces. Also add production deployment and environment reference docs, plus a config-key completeness test.
80 lines
3.4 KiB
HTML
80 lines
3.4 KiB
HTML
<!-- Grants management partial for operator — READ-ONLY.
|
|
Per operator-mpa-conversion D8, Issue/Extend/Revoke and CreateGrant
|
|
are exposed only on /operator/organizations/{orgID}. This view is
|
|
browse/audit only.
|
|
|
|
Delivery renders the derived state from the shared
|
|
ListGrantsWithDelivery query (ux-honest-surfaces design decision 1) —
|
|
the same vocabulary and badge treatment the org-detail composite's
|
|
Grants table uses, so the two surfaces can never disagree. Ledger
|
|
(grants.status) is issuance history and is deliberately NOT a colored
|
|
state badge — see the explanation below. -->
|
|
<h1 class="h2 mb-3">Grants</h1>
|
|
{{ if .Error }}
|
|
<div class="alert alert-danger" role="alert">
|
|
<strong>Error:</strong> {{ .Error }}
|
|
</div>
|
|
{{ else }}
|
|
|
|
|
|
{{ if eq (len .Grants) 0 }}
|
|
<div class="text-center py-4">
|
|
<p class="text-muted mb-2">No grants found.</p>
|
|
{{ if eq (len .Products) 0 }}
|
|
<p class="text-muted small mb-0">A grant delivers a published product to an organization, but no product has been published yet. <a href="/operator/products">Go to Products</a> to publish one.</p>
|
|
{{ else }}
|
|
<p class="text-muted small mb-0">Grants are issued from each organization's detail page, not from here.</p>
|
|
{{ end }}
|
|
</div>
|
|
{{ else }}
|
|
<p class="text-muted small mb-2">
|
|
Grants are the issuance ledger, not the delivery record: Ledger is when
|
|
and why a grant was recorded (and whether it was later revoked or
|
|
expired). Delivery is derived by joining each grant to its pool
|
|
provision — at most one grant per ladder position is
|
|
<span class="badge text-bg-success">Live</span> at a time; the rest are
|
|
history.
|
|
</p>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Organization</th>
|
|
<th>Grant Target</th>
|
|
<th>Qty</th>
|
|
<th>Reason</th>
|
|
<th>Ledger</th>
|
|
<th>Delivery</th>
|
|
<th>Created</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{ range .Grants }}
|
|
<tr{{ if ne .DeliveryState "live" }} class="text-muted"{{ end }}>
|
|
<td>{{ .OrgName }}</td>
|
|
<td>{{ if .ProductName }}{{ .ProductName }} <span class="badge bg-secondary">product</span>{{ else }}{{ .EntitlementSetName }} <span class="badge text-bg-info">set</span>{{ end }}</td>
|
|
<td>{{ .Quantity }}</td>
|
|
<td>{{ .GrantReason }}</td>
|
|
<td><small>{{ .Status }}</small></td>
|
|
<td>
|
|
{{ if eq .DeliveryState "live" }}
|
|
<span class="badge text-bg-success">Live</span>
|
|
{{ if .ExtendsLabel }}<br><small class="text-muted">extends {{ .ExtendsLabel }}</small>{{ end }}
|
|
{{ else if eq .DeliveryState "superseded" }}
|
|
<span class="badge text-bg-secondary">Superseded</span>
|
|
{{ if .ReplacedByLabel }}<br><small class="text-muted">replaced by {{ .ReplacedByLabel }}</small>{{ end }}
|
|
{{ else }}
|
|
<span class="badge text-bg-light border">Inactive</span>
|
|
{{ end }}
|
|
</td>
|
|
<td>{{ .CreatedAt }}</td>
|
|
</tr>
|
|
{{ end }}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p class="text-muted small mt-2">Total: {{ len .Grants }} grants</p>
|
|
{{ end }}
|
|
|
|
{{ end }}
|