fix: remove role gate from Settings, all strings in English

This commit is contained in:
Brückner
2026-06-03 16:08:05 +02:00
parent d364aea4c1
commit f7999cbe55
4 changed files with 31 additions and 44 deletions

View File

@ -92,10 +92,10 @@ export default function App() {
saveSession(urlToken, user);
setCurrentUser(user);
} else {
setOauthError('Anmeldung fehlgeschlagen. Bitte erneut versuchen.');
setOauthError('Login failed. Please try again.');
}
} catch {
setOauthError('Server nicht erreichbar.');
setOauthError('Server unreachable. Please try again.');
} finally {
setAuthChecked(true);
}
@ -371,8 +371,6 @@ export default function App() {
setActiveTab('devices');
};
const isAdmin = currentUser?.role?.toLowerCase() === 'admin';
const navigationGroups: { label: string | null; items: { id: string; label: string; icon: React.ReactNode }[] }[] = [
{
label: null,
@ -401,12 +399,12 @@ export default function App() {
{ id: 'logs', label: 'Logbook', icon: <History className="w-4 h-4 shrink-0" /> },
],
},
...(isAdmin ? [{
{
label: 'System',
items: [
{ id: 'settings', label: 'Einstellungen', icon: <Settings2 className="w-4 h-4 shrink-0" /> },
{ id: 'settings', label: 'Settings', icon: <Settings2 className="w-4 h-4 shrink-0" /> },
],
}] : []),
},
];
// Startup check not done yet

View File

@ -150,7 +150,7 @@ export default function LoginPage({ onLogin, onNavigateToRegister, authError }:
<>
<div className="flex items-center gap-3">
<div className="flex-1 h-px bg-slate-800" />
<span className="text-[10px] font-mono text-slate-500 uppercase tracking-widest">oder</span>
<span className="text-[10px] font-mono text-slate-500 uppercase tracking-widest">or</span>
<div className="flex-1 h-px bg-slate-800" />
</div>
<button

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { authFetch } from '../lib/auth';
import { User } from '../types';
import {
Shield, Activity, Save, CheckCircle, AlertCircle, Eye, EyeOff, Settings2, Lock,
Shield, Activity, Save, CheckCircle, AlertCircle, Eye, EyeOff, Settings2,
} from 'lucide-react';
const SECRET_SENTINEL = '__SET__';
@ -50,14 +50,13 @@ function TextInput({
}
function SecretInput({
value, onChange, alreadySet, show, onToggleShow, placeholder,
value, onChange, alreadySet, show, onToggleShow,
}: {
value: string;
onChange: (v: string) => void;
alreadySet: boolean;
show: boolean;
onToggleShow: () => void;
placeholder?: string;
}) {
return (
<div className="relative">
@ -65,7 +64,7 @@ function SecretInput({
type={show ? 'text' : 'password'}
value={value}
onChange={e => onChange(e.target.value)}
placeholder={alreadySet ? 'Bereits konfiguriert leer lassen zum Behalten' : (placeholder ?? 'Neuen Wert eingeben')}
placeholder={alreadySet ? 'Already configured leave blank to keep' : 'Enter value'}
className="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2.5 pr-10 text-sm text-white placeholder-slate-500 font-mono focus:outline-none focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500/50 transition-all"
/>
<button
@ -80,7 +79,7 @@ function SecretInput({
);
}
export default function Settings({ currentUser }: SettingsProps) {
export default function Settings({ currentUser: _currentUser }: SettingsProps) {
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [error, setError] = useState('');
@ -109,7 +108,7 @@ export default function Settings({ currentUser }: SettingsProps) {
setError('');
try {
const res = await authFetch('/api/settings');
if (!res.ok) { setError('Einstellungen konnten nicht geladen werden.'); return; }
if (!res.ok) { setError('Failed to load settings.'); return; }
const data: RawSettings = await res.json();
setAzureEnabled(data.azure_enabled === 'true');
setAzureClientId(data.azure_client_id || '');
@ -122,7 +121,7 @@ export default function Settings({ currentUser }: SettingsProps) {
setCheckmkApiSecret('');
setCheckmkSyncInterval(data.checkmk_sync_interval_ms || '60000');
} catch {
setError('Netzwerkfehler beim Laden der Einstellungen.');
setError('Network error loading settings.');
} finally {
setLoading(false);
}
@ -146,7 +145,7 @@ export default function Settings({ currentUser }: SettingsProps) {
const res = await authFetch('/api/settings', { method: 'PUT', body: JSON.stringify(payload) });
if (!res.ok) {
const d = await res.json();
setError(d.error || 'Speichern fehlgeschlagen.');
setError(d.error || 'Failed to save settings.');
return;
}
const data: RawSettings = await res.json();
@ -154,24 +153,15 @@ export default function Settings({ currentUser }: SettingsProps) {
setCheckmkSecretSet(data.checkmk_api_secret === SECRET_SENTINEL);
setAzureClientSecret('');
setCheckmkApiSecret('');
setSuccessMsg('Einstellungen gespeichert.');
setSuccessMsg('Settings saved.');
setTimeout(() => setSuccessMsg(''), 4000);
} catch {
setError('Netzwerkfehler beim Speichern.');
setError('Network error saving settings.');
} finally {
setSaving(false);
}
}
if (currentUser.role.toLowerCase() !== 'admin') {
return (
<div className="flex flex-col items-center justify-center h-64 space-y-3">
<Lock className="w-10 h-10 text-slate-600" />
<p className="text-slate-400 text-sm">Einstellungen sind nur für Administratoren zugänglich.</p>
</div>
);
}
if (loading) {
return (
<div className="flex items-center justify-center h-64">
@ -189,8 +179,8 @@ export default function Settings({ currentUser }: SettingsProps) {
<Settings2 className="w-5 h-5 text-cyan-400" />
</div>
<div>
<h1 className="text-lg font-bold text-white">Einstellungen</h1>
<p className="text-xs text-slate-400">Integrationen und Dienst-Konfigurationen</p>
<h1 className="text-lg font-bold text-white">Settings</h1>
<p className="text-xs text-slate-400">Integrations and service configuration</p>
</div>
</div>
@ -217,15 +207,14 @@ export default function Settings({ currentUser }: SettingsProps) {
</div>
<div>
<h3 className="text-sm font-semibold text-white">Microsoft Entra ID</h3>
<p className="text-xs text-slate-500">OAuth 2.0 Login r Organisationsaccounts</p>
<p className="text-xs text-slate-500">OAuth 2.0 login for organizational accounts</p>
</div>
</div>
{/* Toggle */}
<button
type="button"
onClick={() => setAzureEnabled(v => !v)}
className={`relative w-11 h-6 rounded-full transition-colors ${azureEnabled ? 'bg-blue-600' : 'bg-slate-700'}`}
title={azureEnabled ? 'Deaktivieren' : 'Aktivieren'}
title={azureEnabled ? 'Disable' : 'Enable'}
>
<span className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform ${azureEnabled ? 'translate-x-5' : 'translate-x-0'}`} />
</button>
@ -251,7 +240,7 @@ export default function Settings({ currentUser }: SettingsProps) {
/>
</div>
<div>
<FieldLabel>Redirect URI <span className="text-slate-500 font-normal">(leer = automatisch)</span></FieldLabel>
<FieldLabel>Redirect URI <span className="text-slate-500 font-normal">(leave blank for auto)</span></FieldLabel>
<TextInput value={azureRedirectUri} onChange={setAzureRedirectUri} placeholder="https://ghostgrid.internal/api/auth/azure/callback" monospace />
</div>
</div>
@ -265,7 +254,7 @@ export default function Settings({ currentUser }: SettingsProps) {
</div>
<div>
<h3 className="text-sm font-semibold text-white">CheckMK</h3>
<p className="text-xs text-slate-500">Geräte-Status-Synchronisation über die CheckMK REST API</p>
<p className="text-xs text-slate-500">Device status synchronization via the CheckMK REST API</p>
</div>
</div>
@ -290,7 +279,7 @@ export default function Settings({ currentUser }: SettingsProps) {
/>
</div>
<div>
<FieldLabel>Sync-Intervall (ms)</FieldLabel>
<FieldLabel>Sync Interval (ms)</FieldLabel>
<TextInput value={checkmkSyncInterval} onChange={setCheckmkSyncInterval} placeholder="60000" monospace />
</div>
</div>
@ -308,7 +297,7 @@ export default function Settings({ currentUser }: SettingsProps) {
) : (
<Save className="w-4 h-4" />
)}
{saving ? 'Speichert…' : 'Einstellungen speichern'}
{saving ? 'Saving…' : 'Save Settings'}
</button>
</div>
</div>