diff --git a/docs/features/sidebar.mdx b/docs/features/sidebar.mdx index f42fc198..ab32a810 100644 --- a/docs/features/sidebar.mdx +++ b/docs/features/sidebar.mdx @@ -85,7 +85,7 @@ Right-click any stack (or open the kebab that appears on hover) for its context - **Destructive**: **Delete**. - **Auto-Heal** requires a **Skipper** or **Admiral** license. **Schedule task** requires a **Skipper** or **Admiral** license and an **admin** role. + **Auto-Heal** requires a **Skipper** or **Admiral** license; configuring policies (add, toggle, delete) also requires an **admin** role. **Schedule task** requires a **Skipper** or **Admiral** license and an **admin** role. @@ -146,4 +146,7 @@ The footer surfaces the most recent stack lifecycle event on the node. Each tick Scheduling requires a **Skipper** or **Admiral** license and an **admin** role. Ask an admin on this node to schedule the task for you, or sign in with an admin account. + + Reading existing Auto-Heal policies only needs a **Skipper** or **Admiral** license, so the panel still opens for non-admin operators on paid tiers. Adding, enabling, disabling, or deleting policies also requires the **admin** role. Sign in with an admin account, or ask an admin on this node to make the change. + diff --git a/frontend/src/components/StackAlertSheet.tsx b/frontend/src/components/StackAlertSheet.tsx index fb3581ca..b3f2a376 100644 --- a/frontend/src/components/StackAlertSheet.tsx +++ b/frontend/src/components/StackAlertSheet.tsx @@ -482,6 +482,7 @@ function AlertsTab({ stackName }: { stackName: string }) { } function AutoHealTab({ stackName, open }: { stackName: string; open: boolean }) { + const { isAdmin } = useAuth(); const [policies, setPolicies] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); @@ -617,12 +618,14 @@ function AutoHealTab({ stackName, open }: { stackName: string; open: boolean }) onToggle={handleToggle} deleting={deleting} saving={saving} + isAdmin={isAdmin} /> ))} )} + {isAdmin && (
@@ -700,6 +703,7 @@ function AutoHealTab({ stackName, open }: { stackName: string; open: boolean })
+ )} ); } @@ -710,9 +714,10 @@ interface PolicyRowProps { onToggle: (id: number, enabled: boolean) => void; deleting: boolean; saving: boolean; + isAdmin: boolean; } -function PolicyRow({ policy, onDelete, onToggle, deleting, saving }: PolicyRowProps) { +function PolicyRow({ policy, onDelete, onToggle, deleting, saving, isAdmin }: PolicyRowProps) { const [historyOpen, setHistoryOpen] = useState(false); const [history, setHistory] = useState([]); const [loadingHistory, setLoadingHistory] = useState(false); @@ -760,12 +765,14 @@ function PolicyRow({ policy, onDelete, onToggle, deleting, saving }: PolicyRowPr )}
- policy.id != null && onToggle(policy.id, checked)} - disabled={saving} - aria-label={`Toggle policy for ${policy.service_name ?? 'all services'}`} - /> + {isAdmin && ( + policy.id != null && onToggle(policy.id, checked)} + disabled={saving} + aria-label={`Toggle policy for ${policy.service_name ?? 'all services'}`} + /> + )} - + {isAdmin && ( + + )}