email: single-mailbox enroll field on Email Capture panel — v0.1.0:60

Adds a "Test with a single mailbox first" input (pre-filled with the admin's own
address) + Enroll this mailbox button calling the enroll-one endpoint, so capture
can be tried on one mailbox before enrolling the whole domain. runAction now sends
an optional JSON body. Enroll-all stays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Keysat
2026-06-06 12:10:09 -05:00
parent ee02ccfd64
commit 1850bc4431
4 changed files with 53 additions and 9 deletions
+31 -5
View File
@@ -9955,6 +9955,7 @@
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [busy, setBusy] = useState('');
const [oneEmail, setOneEmail] = useState(() => user?.email || '');
const load = useCallback(async () => {
let s;
@@ -9991,12 +9992,14 @@
return () => { cancelled = true; };
}, [load]);
const runAction = async (key, endpoint, successMsg, confirmMsg) => {
const runAction = async (key, endpoint, successMsg, confirmMsg, body) => {
if (busy) return;
if (confirmMsg && !window.confirm(confirmMsg)) return;
try {
setBusy(key);
const res = await api(endpoint, { method: 'POST' }, token);
const opts = { method: 'POST' };
if (body) opts.body = JSON.stringify(body);
const res = await api(endpoint, opts, token);
onShowToast(typeof successMsg === 'function' ? successMsg(res) : successMsg, 'success');
} catch (err) {
onShowToast(getErrorMessage(err, 'Action failed'), 'error');
@@ -10060,12 +10063,35 @@
{isAdmin && (
<div className="section">
<div className="section-title">Actions</div>
<div className="index-action-buttons">
<div className="index-action-hint" style={{ marginTop: 0, marginBottom: '8px' }}>
Test with a single mailbox first:
</div>
<div className="index-action-buttons" style={{ alignItems: 'center', marginBottom: '16px' }}>
<input
className="text-input"
type="email"
placeholder="name@ten31.xyz"
value={oneEmail}
onChange={(e) => setOneEmail(e.target.value)}
style={{ maxWidth: '260px' }}
/>
<button
onClick={() => runAction('enroll', '/api/email/accounts/enroll-all', (r) => `Enrolled ${r?.count ?? 0} mailbox(es)`, 'Enroll all Ten31 mailboxes for capture? This connects each active @ten31.xyz users Gmail via the service account. Domain-wide delegation must already be authorized in Google Workspace admin.')}
onClick={() => {
const addr = (oneEmail || '').trim();
if (!addr) { onShowToast('Enter a mailbox address', 'error'); return; }
runAction('enroll-one', '/api/email/accounts/enroll', (r) => `Enrolled ${r?.email || addr}`, `Enroll just ${addr} for capture?`, { email: addr });
}}
disabled={!enabled || !!busy}
>
{busy === 'enroll' ? 'Enrolling…' : 'Enroll Ten31 mailboxes'}
{busy === 'enroll-one' ? 'Enrolling…' : 'Enroll this mailbox'}
</button>
</div>
<div className="index-action-buttons">
<button
onClick={() => runAction('enroll', '/api/email/accounts/enroll-all', (r) => `Enrolled ${r?.count ?? 0} mailbox(es)`, 'Enroll ALL Ten31 mailboxes for capture? This connects every active @ten31.xyz users Gmail via the service account. Domain-wide delegation must already be authorized in Google Workspace admin.')}
disabled={!enabled || !!busy}
>
{busy === 'enroll' ? 'Enrolling…' : 'Enroll all Ten31 mailboxes'}
</button>
<button
onClick={() => runAction('sync', '/api/email/sync/run-now', 'Sync started')}