Section icons in the change journal, and admin scope on secret reveal

This commit is contained in:
MacRimi
2026-09-12 10:54:36 +02:00
parent 78d2d84f20
commit b5fb747271
12 changed files with 37 additions and 19 deletions
+16 -4
View File
@@ -5,7 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "./ui/card"
import { Badge } from "./ui/badge"
import {
ChevronDown, ChevronRight, FileCode, HelpCircle, Loader2, Package,
Play, Settings2,
Play, Settings2, Sparkles, Terminal, Wrench,
} from "lucide-react"
import { fetchApi } from "../lib/api-config"
import { useT, useI18n } from "../lib/i18n/provider"
@@ -299,8 +299,10 @@ function ChangeCard({ change, expanded, onToggle, t, when }: {
)
}
function GroupSection({ title, groups, openFn, toggleFn, open, toggle, t, when }: {
function GroupSection({ title, icon: Icon, iconClass, groups, openFn, toggleFn, open, toggle, t, when }: {
title: string
icon: typeof Settings2
iconClass: string
groups: { key: string; label: string; version: string; last: number; items: Change[] }[]
openFn: Set<string>; toggleFn: (k: string) => void
open: Set<number>; toggle: (id: number) => void
@@ -309,8 +311,15 @@ function GroupSection({ title, groups, openFn, toggleFn, open, toggle, t, when }
}) {
if (groups.length === 0) return null
return (
<div className="space-y-2">
<h3 className="text-sm font-semibold text-foreground px-1">{title}</h3>
// Padding on the child: the container's space-y-4 overrides any mt-*.
<div className="space-y-2 pt-2">
{/* Same type and icon size as CardTitle, so a block heading here reads
exactly like a card heading on the Settings page. */}
<h3 className="px-1 flex items-center gap-2 text-2xl font-semibold
leading-none tracking-tight text-foreground">
<Icon className={`h-5 w-5 shrink-0 ${iconClass}`} />
{title}
</h3>
{groups.map((g) => {
const fnOpen = openFn.has(g.key)
return (
@@ -460,12 +469,15 @@ export function AuditChanges() {
</Card>
<GroupSection title={t("audit.changes.section.postInstall")}
icon={Sparkles} iconClass="text-orange-500"
groups={blocks.post} openFn={openFn} toggleFn={toggleFn}
open={open} toggle={toggle} t={t} when={when} />
<GroupSection title={t("audit.changes.section.scripts")}
icon={Terminal} iconClass="text-cyan-500"
groups={blocks.scripts} openFn={openFn} toggleFn={toggleFn}
open={open} toggle={toggle} t={t} when={when} />
<GroupSection title={t("audit.changes.section.installs")}
icon={Wrench} iconClass="text-purple-400"
groups={blocks.installs} openFn={openFn} toggleFn={toggleFn}
open={open} toggle={toggle} t={t} when={when} />
{summary && summary.total > 0
+2 -2
View File
@@ -2,7 +2,7 @@
import { useState, useEffect } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card"
import { Wrench, Package, Ruler, HeartPulse, Cpu, MemoryStick, HardDrive, CircleDot, Network, Server, Settings2, FileText, RefreshCw, Shield, AlertTriangle, Info, Loader2, Check, Database, CloudOff, Code, X, Copy, Sparkles, ArrowUpCircle, BellOff, Globe2, Github } from "lucide-react"
import { Package, Ruler, HeartPulse, Cpu, MemoryStick, HardDrive, CircleDot, Network, Server, Settings2, FileText, RefreshCw, Shield, AlertTriangle, Info, Loader2, Check, Database, CloudOff, Code, X, Copy, Sparkles, ArrowUpCircle, BellOff, Globe2, Github } from "lucide-react"
import { Badge } from "./ui/badge"
import { Button } from "./ui/button"
import { NotificationSettings } from "./notification-settings"
@@ -2034,7 +2034,7 @@ export function Settings() {
<Card>
<CardHeader>
<div className="flex items-center gap-2">
<Wrench className="h-5 w-5 text-orange-500" />
<Sparkles className="h-5 w-5 text-orange-500" />
<CardTitle>{t("settings.optimizations.title")}</CardTitle>
</div>
<CardDescription>{t("settings.optimizations.description")}</CardDescription>
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Konfigurieren",
"tokenLabel": "Persönliches Zugriffstoken",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "Das Token wird verschlüsselt gespeichert. ProxMenux verwendet es ausschließlich für schreibgeschützte GitHub-API-Anfragen und zeigt es danach nicht erneut an.",
"tokenHelp": "Das Token wird verschlüsselt gespeichert. ProxMenux verwendet es ausschließlich für schreibgeschützte GitHub-API-Anfragen und zeigt es danach nicht erneut an. Ein Fine-grained-Token mit Lesezugriff auf öffentliche Repositories und ohne Kontoberechtigungen genügt.",
"configured": "Token konfiguriert",
"notConfigured": "Anonymes GitHub-Anfragekontingent wird verwendet",
"removeToken": "Token entfernen",
+1 -1
View File
@@ -1753,7 +1753,7 @@
"configure": "Configure",
"tokenLabel": "Personal access token",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "The token is stored encrypted. ProxMenux uses it only for read-only GitHub API requests and never displays it again.",
"tokenHelp": "The token is stored encrypted. ProxMenux uses it only for read-only GitHub API requests and never displays it again. A fine-grained token with read-only access to public repositories and no account permissions is enough.",
"configured": "Token configured",
"notConfigured": "Using GitHub's anonymous request quota",
"removeToken": "Remove token",
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Configurar",
"tokenLabel": "Token de acceso personal",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "El token se guarda cifrado. ProxMenux solo lo utiliza para consultas de solo lectura a la API de GitHub y no vuelve a mostrarlo.",
"tokenHelp": "El token se guarda cifrado. ProxMenux solo lo utiliza para consultas de solo lectura a la API de GitHub y no vuelve a mostrarlo. Basta con un token fine-grained con acceso de solo lectura a repositorios públicos y sin permisos de cuenta.",
"configured": "Token configurado",
"notConfigured": "Usando la cuota de solicitudes anónimas de GitHub",
"removeToken": "Eliminar token",
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Configurer",
"tokenLabel": "Jeton d'accès personnel",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "Le jeton est stocké sous forme chiffrée. ProxMenux l'utilise uniquement pour des requêtes en lecture seule vers l'API GitHub et ne l'affiche plus ensuite.",
"tokenHelp": "Le jeton est stocké sous forme chiffrée. ProxMenux l'utilise uniquement pour des requêtes en lecture seule vers l'API GitHub et ne l'affiche plus ensuite. Un jeton fine-grained avec un accès en lecture seule aux dépôts publics et sans autorisation de compte suffit.",
"configured": "Jeton configuré",
"notConfigured": "Utilisation du quota de requêtes anonymes de GitHub",
"removeToken": "Supprimer le jeton",
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Configura",
"tokenLabel": "Token di accesso personale",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "Il token viene archiviato in forma cifrata. ProxMenux lo utilizza solo per richieste di sola lettura all'API GitHub e non lo mostra più dopo il salvataggio.",
"tokenHelp": "Il token viene archiviato in forma cifrata. ProxMenux lo utilizza solo per richieste di sola lettura all'API GitHub e non lo mostra più dopo il salvataggio. È sufficiente un token fine-grained con accesso in sola lettura ai repository pubblici e senza permessi sull'account.",
"configured": "Token configurato",
"notConfigured": "Utilizzo della quota di richieste anonime di GitHub",
"removeToken": "Rimuovi token",
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Configurar",
"tokenLabel": "Token de acesso pessoal",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "O token é armazenado de forma cifrada. O ProxMenux utiliza-o apenas para pedidos de leitura à API do GitHub e não volta a apresentá-lo.",
"tokenHelp": "O token é armazenado de forma cifrada. O ProxMenux utiliza-o apenas para pedidos de leitura à API do GitHub e não volta a apresentá-lo. Basta um token fine-grained com acesso de leitura a repositórios públicos e sem permissões de conta.",
"configured": "Token configurado",
"notConfigured": "A utilizar a quota de pedidos anónimos do GitHub",
"removeToken": "Remover token",
+1 -1
View File
@@ -1753,7 +1753,7 @@
"configure": "Nastaviť",
"tokenLabel": "Osobný prístupový token",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "Token sa ukladá šifrovane. ProxMenux ho používa iba na požiadavky GitHub API určené na čítanie a po uložení ho už nezobrazí.",
"tokenHelp": "Token sa ukladá šifrovane. ProxMenux ho používa iba na požiadavky GitHub API určené na čítanie a po uložení ho už nezobrazí. Postačuje fine-grained token s prístupom na čítanie k verejným repozitárom a bez oprávnení k účtu.",
"configured": "Token je nastavený",
"notConfigured": "Používa sa anonymná kvóta požiadaviek GitHubu",
"removeToken": "Odstrániť token",
+1 -1
View File
@@ -1754,7 +1754,7 @@
"configure": "Konfigurera",
"tokenLabel": "Personlig åtkomsttoken",
"tokenPlaceholder": "github_pat_...",
"tokenHelp": "Token lagras krypterad. ProxMenux använder den endast för skrivskyddade anrop till GitHub API och visar den inte igen efter att den har sparats.",
"tokenHelp": "Token lagras krypterad. ProxMenux använder den endast för skrivskyddade anrop till GitHub API och visar den inte igen efter att den har sparats. Det räcker med en fine-grained token med läsbehörighet till publika repositorier och utan kontobehörigheter.",
"configured": "Token konfigurerad",
"notConfigured": "GitHubs anonyma förfrågningskvot används",
"removeToken": "Ta bort token",
+10 -4
View File
@@ -12,7 +12,7 @@ from collections import deque
from flask import Blueprint, jsonify, request
from notification_manager import notification_manager, SENSITIVE_PLACEHOLDER, validate_external_url
from notification_channels import CHANNEL_TYPES as _NOTIF_CHANNEL_TYPES
from jwt_middleware import require_auth
from jwt_middleware import require_auth, require_admin_scope
def _resolve_masked_api_key(provider, api_key):
@@ -314,15 +314,21 @@ def save_notification_settings():
@notification_bp.route('/api/notifications/reveal-secret', methods=['POST'])
@require_auth
@require_admin_scope
def reveal_notification_secret():
"""Return one sensitive config value in cleartext.
Backs the "eye" toggle in the Settings UI. The settings GET masks
every entry in SENSITIVE_KEYS with `'************'` so the secret
never leaves the server just because someone loaded the page; this
endpoint lets an authenticated operator explicitly request the
real value for a single key when they need to inspect it.
endpoint lets an operator explicitly request the real value for a
single key when they need to inspect it.
Requires `full_admin` scope: this is the one route that hands back a
stored credential in cleartext, so a read-only API token — which is
handed out precisely because it cannot reach credentials — must not
reach it. Session logins carry full_admin implicitly, so the eye
toggle in the UI is unaffected.
Body schema (one of):
{"ai_provider": "groq" | "anthropic" | …}
@@ -2322,7 +2322,7 @@ EOF
remove_subscription_banner() {
local FUNC_VERSION="1.1"
local FUNC_VERSION="1.0"
# description: Patch the Proxmox web UI to suppress the "no valid subscription" dialog (PVE 8 + 9 variants supported).
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)