mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-15 11:16:50 +00:00
Section icons in the change journal, and admin scope on secret reveal
This commit is contained in:
@@ -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,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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user