fix: remove MFA card from tenant settings, constrain card widths
MFA enrollment now happens during sign-in. Tenant settings page reduced to: Tenant Details + Auth Policy side-by-side (max 520px each), Passkeys full-width below. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
|||||||
useResetServerAdminPassword,
|
useResetServerAdminPassword,
|
||||||
useTenantAuthSettings, useUpdateTenantAuthSettings,
|
useTenantAuthSettings, useUpdateTenantAuthSettings,
|
||||||
} from '../../api/tenant-hooks';
|
} from '../../api/tenant-hooks';
|
||||||
import { MfaSection } from '../../components/account/MfaSection';
|
|
||||||
import { PasskeySection } from '../../components/account/PasskeySection';
|
import { PasskeySection } from '../../components/account/PasskeySection';
|
||||||
import { useScopes } from '../../auth/useScopes';
|
import { useScopes } from '../../auth/useScopes';
|
||||||
import styles from '../../styles/platform.module.css';
|
import styles from '../../styles/platform.module.css';
|
||||||
@@ -140,85 +139,83 @@ export function SettingsPage() {
|
|||||||
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 20, overflowY: 'auto', flex: 1 }}>
|
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 20, overflowY: 'auto', flex: 1 }}>
|
||||||
<h1 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 600 }}>Settings</h1>
|
<h1 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 600 }}>Settings</h1>
|
||||||
|
|
||||||
{/* Card 1: Tenant Details */}
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 20 }}>
|
||||||
<Card title="Tenant Details">
|
{/* Card 1: Tenant Details */}
|
||||||
<div className={styles.dividerList}>
|
<div style={{ maxWidth: 520, flex: '1 1 400px' }}>
|
||||||
<div className={styles.kvRow}>
|
<Card title="Tenant Details">
|
||||||
<span className={styles.kvLabel}>Name</span>
|
<div className={styles.dividerList}>
|
||||||
<span className={styles.kvValue}>{data.name}</span>
|
<div className={styles.kvRow}>
|
||||||
</div>
|
<span className={styles.kvLabel}>Name</span>
|
||||||
<div className={styles.kvRow}>
|
<span className={styles.kvValue}>{data.name}</span>
|
||||||
<span className={styles.kvLabel}>Slug</span>
|
|
||||||
<span className={styles.kvValueMono}>{data.slug}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.kvRow}>
|
|
||||||
<span className={styles.kvLabel}>Status</span>
|
|
||||||
<Badge label={data.status} color={statusColor(data.status)} />
|
|
||||||
</div>
|
|
||||||
<div className={styles.kvRow}>
|
|
||||||
<span className={styles.kvLabel}>Server Endpoint</span>
|
|
||||||
<span className={styles.kvValueMono}>{data.serverEndpoint ?? '—'}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.kvRow}>
|
|
||||||
<span className={styles.kvLabel}>Created</span>
|
|
||||||
<span className={styles.kvValue}>{new Date(data.createdAt).toLocaleDateString()}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ borderTop: '1px solid var(--border)', marginTop: 16, paddingTop: 16 }}>
|
|
||||||
<p className={styles.description} style={{ margin: '0 0 12px' }}>
|
|
||||||
Reset the built-in admin password for your server dashboard (local login at <code>/login?local</code>).
|
|
||||||
</p>
|
|
||||||
<form
|
|
||||||
onSubmit={async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (serverAdminPw.length < 8) {
|
|
||||||
toast({ title: 'Password must be at least 8 characters', variant: 'error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await resetServerAdmin.mutateAsync(serverAdminPw);
|
|
||||||
toast({ title: 'Server admin password reset successfully', variant: 'success' });
|
|
||||||
setServerAdminPw('');
|
|
||||||
} catch (err) {
|
|
||||||
toast({ title: 'Failed to reset server admin password', description: errorMessage(err), variant: 'error' });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{ display: 'flex', gap: 8, alignItems: 'flex-end' }}
|
|
||||||
>
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<FormField label="Server admin password" htmlFor="server-admin-pw">
|
|
||||||
<Input
|
|
||||||
id="server-admin-pw"
|
|
||||||
type="password"
|
|
||||||
value={serverAdminPw}
|
|
||||||
onChange={(e) => setServerAdminPw(e.target.value)}
|
|
||||||
placeholder="Enter new admin password"
|
|
||||||
required
|
|
||||||
minLength={8}
|
|
||||||
/>
|
|
||||||
</FormField>
|
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" variant="primary" loading={resetServerAdmin.isPending}>
|
<div className={styles.kvRow}>
|
||||||
Reset
|
<span className={styles.kvLabel}>Slug</span>
|
||||||
</Button>
|
<span className={styles.kvValueMono}>{data.slug}</span>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
<div className={styles.kvRow}>
|
||||||
</Card>
|
<span className={styles.kvLabel}>Status</span>
|
||||||
|
<Badge label={data.status} color={statusColor(data.status)} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.kvRow}>
|
||||||
|
<span className={styles.kvLabel}>Server Endpoint</span>
|
||||||
|
<span className={styles.kvValueMono}>{data.serverEndpoint ?? '—'}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.kvRow}>
|
||||||
|
<span className={styles.kvLabel}>Created</span>
|
||||||
|
<span className={styles.kvValue}>{new Date(data.createdAt).toLocaleDateString()}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Card 2: Multi-Factor Authentication (MFA + Passkeys combined) */}
|
<div style={{ borderTop: '1px solid var(--border)', marginTop: 16, paddingTop: 16 }}>
|
||||||
<Card title="Multi-Factor Authentication">
|
<p className={styles.description} style={{ margin: '0 0 12px' }}>
|
||||||
<MfaSection bare />
|
Reset the built-in admin password for your server dashboard (local login at <code>/login?local</code>).
|
||||||
<div style={{ borderTop: '1px solid var(--border)', marginTop: 16, paddingTop: 16 }}>
|
</p>
|
||||||
<h3 style={{ margin: '0 0 8px', fontSize: '0.875rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)' }}>
|
<form
|
||||||
Passkeys
|
onSubmit={async (e) => {
|
||||||
</h3>
|
e.preventDefault();
|
||||||
<PasskeySection bare />
|
if (serverAdminPw.length < 8) {
|
||||||
|
toast({ title: 'Password must be at least 8 characters', variant: 'error' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await resetServerAdmin.mutateAsync(serverAdminPw);
|
||||||
|
toast({ title: 'Server admin password reset successfully', variant: 'success' });
|
||||||
|
setServerAdminPw('');
|
||||||
|
} catch (err) {
|
||||||
|
toast({ title: 'Failed to reset server admin password', description: errorMessage(err), variant: 'error' });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ display: 'flex', gap: 8, alignItems: 'flex-end' }}
|
||||||
|
>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<FormField label="Server admin password" htmlFor="server-admin-pw">
|
||||||
|
<Input
|
||||||
|
id="server-admin-pw"
|
||||||
|
type="password"
|
||||||
|
value={serverAdminPw}
|
||||||
|
onChange={(e) => setServerAdminPw(e.target.value)}
|
||||||
|
placeholder="Enter new admin password"
|
||||||
|
required
|
||||||
|
minLength={8}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
<Button type="submit" variant="primary" loading={resetServerAdmin.isPending}>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Card 3: Authentication Policy (org-wide settings) */}
|
{/* Card 2: Authentication Policy (org-wide settings) */}
|
||||||
<AuthPolicySection />
|
<div style={{ maxWidth: 520, flex: '1 1 400px' }}>
|
||||||
|
<AuthPolicySection />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 3: Passkeys (full width) */}
|
||||||
|
<PasskeySection />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user