{{- /* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial */ -}} {{- /* SPDX-FileCopyrightText: 2025-2026 Christian Galo */ -}} {{/* Organization detail partial for operator. Titled by the organization's own display name; the retired working title named this page for the grant-delivery mechanism instead of the organization it describes (plan-enrollment-administration D5). Built from the page-anatomy parts (docs/design-system.md §6): the header carries the Organizations trail above the name; owner and key live in the details card below it; every section is titled by sectionHeader outside its box; states render through statusBadge; empty sections through emptyState. This is a Go-template comment (stripped at render), not an HTML comment, so its own wording never leaks into the rendered page. */}} {{ if .Error }} {{ else }} {{ template "pageHeader" .Header }} {{ if .ActionError }} {{ end }}
Owner
{{ if .OrgOwnerPersonID }} {{ if .OrgOwnerName }}{{ .OrgOwnerName }}{{ else }}{{ .OrgOwnerPersonID }}{{ end }} {{ else }} {{ end }}
{{/* Read-only key, muted code style, shown only when the organization has one. Personal organizations never do; the System tenant and rows a seed or a configuration file named are the ordinary cases. */}} {{ if .OrgKey }}
Key
{{ .OrgKey }}
{{ end }}
{{ template "sectionHeader" .BillingHeader }}
{{ if not .BillingSummary.HasAccount }} {{ template "emptyState" .NoBillingAccount }} {{ else }} {{/* Three rows in triage order (design D5, round 5): what the organization owes, the standing recurring state, then the most recent invoice. Each row is a muted label over a value line; a badge leads only where there is a state to read. The account's own status is a fourth row that appears only when it is not active, since a permanent Active badge would say nothing. */}}
{{ if .BillingSummary.AccountAbnormal }}
Account
{{ template "statusBadge" .BillingSummary.AccountBadge }}
{{ end }}
Outstanding balance
{{ if gt .BillingSummary.OutstandingBalance 0 }}
{{ template "statusBadge" .BillingSummary.BalanceBadge }} {{ .BillingSummary.OutstandingBalanceFormatted }}
{{ else }}
{{ .BillingSummary.OutstandingBalanceFormatted }}
{{ end }}
Subscriptions
{{ if gt .BillingSummary.SubscriptionCount 0 }}
{{ template "statusBadge" .BillingSummary.SubscriptionsBadge }} {{ .BillingSummary.SubscriptionCountLabel }} {{ if .BillingSummary.SubscriptionNote }} · {{ .BillingSummary.SubscriptionNote }} {{ end }}
{{ else }}
No subscriptions
{{ end }}
Latest invoice
{{ if .BillingSummary.HasInvoice }}
{{ template "statusBadge" .BillingSummary.InvoiceBadge }} {{ if .BillingSummary.LatestInvoiceNumber }} {{ .BillingSummary.LatestInvoiceNumber }} {{ else }} {{ end }} · {{ .BillingSummary.LatestInvoiceDate }}
{{ else }}
No invoices issued
{{ end }}
{{ end }}
{{ template "sectionHeader" .PoolsHeader }} {{ if .PoolMissing }} {{ else if eq (len .Pools) 0 }} {{ template "emptyState" .NoPools }} {{ else }} {{ range .Pools }}

{{ .PoolName }} {{ template "statusBadge" .TypeBadge }} {{ template "statusBadge" .StateBadge }}

{{ if ne .Status "active" }}

This pool is not active; it is not delivering entitlements.

{{ end }} {{ if not .HasAttachment }}

No plan is delivering into this pool

{{ end }}
{{/* One block per DELIVERY (provision), grouped: the product renders once with the single Extend control, and its ladder placements render as rung facts beneath (maintainer design round 2026-08-24; a shared product used to render one line per ladder with a "Same delivery" marker; the grouping conveys that structurally instead). The Extend form is pre-scoped via provision_id; a delivery that is not grant-backed gets a disabled control with the reason. */}} {{ range .Deliveries }}

{{ .ProductName }}

{{ range $i, $rung := .Rungs }}{{ if $i }} · {{ end }}{{ $rung.LadderName }}, rank {{ $rung.Rank }}{{ end }}

{{ if .GrantBacked }} {{/* A panel opener is tertiary, with the plus glyph that rotates into a cross while the panel is open (design D19, round 4); the same openerIcon part the section headers use. */}} {{ else }} {{ template "disabledControl" .ExtendControl }} {{ end }}
{{ end }} {{ if gt (len .Usage) 0 }}
{{ range .Usage }} {{ end }}
Resource Used Limit
{{ .ResourceKey }} {{ .Used }} {{ .Limit }}
{{ end }} {{ range .Deliveries }} {{ if .GrantBacked }}
{{ if gt (len .Rungs) 1 }}

One extension refreshes all {{ len .Rungs }} ladders shown.

{{ end }} {{ template "form" .ExtendForm }}
{{ end }} {{ end }}
{{ end }} {{ end }} {{ if .GrantsError }} {{ end }} {{ if .PoolMissing }} {{ else if .ProductsError }} {{ end }} {{ template "sectionHeader" .PlanGrantsHeader }} {{/* The Issue grant control sits inside the card because its disclosure opens inside it (maintainer 2026-08-24: disclosure actions live in the box they disclose into; navigation actions like Full billing stay on the heading row). It shares the card header with the Active/History tabs. The #plan-grants-panel wrapper is the scoped swap target for the ledger's tab/search/pager controls (GrantsNav .Target), so using them re-renders only this panel and never scrolls the page. */}}
{{ template "listTabs" .GrantsNav }}
{{ if or .PoolMissing .ProductsError (eq (len .IssuanceProducts) 0) }} {{ template "disabledControl" .IssueGrantControl }} {{ else }} {{/* A panel opener is tertiary, with the plus glyph that rotates into a cross while the panel is open (design D19, round 4); the same openerIcon part the section headers use. */}} {{ end }}
{{ if and (not .PoolMissing) (not .ProductsError) (gt (len .IssuanceProducts) 0) }} {{/* Collapsed by default; forced open when this form's submission just failed so field errors are never hidden. */}}

Issue a grant to update this organization's entitlements. A tier product moves the pool to that tier, up or down.

{{ $superseders := false }} {{ range .IssuanceProducts }}{{ if .SupersedesSubscription }}{{ $superseders = true }}{{ end }}{{ end }} {{ if $superseders }} {{ end }} {{ template "form" .IssueGrantForm }}
{{ end }} {{/* Two tabs over one ledger (maintainer design round 2026-08-24): Active (default) shows only grants delivering right now; History is every grant ever issued with the supersession audit trail. Search matches product or reason on both tabs; tab, q, page and per live on the org URL so views deep-link. */}} {{ if eq .GrantsNav.Facet "history" }}

One row per grant ever issued. The Delivery column shows which grants are delivering right now; superseded and inactive rows are history.

{{ end }}
{{ template "listSearch" .GrantsNav }}
{{ if gt (len .Grants) 0 }}
{{ range .Grants }} {{ end }}
Product Reason Issuance {{ template "helpIcon" (helpIcon "Issuance" "What the record says happened to the grant: active, revoked, or expired.") }} Delivery {{ template "helpIcon" (helpIcon "Delivery" "Whether the grant is delivering into the pool now.") }} Granted by Qty Activated Ended Actions
{{ if .ProductName }}{{ .ProductName }}{{ else }}—{{ end }} {{ .GrantReason }}{{ if .Note }}
{{ .Note }}
{{ end }}
{{ .Issuance }} {{ template "statusBadge" .DeliveryBadge }} {{/* The superseded row names its replacement; the live row names nothing, since "extends X" only repeated the Product column (maintainer, 2026-09-05). */}} {{ if eq .DeliveryState "superseded" }} {{ if .ReplacedByLabel }}
replaced by {{ .ReplacedByLabel }}{{ end }} {{ end }}
{{ if .GrantedByName }}{{ .GrantedByName }}{{ else }}System{{ end }} {{ .Quantity }} {{ if .ActivatedAt }}{{ .ActivatedAt }}{{ else }}—{{ end }} {{ if .EndedAt }}{{ .EndedAt }}{{ else }}—{{ end }} {{ if eq .DeliveryState "live" }} {{ if ne .GrantReason "default" }} {{ end }} {{ end }}
{{ template "listPager" .GrantsNav }} {{ else if .GrantsNav.Q }} {{ template "listNoMatch" .GrantsNav }} {{ else }} {{ template "emptyState" .NoGrants }} {{ end }}
{{ template "sectionHeader" .MembersHeader }}
{{ if .MembersError }} {{ end }} {{ if eq (len .Members) 0 }} {{ template "emptyState" .NoMembers }} {{ else }}
{{ range .Members }} {{ end }}
Name Email Role Joined
{{ .DisplayName }} {{ .Email }} {{ .RoleName }} {{ .JoinedAt }}
{{ if .MembersCapped }}

Showing the latest 16 of {{ .MembersTotal }}.

{{ end }} {{ end }}
{{/* The composite's trail of entitlement set rule commits that moved this organization's pools (plan-enrollment-administration "Entitlement changes is the composite's trail of rule commits"): newest first, its own ec_ pager, every cell the label recorded with the row so a later rename does not rewrite what the operator sees. */}} {{ template "sectionHeader" .EntitlementChangesHeader }} {{/* #entitlement-changes-panel: scoped swap target for this list's pager, so paging never scrolls the page (EntitlementChangesNav.Target). */}}
{{ if .EntitlementChangesError }} {{ end }} {{ if eq (len .EntitlementChanges) 0 }} {{ template "emptyState" .NoEntitlementChanges }} {{ else }}
{{ range .EntitlementChanges }} {{ end }}
Resource Limit Set Note By When
{{ if .ResourceLabel }}{{ .ResourceLabel }} ({{ .ResourceKey }}){{ else }}{{ .ResourceKey }}{{ end }} {{ .LimitLine }} {{ .SetName }} {{ .Note }} {{ if .ActorName }}{{ .ActorName }}{{ else }}{{ .ActorType }}{{ end }} {{ .When }}
{{ template "listPager" .EntitlementChangesNav }} {{ end }}
{{/* Formerly "Position history"; maintainer design round 2026-08-24: rows carry humanized verbs and tier NAMES instead of integer ranks (Go-template comment so it never ships). The Reason cell renders in words: a grant-backed row shows the grant's reason label with its note beneath, any other row shows the machine reason's sentence; the raw reason string rides as the cell's title in every case (tier-changes-ledger design D3, D4). */}} {{ template "sectionHeader" .TierChangesHeader }} {{/* #tier-changes-panel: scoped swap target for this list's pager, so paging never scrolls the page (TierChangesNav.Target). */}}
{{ if .TransitionsError }} {{ end }} {{ if eq (len .Transitions) 0 }} {{ template "emptyState" .NoTierChanges }} {{ else }}
{{ range .Transitions }} {{ .ReasonLabel }}{{ if .ReasonNote }}
{{ .ReasonNote }}
{{ end }}
{{ end }}
Ladder Change From To By Reason When
{{ .LadderName }} {{ template "statusBadge" .ChangeBadge }} {{ .FromLabel }} {{ .ToLabel }} {{ if .ActorName }}{{ .ActorName }}{{ else }}{{ .ActorType }}{{ end }} {{ .EffectiveAt }}
{{ template "listPager" .TierChangesNav }} {{ end }}
{{ end }}