mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(web): add MFA login prompt and security settings UI
Handle MFA challenge in login flow (TOTP code input after password verification, recovery code hint, back navigation). Add admin security settings section with session idle timeout, max sessions per user, MFA policy selector, SSO enforcement toggle with break-glass username, and password policy controls. Propagate new i18n keys to all 21 locales.
This commit is contained in:
@@ -805,6 +805,7 @@ function SystemSection() {
|
||||
|
||||
function SecuritySection() {
|
||||
const { t } = useTranslation();
|
||||
const { hasPermission } = useAuth();
|
||||
const [currentPassword, setCurrentPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
@@ -962,6 +963,278 @@ function SecuritySection() {
|
||||
<div className="border-t border-border pt-4">
|
||||
<p className="text-sm text-muted-foreground">{t.settings.security.loginAttemptLimitNote}</p>
|
||||
</div>
|
||||
|
||||
{hasPermission("settings:write") && <AdminSecuritySettings />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AdminSecuritySettings() {
|
||||
const { t } = useTranslation();
|
||||
const [settings, setSettings] = useState<Record<string, string>>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [saveMsg, setSaveMsg] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiGet<{ settings: Record<string, string> }>("/v1/settings")
|
||||
.then((data) => setSettings(data.settings))
|
||||
.catch(() => {})
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const updateSetting = useCallback((key: string, value: string) => {
|
||||
setSettings((prev) => ({ ...prev, [key]: value }));
|
||||
}, []);
|
||||
|
||||
const handleSave = useCallback(async () => {
|
||||
setSaving(true);
|
||||
setSaveMsg(null);
|
||||
try {
|
||||
await apiPut("/v1/settings", settings);
|
||||
setSaveMsg(t.settings.security.securitySettingsSaved);
|
||||
} catch {
|
||||
setSaveMsg(t.settings.security.securitySettingsFailed);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
setTimeout(() => setSaveMsg(null), 3000);
|
||||
}
|
||||
}, [settings, t]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-t border-border pt-6 space-y-6">
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-foreground">
|
||||
{t.settings.security.adminHeading}
|
||||
</h4>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t.settings.security.adminDescription}</p>
|
||||
</div>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.sessionIdleTimeout}
|
||||
description={t.settings.security.sessionIdleTimeoutDesc}
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
value={settings.sessionIdleTimeoutMinutes || "0"}
|
||||
onChange={(e) => updateSetting("sessionIdleTimeoutMinutes", e.target.value)}
|
||||
aria-label={t.settings.security.sessionIdleTimeout}
|
||||
className="px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground w-24"
|
||||
min={0}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.maxSessionsPerUser}
|
||||
description={t.settings.security.maxSessionsPerUserDesc}
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
value={settings.maxSessionsPerUser || "0"}
|
||||
onChange={(e) => updateSetting("maxSessionsPerUser", e.target.value)}
|
||||
aria-label={t.settings.security.maxSessionsPerUser}
|
||||
className="px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground w-24"
|
||||
min={0}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.mfaPolicy}
|
||||
description={t.settings.security.mfaPolicyDesc}
|
||||
>
|
||||
<select
|
||||
value={settings.mfaPolicy || "optional"}
|
||||
onChange={(e) => updateSetting("mfaPolicy", e.target.value)}
|
||||
aria-label={t.settings.security.mfaPolicy}
|
||||
className="px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground"
|
||||
>
|
||||
<option value="optional">{t.settings.security.mfaPolicyOptional}</option>
|
||||
<option value="admins_only">{t.settings.security.mfaPolicyAdminsOnly}</option>
|
||||
<option value="required">{t.settings.security.mfaPolicyRequired}</option>
|
||||
</select>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.ssoEnforcement}
|
||||
description={t.settings.security.ssoEnforcementDesc}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={settings.ssoEnforcement === "true"}
|
||||
aria-label={t.settings.security.ssoEnforcement}
|
||||
onClick={() =>
|
||||
updateSetting("ssoEnforcement", settings.ssoEnforcement === "true" ? "false" : "true")
|
||||
}
|
||||
className={cn(
|
||||
"w-11 h-6 rounded-full transition-colors relative",
|
||||
settings.ssoEnforcement === "true" ? "bg-primary" : "bg-muted-foreground/30",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"block w-4 h-4 rounded-full bg-white absolute top-1 transition-transform",
|
||||
settings.ssoEnforcement === "true" ? "translate-x-6" : "translate-x-1",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</SettingRow>
|
||||
|
||||
{settings.ssoEnforcement === "true" && (
|
||||
<SettingRow
|
||||
label={t.settings.security.ssoBreakGlassUsername}
|
||||
description={t.settings.security.ssoBreakGlassUsernameDesc}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.ssoBreakGlassUsername || ""}
|
||||
onChange={(e) => updateSetting("ssoBreakGlassUsername", e.target.value)}
|
||||
aria-label={t.settings.security.ssoBreakGlassUsername}
|
||||
className="px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground w-40"
|
||||
placeholder="admin"
|
||||
/>
|
||||
</SettingRow>
|
||||
)}
|
||||
|
||||
<div className="pt-2 border-t border-border">
|
||||
<h4 className="text-sm font-semibold text-foreground mb-3">
|
||||
{t.settings.security.passwordPolicyHeading}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.passwordMinLength}
|
||||
description={t.settings.security.passwordMinLengthDesc}
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
value={settings.passwordMinLength || "8"}
|
||||
onChange={(e) => updateSetting("passwordMinLength", e.target.value)}
|
||||
aria-label={t.settings.security.passwordMinLength}
|
||||
className="px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground w-24"
|
||||
min={4}
|
||||
max={128}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.passwordRequireUppercase}
|
||||
description={t.settings.security.passwordRequireUppercaseDesc}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={settings.passwordRequireUppercase !== "false"}
|
||||
aria-label={t.settings.security.passwordRequireUppercase}
|
||||
onClick={() =>
|
||||
updateSetting(
|
||||
"passwordRequireUppercase",
|
||||
settings.passwordRequireUppercase === "false" ? "true" : "false",
|
||||
)
|
||||
}
|
||||
className={cn(
|
||||
"w-11 h-6 rounded-full transition-colors relative",
|
||||
settings.passwordRequireUppercase !== "false" ? "bg-primary" : "bg-muted-foreground/30",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"block w-4 h-4 rounded-full bg-white absolute top-1 transition-transform",
|
||||
settings.passwordRequireUppercase !== "false" ? "translate-x-6" : "translate-x-1",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.passwordRequireNumber}
|
||||
description={t.settings.security.passwordRequireNumberDesc}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={settings.passwordRequireNumber !== "false"}
|
||||
aria-label={t.settings.security.passwordRequireNumber}
|
||||
onClick={() =>
|
||||
updateSetting(
|
||||
"passwordRequireNumber",
|
||||
settings.passwordRequireNumber === "false" ? "true" : "false",
|
||||
)
|
||||
}
|
||||
className={cn(
|
||||
"w-11 h-6 rounded-full transition-colors relative",
|
||||
settings.passwordRequireNumber !== "false" ? "bg-primary" : "bg-muted-foreground/30",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"block w-4 h-4 rounded-full bg-white absolute top-1 transition-transform",
|
||||
settings.passwordRequireNumber !== "false" ? "translate-x-6" : "translate-x-1",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t.settings.security.passwordRequireSpecial}
|
||||
description={t.settings.security.passwordRequireSpecialDesc}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={settings.passwordRequireSpecial === "true"}
|
||||
aria-label={t.settings.security.passwordRequireSpecial}
|
||||
onClick={() =>
|
||||
updateSetting(
|
||||
"passwordRequireSpecial",
|
||||
settings.passwordRequireSpecial === "true" ? "false" : "true",
|
||||
)
|
||||
}
|
||||
className={cn(
|
||||
"w-11 h-6 rounded-full transition-colors relative",
|
||||
settings.passwordRequireSpecial === "true" ? "bg-primary" : "bg-muted-foreground/30",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"block w-4 h-4 rounded-full bg-white absolute top-1 transition-transform",
|
||||
settings.passwordRequireSpecial === "true" ? "translate-x-6" : "translate-x-1",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</SettingRow>
|
||||
|
||||
<div className="flex items-center gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-primary-foreground text-sm font-medium hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{saving && <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden="true" />}
|
||||
{t.settings.system.saveButton}
|
||||
</button>
|
||||
{saveMsg && (
|
||||
<span
|
||||
className={cn(
|
||||
"text-sm",
|
||||
saveMsg === t.settings.security.securitySettingsFailed
|
||||
? "text-destructive"
|
||||
: "text-green-600 dark:text-green-400",
|
||||
)}
|
||||
>
|
||||
{saveMsg}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2019,9 +2292,7 @@ function TeamsSection() {
|
||||
return;
|
||||
}
|
||||
setExpandedTeamId(tm.id);
|
||||
setQuotaMb(
|
||||
tm.storageQuota ? String(Math.round(tm.storageQuota / (1024 * 1024))) : "",
|
||||
);
|
||||
setQuotaMb(tm.storageQuota ? String(Math.round(tm.storageQuota / (1024 * 1024))) : "");
|
||||
setRetention(tm.retentionHours ? String(tm.retentionHours) : "");
|
||||
},
|
||||
[expandedTeamId],
|
||||
@@ -2140,175 +2411,177 @@ function TeamsSection() {
|
||||
</div>
|
||||
) : (
|
||||
teams.map((tm) => (
|
||||
<Fragment key={tm.id}>
|
||||
<div
|
||||
className={cn(
|
||||
"items-center px-4 py-3 border-b border-border last:border-0 last:rounded-b-lg hover:bg-muted/20 transition-colors",
|
||||
isMobile ? "flex gap-3" : "grid grid-cols-[1fr_100px_60px] gap-2",
|
||||
)}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
{editingTeamId === tm.id ? (
|
||||
<Fragment key={tm.id}>
|
||||
<div
|
||||
className={cn(
|
||||
"items-center px-4 py-3 border-b border-border last:border-0 last:rounded-b-lg hover:bg-muted/20 transition-colors",
|
||||
isMobile ? "flex gap-3" : "grid grid-cols-[1fr_100px_60px] gap-2",
|
||||
)}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
{editingTeamId === tm.id ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={editingTeamName}
|
||||
onChange={(e) => setEditingTeamName(e.target.value)}
|
||||
className="px-2 py-1 rounded border border-border bg-background text-sm text-foreground w-40"
|
||||
ref={(el) => el?.focus()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") handleRename(tm.id);
|
||||
if (e.key === "Escape") setEditingTeamId(null);
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRename(tm.id)}
|
||||
className="text-xs text-primary hover:underline"
|
||||
>
|
||||
{t.common.save}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditingTeamId(null)}
|
||||
className="text-xs text-muted-foreground hover:underline"
|
||||
>
|
||||
{t.common.cancel}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<span className="text-sm font-medium text-foreground truncate block">
|
||||
{tm.name}
|
||||
</span>
|
||||
{isMobile && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{tm.memberCount} {plural(tm.memberCount, "member", "members")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!isMobile && (
|
||||
<span className="text-sm text-muted-foreground">{tm.memberCount}</span>
|
||||
)}
|
||||
<div className="flex items-center gap-1 justify-end relative shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenMenuId(openMenuId === tm.id ? null : tm.id);
|
||||
}}
|
||||
className="p-1.5 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</button>
|
||||
{openMenuId === tm.id && (
|
||||
<div
|
||||
role="menu"
|
||||
className="absolute right-0 top-8 z-50 w-36 rounded-lg border border-border bg-background shadow-lg py-1"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setEditingTeamId(tm.id);
|
||||
setEditingTeamName(tm.name);
|
||||
setOpenMenuId(null);
|
||||
}}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5" />
|
||||
{t.settings.teams.renameAction}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
handleExpandTeam(tm);
|
||||
setOpenMenuId(null);
|
||||
}}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<Settings className="h-3.5 w-3.5" />
|
||||
{t.settings.heading}
|
||||
</button>
|
||||
<div className="border-t border-border my-1" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDelete(tm.id, tm.name)}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-destructive hover:bg-destructive/10 transition-colors"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
{t.settings.teams.deleteAction}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{expandedTeamId === tm.id && (
|
||||
<div className="px-4 py-3 border-b border-border last:border-0 bg-muted/10 space-y-3">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor={`quota-${tm.id}`}
|
||||
className="text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
{t.settings.teams.teamStorageQuota}
|
||||
</label>
|
||||
<input
|
||||
id={`quota-${tm.id}`}
|
||||
type="number"
|
||||
min="0"
|
||||
value={quotaMb}
|
||||
onChange={(e) => setQuotaMb(e.target.value)}
|
||||
placeholder="0"
|
||||
className="w-full px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
{t.settings.teams.teamStorageQuotaDesc}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor={`retention-${tm.id}`}
|
||||
className="text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
{t.settings.teams.teamRetentionHours}
|
||||
</label>
|
||||
<input
|
||||
id={`retention-${tm.id}`}
|
||||
type="number"
|
||||
min="0"
|
||||
value={retention}
|
||||
onChange={(e) => setRetention(e.target.value)}
|
||||
placeholder="0"
|
||||
className="w-full px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
{t.settings.teams.teamRetentionHoursDesc}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={editingTeamName}
|
||||
onChange={(e) => setEditingTeamName(e.target.value)}
|
||||
className="px-2 py-1 rounded border border-border bg-background text-sm text-foreground w-40"
|
||||
ref={(el) => el?.focus()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") handleRename(tm.id);
|
||||
if (e.key === "Escape") setEditingTeamId(null);
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRename(tm.id)}
|
||||
className="text-xs text-primary hover:underline"
|
||||
disabled={savingQuota}
|
||||
onClick={() => handleSaveQuota(tm.id)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-primary text-primary-foreground text-xs font-medium hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{savingQuota && (
|
||||
<Loader2 className="h-3 w-3 animate-spin" aria-hidden="true" />
|
||||
)}
|
||||
{t.common.save}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditingTeamId(null)}
|
||||
className="text-xs text-muted-foreground hover:underline"
|
||||
onClick={() => setExpandedTeamId(null)}
|
||||
className="px-3 py-1.5 rounded-lg border border-border text-xs text-muted-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
{t.common.cancel}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<span className="text-sm font-medium text-foreground truncate block">
|
||||
{tm.name}
|
||||
</span>
|
||||
{isMobile && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{tm.memberCount} {plural(tm.memberCount, "member", "members")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!isMobile && <span className="text-sm text-muted-foreground">{tm.memberCount}</span>}
|
||||
<div className="flex items-center gap-1 justify-end relative shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenMenuId(openMenuId === tm.id ? null : tm.id);
|
||||
}}
|
||||
className="p-1.5 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</button>
|
||||
{openMenuId === tm.id && (
|
||||
<div
|
||||
role="menu"
|
||||
className="absolute right-0 top-8 z-50 w-36 rounded-lg border border-border bg-background shadow-lg py-1"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setEditingTeamId(tm.id);
|
||||
setEditingTeamName(tm.name);
|
||||
setOpenMenuId(null);
|
||||
}}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5" />
|
||||
{t.settings.teams.renameAction}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
handleExpandTeam(tm);
|
||||
setOpenMenuId(null);
|
||||
}}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<Settings className="h-3.5 w-3.5" />
|
||||
{t.settings.heading}
|
||||
</button>
|
||||
<div className="border-t border-border my-1" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDelete(tm.id, tm.name)}
|
||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-destructive hover:bg-destructive/10 transition-colors"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
{t.settings.teams.deleteAction}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{expandedTeamId === tm.id && (
|
||||
<div className="px-4 py-3 border-b border-border last:border-0 bg-muted/10 space-y-3">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor={`quota-${tm.id}`}
|
||||
className="text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
{t.settings.teams.teamStorageQuota}
|
||||
</label>
|
||||
<input
|
||||
id={`quota-${tm.id}`}
|
||||
type="number"
|
||||
min="0"
|
||||
value={quotaMb}
|
||||
onChange={(e) => setQuotaMb(e.target.value)}
|
||||
placeholder="0"
|
||||
className="w-full px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
{t.settings.teams.teamStorageQuotaDesc}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor={`retention-${tm.id}`}
|
||||
className="text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
{t.settings.teams.teamRetentionHours}
|
||||
</label>
|
||||
<input
|
||||
id={`retention-${tm.id}`}
|
||||
type="number"
|
||||
min="0"
|
||||
value={retention}
|
||||
onChange={(e) => setRetention(e.target.value)}
|
||||
placeholder="0"
|
||||
className="w-full px-3 py-1.5 rounded-lg border border-border bg-background text-sm text-foreground"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
{t.settings.teams.teamRetentionHoursDesc}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
disabled={savingQuota}
|
||||
onClick={() => handleSaveQuota(tm.id)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-primary text-primary-foreground text-xs font-medium hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{savingQuota && (
|
||||
<Loader2 className="h-3 w-3 animate-spin" aria-hidden="true" />
|
||||
)}
|
||||
{t.common.save}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpandedTeamId(null)}
|
||||
className="px-3 py-1.5 rounded-lg border border-border text-xs text-muted-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
{t.common.cancel}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
@@ -2861,9 +3134,7 @@ function AuditLogSection() {
|
||||
<th className="text-start px-3 py-2 font-medium text-muted-foreground">
|
||||
{t.settings.auditLog.tableHeaderUser}
|
||||
</th>
|
||||
<th className="text-start px-3 py-2 font-medium text-muted-foreground">
|
||||
IP
|
||||
</th>
|
||||
<th className="text-start px-3 py-2 font-medium text-muted-foreground">IP</th>
|
||||
<th className="text-start px-3 py-2 font-medium text-muted-foreground">
|
||||
{t.settings.auditLog.tableHeaderAction}
|
||||
</th>
|
||||
|
||||
@@ -7,6 +7,7 @@ interface AuthState {
|
||||
authEnabled: boolean;
|
||||
isAuthenticated: boolean;
|
||||
mustChangePassword: boolean;
|
||||
mfaRequired: boolean;
|
||||
role: string | null;
|
||||
permissions: string[];
|
||||
analyticsEnabled: boolean | null;
|
||||
@@ -44,6 +45,7 @@ export function useAuth() {
|
||||
authEnabled: false,
|
||||
isAuthenticated: false,
|
||||
mustChangePassword: false,
|
||||
mfaRequired: false,
|
||||
role: null,
|
||||
permissions: [],
|
||||
analyticsEnabled: null,
|
||||
@@ -73,6 +75,7 @@ export function useAuth() {
|
||||
authEnabled: false,
|
||||
isAuthenticated: true,
|
||||
mustChangePassword: false,
|
||||
mfaRequired: false,
|
||||
role: "admin",
|
||||
permissions: ANON_ADMIN_PERMISSIONS,
|
||||
analyticsEnabled: null,
|
||||
@@ -104,6 +107,7 @@ export function useAuth() {
|
||||
authEnabled: true,
|
||||
isAuthenticated: true,
|
||||
mustChangePassword: mustChange,
|
||||
mfaRequired: session.user?.mfaRequired === true,
|
||||
role: session.user?.role ?? null,
|
||||
permissions: session.user?.permissions ?? [],
|
||||
analyticsEnabled: session.user?.analyticsEnabled ?? null,
|
||||
@@ -125,6 +129,7 @@ export function useAuth() {
|
||||
authEnabled: true,
|
||||
isAuthenticated: false,
|
||||
mustChangePassword: false,
|
||||
mfaRequired: false,
|
||||
role: null,
|
||||
permissions: [],
|
||||
analyticsEnabled: null,
|
||||
|
||||
@@ -133,6 +133,11 @@ export function LoginPage() {
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [showMfaPrompt, setShowMfaPrompt] = useState(false);
|
||||
const [mfaToken, setMfaToken] = useState("");
|
||||
const [mfaCode, setMfaCode] = useState("");
|
||||
const [mfaLoading, setMfaLoading] = useState(false);
|
||||
const mfaInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const authError = searchParams.get("error");
|
||||
@@ -167,6 +172,12 @@ export function LoginPage() {
|
||||
return;
|
||||
}
|
||||
const data = await res.json();
|
||||
if (data.requiresMfa) {
|
||||
setMfaToken(data.mfaToken);
|
||||
setShowMfaPrompt(true);
|
||||
setTimeout(() => mfaInputRef.current?.focus(), 100);
|
||||
return;
|
||||
}
|
||||
setToken(data.token);
|
||||
localStorage.setItem("snapotter-username", data.user?.username || username);
|
||||
if (data.user?.mustChangePassword) {
|
||||
@@ -181,6 +192,35 @@ export function LoginPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleMfaComplete = async () => {
|
||||
setMfaLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const res = await fetch("/api/auth/mfa/complete", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ mfaToken, code: mfaCode }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
setError(t.auth.mfaInvalidCode);
|
||||
setMfaCode("");
|
||||
return;
|
||||
}
|
||||
const data = await res.json();
|
||||
setToken(data.token);
|
||||
localStorage.setItem("snapotter-username", data.user?.username || username);
|
||||
if (data.user?.mustChangePassword) {
|
||||
window.location.href = "/change-password";
|
||||
} else {
|
||||
window.location.href = "/";
|
||||
}
|
||||
} catch {
|
||||
setError(t.auth.connectionError);
|
||||
} finally {
|
||||
setMfaLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-background">
|
||||
<div className="flex-1 flex items-center justify-center p-8">
|
||||
@@ -219,48 +259,123 @@ export function LoginPage() {
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit} className={`space-y-4${ssoEnforced ? " opacity-60" : ""}`}>
|
||||
<div>
|
||||
<label htmlFor="username" className="block text-sm font-medium mb-1 text-foreground">
|
||||
{t.auth.username}
|
||||
</label>
|
||||
{showMfaPrompt ? (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="text-primary"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<rect width="18" height="11" x="3" y="11" rx="2" ry="2" />
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground">{t.auth.mfaRequired}</p>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
id="username"
|
||||
ref={mfaInputRef}
|
||||
type="text"
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
placeholder={t.auth.enterUsername}
|
||||
className="w-full px-4 py-3 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
required
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxLength={8}
|
||||
autoComplete="one-time-code"
|
||||
placeholder="000000"
|
||||
value={mfaCode}
|
||||
onChange={(e) => setMfaCode(e.target.value.replace(/[^0-9]/g, ""))}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && mfaCode.length >= 6) handleMfaComplete();
|
||||
}}
|
||||
className="w-full px-4 py-3 rounded-lg border border-border bg-background text-foreground text-center text-2xl font-mono tracking-[0.5em] focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
/>
|
||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleMfaComplete}
|
||||
disabled={mfaLoading || mfaCode.length < 6}
|
||||
className="w-full py-3 rounded-lg bg-primary/80 text-primary-foreground font-medium hover:bg-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{mfaLoading ? t.auth.verifying : t.auth.verify}
|
||||
</button>
|
||||
<p className="text-xs text-muted-foreground text-center">{t.auth.mfaRecoveryHint}</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setShowMfaPrompt(false);
|
||||
setMfaToken("");
|
||||
setMfaCode("");
|
||||
setError("");
|
||||
}}
|
||||
className="w-full text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{t.common.back}
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="password" className="block text-sm font-medium mb-1 text-foreground">
|
||||
{t.auth.password}
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder={t.auth.enterPassword}
|
||||
className="w-full px-4 py-3 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading || !username || !password}
|
||||
className="w-full py-3 rounded-lg bg-primary/80 text-primary-foreground font-medium hover:bg-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
) : (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className={`space-y-4${ssoEnforced ? " opacity-60" : ""}`}
|
||||
>
|
||||
{loading ? t.auth.loggingIn : t.auth.loginButton}
|
||||
</button>
|
||||
</form>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="username"
|
||||
className="block text-sm font-medium mb-1 text-foreground"
|
||||
>
|
||||
{t.auth.username}
|
||||
</label>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
placeholder={t.auth.enterUsername}
|
||||
className="w-full px-4 py-3 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="password"
|
||||
className="block text-sm font-medium mb-1 text-foreground"
|
||||
>
|
||||
{t.auth.password}
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder={t.auth.enterPassword}
|
||||
className="w-full px-4 py-3 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading || !username || !password}
|
||||
className="w-full py-3 rounded-lg bg-primary/80 text-primary-foreground font-medium hover:bg-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{loading ? t.auth.loggingIn : t.auth.loginButton}
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
{!ssoEnforced && (oidcEnabled || samlEnabled) && (
|
||||
<>
|
||||
<div className="flex items-center gap-3 my-4">
|
||||
|
||||
@@ -2711,6 +2711,33 @@ export const ar: TranslationKeys = {
|
||||
currentPasswordIncorrect: "كلمة المرور الحالية غير صحيحة",
|
||||
changePasswordButton: "تغيير كلمة المرور",
|
||||
loginAttemptLimitNote: "يمكن ضبط حدود محاولات تسجيل الدخول في إعدادات النظام.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "الأعضاء",
|
||||
@@ -3002,6 +3029,13 @@ export const ar: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "يتم إدارة تغيير كلمة المرور بواسطة مزود الهوية الخاص بك.",
|
||||
enterUsername: "أدخل اسم المستخدم",
|
||||
|
||||
@@ -2727,6 +2727,33 @@ export const de: TranslationKeys = {
|
||||
changePasswordButton: "Passwort aendern",
|
||||
loginAttemptLimitNote:
|
||||
"Anmeldeversuchslimits koennen in den Systemeinstellungen konfiguriert werden.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Personen",
|
||||
@@ -3029,6 +3056,13 @@ export const de: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Passwortaenderungen werden von Ihrem Identitaetsanbieter verwaltet.",
|
||||
|
||||
@@ -2675,6 +2675,33 @@ export const en = {
|
||||
currentPasswordIncorrect: "Current password is incorrect",
|
||||
changePasswordButton: "Change Password",
|
||||
loginAttemptLimitNote: "Login attempt limits can be configured in System Settings.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "People",
|
||||
@@ -2968,6 +2995,13 @@ export const en = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Password changes are managed by your identity provider.",
|
||||
enterUsername: "Enter username",
|
||||
|
||||
@@ -2709,6 +2709,33 @@ export const es: TranslationKeys = {
|
||||
changePasswordButton: "Cambiar contrasena",
|
||||
loginAttemptLimitNote:
|
||||
"Los limites de intentos de inicio de sesion se pueden configurar en Configuracion del sistema.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Personas",
|
||||
@@ -3007,6 +3034,13 @@ export const es: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Los cambios de contrasena son administrados por tu proveedor de identidad.",
|
||||
|
||||
@@ -2728,6 +2728,33 @@ export const fr: TranslationKeys = {
|
||||
changePasswordButton: "Changer le mot de passe",
|
||||
loginAttemptLimitNote:
|
||||
"Les limites de tentatives de connexion peuvent etre configurees dans les Parametres systeme.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Personnes",
|
||||
@@ -3027,6 +3054,13 @@ export const fr: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Les modifications de mot de passe sont gerees par votre fournisseur d'identite.",
|
||||
|
||||
@@ -2707,6 +2707,33 @@ export const hi: TranslationKeys = {
|
||||
currentPasswordIncorrect: "मौजूदा पासवर्ड गलत है",
|
||||
changePasswordButton: "पासवर्ड बदलें",
|
||||
loginAttemptLimitNote: "लॉगिन प्रयास सीमाएं सिस्टम सेटिंग्स में कॉन्फ़िगर की जा सकती हैं।",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "सदस्य",
|
||||
@@ -2999,6 +3026,13 @@ export const hi: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "पासवर्ड बदलाव आपके आइडेंटिटी प्रोवाइडर द्वारा प्रबंधित किए जाते हैं।",
|
||||
enterUsername: "यूज़रनेम दर्ज करें",
|
||||
|
||||
@@ -2719,6 +2719,33 @@ export const id: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Kata sandi saat ini salah",
|
||||
changePasswordButton: "Ubah Kata Sandi",
|
||||
loginAttemptLimitNote: "Batas percobaan login dapat dikonfigurasi di Pengaturan Sistem.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Anggota",
|
||||
@@ -3015,6 +3042,13 @@ export const id: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Perubahan kata sandi dikelola oleh penyedia identitas Anda.",
|
||||
enterUsername: "Masukkan nama pengguna",
|
||||
|
||||
@@ -2721,6 +2721,33 @@ export const it: TranslationKeys = {
|
||||
changePasswordButton: "Cambia password",
|
||||
loginAttemptLimitNote:
|
||||
"I limiti dei tentativi di accesso possono essere configurati nelle Impostazioni di sistema.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Persone",
|
||||
@@ -3021,6 +3048,13 @@ export const it: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Le modifiche alla password sono gestite dal tuo provider di identita.",
|
||||
|
||||
@@ -2677,6 +2677,33 @@ export const ja: TranslationKeys = {
|
||||
currentPasswordIncorrect: "現在のパスワードが正しくありません",
|
||||
changePasswordButton: "パスワード変更",
|
||||
loginAttemptLimitNote: "ログイン試行制限はシステム設定で構成できます。",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "メンバー",
|
||||
@@ -2972,6 +2999,13 @@ export const ja: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "パスワードはIDプロバイダーで管理されています。",
|
||||
enterUsername: "ユーザー名を入力",
|
||||
|
||||
@@ -2662,6 +2662,33 @@ export const ko: TranslationKeys = {
|
||||
currentPasswordIncorrect: "현재 비밀번호가 올바르지 않습니다",
|
||||
changePasswordButton: "비밀번호 변경",
|
||||
loginAttemptLimitNote: "로그인 시도 제한은 시스템 설정에서 구성할 수 있습니다.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "멤버",
|
||||
@@ -2957,6 +2984,13 @@ export const ko: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "비밀번호는 ID 제공자에서 관리됩니다.",
|
||||
enterUsername: "사용자명 입력",
|
||||
|
||||
@@ -2722,6 +2722,33 @@ export const nl: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Huidig wachtwoord is onjuist",
|
||||
changePasswordButton: "Wachtwoord wijzigen",
|
||||
loginAttemptLimitNote: "Inlogpogingslimieten kun je instellen bij Systeeminstellingen.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Personen",
|
||||
@@ -3018,6 +3045,13 @@ export const nl: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Wachtwoordwijzigingen worden beheerd door je identiteitsprovider.",
|
||||
enterUsername: "Voer gebruikersnaam in",
|
||||
|
||||
@@ -2725,6 +2725,33 @@ export const pl: TranslationKeys = {
|
||||
changePasswordButton: "Zmień hasło",
|
||||
loginAttemptLimitNote:
|
||||
"Limity prób logowania można skonfigurować w Ustawieniach systemowych.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Użytkownicy",
|
||||
@@ -3025,6 +3052,13 @@ export const pl: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Zarządzanie hasłem odbywa się przez dostawcę tożsamości.",
|
||||
enterUsername: "Wprowadź nazwę użytkownika",
|
||||
|
||||
@@ -2721,6 +2721,33 @@ export const ptBR: TranslationKeys = {
|
||||
changePasswordButton: "Alterar senha",
|
||||
loginAttemptLimitNote:
|
||||
"Os limites de tentativas de login podem ser configurados nas Configuracoes do sistema.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Pessoas",
|
||||
@@ -3018,6 +3045,13 @@ export const ptBR: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Alteracoes de senha sao gerenciadas pelo seu provedor de identidade.",
|
||||
|
||||
@@ -2720,6 +2720,33 @@ export const ru: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Текущий пароль неверен",
|
||||
changePasswordButton: "Изменить пароль",
|
||||
loginAttemptLimitNote: "Лимиты попыток входа можно настроить в Системных настройках.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Пользователи",
|
||||
@@ -3017,6 +3044,13 @@ export const ru: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Управление паролем осуществляется Вашим провайдером идентификации.",
|
||||
enterUsername: "Введите имя пользователя",
|
||||
|
||||
@@ -2717,6 +2717,33 @@ export const sv: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Nuvarande losenord ar felaktigt",
|
||||
changePasswordButton: "Byt losenord",
|
||||
loginAttemptLimitNote: "Inloggningsforsaksgranser kan konfigureras i Systeminstallningar.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Personer",
|
||||
@@ -3013,6 +3040,13 @@ export const sv: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Losenordsandringar hanteras av din identitetsleverantor.",
|
||||
enterUsername: "Ange anvandarnamn",
|
||||
|
||||
@@ -2699,6 +2699,33 @@ export const th: TranslationKeys = {
|
||||
currentPasswordIncorrect: "รหัสผ่านปัจจุบันไม่ถูกต้อง",
|
||||
changePasswordButton: "เปลี่ยนรหัสผ่าน",
|
||||
loginAttemptLimitNote: "สามารถกำหนดจำนวนครั้งจำกัดการเข้าสู่ระบบได้ในตั้งค่าระบบ",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "สมาชิก",
|
||||
@@ -2990,6 +3017,13 @@ export const th: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "การเปลี่ยนรหัสผ่านจัดการโดยผู้ให้บริการยืนยันตัวตนของคุณ",
|
||||
enterUsername: "กรอกชื่อผู้ใช้",
|
||||
|
||||
@@ -2723,6 +2723,33 @@ export const tr: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Mevcut parola yanlış",
|
||||
changePasswordButton: "Parolayı Değiştir",
|
||||
loginAttemptLimitNote: "Giriş deneme limitleri Sistem Ayarlarından yapılandırılabilir.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Kişiler",
|
||||
@@ -3021,6 +3048,13 @@ export const tr: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider:
|
||||
"Parola değişiklikleri kimlik sağlayıcınız tarafından yönetilmektedir.",
|
||||
|
||||
@@ -2720,6 +2720,33 @@ export const uk: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Поточний пароль невірний",
|
||||
changePasswordButton: "Змінити пароль",
|
||||
loginAttemptLimitNote: "Ліміти спроб входу можна налаштувати в Системних налаштуваннях.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Користувачі",
|
||||
@@ -3018,6 +3045,13 @@ export const uk: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Керування паролем здійснюється Вашим постачальником ідентифікації.",
|
||||
enterUsername: "Введіть ім'я користувача",
|
||||
|
||||
@@ -2719,6 +2719,33 @@ export const vi: TranslationKeys = {
|
||||
currentPasswordIncorrect: "Mật khẩu hiện tại không đúng",
|
||||
changePasswordButton: "Đổi mật khẩu",
|
||||
loginAttemptLimitNote: "Giới hạn đăng nhập có thể được cấu hình trong Cài đặt hệ thống.",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "Thành viên",
|
||||
@@ -3013,6 +3040,13 @@ export const vi: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "Việc đổi mật khẩu được quản lý bởi nhà cung cấp danh tính của bạn.",
|
||||
enterUsername: "Nhập tên đăng nhập",
|
||||
|
||||
@@ -2651,6 +2651,33 @@ export const zhCN: TranslationKeys = {
|
||||
currentPasswordIncorrect: "当前密码不正确",
|
||||
changePasswordButton: "修改密码",
|
||||
loginAttemptLimitNote: "登录尝试限制可在系统设置中配置。",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "成员",
|
||||
@@ -2942,6 +2969,13 @@ export const zhCN: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "密码修改由您的身份提供商管理。",
|
||||
enterUsername: "输入用户名",
|
||||
|
||||
@@ -2649,6 +2649,33 @@ export const zhTW: TranslationKeys = {
|
||||
currentPasswordIncorrect: "目前密碼不正確",
|
||||
changePasswordButton: "變更密碼",
|
||||
loginAttemptLimitNote: "登入嘗試限制可在系統設定中配置。",
|
||||
adminHeading: "Admin Security Settings",
|
||||
adminDescription: "Enterprise security policy settings. These apply to all users.",
|
||||
sessionIdleTimeout: "Session Idle Timeout (minutes)",
|
||||
sessionIdleTimeoutDesc: "Automatically log out idle sessions. 0 = disabled.",
|
||||
maxSessionsPerUser: "Max Sessions Per User",
|
||||
maxSessionsPerUserDesc: "Limit concurrent sessions per user. 0 = unlimited.",
|
||||
mfaPolicy: "MFA Policy",
|
||||
mfaPolicyDesc: "Require multi-factor authentication for users.",
|
||||
mfaPolicyOptional: "Optional",
|
||||
mfaPolicyAdminsOnly: "Required for admins",
|
||||
mfaPolicyRequired: "Required for all users",
|
||||
ssoEnforcement: "SSO Enforcement",
|
||||
ssoEnforcementDesc: "Require SSO login for all non-break-glass users.",
|
||||
ssoBreakGlassUsername: "Break Glass Admin Username",
|
||||
ssoBreakGlassUsernameDesc:
|
||||
"This admin can still log in with local credentials when SSO is enforced.",
|
||||
passwordMinLength: "Minimum Password Length",
|
||||
passwordMinLengthDesc: "Minimum number of characters required for passwords.",
|
||||
passwordRequireUppercase: "Require Uppercase",
|
||||
passwordRequireUppercaseDesc: "Require at least one uppercase letter.",
|
||||
passwordRequireNumber: "Require Number",
|
||||
passwordRequireNumberDesc: "Require at least one number.",
|
||||
passwordRequireSpecial: "Require Special Character",
|
||||
passwordRequireSpecialDesc: "Require at least one special character.",
|
||||
passwordPolicyHeading: "Password Policy",
|
||||
securitySettingsSaved: "Security settings saved",
|
||||
securitySettingsFailed: "Failed to save security settings",
|
||||
},
|
||||
people: {
|
||||
heading: "成員",
|
||||
@@ -2940,6 +2967,13 @@ export const zhTW: TranslationKeys = {
|
||||
"Your account is not authorized to access this application. Contact your administrator.",
|
||||
samlUserLimitReached: "User limit reached. Contact your administrator.",
|
||||
ssoEnforcedLocalRestricted: "Local login is restricted to authorized administrators.",
|
||||
mfaRequired: "Enter your authentication code",
|
||||
mfaRecoveryHint: "You can also use a recovery code",
|
||||
verify: "Verify",
|
||||
verifying: "Verifying...",
|
||||
mfaInvalidCode: "Invalid code. Please try again.",
|
||||
mfaEnrollmentRequired:
|
||||
"Your organization requires multi-factor authentication. Please set up MFA in your account settings.",
|
||||
methodSaml: "SAML",
|
||||
passwordManagedByProvider: "密碼由您的身分提供者管理。",
|
||||
enterUsername: "輸入使用者名稱",
|
||||
|
||||
Reference in New Issue
Block a user