- Restructure operator sidebar into a flat task list with indented children; fold plan topology into plan ladders - Expand member catalog non-plan section to all published non-tier products; require recurring Stripe-mapped prices for purchase - Add operator domains placements and terminal-claims ledger; redirect /domains to the FedWiki Sites Domains anchor - Apply canonical vocabulary and chrome/form conventions; migrate seeded FedWiki Sites display name
106 lines
6.1 KiB
HTML
106 lines
6.1 KiB
HTML
<!-- Entitlement set rules detail partial for operator -->
|
|
<div class="card mb-3">
|
|
<div class="card-body">
|
|
<h1 class="card-title mb-3 h6">Rules: {{ .EntitlementSet.Name }}</h1>
|
|
|
|
{{ if .Error }}
|
|
<div class="alert alert-danger" role="alert">{{ .Error }}</div>
|
|
{{ end }}
|
|
|
|
<p class="text-muted small mb-3">Rule changes take effect at a pool's next conferral, not immediately. Adding or deleting a rule here does not re-materialize entitlements already delivered to a pool.</p>
|
|
|
|
<!-- Add Rule Form -->
|
|
<div class="card bg-light mb-3">
|
|
<div class="card-body">
|
|
<h2 class="card-subtitle mb-2 h6">Add Rule</h2>
|
|
<form autocomplete="off" hx-post="{{ routeURL "/partials/operator/entitlement-sets/{setID}/rules" .EntitlementSet.SetID }}" hx-target="#operator-body" hx-swap="innerHTML" hx-disabled-elt="find button[type=submit]">
|
|
<div class="row g-2 align-items-end">
|
|
<div class="col-md-3">
|
|
<label for="ruleResourceKey" class="form-label form-label-sm">Resource Key</label>
|
|
{{ $err := index .FieldErrors "resource_key" }}
|
|
<!-- Key-first flow: the rule type is derived from the selected
|
|
key's kind, so choosing a key re-renders the fields region
|
|
rather than the operator picking a rule type. -->
|
|
<!-- hx-disabled-elt="this": the form's inherited
|
|
"find button[type=submit]" scopes to the
|
|
triggering element (this select), which holds
|
|
no button — htmx logs a no-match error. -->
|
|
<select class="form-select form-select-sm {{ if $err }}is-invalid{{ end }}" aria-invalid="{{ if $err }}true{{ else }}false{{ end }}" id="ruleResourceKey" name="resource_key" required
|
|
hx-get="{{ routeURL "/partials/operator/entitlement-sets/{setID}/rules/fields" .EntitlementSet.SetID }}"
|
|
hx-trigger="change" hx-target="#ruleFields" hx-swap="innerHTML" hx-disabled-elt="this">
|
|
<option value="">Select key...</option>
|
|
{{ range .ResourceKeys }}
|
|
<option value="{{ .ResourceKey }}" {{ if eq .ResourceKey $.RuleFields.SelectedKey }}selected{{ end }}>{{ .DisplayName }} ({{ .ResourceKey }})</option>
|
|
{{ end }}
|
|
</select>
|
|
{{ with $err }}<div class="invalid-feedback">{{ . }}</div>{{ end }}
|
|
</div>
|
|
<div class="col-md-7" id="ruleFields">
|
|
{{ template "operator_entitlement_set_rule_fields.html" .RuleFields }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="submit" class="btn btn-outline-primary btn-sm w-100">Add Rule</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rules List -->
|
|
{{ if eq (len .Rules) 0 }}
|
|
<div class="text-center py-3">
|
|
<p class="text-muted mb-0">No rules defined for this set.</p>
|
|
</div>
|
|
{{ else }}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Resource Key</th>
|
|
<th>Value</th>
|
|
<th>Per Unit</th>
|
|
<th>Stacking</th>
|
|
<th>Active</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{ range .Rules }}
|
|
<tr>
|
|
<td>{{ if .DisplayName }}{{ .DisplayName }} <span class="text-muted small">({{ .ResourceKey }})</span>{{ else }}<code>{{ .ResourceKey }}</code>{{ end }}</td>
|
|
{{ if eq .RuleType "boolean" }}
|
|
<td colspan="3" class="text-muted">Included (on/off capability)</td>
|
|
{{ else }}
|
|
<td>{{ .ResourceValue }}</td>
|
|
<td>{{ if .ResourcePerUnit }}Yes{{ else }}No{{ end }}</td>
|
|
<td>{{ .StackingPolicy }}</td>
|
|
{{ end }}
|
|
<td>
|
|
{{ if .IsActive }}<span class="badge bg-success">Active</span>
|
|
{{ else }}<span class="badge text-bg-secondary">Inactive</span>{{ end }}
|
|
</td>
|
|
<td>
|
|
{{ if .IsLiveBacking }}
|
|
<div class="text-muted small mb-1">Backs entitlements pools currently hold; their materialized limits persist until the pool's next conferral, then future conferrals stop including this resource.</div>
|
|
{{ end }}
|
|
<button type="button" class="btn btn-outline-danger btn-sm"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#confirmActionModal"
|
|
data-action-url="{{ routeURL "/partials/operator/entitlement-sets/{setID}/rules/{ruleID}" $.EntitlementSet.SetID .RuleID }}"
|
|
data-action-method="delete"
|
|
data-action-target="#operator-body"
|
|
data-action-title="Delete rule"
|
|
data-action-body="Delete this rule? Pools that already have this limit keep their current values; the change applies to future provisions only."
|
|
data-action-confirm-label="Delete rule">
|
|
Delete
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{{ end }}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
</div>
|