@agenticmail/enterprise 0.5.296 → 0.5.297
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-A5LURBEY.js +1519 -0
- package/dist/chunk-WQRGOMQJ.js +4008 -0
- package/dist/chunk-Y3WLLVOK.js +48 -0
- package/dist/cli-agent-WSCDFYMU.js +1778 -0
- package/dist/cli-recover-NXARYVSH.js +487 -0
- package/dist/cli-serve-GTTDOLB7.js +143 -0
- package/dist/cli-verify-RKB6KQN4.js +149 -0
- package/dist/cli.js +5 -5
- package/dist/dashboard/pages/users.js +120 -12
- package/dist/factory-M6E7YAKW.js +9 -0
- package/dist/index.js +3 -3
- package/dist/postgres-LJSV5YUF.js +771 -0
- package/dist/server-VTMQY7VU.js +15 -0
- package/dist/setup-HK4WDXUL.js +20 -0
- package/dist/sqlite-E5KKAJ24.js +503 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +59 -3
- package/src/auth/routes.ts +5 -0
- package/src/dashboard/pages/users.js +120 -12
- package/src/db/adapter.ts +1 -0
- package/src/db/postgres.ts +2 -0
- package/src/db/sqlite.ts +1 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DomainLock
|
|
3
|
+
} from "./chunk-UPU23ZRG.js";
|
|
4
|
+
import "./chunk-KFQGP6VL.js";
|
|
5
|
+
|
|
6
|
+
// src/domain-lock/cli-verify.ts
|
|
7
|
+
function getFlag(args, name) {
|
|
8
|
+
const idx = args.indexOf(name);
|
|
9
|
+
if (idx !== -1 && args[idx + 1]) return args[idx + 1];
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
function hasFlag(args, name) {
|
|
13
|
+
return args.includes(name);
|
|
14
|
+
}
|
|
15
|
+
function detectDbType(url) {
|
|
16
|
+
const u = url.toLowerCase().trim();
|
|
17
|
+
if (u.startsWith("postgres") || u.startsWith("pg:")) return "postgres";
|
|
18
|
+
if (u.startsWith("mysql")) return "mysql";
|
|
19
|
+
if (u.startsWith("mongodb")) return "mongodb";
|
|
20
|
+
if (u.startsWith("libsql") || u.includes(".turso.io")) return "turso";
|
|
21
|
+
if (u.endsWith(".db") || u.endsWith(".sqlite") || u.endsWith(".sqlite3") || u.startsWith("file:")) return "sqlite";
|
|
22
|
+
return "postgres";
|
|
23
|
+
}
|
|
24
|
+
async function runVerifyDomain(args) {
|
|
25
|
+
const { default: chalk } = await import("chalk");
|
|
26
|
+
const { default: ora } = await import("ora");
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log(chalk.bold(" AgenticMail Enterprise \u2014 Domain Verification"));
|
|
29
|
+
console.log("");
|
|
30
|
+
let domain = getFlag(args, "--domain");
|
|
31
|
+
let dnsChallenge;
|
|
32
|
+
let db = null;
|
|
33
|
+
let dbConnected = false;
|
|
34
|
+
const envDbUrl = process.env.DATABASE_URL;
|
|
35
|
+
if (envDbUrl) {
|
|
36
|
+
const dbType = detectDbType(envDbUrl);
|
|
37
|
+
const spinner = ora(`Connecting to database (${dbType})...`).start();
|
|
38
|
+
try {
|
|
39
|
+
const { createAdapter } = await import("./factory-M6E7YAKW.js");
|
|
40
|
+
db = await createAdapter({ type: dbType, connectionString: envDbUrl });
|
|
41
|
+
await db.migrate();
|
|
42
|
+
const settings = await db.getSettings();
|
|
43
|
+
if (!domain && settings?.domain) domain = settings.domain;
|
|
44
|
+
if (settings?.domainDnsChallenge) dnsChallenge = settings.domainDnsChallenge;
|
|
45
|
+
dbConnected = true;
|
|
46
|
+
spinner.succeed(`Connected to ${dbType} database` + (domain ? ` (domain: ${domain})` : ""));
|
|
47
|
+
} catch (err) {
|
|
48
|
+
spinner.warn(`Could not connect via DATABASE_URL: ${err.message}`);
|
|
49
|
+
db = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!dbConnected) {
|
|
53
|
+
const dbPath = getFlag(args, "--db");
|
|
54
|
+
const dbType = getFlag(args, "--db-type") || "sqlite";
|
|
55
|
+
if (dbPath) {
|
|
56
|
+
const spinner = ora(`Connecting to ${dbType} database...`).start();
|
|
57
|
+
try {
|
|
58
|
+
const { createAdapter } = await import("./factory-M6E7YAKW.js");
|
|
59
|
+
db = await createAdapter({ type: dbType, connectionString: dbPath });
|
|
60
|
+
await db.migrate();
|
|
61
|
+
const settings = await db.getSettings();
|
|
62
|
+
if (!domain && settings?.domain) domain = settings.domain;
|
|
63
|
+
if (settings?.domainDnsChallenge) dnsChallenge = settings.domainDnsChallenge;
|
|
64
|
+
dbConnected = true;
|
|
65
|
+
spinner.succeed(`Connected to ${dbType} database`);
|
|
66
|
+
} catch {
|
|
67
|
+
spinner.warn("Could not read local database");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!domain) {
|
|
72
|
+
const { default: inquirer } = await import("inquirer");
|
|
73
|
+
const answer = await inquirer.prompt([{
|
|
74
|
+
type: "input",
|
|
75
|
+
name: "domain",
|
|
76
|
+
message: "Domain to verify:",
|
|
77
|
+
suffix: chalk.dim(" (e.g. agents.yourcompany.com)"),
|
|
78
|
+
validate: (v) => v.includes(".") || "Enter a valid domain",
|
|
79
|
+
filter: (v) => v.trim().toLowerCase()
|
|
80
|
+
}]);
|
|
81
|
+
domain = answer.domain;
|
|
82
|
+
}
|
|
83
|
+
const lock = new DomainLock();
|
|
84
|
+
const maxAttempts = hasFlag(args, "--poll") ? 5 : 1;
|
|
85
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
86
|
+
const spinner = ora(
|
|
87
|
+
maxAttempts > 1 ? `Checking DNS verification (attempt ${attempt}/${maxAttempts})...` : "Checking DNS verification..."
|
|
88
|
+
).start();
|
|
89
|
+
try {
|
|
90
|
+
const result = await lock.checkVerification(domain);
|
|
91
|
+
if (!result.success) {
|
|
92
|
+
spinner.fail("Verification check failed");
|
|
93
|
+
console.log("");
|
|
94
|
+
console.error(chalk.red(` ${result.error}`));
|
|
95
|
+
console.log("");
|
|
96
|
+
if (db) await db.disconnect();
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
if (result.verified) {
|
|
100
|
+
spinner.succeed("Domain verified!");
|
|
101
|
+
if (dbConnected && db) {
|
|
102
|
+
try {
|
|
103
|
+
await db.updateSettings({
|
|
104
|
+
domainStatus: "verified",
|
|
105
|
+
domainVerifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
106
|
+
});
|
|
107
|
+
console.log(chalk.dim(" Database updated with verified status."));
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
console.log("");
|
|
112
|
+
console.log(chalk.green.bold(` \u2713 ${domain} is verified and protected.`));
|
|
113
|
+
console.log(chalk.dim(" Your deployment domain is locked. No other instance can claim it."));
|
|
114
|
+
console.log(chalk.dim(" The system now operates 100% offline \u2014 no outbound calls are made."));
|
|
115
|
+
console.log("");
|
|
116
|
+
if (db) await db.disconnect();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
} catch (err) {
|
|
120
|
+
spinner.warn(`Check failed: ${err.message}`);
|
|
121
|
+
}
|
|
122
|
+
if (attempt < maxAttempts) {
|
|
123
|
+
const waitSpinner = ora(`DNS record not found yet. Retrying in 10 seconds...`).start();
|
|
124
|
+
await new Promise((r) => setTimeout(r, 1e4));
|
|
125
|
+
waitSpinner.stop();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
console.log("");
|
|
129
|
+
console.log(chalk.yellow(" DNS record not detected yet."));
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log(chalk.bold(" Make sure this TXT record exists at your DNS provider:"));
|
|
132
|
+
console.log("");
|
|
133
|
+
console.log(` ${chalk.bold("Host:")} ${chalk.cyan(`_agenticmail-verify.${domain}`)}`);
|
|
134
|
+
console.log(` ${chalk.bold("Type:")} ${chalk.cyan("TXT")}`);
|
|
135
|
+
if (dnsChallenge) {
|
|
136
|
+
console.log(` ${chalk.bold("Value:")} ${chalk.cyan(dnsChallenge)}`);
|
|
137
|
+
} else {
|
|
138
|
+
console.log(` ${chalk.bold("Value:")} ${chalk.dim("(check your dashboard or setup output)")}`);
|
|
139
|
+
}
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log(chalk.dim(" DNS propagation can take up to 48 hours."));
|
|
142
|
+
console.log(chalk.dim(" Run with --poll to retry automatically:"));
|
|
143
|
+
console.log(chalk.dim(` npx @agenticmail/enterprise verify-domain --domain ${domain} --poll`));
|
|
144
|
+
console.log("");
|
|
145
|
+
if (db) await db.disconnect();
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
runVerifyDomain
|
|
149
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -14,10 +14,10 @@ switch (command) {
|
|
|
14
14
|
import("./cli-submit-skill-LDFJGSKO.js").then((m) => m.runSubmitSkill(args.slice(1))).catch(fatal);
|
|
15
15
|
break;
|
|
16
16
|
case "recover":
|
|
17
|
-
import("./cli-recover-
|
|
17
|
+
import("./cli-recover-NXARYVSH.js").then((m) => m.runRecover(args.slice(1))).catch(fatal);
|
|
18
18
|
break;
|
|
19
19
|
case "verify-domain":
|
|
20
|
-
import("./cli-verify-
|
|
20
|
+
import("./cli-verify-RKB6KQN4.js").then((m) => m.runVerifyDomain(args.slice(1))).catch(fatal);
|
|
21
21
|
break;
|
|
22
22
|
case "reset-password":
|
|
23
23
|
import("./cli-reset-password-SO5Y6MW7.js").then((m) => m.runResetPassword(args.slice(1))).catch(fatal);
|
|
@@ -57,14 +57,14 @@ Skill Development:
|
|
|
57
57
|
break;
|
|
58
58
|
case "serve":
|
|
59
59
|
case "start":
|
|
60
|
-
import("./cli-serve-
|
|
60
|
+
import("./cli-serve-GTTDOLB7.js").then((m) => m.runServe(args.slice(1))).catch(fatal);
|
|
61
61
|
break;
|
|
62
62
|
case "agent":
|
|
63
|
-
import("./cli-agent-
|
|
63
|
+
import("./cli-agent-WSCDFYMU.js").then((m) => m.runAgent(args.slice(1))).catch(fatal);
|
|
64
64
|
break;
|
|
65
65
|
case "setup":
|
|
66
66
|
default:
|
|
67
|
-
import("./setup-
|
|
67
|
+
import("./setup-HK4WDXUL.js").then((m) => m.runSetupWizard()).catch(fatal);
|
|
68
68
|
break;
|
|
69
69
|
}
|
|
70
70
|
function fatal(err) {
|
|
@@ -295,7 +295,8 @@ function InlinePermissionPicker({ permissions, pageRegistry, onChange }) {
|
|
|
295
295
|
// ─── Users Page ────────────────────────────────────
|
|
296
296
|
|
|
297
297
|
export function UsersPage() {
|
|
298
|
-
var
|
|
298
|
+
var app = useApp();
|
|
299
|
+
var toast = app.toast;
|
|
299
300
|
var [users, setUsers] = useState([]);
|
|
300
301
|
var [creating, setCreating] = useState(false);
|
|
301
302
|
var [form, setForm] = useState({ email: '', password: '', name: '', role: 'viewer', permissions: '*' });
|
|
@@ -343,22 +344,39 @@ export function UsersPage() {
|
|
|
343
344
|
setResetting(false);
|
|
344
345
|
};
|
|
345
346
|
|
|
346
|
-
var
|
|
347
|
+
var toggleActive = async function(user) {
|
|
348
|
+
var action = user.isActive === false ? 'reactivate' : 'deactivate';
|
|
347
349
|
var ok = await showConfirm({
|
|
348
|
-
title: '
|
|
349
|
-
message:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
350
|
+
title: action === 'deactivate' ? 'Deactivate User' : 'Reactivate User',
|
|
351
|
+
message: action === 'deactivate'
|
|
352
|
+
? 'Deactivate "' + (user.name || user.email) + '"? They will be unable to log in and will see a message to contact their organization.'
|
|
353
|
+
: 'Reactivate "' + (user.name || user.email) + '"? They will be able to log in again.',
|
|
354
|
+
danger: action === 'deactivate',
|
|
355
|
+
confirmText: action === 'deactivate' ? 'Deactivate' : 'Reactivate'
|
|
353
356
|
});
|
|
354
357
|
if (!ok) return;
|
|
355
358
|
try {
|
|
356
|
-
await apiCall('/users/' + user.id, { method: '
|
|
357
|
-
toast('User
|
|
359
|
+
await apiCall('/users/' + user.id + '/' + action, { method: 'POST' });
|
|
360
|
+
toast('User ' + action + 'd', 'success');
|
|
358
361
|
load();
|
|
359
362
|
} catch (e) { toast(e.message, 'error'); }
|
|
360
363
|
};
|
|
361
364
|
|
|
365
|
+
var [deleteStep, setDeleteStep] = useState(0);
|
|
366
|
+
var [deleteTarget, setDeleteTarget] = useState(null);
|
|
367
|
+
var [deleteTyped, setDeleteTyped] = useState('');
|
|
368
|
+
|
|
369
|
+
var startDelete = function(user) { setDeleteTarget(user); setDeleteStep(1); setDeleteTyped(''); };
|
|
370
|
+
var cancelDelete = function() { setDeleteTarget(null); setDeleteStep(0); setDeleteTyped(''); };
|
|
371
|
+
|
|
372
|
+
var confirmDelete = async function() {
|
|
373
|
+
try {
|
|
374
|
+
await apiCall('/users/' + deleteTarget.id, { method: 'DELETE', body: JSON.stringify({ confirmationToken: 'DELETE_USER_' + deleteTarget.email }) });
|
|
375
|
+
toast('User permanently deleted', 'success');
|
|
376
|
+
cancelDelete(); load();
|
|
377
|
+
} catch (e) { toast(e.message, 'error'); }
|
|
378
|
+
};
|
|
379
|
+
|
|
362
380
|
var openPermissions = async function(user) {
|
|
363
381
|
try {
|
|
364
382
|
var d = await apiCall('/users/' + user.id + '/permissions');
|
|
@@ -485,18 +503,100 @@ export function UsersPage() {
|
|
|
485
503
|
onClose: function() { setPermTarget(null); }
|
|
486
504
|
}),
|
|
487
505
|
|
|
506
|
+
// 5-step delete confirmation modal
|
|
507
|
+
deleteTarget && h(Modal, {
|
|
508
|
+
title: 'Delete User — Step ' + deleteStep + ' of 5',
|
|
509
|
+
onClose: cancelDelete,
|
|
510
|
+
width: 480,
|
|
511
|
+
footer: h(Fragment, null,
|
|
512
|
+
h('button', { className: 'btn btn-secondary', onClick: deleteStep === 1 ? cancelDelete : function() { setDeleteStep(deleteStep - 1); } }, deleteStep === 1 ? 'Cancel' : 'Back'),
|
|
513
|
+
deleteStep < 5
|
|
514
|
+
? h('button', { className: 'btn btn-' + (deleteStep >= 3 ? 'danger' : 'primary'), onClick: function() { setDeleteStep(deleteStep + 1); } }, 'Continue')
|
|
515
|
+
: h('button', { className: 'btn btn-danger', onClick: confirmDelete, disabled: deleteTyped !== deleteTarget.email }, 'Permanently Delete')
|
|
516
|
+
)
|
|
517
|
+
},
|
|
518
|
+
// Step 1: Warning
|
|
519
|
+
deleteStep === 1 && h('div', null,
|
|
520
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, padding: 16, background: 'var(--danger-soft, rgba(220,38,38,0.08))', borderRadius: 8, marginBottom: 16 } },
|
|
521
|
+
h('svg', { width: 24, height: 24, viewBox: '0 0 24 24', fill: 'none', stroke: 'var(--danger)', strokeWidth: 2 }, h('path', { d: 'M12 9v4m0 4h.01M10.29 3.86l-8.6 14.86A2 2 0 0 0 3.4 21h17.2a2 2 0 0 0 1.71-2.98L13.71 3.86a2 2 0 0 0-3.42 0z' })),
|
|
522
|
+
h('div', null,
|
|
523
|
+
h('strong', null, 'Permanent Deletion'),
|
|
524
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginTop: 2 } }, 'This action cannot be undone.')
|
|
525
|
+
)
|
|
526
|
+
),
|
|
527
|
+
h('p', { style: { fontSize: 13 } }, 'You are about to permanently delete the user account for:'),
|
|
528
|
+
h('div', { style: { padding: 12, background: 'var(--bg-tertiary)', borderRadius: 8, marginTop: 8 } },
|
|
529
|
+
h('strong', null, deleteTarget.name || 'Unnamed'), h('br'),
|
|
530
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)' } }, deleteTarget.email)
|
|
531
|
+
),
|
|
532
|
+
h('p', { style: { fontSize: 12, color: 'var(--text-muted)', marginTop: 12 } }, 'Consider deactivating instead — deactivated users can be reactivated later.')
|
|
533
|
+
),
|
|
534
|
+
// Step 2: Data loss
|
|
535
|
+
deleteStep === 2 && h('div', null,
|
|
536
|
+
h('h4', { style: { marginBottom: 12 } }, 'Data That Will Be Lost'),
|
|
537
|
+
h('ul', { style: { paddingLeft: 20, fontSize: 13, lineHeight: 1.8 } },
|
|
538
|
+
h('li', null, 'All login sessions will be terminated immediately'),
|
|
539
|
+
h('li', null, 'Audit log entries will be orphaned (no user reference)'),
|
|
540
|
+
h('li', null, 'Any API keys created by this user will be revoked'),
|
|
541
|
+
h('li', null, 'Permission grants and role assignments will be removed'),
|
|
542
|
+
h('li', null, '2FA configuration and backup codes will be destroyed')
|
|
543
|
+
)
|
|
544
|
+
),
|
|
545
|
+
// Step 3: Impact
|
|
546
|
+
deleteStep === 3 && h('div', null,
|
|
547
|
+
h('h4', { style: { marginBottom: 12 } }, 'Impact Assessment'),
|
|
548
|
+
h('div', { style: { padding: 12, background: 'var(--warning-soft, rgba(245,158,11,0.08))', borderRadius: 8, fontSize: 13, lineHeight: 1.6 } },
|
|
549
|
+
h('p', null, 'If this user manages or supervises any agents, those agents will lose their manager assignment.'),
|
|
550
|
+
h('p', { style: { marginTop: 8 } }, 'If this user created approval workflows, pending approvals may become orphaned.'),
|
|
551
|
+
h('p', { style: { marginTop: 8 } }, 'Any scheduled tasks or cron jobs created by this user will continue to run but cannot be modified.')
|
|
552
|
+
)
|
|
553
|
+
),
|
|
554
|
+
// Step 4: Alternative
|
|
555
|
+
deleteStep === 4 && h('div', null,
|
|
556
|
+
h('h4', { style: { marginBottom: 12 } }, 'Are You Sure?'),
|
|
557
|
+
h('div', { style: { padding: 16, background: 'var(--success-soft, rgba(21,128,61,0.08))', borderRadius: 8, marginBottom: 16 } },
|
|
558
|
+
h('strong', null, 'Recommended alternative: Deactivate'),
|
|
559
|
+
h('p', { style: { fontSize: 12, color: 'var(--text-secondary)', marginTop: 4 } }, 'Deactivating blocks login while preserving all data. The user can be reactivated at any time. This is the safe option.')
|
|
560
|
+
),
|
|
561
|
+
h('div', { style: { padding: 16, background: 'var(--danger-soft, rgba(220,38,38,0.08))', borderRadius: 8 } },
|
|
562
|
+
h('strong', null, 'Permanent deletion'),
|
|
563
|
+
h('p', { style: { fontSize: 12, color: 'var(--text-secondary)', marginTop: 4 } }, 'Removes the user and all associated data forever. There is no recovery.')
|
|
564
|
+
)
|
|
565
|
+
),
|
|
566
|
+
// Step 5: Type email to confirm
|
|
567
|
+
deleteStep === 5 && h('div', null,
|
|
568
|
+
h('h4', { style: { marginBottom: 12, color: 'var(--danger)' } }, 'Final Confirmation'),
|
|
569
|
+
h('p', { style: { fontSize: 13, marginBottom: 12 } }, 'Type the user\'s email address to confirm permanent deletion:'),
|
|
570
|
+
h('div', { style: { padding: 8, background: 'var(--bg-tertiary)', borderRadius: 6, fontFamily: 'var(--font-mono)', fontSize: 13, textAlign: 'center', marginBottom: 12 } }, deleteTarget.email),
|
|
571
|
+
h('input', {
|
|
572
|
+
className: 'input', type: 'text', value: deleteTyped,
|
|
573
|
+
onChange: function(e) { setDeleteTyped(e.target.value); },
|
|
574
|
+
placeholder: 'Type email to confirm',
|
|
575
|
+
autoFocus: true,
|
|
576
|
+
style: { fontFamily: 'var(--font-mono)', fontSize: 13, borderColor: deleteTyped === deleteTarget.email ? 'var(--danger)' : 'var(--border)' }
|
|
577
|
+
}),
|
|
578
|
+
deleteTyped && deleteTyped !== deleteTarget.email && h('div', { style: { fontSize: 11, color: 'var(--danger)', marginTop: 4 } }, 'Email does not match')
|
|
579
|
+
)
|
|
580
|
+
),
|
|
581
|
+
|
|
488
582
|
// Users table
|
|
489
583
|
h('div', { className: 'card' },
|
|
490
584
|
h('div', { className: 'card-body-flush' },
|
|
491
585
|
users.length === 0 ? h('div', { style: { padding: 24, textAlign: 'center', color: 'var(--text-muted)' } }, 'No users')
|
|
492
586
|
: h('table', null,
|
|
493
|
-
h('thead', null, h('tr', null, h('th', null, 'Name'), h('th', null, 'Email'), h('th', null, 'Role'), h('th', null, 'Access'), h('th', null, '2FA'), h('th', null, 'Created'), h('th', { style: { width:
|
|
587
|
+
h('thead', null, h('tr', null, h('th', null, 'Name'), h('th', null, 'Email'), h('th', null, 'Role'), h('th', null, 'Status'), h('th', null, 'Access'), h('th', null, '2FA'), h('th', null, 'Created'), h('th', { style: { width: 200 } }, 'Actions'))),
|
|
494
588
|
h('tbody', null, users.map(function(u) {
|
|
495
589
|
var isRestricted = u.role === 'member' || u.role === 'viewer';
|
|
496
|
-
|
|
590
|
+
var isDeactivated = u.isActive === false;
|
|
591
|
+
var isSelf = u.id === ((app || {}).user || {}).id;
|
|
592
|
+
return h('tr', { key: u.id, style: isDeactivated ? { opacity: 0.6 } : {} },
|
|
497
593
|
h('td', null, h('strong', null, u.name || '-')),
|
|
498
594
|
h('td', null, h('span', { style: { fontFamily: 'var(--font-mono)', fontSize: 12 } }, u.email)),
|
|
499
595
|
h('td', null, h('span', { className: 'badge badge-' + (u.role === 'owner' ? 'warning' : u.role === 'admin' ? 'primary' : 'neutral') }, u.role)),
|
|
596
|
+
h('td', null, isDeactivated
|
|
597
|
+
? h('span', { className: 'badge badge-danger', style: { fontSize: 10 } }, 'Deactivated')
|
|
598
|
+
: h('span', { className: 'badge badge-success', style: { fontSize: 10 } }, 'Active')
|
|
599
|
+
),
|
|
500
600
|
h('td', null, permBadge(u)),
|
|
501
601
|
h('td', null, u.totpEnabled ? h('span', { className: 'badge badge-success' }, 'On') : h('span', { className: 'badge badge-neutral' }, 'Off')),
|
|
502
602
|
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, u.createdAt ? new Date(u.createdAt).toLocaleDateString() : '-'),
|
|
@@ -509,7 +609,15 @@ export function UsersPage() {
|
|
|
509
609
|
style: !isRestricted ? { opacity: 0.4 } : {}
|
|
510
610
|
}, I.shield()),
|
|
511
611
|
h('button', { className: 'btn btn-ghost btn-sm', title: 'Reset Password', onClick: function() { setResetTarget(u); setNewPassword(''); } }, I.lock()),
|
|
512
|
-
|
|
612
|
+
// Deactivate / Reactivate
|
|
613
|
+
!isSelf && h('button', {
|
|
614
|
+
className: 'btn btn-ghost btn-sm',
|
|
615
|
+
title: isDeactivated ? 'Reactivate User' : 'Deactivate User',
|
|
616
|
+
onClick: function() { toggleActive(u); },
|
|
617
|
+
style: { color: isDeactivated ? 'var(--success, #15803d)' : 'var(--warning, #f59e0b)' }
|
|
618
|
+
}, isDeactivated ? I.check() : I.pause()),
|
|
619
|
+
// Delete (owner only)
|
|
620
|
+
!isSelf && h('button', { className: 'btn btn-ghost btn-sm', title: 'Delete User Permanently', onClick: function() { startDelete(u); }, style: { color: 'var(--danger)' } }, I.trash())
|
|
513
621
|
)
|
|
514
622
|
)
|
|
515
623
|
);
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
provision,
|
|
3
3
|
runSetupWizard
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-A5LURBEY.js";
|
|
5
5
|
import {
|
|
6
6
|
AgenticMailManager,
|
|
7
7
|
GoogleEmailProvider,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
requireRole,
|
|
43
43
|
securityHeaders,
|
|
44
44
|
validate
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-WQRGOMQJ.js";
|
|
46
46
|
import "./chunk-OF4MUWWS.js";
|
|
47
47
|
import {
|
|
48
48
|
PROVIDER_REGISTRY,
|
|
@@ -113,7 +113,7 @@ import {
|
|
|
113
113
|
import {
|
|
114
114
|
createAdapter,
|
|
115
115
|
getSupportedDatabases
|
|
116
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-Y3WLLVOK.js";
|
|
117
117
|
import {
|
|
118
118
|
AGENTICMAIL_TOOLS,
|
|
119
119
|
ALL_TOOLS,
|