@agenticmail/enterprise 0.5.304 → 0.5.306
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-4QGERCWK.js +4400 -0
- package/dist/chunk-N5JFOIJN.js +1519 -0
- package/dist/cli-serve-KZT4WNKR.js +143 -0
- package/dist/cli.js +2 -2
- package/dist/dashboard/pages/approvals.js +2 -2
- package/dist/dashboard/pages/dashboard.js +6 -5
- package/dist/dashboard/pages/guardrails.js +2 -2
- package/dist/dashboard/pages/journal.js +2 -2
- package/dist/dashboard/pages/knowledge-contributions.js +1 -1
- package/dist/dashboard/pages/knowledge.js +14 -5
- package/dist/dashboard/pages/messages.js +2 -2
- package/dist/dashboard/pages/org-chart.js +2 -2
- package/dist/dashboard/pages/task-pipeline.js +17 -7
- package/dist/dashboard/pages/users.js +90 -1
- package/dist/dashboard/pages/workforce.js +2 -2
- package/dist/index.js +2 -2
- package/dist/server-43HP7BAB.js +15 -0
- package/dist/setup-2NQBX5FF.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +8 -2
- package/src/dashboard/pages/approvals.js +2 -2
- package/src/dashboard/pages/dashboard.js +6 -5
- package/src/dashboard/pages/guardrails.js +2 -2
- package/src/dashboard/pages/journal.js +2 -2
- package/src/dashboard/pages/knowledge-contributions.js +1 -1
- package/src/dashboard/pages/knowledge.js +14 -5
- package/src/dashboard/pages/messages.js +2 -2
- package/src/dashboard/pages/org-chart.js +2 -2
- package/src/dashboard/pages/task-pipeline.js +17 -7
- package/src/dashboard/pages/users.js +66 -1
- package/src/dashboard/pages/workforce.js +2 -2
|
@@ -48,7 +48,7 @@ export function SetupChecklist({ onNavigate }) {
|
|
|
48
48
|
|
|
49
49
|
export function DashboardPage() {
|
|
50
50
|
var orgCtx = useOrgContext();
|
|
51
|
-
var
|
|
51
|
+
var clientOrgFilter = orgCtx.selectedOrgId || '';
|
|
52
52
|
const [stats, setStats] = useState(null);
|
|
53
53
|
const [agents, setAgents] = useState([]);
|
|
54
54
|
const [events, setEvents] = useState([]);
|
|
@@ -59,11 +59,12 @@ export function DashboardPage() {
|
|
|
59
59
|
var selectedEvent = _selectedEvent[0]; var setSelectedEvent = _selectedEvent[1];
|
|
60
60
|
|
|
61
61
|
useEffect(() => {
|
|
62
|
+
var agentUrl = clientOrgFilter ? '/agents?clientOrgId=' + clientOrgFilter : '/agents';
|
|
62
63
|
apiCall('/stats').then(setStats).catch(() => {});
|
|
63
|
-
apiCall(
|
|
64
|
-
engineCall('/agents?orgId=' +
|
|
64
|
+
apiCall(agentUrl).then(d => setAgents(d.agents || d || [])).catch(() => {});
|
|
65
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setEngineAgents(d.agents || [])).catch(() => {});
|
|
65
66
|
engineCall('/activity/events?limit=10').then(d => setEvents(d.events || [])).catch(() => {});
|
|
66
|
-
}, [
|
|
67
|
+
}, [clientOrgFilter]);
|
|
67
68
|
|
|
68
69
|
// Merge admin + engine agents; engine agents (appended last) win in the data map
|
|
69
70
|
var mergedForMap = [].concat(agents, engineAgents);
|
|
@@ -81,7 +82,7 @@ export function DashboardPage() {
|
|
|
81
82
|
h('div', { className: 'stat-grid' },
|
|
82
83
|
h('div', { className: 'stat-card' }, h('div', { className: 'stat-label', style: { display: 'flex', alignItems: 'center' } }, 'Total Agents', h(HelpButton, { label: 'Total Agents' },
|
|
83
84
|
h('p', null, 'The total number of agents created in your organization, including active, paused, and archived agents.')
|
|
84
|
-
)), h('div', { className: 'stat-value' }, stats?.totalAgents ?? agents.length ?? '-')),
|
|
85
|
+
)), h('div', { className: 'stat-value' }, clientOrgFilter ? agents.length : (stats?.totalAgents ?? agents.length ?? '-'))),
|
|
85
86
|
h('div', { className: 'stat-card' }, h('div', { className: 'stat-label', style: { display: 'flex', alignItems: 'center' } }, 'Active Agents', h(HelpButton, { label: 'Active Agents' },
|
|
86
87
|
h('p', null, 'Agents currently running and available to process tasks. If this is lower than Total Agents, some agents may be paused or archived.')
|
|
87
88
|
)), h('div', { className: 'stat-value', style: { color: 'var(--success)' } }, (stats?.activeAgents ?? agents.filter(function(a) { return a.status === 'active'; }).length) || '-')),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { HelpButton } from '../components/help-button.js';
|
|
4
4
|
import { useOrgContext } from '../components/org-switcher.js';
|
|
@@ -104,7 +104,7 @@ export function GuardrailsPage() {
|
|
|
104
104
|
var _ag = useState([]);
|
|
105
105
|
var agents = _ag[0]; var setAgents = _ag[1];
|
|
106
106
|
useEffect(function() {
|
|
107
|
-
|
|
107
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).then(function(d) { setAgents(d.agents || []); }).catch(function() {});
|
|
108
108
|
}, []);
|
|
109
109
|
|
|
110
110
|
var TABS = [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { HelpButton } from '../components/help-button.js';
|
|
4
4
|
import { useOrgContext } from '../components/org-switcher.js';
|
|
@@ -16,7 +16,7 @@ export function JournalPage() {
|
|
|
16
16
|
const load = () => {
|
|
17
17
|
engineCall('/journal?orgId=' + effectiveOrgId + '&limit=50').then(d => { setEntries(d.entries || []); setTotal(d.total || 0); }).catch(() => {});
|
|
18
18
|
engineCall('/journal/stats/default').then(d => setStats(d)).catch(() => {});
|
|
19
|
-
|
|
19
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
20
20
|
};
|
|
21
21
|
useEffect(load, []);
|
|
22
22
|
|
|
@@ -42,7 +42,7 @@ export function KnowledgeContributionsPage() {
|
|
|
42
42
|
var [searchAgentFilter, setSearchAgentFilter] = useState('');
|
|
43
43
|
|
|
44
44
|
// Effective org ID: uses client org if selected, else default
|
|
45
|
-
var effectiveOrgId = orgCtx.selectedOrgId ||
|
|
45
|
+
var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
|
|
46
46
|
|
|
47
47
|
var loadBases = useCallback(function() {
|
|
48
48
|
Promise.all([
|
|
@@ -17,7 +17,7 @@ export function KnowledgeBasePage() {
|
|
|
17
17
|
const [chunks, setChunks] = useState([]);
|
|
18
18
|
const [selectedDoc, setSelectedDoc] = useState(null);
|
|
19
19
|
const [editing, setEditing] = useState(false);
|
|
20
|
-
const [editForm, setEditForm] = useState({ name: '', description: '' });
|
|
20
|
+
const [editForm, setEditForm] = useState({ name: '', description: '', clientOrgId: '' });
|
|
21
21
|
const [loading, setLoading] = useState(false);
|
|
22
22
|
const [showImport, setShowImport] = useState(false);
|
|
23
23
|
const [importKb, setImportKb] = useState(null);
|
|
@@ -54,7 +54,7 @@ export function KnowledgeBasePage() {
|
|
|
54
54
|
setDocs(kbData.documents || []);
|
|
55
55
|
setChunks([]);
|
|
56
56
|
setSelectedDoc(null);
|
|
57
|
-
setEditForm({ name: kbData.name || '', description: kbData.description || '' });
|
|
57
|
+
setEditForm({ name: kbData.name || '', description: kbData.description || '', clientOrgId: kbData.clientOrgId || '' });
|
|
58
58
|
} catch (e) {
|
|
59
59
|
toast('Failed to load knowledge base: ' + e.message, 'error');
|
|
60
60
|
}
|
|
@@ -122,9 +122,9 @@ export function KnowledgeBasePage() {
|
|
|
122
122
|
const saveEdit = async () => {
|
|
123
123
|
if (!selected) return;
|
|
124
124
|
try {
|
|
125
|
-
await engineCall('/knowledge-bases/' + selected.id, { method: 'PUT', body: JSON.stringify({ name: editForm.name, description: editForm.description }) });
|
|
125
|
+
await engineCall('/knowledge-bases/' + selected.id, { method: 'PUT', body: JSON.stringify({ name: editForm.name, description: editForm.description, clientOrgId: editForm.clientOrgId || null }) });
|
|
126
126
|
toast('Knowledge base updated', 'success');
|
|
127
|
-
setSelected(s => ({ ...s, name: editForm.name, description: editForm.description }));
|
|
127
|
+
setSelected(s => ({ ...s, name: editForm.name, description: editForm.description, clientOrgId: editForm.clientOrgId }));
|
|
128
128
|
setEditing(false);
|
|
129
129
|
load();
|
|
130
130
|
} catch (e) { toast(e.message, 'error'); }
|
|
@@ -171,7 +171,16 @@ export function KnowledgeBasePage() {
|
|
|
171
171
|
h('div', { className: 'card', style: { marginBottom: 16 } },
|
|
172
172
|
h('div', { className: 'card-body' },
|
|
173
173
|
editing
|
|
174
|
-
? h(
|
|
174
|
+
? h(Fragment, null,
|
|
175
|
+
h('textarea', { className: 'input', rows: 3, value: editForm.description, onChange: e => setEditForm(f => ({ ...f, description: e.target.value })), placeholder: 'Knowledge base description...', style: { marginBottom: 8 } }),
|
|
176
|
+
clientOrgs.length > 0 && h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
|
|
177
|
+
h('label', { style: { fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap' } }, 'Organization:'),
|
|
178
|
+
h('select', { className: 'input', value: editForm.clientOrgId, onChange: e => setEditForm(f => ({ ...f, clientOrgId: e.target.value })), style: { fontSize: 12, maxWidth: 250 } },
|
|
179
|
+
h('option', { value: '' }, 'My Organization (internal)'),
|
|
180
|
+
clientOrgs.filter(o => o.is_active !== false).map(o => h('option', { key: o.id, value: o.id }, o.name))
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
)
|
|
175
184
|
: h('p', { style: { color: 'var(--text-secondary)', fontSize: 13, margin: 0 } }, selected.description || 'No description'),
|
|
176
185
|
h('div', { style: { display: 'flex', gap: 12, marginTop: 12, fontSize: 12, color: 'var(--text-muted)' } },
|
|
177
186
|
h('span', null, 'ID: ', h('code', null, selected.id)),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useRef, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useRef, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { HelpButton } from '../components/help-button.js';
|
|
4
4
|
import { useOrgContext } from '../components/org-switcher.js';
|
|
@@ -22,7 +22,7 @@ export function MessagesPage() {
|
|
|
22
22
|
engineCall('/messages?orgId=' + effectiveOrgId + '&limit=100').then(d => setMessages(d.messages || [])).catch(() => {});
|
|
23
23
|
};
|
|
24
24
|
const loadAgents = () => {
|
|
25
|
-
|
|
25
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
26
26
|
};
|
|
27
27
|
const loadTopology = () => {
|
|
28
28
|
engineCall('/messages/topology?orgId=' + effectiveOrgId).then(d => setTopology(d.topology || null)).catch(() => {});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, useRef, Fragment, useApp, engineCall, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, useRef, Fragment, useApp, engineCall, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { HelpButton } from '../components/help-button.js';
|
|
4
4
|
import { useOrgContext } from '../components/org-switcher.js';
|
|
@@ -154,7 +154,7 @@ export function OrgChartPage() {
|
|
|
154
154
|
setLoading(true); setError(null);
|
|
155
155
|
Promise.all([
|
|
156
156
|
engineCall('/hierarchy/org-chart').catch(function() { return null; }),
|
|
157
|
-
|
|
157
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).catch(function() { return { agents: [] }; }),
|
|
158
158
|
]).then(function(res) {
|
|
159
159
|
var hierRes = res[0]; var agentRes = res[1];
|
|
160
160
|
var avatarMap = {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, useRef, Fragment, useApp, engineCall, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, useRef, Fragment, useApp, engineCall, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { HelpButton } from '../components/help-button.js';
|
|
4
4
|
import { useOrgContext } from '../components/org-switcher.js';
|
|
@@ -440,7 +440,7 @@ export function TaskPipelinePage() {
|
|
|
440
440
|
var app = useApp();
|
|
441
441
|
var toast = app.toast;
|
|
442
442
|
var orgCtx = useOrgContext();
|
|
443
|
-
var effectiveOrgId = orgCtx.selectedOrgId ||
|
|
443
|
+
var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
|
|
444
444
|
var _tasks = useState([]);
|
|
445
445
|
var tasks = _tasks[0]; var setTasks = _tasks[1];
|
|
446
446
|
var _stats = useState({ created: 0, assigned: 0, inProgress: 0, completed: 0, failed: 0, cancelled: 0, total: 0, todayCompleted: 0, todayFailed: 0, todayCreated: 0, avgDurationMs: 0, totalCost: 0, totalTokens: 0, topAgents: [] });
|
|
@@ -477,16 +477,26 @@ export function TaskPipelinePage() {
|
|
|
477
477
|
Promise.all([
|
|
478
478
|
engineCall('/task-pipeline?limit=200'),
|
|
479
479
|
engineCall('/task-pipeline/stats'),
|
|
480
|
-
|
|
480
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).catch(function() { return { agents: [] }; }),
|
|
481
481
|
]).then(function(res) {
|
|
482
|
-
|
|
483
|
-
|
|
482
|
+
var allTasks = res[0]?.tasks || [];
|
|
483
|
+
var orgAgents = res[2]?.agents || [];
|
|
484
484
|
// Build agent avatar/name map
|
|
485
485
|
var map = {};
|
|
486
|
-
|
|
487
|
-
map[a.id] = { name: a.config?.name || a.id, avatar: a.config?.identity?.avatar || a.config?.avatar || a.config?.persona?.avatar || null };
|
|
486
|
+
orgAgents.forEach(function(a) {
|
|
487
|
+
map[a.id] = { name: a.config?.name || a.name || a.id, avatar: a.config?.identity?.avatar || a.config?.avatar || a.config?.persona?.avatar || null };
|
|
488
488
|
});
|
|
489
489
|
setAgentMap(map);
|
|
490
|
+
// Filter tasks by org's agents when org is selected
|
|
491
|
+
if (orgCtx.selectedOrgId && orgAgents.length > 0) {
|
|
492
|
+
var agentIds = {};
|
|
493
|
+
orgAgents.forEach(function(a) { agentIds[a.id] = true; });
|
|
494
|
+
allTasks = allTasks.filter(function(t) { return agentIds[t.assignedAgent] || agentIds[t.createdBy]; });
|
|
495
|
+
} else if (orgCtx.selectedOrgId && orgAgents.length === 0) {
|
|
496
|
+
allTasks = []; // No agents in this org = no tasks
|
|
497
|
+
}
|
|
498
|
+
setTasks(allTasks);
|
|
499
|
+
setStats(res[1] || stats);
|
|
490
500
|
}).catch(function(err) { console.error('[TaskPipeline]', err); })
|
|
491
501
|
.finally(function() { setLoading(false); });
|
|
492
502
|
}, [effectiveOrgId]);
|
|
@@ -494,6 +494,21 @@ export function UsersPage() {
|
|
|
494
494
|
setResetting(false);
|
|
495
495
|
};
|
|
496
496
|
|
|
497
|
+
var openEditUser = function(u) {
|
|
498
|
+
setEditUser(u);
|
|
499
|
+
setEditForm({ name: u.name || '', role: u.role || 'viewer', clientOrgId: u.clientOrgId || '' });
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
var doEditUser = async function() {
|
|
503
|
+
if (!editUser) return;
|
|
504
|
+
try {
|
|
505
|
+
await apiCall('/users/' + editUser.id, { method: 'PATCH', body: JSON.stringify({ name: editForm.name, role: editForm.role, clientOrgId: editForm.clientOrgId || null }) });
|
|
506
|
+
toast('User updated', 'success');
|
|
507
|
+
setEditUser(null);
|
|
508
|
+
load();
|
|
509
|
+
} catch (e) { toast(e.message || 'Update failed', 'error'); }
|
|
510
|
+
};
|
|
511
|
+
|
|
497
512
|
var toggleActive = async function(user) {
|
|
498
513
|
var action = user.isActive === false ? 'reactivate' : 'deactivate';
|
|
499
514
|
var ok = await showConfirm({
|
|
@@ -515,6 +530,8 @@ export function UsersPage() {
|
|
|
515
530
|
var [deleteStep, setDeleteStep] = useState(0);
|
|
516
531
|
var [deleteTarget, setDeleteTarget] = useState(null);
|
|
517
532
|
var [deleteTyped, setDeleteTyped] = useState('');
|
|
533
|
+
var [editUser, setEditUser] = useState(null);
|
|
534
|
+
var [editForm, setEditForm] = useState({ name: '', role: '', clientOrgId: '' });
|
|
518
535
|
|
|
519
536
|
var startDelete = function(user) { setDeleteTarget(user); setDeleteStep(1); setDeleteTyped(''); };
|
|
520
537
|
var cancelDelete = function() { setDeleteTarget(null); setDeleteStep(0); setDeleteTyped(''); };
|
|
@@ -655,13 +672,60 @@ export function UsersPage() {
|
|
|
655
672
|
),
|
|
656
673
|
|
|
657
674
|
// Permission editor modal
|
|
675
|
+
// Edit User modal
|
|
676
|
+
editUser && h(Modal, {
|
|
677
|
+
title: 'Edit User — ' + (editUser.name || editUser.email),
|
|
678
|
+
onClose: function() { setEditUser(null); },
|
|
679
|
+
width: 420,
|
|
680
|
+
footer: h(Fragment, null,
|
|
681
|
+
h('button', { className: 'btn btn-secondary', onClick: function() { setEditUser(null); } }, 'Cancel'),
|
|
682
|
+
h('button', { className: 'btn btn-primary', onClick: doEditUser }, 'Save Changes')
|
|
683
|
+
)
|
|
684
|
+
},
|
|
685
|
+
h('div', { className: 'form-group' },
|
|
686
|
+
h('label', { className: 'form-label' }, 'Name'),
|
|
687
|
+
h('input', { className: 'input', value: editForm.name, onChange: function(e) { setEditForm(function(f) { return Object.assign({}, f, { name: e.target.value }); }); } })
|
|
688
|
+
),
|
|
689
|
+
h('div', { className: 'form-group' },
|
|
690
|
+
h('label', { className: 'form-label' }, 'Role'),
|
|
691
|
+
h('select', { className: 'input', value: editForm.role, onChange: function(e) { setEditForm(function(f) { return Object.assign({}, f, { role: e.target.value }); }); } },
|
|
692
|
+
h('option', { value: 'viewer' }, 'Viewer'),
|
|
693
|
+
h('option', { value: 'member' }, 'Member'),
|
|
694
|
+
h('option', { value: 'admin' }, 'Admin'),
|
|
695
|
+
h('option', { value: 'owner' }, 'Owner')
|
|
696
|
+
),
|
|
697
|
+
h('div', { style: { fontSize: 11, color: 'var(--text-muted)', marginTop: 4 } },
|
|
698
|
+
editForm.role === 'owner' ? 'Full access to everything. Cannot be restricted.' :
|
|
699
|
+
editForm.role === 'admin' ? 'Full access by default. Can be restricted via permissions.' :
|
|
700
|
+
editForm.role === 'member' ? 'Access controlled by permissions. Can view and act on assigned pages.' :
|
|
701
|
+
'Read-only access. Can view but not modify.'
|
|
702
|
+
)
|
|
703
|
+
),
|
|
704
|
+
clientOrgs.length > 0 && h('div', { className: 'form-group' },
|
|
705
|
+
h('label', { className: 'form-label' }, 'Client Organization'),
|
|
706
|
+
h('select', { className: 'input', value: editForm.clientOrgId, onChange: function(e) { setEditForm(function(f) { return Object.assign({}, f, { clientOrgId: e.target.value }); }); } },
|
|
707
|
+
h('option', { value: '' }, 'None (Internal User)'),
|
|
708
|
+
clientOrgs.filter(function(o) { return o.is_active !== false; }).map(function(o) {
|
|
709
|
+
return h('option', { key: o.id, value: o.id }, o.name);
|
|
710
|
+
})
|
|
711
|
+
),
|
|
712
|
+
editForm.clientOrgId && h('div', { style: { fontSize: 11, color: 'var(--warning, #f59e0b)', marginTop: 4 } },
|
|
713
|
+
'This user will only see agents and data from this organization.'
|
|
714
|
+
)
|
|
715
|
+
),
|
|
716
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', padding: '8px 0', borderTop: '1px solid var(--border)', marginTop: 8 } },
|
|
717
|
+
'Email: ', h('code', null, editUser.email), ' (cannot be changed)'
|
|
718
|
+
)
|
|
719
|
+
),
|
|
720
|
+
|
|
658
721
|
permTarget && pageRegistry && h(PermissionEditor, {
|
|
659
722
|
userId: permTarget.id,
|
|
660
723
|
userName: permTarget.name || permTarget.email,
|
|
661
724
|
currentPerms: permGrants,
|
|
662
725
|
pageRegistry: pageRegistry,
|
|
663
726
|
onSave: savePermissions,
|
|
664
|
-
onClose: function() { setPermTarget(null); }
|
|
727
|
+
onClose: function() { setPermTarget(null); },
|
|
728
|
+
userObj: permTarget
|
|
665
729
|
}),
|
|
666
730
|
|
|
667
731
|
// 5-step delete confirmation modal
|
|
@@ -767,6 +831,7 @@ export function UsersPage() {
|
|
|
767
831
|
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, u.createdAt ? new Date(u.createdAt).toLocaleDateString() : '-'),
|
|
768
832
|
h('td', null,
|
|
769
833
|
h('div', { style: { display: 'flex', gap: 4 } },
|
|
834
|
+
h('button', { className: 'btn btn-ghost btn-sm', title: 'Edit User', onClick: function() { openEditUser(u); } }, I.edit()),
|
|
770
835
|
h('button', {
|
|
771
836
|
className: 'btn btn-ghost btn-sm',
|
|
772
837
|
title: isRestricted ? 'Edit Permissions' : 'Permissions (Owner/Admin have full access)',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge, getOrgId } , apiCall } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { TimezoneSelect } from '../components/timezones.js';
|
|
4
4
|
import { HelpButton } from '../components/help-button.js';
|
|
@@ -47,7 +47,7 @@ export function WorkforcePage() {
|
|
|
47
47
|
setSchedules(schedulesRes.schedules || []);
|
|
48
48
|
setBudgetData(budgetRes);
|
|
49
49
|
setClockRecords(recordsRes.records || []);
|
|
50
|
-
|
|
50
|
+
apiCall('/agents' + (orgCtx.selectedOrgId ? '?clientOrgId=' + orgCtx.selectedOrgId : '')).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
51
51
|
} catch (err) { toast('Failed to load workforce data', 'error'); }
|
|
52
52
|
setLoading(false);
|
|
53
53
|
};
|