Improve admin page structure and styling for clarity
All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 7s

Updated the Admin Users Page by reorganizing sections, improving labels, and adding descriptions for better usability. Adjusted styles to enhance visual hierarchy and provide consistent spacing and formatting throughout.
This commit is contained in:
2026-02-12 15:09:51 +01:00
parent 51eece14c2
commit 7acfb498b4
2 changed files with 69 additions and 26 deletions

View File

@@ -119,24 +119,37 @@ export function AdminUsersPage() {
return ( return (
<div className="admin-settings-page"> <div className="admin-settings-page">
<h2>Admin Settings - Users</h2> <h2>Admin Settings</h2>
<p className="muted admin-page-subtitle">Manage users and outgoing notifications for this NexaPG instance.</p>
{error && <div className="card error">{error}</div>} {error && <div className="card error">{error}</div>}
<div className="card"> <div className="card">
<h3>User Management</h3> <div className="admin-section-head">
<h3>User Management</h3>
<p className="muted">Create accounts and manage access roles.</p>
</div>
<form className="grid three admin-user-form" onSubmit={create}> <form className="grid three admin-user-form" onSubmit={create}>
<input value={form.email} placeholder="E-Mail" onChange={(e) => setForm({ ...form, email: e.target.value })} /> <div className="admin-field">
<input <label>Email</label>
type="password" <input value={form.email} placeholder="user@example.com" onChange={(e) => setForm({ ...form, email: e.target.value })} />
value={form.password} </div>
placeholder="Password" <div className="admin-field">
onChange={(e) => setForm({ ...form, password: e.target.value })} <label>Password</label>
/> <input
<select value={form.role} onChange={(e) => setForm({ ...form, role: e.target.value })}> type="password"
<option value="viewer">viewer</option> value={form.password}
<option value="operator">operator</option> placeholder="Set initial password"
<option value="admin">admin</option> onChange={(e) => setForm({ ...form, password: e.target.value })}
</select> />
</div>
<div className="admin-field">
<label>Role</label>
<select value={form.role} onChange={(e) => setForm({ ...form, role: e.target.value })}>
<option value="viewer">viewer</option>
<option value="operator">operator</option>
<option value="admin">admin</option>
</select>
</div>
<div className="form-actions field-full"> <div className="form-actions field-full">
<button className="primary-btn" type="submit">Create User</button> <button className="primary-btn" type="submit">Create User</button>
</div> </div>
@@ -183,10 +196,10 @@ export function AdminUsersPage() {
</div> </div>
<div className="card"> <div className="card">
<h3>Alert Email Notifications (SMTP)</h3> <div className="admin-section-head">
<p className="muted"> <h3>Alert Email Notifications (SMTP)</h3>
Configure outgoing SMTP for alert emails. This is send-only; no inbound mailbox is used. <p className="muted">Configure send-only SMTP for warning and alert notifications.</p>
</p> </div>
{smtpInfo && <div className="test-connection-result ok">{smtpInfo}</div>} {smtpInfo && <div className="test-connection-result ok">{smtpInfo}</div>}
<form className="grid two admin-smtp-form" onSubmit={saveSmtp}> <form className="grid two admin-smtp-form" onSubmit={saveSmtp}>
<label className="toggle-check field-full"> <label className="toggle-check field-full">
@@ -201,7 +214,7 @@ export function AdminUsersPage() {
</span> </span>
</label> </label>
<div> <div className="admin-field">
<label>SMTP host</label> <label>SMTP host</label>
<input <input
value={emailSettings.smtp_host} value={emailSettings.smtp_host}
@@ -209,7 +222,7 @@ export function AdminUsersPage() {
onChange={(e) => setEmailSettings({ ...emailSettings, smtp_host: e.target.value })} onChange={(e) => setEmailSettings({ ...emailSettings, smtp_host: e.target.value })}
/> />
</div> </div>
<div> <div className="admin-field">
<label>SMTP port</label> <label>SMTP port</label>
<input <input
type="number" type="number"
@@ -218,7 +231,7 @@ export function AdminUsersPage() {
/> />
</div> </div>
<div> <div className="admin-field">
<label>SMTP username</label> <label>SMTP username</label>
<input <input
value={emailSettings.smtp_username} value={emailSettings.smtp_username}
@@ -226,7 +239,7 @@ export function AdminUsersPage() {
onChange={(e) => setEmailSettings({ ...emailSettings, smtp_username: e.target.value })} onChange={(e) => setEmailSettings({ ...emailSettings, smtp_username: e.target.value })}
/> />
</div> </div>
<div> <div className="admin-field">
<label>SMTP password</label> <label>SMTP password</label>
<input <input
type="password" type="password"
@@ -236,7 +249,7 @@ export function AdminUsersPage() {
/> />
</div> </div>
<div> <div className="admin-field">
<label>From email</label> <label>From email</label>
<input <input
value={emailSettings.from_email} value={emailSettings.from_email}
@@ -244,7 +257,7 @@ export function AdminUsersPage() {
onChange={(e) => setEmailSettings({ ...emailSettings, from_email: e.target.value })} onChange={(e) => setEmailSettings({ ...emailSettings, from_email: e.target.value })}
/> />
</div> </div>
<div> <div className="admin-field">
<label>Alert recipients (comma-separated)</label> <label>Alert recipients (comma-separated)</label>
<input <input
value={emailSettings.alert_recipients} value={emailSettings.alert_recipients}

View File

@@ -981,18 +981,47 @@ td {
.admin-settings-page h2 { .admin-settings-page h2 {
margin-top: 4px; margin-top: 4px;
margin-bottom: 14px; margin-bottom: 4px;
} }
.admin-settings-page h3 { .admin-settings-page h3 {
margin-top: 0; margin-top: 0;
margin-bottom: 10px; margin-bottom: 2px;
}
.admin-page-subtitle {
margin: 0 0 14px;
}
.admin-section-head {
margin-bottom: 12px;
padding-bottom: 10px;
border-bottom: 1px solid #264671;
}
.admin-section-head p {
margin: 4px 0 0;
font-size: 13px;
} }
.admin-user-form { .admin-user-form {
gap: 10px; gap: 10px;
} }
.admin-field label {
display: block;
margin-bottom: 6px;
color: #c6d7f1;
font-size: 13px;
font-weight: 600;
}
.admin-field input,
.admin-field select {
width: 100%;
min-height: 38px;
}
.admin-users-table-wrap table tbody .admin-user-row td { .admin-users-table-wrap table tbody .admin-user-row td {
padding-top: 11px; padding-top: 11px;
padding-bottom: 11px; padding-bottom: 11px;
@@ -1045,6 +1074,7 @@ td {
.admin-test-recipient { .admin-test-recipient {
min-width: 260px; min-width: 260px;
max-width: 320px;
} }
.muted { .muted {