@agenticmail/enterprise 0.5.15 → 0.5.17
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-4F3XGZWR.js +2295 -0
- package/dist/chunk-52DDMP6J.js +12666 -0
- package/dist/chunk-7JFYYBVR.js +1987 -0
- package/dist/chunk-7PFGWQMJ.js +12666 -0
- package/dist/chunk-BCDVBHJY.js +9080 -0
- package/dist/chunk-JDHG37BH.js +9048 -0
- package/dist/chunk-LJNMWZ7Z.js +1987 -0
- package/dist/chunk-MCOXOTGK.js +889 -0
- package/dist/chunk-TXWPXWDR.js +889 -0
- package/dist/cli.js +1 -1
- package/dist/dashboard/components/utils.js +12 -0
- package/dist/dashboard/pages/activity.js +2 -2
- package/dist/dashboard/pages/agent-detail.js +12 -12
- package/dist/dashboard/pages/agents.js +4 -4
- package/dist/dashboard/pages/approvals.js +2 -2
- package/dist/dashboard/pages/community-skills.js +12 -12
- package/dist/dashboard/pages/compliance.js +4 -4
- package/dist/dashboard/pages/dashboard.js +3 -3
- package/dist/dashboard/pages/dlp.js +6 -6
- package/dist/dashboard/pages/guardrails.js +17 -17
- package/dist/dashboard/pages/journal.js +3 -3
- package/dist/dashboard/pages/knowledge-contributions.js +8 -8
- package/dist/dashboard/pages/knowledge.js +2 -2
- package/dist/dashboard/pages/messages.js +5 -5
- package/dist/dashboard/pages/settings.js +8 -8
- package/dist/dashboard/pages/skills.js +4 -4
- package/dist/dashboard/pages/vault.js +5 -5
- package/dist/dashboard/pages/workforce.js +2 -2
- package/dist/db-adapter-DZFYOL4K.js +7 -0
- package/dist/index.js +5 -5
- package/dist/routes-T6LJPTIF.js +5674 -0
- package/dist/routes-YDCUZKFN.js +5674 -0
- package/dist/runtime-O4FBRIDG.js +47 -0
- package/dist/runtime-U54X4BFZ.js +47 -0
- package/dist/server-47SBCNL5.js +11 -0
- package/dist/server-HDNZOS5V.js +11 -0
- package/dist/setup-QBFQ5AWO.js +20 -0
- package/dist/setup-RWM6G6BK.js +20 -0
- package/package.json +1 -1
- package/src/dashboard/components/utils.js +12 -0
- package/src/dashboard/pages/activity.js +2 -2
- package/src/dashboard/pages/agent-detail.js +12 -12
- package/src/dashboard/pages/agents.js +4 -4
- package/src/dashboard/pages/approvals.js +2 -2
- package/src/dashboard/pages/community-skills.js +12 -12
- package/src/dashboard/pages/compliance.js +4 -4
- package/src/dashboard/pages/dashboard.js +3 -3
- package/src/dashboard/pages/dlp.js +6 -6
- package/src/dashboard/pages/guardrails.js +17 -17
- package/src/dashboard/pages/journal.js +3 -3
- package/src/dashboard/pages/knowledge-contributions.js +8 -8
- package/src/dashboard/pages/knowledge.js +2 -2
- package/src/dashboard/pages/messages.js +5 -5
- package/src/dashboard/pages/settings.js +8 -8
- package/src/dashboard/pages/skills.js +4 -4
- package/src/dashboard/pages/vault.js +5 -5
- package/src/dashboard/pages/workforce.js +2 -2
- package/src/engine/agent-memory.ts +3 -2
- package/src/engine/approvals.ts +2 -1
- package/src/engine/communication.ts +2 -1
- package/src/engine/compliance.ts +3 -2
- package/src/engine/db-adapter.ts +40 -34
- package/src/engine/vault.ts +8 -3
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,18 @@ export { h, useState, useEffect, useCallback, useRef, Fragment, createContext, u
|
|
|
5
5
|
|
|
6
6
|
export function useApp() { return useContext(AppContext); }
|
|
7
7
|
|
|
8
|
+
// Org ID — auto-generated unique identifier, persisted in localStorage
|
|
9
|
+
export function getOrgId() {
|
|
10
|
+
var id = localStorage.getItem('em_org_id');
|
|
11
|
+
if (!id) {
|
|
12
|
+
var chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
13
|
+
id = '';
|
|
14
|
+
for (var i = 0; i < 10; i++) id += chars[Math.floor(Math.random() * chars.length)];
|
|
15
|
+
localStorage.setItem('em_org_id', id);
|
|
16
|
+
}
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
// Derive accent color variants from a hex color
|
|
9
21
|
export function applyBrandColor(hex) {
|
|
10
22
|
if (!hex || !/^#[0-9a-fA-F]{6}$/.test(hex)) return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
|
|
3
3
|
export function ActivityPage() {
|
|
4
4
|
const [events, setEvents] = useState([]);
|
|
@@ -10,7 +10,7 @@ export function ActivityPage() {
|
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
engineCall('/activity/events?limit=100').then(d => setEvents(d.events || [])).catch(() => {});
|
|
12
12
|
engineCall('/activity/tool-calls?limit=100').then(d => setToolCalls(d.toolCalls || [])).catch(() => {});
|
|
13
|
-
engineCall('/agents?orgId=
|
|
13
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
14
14
|
}, []);
|
|
15
15
|
|
|
16
16
|
const emailMap = buildAgentEmailMap(agents);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, apiCall, engineCall, formatUptime, buildAgentDataMap, renderAgentBadge, showConfirm } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, apiCall, engineCall, formatUptime, buildAgentDataMap, renderAgentBadge, showConfirm , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { DetailModal } from '../components/modal.js';
|
|
4
4
|
import { CULTURES, LANGUAGES, DEFAULT_TRAITS, computeAge, PersonaForm } from '../components/persona-fields.js';
|
|
@@ -202,7 +202,7 @@ function OverviewSection(props) {
|
|
|
202
202
|
|
|
203
203
|
var initiateOnboarding = function() {
|
|
204
204
|
setActing('onboard');
|
|
205
|
-
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId:
|
|
205
|
+
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
206
206
|
.then(function() { toast('Onboarding initiated', 'success'); setOnboardingStatus(function(s) { return Object.assign({}, s, { onboarded: true, status: 'in_progress' }); }); reload(); })
|
|
207
207
|
.catch(function(err) { toast(err.message, 'error'); })
|
|
208
208
|
.finally(function() { setActing(''); });
|
|
@@ -700,7 +700,7 @@ function PermissionsSection(props) {
|
|
|
700
700
|
useEffect(function() {
|
|
701
701
|
setLoading(true);
|
|
702
702
|
Promise.all([
|
|
703
|
-
engineCall('/policies/agent/' + agentId + '?orgId=
|
|
703
|
+
engineCall('/policies/agent/' + agentId + '?orgId=' + getOrgId()).catch(function() { return { policies: [] }; }),
|
|
704
704
|
engineCall('/profiles/presets').catch(function() { return { presets: [] }; }),
|
|
705
705
|
engineCall('/souls/by-category').catch(function() { return { categories: {}, categoryMeta: {} }; })
|
|
706
706
|
]).then(function(results) {
|
|
@@ -1490,7 +1490,7 @@ function ActivitySection(props) {
|
|
|
1490
1490
|
.catch(function() {});
|
|
1491
1491
|
};
|
|
1492
1492
|
var loadJournal = function() {
|
|
1493
|
-
engineCall('/journal?agentId=' + agentId + '&orgId=
|
|
1493
|
+
engineCall('/journal?agentId=' + agentId + '&orgId=' + getOrgId() + '&limit=50')
|
|
1494
1494
|
.then(function(d) { setJournalEntries(d.entries || []); })
|
|
1495
1495
|
.catch(function() {});
|
|
1496
1496
|
};
|
|
@@ -1500,7 +1500,7 @@ function ActivitySection(props) {
|
|
|
1500
1500
|
Promise.all([
|
|
1501
1501
|
engineCall('/activity/events?agentId=' + agentId + '&limit=50').then(function(d) { setEvents(d.events || []); }).catch(function() {}),
|
|
1502
1502
|
engineCall('/activity/tool-calls?agentId=' + agentId + '&limit=50').then(function(d) { setToolCalls(d.toolCalls || []); }).catch(function() {}),
|
|
1503
|
-
engineCall('/journal?agentId=' + agentId + '&orgId=
|
|
1503
|
+
engineCall('/journal?agentId=' + agentId + '&orgId=' + getOrgId() + '&limit=50').then(function(d) { setJournalEntries(d.entries || []); }).catch(function() {}),
|
|
1504
1504
|
]).then(function() { setLoading(false); }).catch(function() { setLoading(false); });
|
|
1505
1505
|
};
|
|
1506
1506
|
|
|
@@ -1674,17 +1674,17 @@ function CommunicationSection(props) {
|
|
|
1674
1674
|
var form = _form[0]; var setForm = _form[1];
|
|
1675
1675
|
|
|
1676
1676
|
var loadMessages = function() {
|
|
1677
|
-
engineCall('/messages?agentId=' + agentId + '&orgId=
|
|
1677
|
+
engineCall('/messages?agentId=' + agentId + '&orgId=' + getOrgId() + '&limit=50')
|
|
1678
1678
|
.then(function(d) { setMessages(d.messages || []); })
|
|
1679
1679
|
.catch(function() {});
|
|
1680
1680
|
};
|
|
1681
1681
|
var loadInbox = function() {
|
|
1682
|
-
engineCall('/messages/inbox/' + agentId + '?orgId=
|
|
1682
|
+
engineCall('/messages/inbox/' + agentId + '?orgId=' + getOrgId())
|
|
1683
1683
|
.then(function(d) { setInbox(d.messages || []); })
|
|
1684
1684
|
.catch(function() {});
|
|
1685
1685
|
};
|
|
1686
1686
|
var loadTopology = function() {
|
|
1687
|
-
engineCall('/messages/topology?agentId=' + agentId + '&orgId=
|
|
1687
|
+
engineCall('/messages/topology?agentId=' + agentId + '&orgId=' + getOrgId())
|
|
1688
1688
|
.then(function(d) { setTopology(d.topology || d || null); })
|
|
1689
1689
|
.catch(function() {});
|
|
1690
1690
|
};
|
|
@@ -1708,7 +1708,7 @@ function CommunicationSection(props) {
|
|
|
1708
1708
|
var body = {
|
|
1709
1709
|
fromAgentId: agentId,
|
|
1710
1710
|
toAgentId: form.toAgentId,
|
|
1711
|
-
orgId:
|
|
1711
|
+
orgId: getOrgId(),
|
|
1712
1712
|
subject: form.subject,
|
|
1713
1713
|
content: form.content,
|
|
1714
1714
|
priority: form.priority
|
|
@@ -1991,7 +1991,7 @@ function MemorySection(props) {
|
|
|
1991
1991
|
var tagsArray = createForm.tags ? createForm.tags.split(',').map(function(s) { return s.trim(); }).filter(Boolean) : [];
|
|
1992
1992
|
var body = {
|
|
1993
1993
|
agentId: agentId,
|
|
1994
|
-
orgId:
|
|
1994
|
+
orgId: getOrgId(),
|
|
1995
1995
|
title: createForm.title,
|
|
1996
1996
|
content: createForm.content,
|
|
1997
1997
|
category: createForm.category,
|
|
@@ -2549,7 +2549,7 @@ function GuardrailsSection(props) {
|
|
|
2549
2549
|
};
|
|
2550
2550
|
|
|
2551
2551
|
var initiateOnboarding = function() {
|
|
2552
|
-
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId:
|
|
2552
|
+
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
2553
2553
|
.then(function() { toast('Onboarding initiated', 'success'); loadAll(); })
|
|
2554
2554
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2555
2555
|
};
|
|
@@ -3448,7 +3448,7 @@ function AgentDetailPage(props) {
|
|
|
3448
3448
|
Promise.all([
|
|
3449
3449
|
engineCall('/bridge/agents/' + agentId + '/full').catch(function() { return null; }),
|
|
3450
3450
|
apiCall('/agents/' + agentId).catch(function() { return null; }),
|
|
3451
|
-
engineCall('/agents?orgId=
|
|
3451
|
+
engineCall('/agents?orgId=' + getOrgId()).catch(function() { return { agents: [] }; })
|
|
3452
3452
|
]).then(function(results) {
|
|
3453
3453
|
var fullData = results[0];
|
|
3454
3454
|
var adminData = results[1];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, apiCall, engineCall, DEPLOY_PHASES, DEPLOY_PHASE_LABELS, showConfirm } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, apiCall, engineCall, DEPLOY_PHASES, DEPLOY_PHASE_LABELS, showConfirm , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { CULTURES, LANGUAGES, PersonaForm } from '../components/persona-fields.js';
|
|
4
4
|
|
|
@@ -16,7 +16,7 @@ export function DeployModal({ agentId, agentConfig, onClose, onDeployed, toast }
|
|
|
16
16
|
const [error, setError] = useState('');
|
|
17
17
|
|
|
18
18
|
useEffect(() => {
|
|
19
|
-
engineCall('/deploy-credentials?orgId=
|
|
19
|
+
engineCall('/deploy-credentials?orgId=' + getOrgId()).then(d => setCredentials(d.credentials || [])).catch(() => {});
|
|
20
20
|
}, []);
|
|
21
21
|
|
|
22
22
|
const targets = [
|
|
@@ -400,7 +400,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
400
400
|
setLoading(true);
|
|
401
401
|
try {
|
|
402
402
|
const result = await engineCall('/bridge/agents', { method: 'POST', body: JSON.stringify({
|
|
403
|
-
orgId:
|
|
403
|
+
orgId: getOrgId(),
|
|
404
404
|
name: form.name,
|
|
405
405
|
displayName: form.name,
|
|
406
406
|
email: form.email || form.name.toLowerCase().replace(/\s+/g, '.') + '@agenticmail.local',
|
|
@@ -436,7 +436,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
436
436
|
|
|
437
437
|
if (form.autoOnboard && agentId) {
|
|
438
438
|
try {
|
|
439
|
-
await engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId:
|
|
439
|
+
await engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) });
|
|
440
440
|
toast('Agent "' + form.name + '" created and onboarding started', 'success');
|
|
441
441
|
} catch (e) {
|
|
442
442
|
toast('Agent created but onboarding failed: ' + e.message, 'warning');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall, showConfirm, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall, showConfirm, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function ApprovalsPage() {
|
|
@@ -12,7 +12,7 @@ export function ApprovalsPage() {
|
|
|
12
12
|
const load = () => {
|
|
13
13
|
engineCall('/approvals/pending').then(d => setPending(d.requests || [])).catch(() => {});
|
|
14
14
|
engineCall('/approvals/history?limit=50').then(d => setHistory(d.requests || [])).catch(() => {});
|
|
15
|
-
engineCall('/agents?orgId=
|
|
15
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
16
16
|
};
|
|
17
17
|
useEffect(() => { load(); }, []);
|
|
18
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function CommunitySkillsPage() {
|
|
@@ -37,7 +37,7 @@ export function CommunitySkillsPage() {
|
|
|
37
37
|
engineCall('/community/skills?' + params.toString())
|
|
38
38
|
.then(d => { setSkills(d.skills || []); setTotal(d.total || 0); })
|
|
39
39
|
.catch(() => {});
|
|
40
|
-
engineCall('/community/installed?orgId=
|
|
40
|
+
engineCall('/community/installed?orgId=' + getOrgId())
|
|
41
41
|
.then(d => setInstalled(d.installed || []))
|
|
42
42
|
.catch(() => {});
|
|
43
43
|
engineCall('/community/skills/featured')
|
|
@@ -52,16 +52,16 @@ export function CommunitySkillsPage() {
|
|
|
52
52
|
}, [filters]);
|
|
53
53
|
|
|
54
54
|
var loadUpdates = useCallback(function() {
|
|
55
|
-
engineCall('/skill-updates/config?orgId=
|
|
55
|
+
engineCall('/skill-updates/config?orgId=' + getOrgId())
|
|
56
56
|
.then(function(d) { setUpdateConfig(d.config || d || { autoUpdate: false, checkInterval: 'daily', maxRiskLevel: 'medium' }); })
|
|
57
57
|
.catch(function() {});
|
|
58
|
-
engineCall('/skill-updates/available?orgId=
|
|
58
|
+
engineCall('/skill-updates/available?orgId=' + getOrgId())
|
|
59
59
|
.then(function(d) { setAvailableUpdates(d.updates || []); })
|
|
60
60
|
.catch(function() {});
|
|
61
|
-
engineCall('/skill-updates/history?orgId=
|
|
61
|
+
engineCall('/skill-updates/history?orgId=' + getOrgId())
|
|
62
62
|
.then(function(d) { setUpdateHistory(d.history || d.updates || []); })
|
|
63
63
|
.catch(function() {});
|
|
64
|
-
engineCall('/skill-updates/stats?orgId=
|
|
64
|
+
engineCall('/skill-updates/stats?orgId=' + getOrgId())
|
|
65
65
|
.then(function(d) { setUpdateStats(d || {}); })
|
|
66
66
|
.catch(function() {});
|
|
67
67
|
}, []);
|
|
@@ -87,7 +87,7 @@ export function CommunitySkillsPage() {
|
|
|
87
87
|
try {
|
|
88
88
|
await engineCall('/community/skills/' + skillId + '/install', {
|
|
89
89
|
method: 'POST',
|
|
90
|
-
body: JSON.stringify({ orgId:
|
|
90
|
+
body: JSON.stringify({ orgId: getOrgId() })
|
|
91
91
|
});
|
|
92
92
|
toast('Skill installed', 'success');
|
|
93
93
|
load();
|
|
@@ -98,7 +98,7 @@ export function CommunitySkillsPage() {
|
|
|
98
98
|
try {
|
|
99
99
|
await engineCall('/community/skills/' + skillId + '/uninstall', {
|
|
100
100
|
method: 'DELETE',
|
|
101
|
-
body: JSON.stringify({ orgId:
|
|
101
|
+
body: JSON.stringify({ orgId: getOrgId() })
|
|
102
102
|
});
|
|
103
103
|
toast('Skill uninstalled', 'success');
|
|
104
104
|
load();
|
|
@@ -109,7 +109,7 @@ export function CommunitySkillsPage() {
|
|
|
109
109
|
try {
|
|
110
110
|
await engineCall('/community/skills/' + skillId + '/' + (enable ? 'enable' : 'disable'), {
|
|
111
111
|
method: 'PUT',
|
|
112
|
-
body: JSON.stringify({ orgId:
|
|
112
|
+
body: JSON.stringify({ orgId: getOrgId() })
|
|
113
113
|
});
|
|
114
114
|
toast('Skill ' + (enable ? 'enabled' : 'disabled'), 'success');
|
|
115
115
|
load();
|
|
@@ -166,7 +166,7 @@ export function CommunitySkillsPage() {
|
|
|
166
166
|
try {
|
|
167
167
|
await engineCall('/skill-updates/check', {
|
|
168
168
|
method: 'POST',
|
|
169
|
-
body: JSON.stringify({ orgId:
|
|
169
|
+
body: JSON.stringify({ orgId: getOrgId() })
|
|
170
170
|
});
|
|
171
171
|
toast('Update check complete', 'success');
|
|
172
172
|
loadUpdates();
|
|
@@ -179,7 +179,7 @@ export function CommunitySkillsPage() {
|
|
|
179
179
|
await engineCall('/skill-updates/config', {
|
|
180
180
|
method: 'PUT',
|
|
181
181
|
body: JSON.stringify({
|
|
182
|
-
orgId:
|
|
182
|
+
orgId: getOrgId(),
|
|
183
183
|
autoUpdate: updateConfig.autoUpdate,
|
|
184
184
|
checkInterval: updateConfig.checkInterval,
|
|
185
185
|
maxRiskLevel: updateConfig.maxRiskLevel
|
|
@@ -210,7 +210,7 @@ export function CommunitySkillsPage() {
|
|
|
210
210
|
try {
|
|
211
211
|
await engineCall('/skill-updates/apply-all', {
|
|
212
212
|
method: 'POST',
|
|
213
|
-
body: JSON.stringify({ orgId:
|
|
213
|
+
body: JSON.stringify({ orgId: getOrgId() })
|
|
214
214
|
});
|
|
215
215
|
toast('All updates applied', 'success');
|
|
216
216
|
loadUpdates();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function CompliancePage() {
|
|
@@ -6,13 +6,13 @@ export function CompliancePage() {
|
|
|
6
6
|
const [reports, setReports] = useState([]);
|
|
7
7
|
const [tab, setTab] = useState('reports');
|
|
8
8
|
const [generating, setGenerating] = useState(false);
|
|
9
|
-
const [form, setForm] = useState({ type: 'soc2', orgId:
|
|
9
|
+
const [form, setForm] = useState({ type: 'soc2', orgId: getOrgId(), agentId: '', from: new Date(Date.now() - 30 * 86400000).toISOString().split('T')[0], to: new Date().toISOString().split('T')[0] });
|
|
10
10
|
|
|
11
11
|
const [agents, setAgents] = useState([]);
|
|
12
12
|
|
|
13
13
|
const load = () => {
|
|
14
|
-
engineCall('/compliance/reports?orgId=
|
|
15
|
-
engineCall('/agents?orgId=
|
|
14
|
+
engineCall('/compliance/reports?orgId=' + getOrgId()).then(d => setReports(d.reports || [])).catch(() => {});
|
|
15
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
16
16
|
};
|
|
17
17
|
useEffect(load, []);
|
|
18
18
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
2
|
-
import { useApp, apiCall, engineCall } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
|
+
import { useApp, apiCall, engineCall , getOrgId } from '../components/utils.js';
|
|
3
3
|
import { I } from '../components/icons.js';
|
|
4
4
|
import { DetailModal } from '../components/modal.js';
|
|
5
5
|
|
|
@@ -58,7 +58,7 @@ export function DashboardPage() {
|
|
|
58
58
|
useEffect(() => {
|
|
59
59
|
apiCall('/stats').then(setStats).catch(() => {});
|
|
60
60
|
apiCall('/agents').then(d => setAgents(d.agents || d || [])).catch(() => {});
|
|
61
|
-
engineCall('/agents?orgId=
|
|
61
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setEngineAgents(d.agents || [])).catch(() => {});
|
|
62
62
|
engineCall('/activity/events?limit=10').then(d => setEvents(d.events || [])).catch(() => {});
|
|
63
63
|
}, []);
|
|
64
64
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function DLPPage() {
|
|
@@ -7,16 +7,16 @@ export function DLPPage() {
|
|
|
7
7
|
const [violations, setViolations] = useState([]);
|
|
8
8
|
const [tab, setTab] = useState('rules');
|
|
9
9
|
const [showModal, setShowModal] = useState(false);
|
|
10
|
-
const [form, setForm] = useState({ name: '', orgId:
|
|
10
|
+
const [form, setForm] = useState({ name: '', orgId: getOrgId(), patternType: 'regex', pattern: '', action: 'block', appliesTo: 'both', severity: 'high', enabled: true });
|
|
11
11
|
const [testContent, setTestContent] = useState('');
|
|
12
12
|
const [testResults, setTestResults] = useState(null);
|
|
13
13
|
|
|
14
14
|
const [agents, setAgents] = useState([]);
|
|
15
15
|
|
|
16
16
|
const load = () => {
|
|
17
|
-
engineCall('/dlp/rules?orgId=
|
|
18
|
-
engineCall('/dlp/violations?orgId=
|
|
19
|
-
engineCall('/agents?orgId=
|
|
17
|
+
engineCall('/dlp/rules?orgId=' + getOrgId()).then(d => setRules(d.rules || [])).catch(() => {});
|
|
18
|
+
engineCall('/dlp/violations?orgId=' + getOrgId() + '&limit=100').then(d => setViolations(d.violations || [])).catch(() => {});
|
|
19
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
20
20
|
};
|
|
21
21
|
useEffect(load, []);
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ export function DLPPage() {
|
|
|
31
31
|
};
|
|
32
32
|
const testScan = async () => {
|
|
33
33
|
if (!testContent) return;
|
|
34
|
-
try { const r = await engineCall('/dlp/scan', { method: 'POST', body: JSON.stringify({ orgId:
|
|
34
|
+
try { const r = await engineCall('/dlp/scan', { method: 'POST', body: JSON.stringify({ orgId: getOrgId(), content: testContent }) }); setTestResults(r); } catch (e) { toast(e.message, 'error'); }
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const severityColor = (s) => s === 'critical' ? 'var(--danger)' : s === 'high' ? 'var(--warning)' : s === 'medium' ? 'var(--info)' : 'var(--text-muted)';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
// ─── Constants ──────────────────────────────────────────
|
|
@@ -100,7 +100,7 @@ export function GuardrailsPage() {
|
|
|
100
100
|
var _ag = useState([]);
|
|
101
101
|
var agents = _ag[0]; var setAgents = _ag[1];
|
|
102
102
|
useEffect(function() {
|
|
103
|
-
engineCall('/agents?orgId=
|
|
103
|
+
engineCall('/agents?orgId=' + getOrgId()).then(function(d) { setAgents(d.agents || []); }).catch(function() {});
|
|
104
104
|
}, []);
|
|
105
105
|
|
|
106
106
|
var TABS = [
|
|
@@ -148,8 +148,8 @@ function OverviewTab(props) {
|
|
|
148
148
|
var load = function() {
|
|
149
149
|
setLoading(true);
|
|
150
150
|
Promise.all([
|
|
151
|
-
engineCall('/guardrails/interventions?orgId=
|
|
152
|
-
engineCall('/policies?orgId=
|
|
151
|
+
engineCall('/guardrails/interventions?orgId=' + getOrgId() + '&limit=10').catch(function() { return { interventions: [] }; }),
|
|
152
|
+
engineCall('/policies?orgId=' + getOrgId()).catch(function() { return { policies: [] }; }),
|
|
153
153
|
engineCall('/onboarding/org/default').catch(function() { return { progress: [] }; }),
|
|
154
154
|
]).then(function(res) {
|
|
155
155
|
setInterventions(res[0].interventions || []);
|
|
@@ -256,17 +256,17 @@ function PoliciesTab() {
|
|
|
256
256
|
var editPolicy = _edit[0]; var setEditPolicy = _edit[1];
|
|
257
257
|
var _exp = useState(null);
|
|
258
258
|
var expanded = _exp[0]; var setExpanded = _exp[1];
|
|
259
|
-
var _form = useState({ orgId:
|
|
259
|
+
var _form = useState({ orgId: getOrgId(), name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
|
|
260
260
|
var form = _form[0]; var setForm = _form[1];
|
|
261
261
|
|
|
262
262
|
var load = function() {
|
|
263
|
-
engineCall('/policies?orgId=
|
|
263
|
+
engineCall('/policies?orgId=' + getOrgId()).then(function(d) { setPolicies(d.policies || []); }).catch(function() {});
|
|
264
264
|
};
|
|
265
265
|
useEffect(load, []);
|
|
266
266
|
|
|
267
267
|
var openCreate = function() {
|
|
268
268
|
setEditPolicy(null);
|
|
269
|
-
setForm({ orgId:
|
|
269
|
+
setForm({ orgId: getOrgId(), name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
|
|
270
270
|
setShowModal(true);
|
|
271
271
|
};
|
|
272
272
|
var openEdit = function(p) {
|
|
@@ -288,7 +288,7 @@ function PoliciesTab() {
|
|
|
288
288
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
289
289
|
};
|
|
290
290
|
var applyDefaults = function() {
|
|
291
|
-
engineCall('/policies/templates/apply', { method: 'POST', body: JSON.stringify({ orgId:
|
|
291
|
+
engineCall('/policies/templates/apply', { method: 'POST', body: JSON.stringify({ orgId: getOrgId(), createdBy: 'admin' }) })
|
|
292
292
|
.then(function(d) { toast('Applied ' + (d.policies ? d.policies.length : 0) + ' default templates', 'success'); load(); })
|
|
293
293
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
294
294
|
};
|
|
@@ -425,7 +425,7 @@ function OnboardingTab(props) {
|
|
|
425
425
|
|
|
426
426
|
var initiate = function() {
|
|
427
427
|
if (!initAgentId) { toast('Enter an agent ID', 'error'); return; }
|
|
428
|
-
engineCall('/onboarding/initiate/' + initAgentId, { method: 'POST', body: JSON.stringify({ orgId:
|
|
428
|
+
engineCall('/onboarding/initiate/' + initAgentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
429
429
|
.then(function() { toast('Onboarding initiated', 'success'); setInitAgentId(''); load(); })
|
|
430
430
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
431
431
|
};
|
|
@@ -435,7 +435,7 @@ function OnboardingTab(props) {
|
|
|
435
435
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
436
436
|
};
|
|
437
437
|
var checkChanges = function() {
|
|
438
|
-
engineCall('/onboarding/check-changes', { method: 'POST', body: JSON.stringify({ orgId:
|
|
438
|
+
engineCall('/onboarding/check-changes', { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
439
439
|
.then(function(d) {
|
|
440
440
|
var stale = d.staleAgents || [];
|
|
441
441
|
if (stale.length === 0) { toast('All agents up to date', 'success'); }
|
|
@@ -529,7 +529,7 @@ function MemoryTab(props) {
|
|
|
529
529
|
var showCreate = _show[0]; var setShowCreate = _show[1];
|
|
530
530
|
var _exp = useState(null);
|
|
531
531
|
var expanded = _exp[0]; var setExpanded = _exp[1];
|
|
532
|
-
var _form = useState({ agentId: '', orgId:
|
|
532
|
+
var _form = useState({ agentId: '', orgId: getOrgId(), category: 'org_knowledge', title: '', content: '', source: 'admin', importance: 'normal', tags: [] });
|
|
533
533
|
var form = _form[0]; var setForm = _form[1];
|
|
534
534
|
|
|
535
535
|
var loadMemories = function(aid) {
|
|
@@ -736,13 +736,13 @@ function RulesTab(props) {
|
|
|
736
736
|
var _showAnomaly = useState(false);
|
|
737
737
|
var showAnomalyModal = _showAnomaly[0]; var setShowAnomalyModal = _showAnomaly[1];
|
|
738
738
|
var _form = useState({
|
|
739
|
-
orgId:
|
|
739
|
+
orgId: getOrgId(), name: '', description: '', category: 'anomaly', ruleType: 'threshold',
|
|
740
740
|
conditions: { threshold: 10, windowMinutes: 60 },
|
|
741
741
|
action: 'alert', severity: 'medium', cooldownMinutes: 15, enabled: true
|
|
742
742
|
});
|
|
743
743
|
var form = _form[0]; var setForm = _form[1];
|
|
744
744
|
var _anomalyForm = useState({
|
|
745
|
-
orgId:
|
|
745
|
+
orgId: getOrgId(), name: '', ruleType: 'error_rate',
|
|
746
746
|
config: { maxErrorsPerHour: 50, windowMinutes: 60 }, action: 'pause', enabled: true
|
|
747
747
|
});
|
|
748
748
|
var anomalyForm = _anomalyForm[0]; var setAnomalyForm = _anomalyForm[1];
|
|
@@ -751,9 +751,9 @@ function RulesTab(props) {
|
|
|
751
751
|
|
|
752
752
|
var load = function() {
|
|
753
753
|
Promise.all([
|
|
754
|
-
engineCall('/guardrails/rules?orgId=
|
|
755
|
-
engineCall('/anomaly-rules?orgId=
|
|
756
|
-
engineCall('/guardrails/interventions?orgId=
|
|
754
|
+
engineCall('/guardrails/rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
|
|
755
|
+
engineCall('/anomaly-rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
|
|
756
|
+
engineCall('/guardrails/interventions?orgId=' + getOrgId() + '&limit=50').catch(function() { return { interventions: [] }; }),
|
|
757
757
|
]).then(function(res) {
|
|
758
758
|
setRules(res[0].rules || []);
|
|
759
759
|
setAnomalyRules(res[1].rules || []);
|
|
@@ -765,7 +765,7 @@ function RulesTab(props) {
|
|
|
765
765
|
// Guardrail rules CRUD
|
|
766
766
|
var openCreateRule = function() {
|
|
767
767
|
setEditRule(null);
|
|
768
|
-
setForm({ orgId:
|
|
768
|
+
setForm({ orgId: getOrgId(), name: '', description: '', category: 'anomaly', ruleType: 'threshold', conditions: { threshold: 10, windowMinutes: 60 }, action: 'alert', severity: 'medium', cooldownMinutes: 15, enabled: true });
|
|
769
769
|
setShowModal(true);
|
|
770
770
|
};
|
|
771
771
|
var openEditRule = function(r) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall, buildAgentEmailMap, buildAgentDataMap, resolveAgentEmail, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function JournalPage() {
|
|
@@ -10,9 +10,9 @@ export function JournalPage() {
|
|
|
10
10
|
const [agents, setAgents] = useState([]);
|
|
11
11
|
|
|
12
12
|
const load = () => {
|
|
13
|
-
engineCall('/journal?orgId=
|
|
13
|
+
engineCall('/journal?orgId=' + getOrgId() + '&limit=50').then(d => { setEntries(d.entries || []); setTotal(d.total || 0); }).catch(() => {});
|
|
14
14
|
engineCall('/journal/stats/default').then(d => setStats(d)).catch(() => {});
|
|
15
|
-
engineCall('/agents?orgId=
|
|
15
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
16
16
|
};
|
|
17
17
|
useEffect(load, []);
|
|
18
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { Modal } from '../components/modal.js';
|
|
4
4
|
|
|
@@ -25,7 +25,7 @@ export function KnowledgeContributionsPage() {
|
|
|
25
25
|
var [editSchedule, setEditSchedule] = useState(null);
|
|
26
26
|
|
|
27
27
|
var loadBases = useCallback(function() {
|
|
28
|
-
engineCall('/knowledge-contribution/bases?orgId=
|
|
28
|
+
engineCall('/knowledge-contribution/bases?orgId=' + getOrgId())
|
|
29
29
|
.then(function(d) { setBases(d.bases || d.knowledgeBases || []); })
|
|
30
30
|
.catch(function() {});
|
|
31
31
|
}, []);
|
|
@@ -37,19 +37,19 @@ export function KnowledgeContributionsPage() {
|
|
|
37
37
|
}, []);
|
|
38
38
|
|
|
39
39
|
var loadStats = useCallback(function() {
|
|
40
|
-
engineCall('/knowledge-contribution/stats?orgId=
|
|
40
|
+
engineCall('/knowledge-contribution/stats?orgId=' + getOrgId())
|
|
41
41
|
.then(function(d) { setStats(d || {}); })
|
|
42
42
|
.catch(function() {});
|
|
43
43
|
}, []);
|
|
44
44
|
|
|
45
45
|
var loadContributions = useCallback(function() {
|
|
46
|
-
engineCall('/knowledge-contribution/contributions?orgId=
|
|
46
|
+
engineCall('/knowledge-contribution/contributions?orgId=' + getOrgId())
|
|
47
47
|
.then(function(d) { setContributions(d.contributions || d.cycles || []); })
|
|
48
48
|
.catch(function() {});
|
|
49
49
|
}, []);
|
|
50
50
|
|
|
51
51
|
var loadSchedules = useCallback(function() {
|
|
52
|
-
engineCall('/knowledge-contribution/schedules?orgId=
|
|
52
|
+
engineCall('/knowledge-contribution/schedules?orgId=' + getOrgId())
|
|
53
53
|
.then(function(d) { setSchedules(d.schedules || []); })
|
|
54
54
|
.catch(function() {});
|
|
55
55
|
}, []);
|
|
@@ -83,7 +83,7 @@ export function KnowledgeContributionsPage() {
|
|
|
83
83
|
try {
|
|
84
84
|
await engineCall('/knowledge-contribution/bases', {
|
|
85
85
|
method: 'POST',
|
|
86
|
-
body: JSON.stringify({ name: baseForm.name, description: baseForm.description, role: baseForm.role, orgId:
|
|
86
|
+
body: JSON.stringify({ name: baseForm.name, description: baseForm.description, role: baseForm.role, orgId: getOrgId() })
|
|
87
87
|
});
|
|
88
88
|
toast('Knowledge base created', 'success');
|
|
89
89
|
setShowCreateBase(false);
|
|
@@ -134,7 +134,7 @@ export function KnowledgeContributionsPage() {
|
|
|
134
134
|
try {
|
|
135
135
|
await engineCall('/knowledge-contribution/contribute/' + triggerAgent, {
|
|
136
136
|
method: 'POST',
|
|
137
|
-
body: JSON.stringify({ targetBaseId: triggerBase || undefined, orgId:
|
|
137
|
+
body: JSON.stringify({ targetBaseId: triggerBase || undefined, orgId: getOrgId() })
|
|
138
138
|
});
|
|
139
139
|
toast('Contribution triggered', 'success');
|
|
140
140
|
setShowTrigger(false);
|
|
@@ -155,7 +155,7 @@ export function KnowledgeContributionsPage() {
|
|
|
155
155
|
frequency: scheduleForm.frequency,
|
|
156
156
|
dayOfWeek: scheduleForm.dayOfWeek,
|
|
157
157
|
minConfidence: parseFloat(scheduleForm.minConfidence) || 0.7,
|
|
158
|
-
orgId:
|
|
158
|
+
orgId: getOrgId()
|
|
159
159
|
})
|
|
160
160
|
});
|
|
161
161
|
toast('Schedule created', 'success');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, Fragment, useApp, engineCall } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, Fragment, useApp, engineCall , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
import { Modal } from '../components/modal.js';
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ export function KnowledgeBasePage() {
|
|
|
13
13
|
|
|
14
14
|
const create = async () => {
|
|
15
15
|
try {
|
|
16
|
-
await engineCall('/knowledge-bases', { method: 'POST', body: JSON.stringify({ name: form.name, description: form.description, orgId:
|
|
16
|
+
await engineCall('/knowledge-bases', { method: 'POST', body: JSON.stringify({ name: form.name, description: form.description, orgId: getOrgId() }) });
|
|
17
17
|
toast('Knowledge base created', 'success');
|
|
18
18
|
setCreating(false); setForm({ name: '', description: '' }); load();
|
|
19
19
|
} catch (e) { toast(e.message, 'error'); }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, useState, useEffect, useRef, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge } from '../components/utils.js';
|
|
1
|
+
import { h, useState, useEffect, useRef, Fragment, useApp, engineCall, buildAgentEmailMap, resolveAgentEmail, buildAgentDataMap, renderAgentBadge , getOrgId } from '../components/utils.js';
|
|
2
2
|
import { I } from '../components/icons.js';
|
|
3
3
|
|
|
4
4
|
export function MessagesPage() {
|
|
@@ -9,19 +9,19 @@ export function MessagesPage() {
|
|
|
9
9
|
const [mainTab, setMainTab] = useState('messages');
|
|
10
10
|
const [subTab, setSubTab] = useState('all');
|
|
11
11
|
const [showModal, setShowModal] = useState(false);
|
|
12
|
-
const [form, setForm] = useState({ orgId:
|
|
12
|
+
const [form, setForm] = useState({ orgId: getOrgId(), fromAgentId: '', toAgentId: '', subject: '', content: '', priority: 'normal' });
|
|
13
13
|
const [selectedNode, setSelectedNode] = useState(null);
|
|
14
14
|
const [nodePositions, setNodePositions] = useState([]);
|
|
15
15
|
const svgRef = useRef(null);
|
|
16
16
|
|
|
17
17
|
const loadMessages = () => {
|
|
18
|
-
engineCall('/messages?orgId=
|
|
18
|
+
engineCall('/messages?orgId=' + getOrgId() + '&limit=100').then(d => setMessages(d.messages || [])).catch(() => {});
|
|
19
19
|
};
|
|
20
20
|
const loadAgents = () => {
|
|
21
|
-
engineCall('/agents?orgId=
|
|
21
|
+
engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
|
|
22
22
|
};
|
|
23
23
|
const loadTopology = () => {
|
|
24
|
-
engineCall('/messages/topology?orgId=
|
|
24
|
+
engineCall('/messages/topology?orgId=' + getOrgId()).then(d => setTopology(d.topology || null)).catch(() => {});
|
|
25
25
|
};
|
|
26
26
|
useEffect(() => { loadMessages(); loadAgents(); loadTopology(); }, []);
|
|
27
27
|
|