@agenticmail/enterprise 0.5.301 → 0.5.302

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.
@@ -2,8 +2,11 @@ import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, getO
2
2
  import { I } from '../components/icons.js';
3
3
  import { Modal } from '../components/modal.js';
4
4
  import { HelpButton } from '../components/help-button.js';
5
+ import { useOrgContext } from '../components/org-switcher.js';
5
6
 
6
7
  export function SkillsPage() {
8
+ var orgCtx = useOrgContext();
9
+ var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
7
10
  var app = useApp();
8
11
  var toast = app.toast;
9
12
  var setPage = app.setPage;
@@ -66,7 +69,7 @@ export function SkillsPage() {
66
69
  // Load installed skills + statuses
67
70
  var loadInstalled = useCallback(function() {
68
71
  setInstalledLoading(true);
69
- engineCall('/community/installed?orgId=' + getOrgId())
72
+ engineCall('/community/installed?orgId=' + effectiveOrgId)
70
73
  .then(function(d) {
71
74
  var items = d.installed || [];
72
75
  setInstalled(items);
@@ -162,7 +165,7 @@ export function SkillsPage() {
162
165
  var payload = isMultiField
163
166
  ? { credentials: tokenModal.fields.reduce(function(o, f) { o[f] = credFields[f].trim(); return o; }, {}) }
164
167
  : { token: tokenValue };
165
- await engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + getOrgId(), {
168
+ await engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + effectiveOrgId, {
166
169
  method: 'POST',
167
170
  body: JSON.stringify(payload)
168
171
  });
@@ -183,7 +186,7 @@ export function SkillsPage() {
183
186
  try {
184
187
  await engineCall('/community/skills/' + skillId + '/' + (enable ? 'enable' : 'disable'), {
185
188
  method: 'PUT',
186
- body: JSON.stringify({ orgId: getOrgId() })
189
+ body: JSON.stringify({ orgId: effectiveOrgId })
187
190
  });
188
191
  toast('Skill ' + (enable ? 'enabled' : 'disabled'), 'success');
189
192
  loadInstalled();
@@ -201,7 +204,7 @@ export function SkillsPage() {
201
204
  try {
202
205
  await engineCall('/community/skills/' + skillId + '/uninstall', {
203
206
  method: 'DELETE',
204
- body: JSON.stringify({ orgId: getOrgId() })
207
+ body: JSON.stringify({ orgId: effectiveOrgId })
205
208
  });
206
209
  toast('Skill uninstalled', 'success');
207
210
  loadInstalled();
@@ -240,7 +243,7 @@ export function SkillsPage() {
240
243
  try {
241
244
  await engineCall('/community/skills/' + skillId + '/install', {
242
245
  method: 'POST',
243
- body: JSON.stringify({ orgId: getOrgId() })
246
+ body: JSON.stringify({ orgId: effectiveOrgId })
244
247
  });
245
248
  toast('Skill installed', 'success');
246
249
  loadInstalled();
@@ -269,7 +272,7 @@ export function SkillsPage() {
269
272
 
270
273
  var loadIntegrations = useCallback(function() {
271
274
  setIntLoading(true);
272
- engineCall('/integrations/catalog?orgId=' + getOrgId())
275
+ engineCall('/integrations/catalog?orgId=' + effectiveOrgId)
273
276
  .then(function(d) {
274
277
  setIntegrations(d.catalog || []);
275
278
  setIntCategories(d.categories || []);
@@ -302,7 +305,7 @@ export function SkillsPage() {
302
305
  setOauthSaving(false);
303
306
  // For OAuth2, check if app is already configured
304
307
  if (int.authType === 'oauth2' && int.oauthProvider) {
305
- engineCall('/oauth/app-config/' + int.oauthProvider + '?orgId=' + getOrgId())
308
+ engineCall('/oauth/app-config/' + int.oauthProvider + '?orgId=' + effectiveOrgId)
306
309
  .then(function(d) { if (d.configured) setOauthAppConfigured(true); })
307
310
  .catch(function() {});
308
311
  }
@@ -312,14 +315,14 @@ export function SkillsPage() {
312
315
  if (!tokenModal || !tokenModal.oauthProvider) return;
313
316
  if (!oauthClientId.trim() || !oauthClientSecret.trim()) return;
314
317
  setOauthSaving(true);
315
- engineCall('/oauth/app-config/' + tokenModal.oauthProvider + '?orgId=' + getOrgId(), {
318
+ engineCall('/oauth/app-config/' + tokenModal.oauthProvider + '?orgId=' + effectiveOrgId, {
316
319
  method: 'POST',
317
320
  body: JSON.stringify({ clientId: oauthClientId.trim(), clientSecret: oauthClientSecret.trim() })
318
321
  })
319
322
  .then(function() {
320
323
  setOauthAppConfigured(true);
321
324
  toast('OAuth app configured for ' + tokenModal.skill.name, 'success');
322
- return engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + getOrgId());
325
+ return engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + effectiveOrgId);
323
326
  })
324
327
  .then(function(d) {
325
328
  if (d && (d.authUrl || d.authorizationUrl)) {
@@ -336,7 +339,7 @@ export function SkillsPage() {
336
339
 
337
340
  var launchOauthFlow = function() {
338
341
  if (!tokenModal) return;
339
- engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + getOrgId())
342
+ engineCall('/oauth/authorize/' + tokenModal.skillId + '?orgId=' + effectiveOrgId)
340
343
  .then(function(d) {
341
344
  if (d && (d.authUrl || d.authorizationUrl)) {
342
345
  var popup = window.open(d.authUrl || d.authorizationUrl, 'oauth_connect', 'width=600,height=700,popup=yes');
@@ -353,7 +356,7 @@ export function SkillsPage() {
353
356
 
354
357
  var disconnectIntegration = function(int) {
355
358
  if (!confirm('Disconnect ' + int.name + '? Agents will lose access to its tools.')) return;
356
- engineCall('/oauth/disconnect/' + int.skillId + '?orgId=' + getOrgId(), { method: 'DELETE' })
359
+ engineCall('/oauth/disconnect/' + int.skillId + '?orgId=' + effectiveOrgId, { method: 'DELETE' })
357
360
  .then(function() { toast(int.name + ' disconnected', 'success'); loadIntegrations(); })
358
361
  .catch(function(e) { toast('Failed: ' + e.message, 'error'); });
359
362
  };
@@ -380,6 +383,7 @@ export function SkillsPage() {
380
383
  // ── Builtin Tab ──
381
384
  var renderBuiltin = function() {
382
385
  return h(Fragment, null,
386
+ h(orgCtx.Switcher),
383
387
  h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
384
388
  h('div', { style: { position: 'relative', flex: 1, maxWidth: 320 } },
385
389
  h('input', {
@@ -1,6 +1,7 @@
1
1
  import { h, useState, useEffect, useCallback, useRef, Fragment, useApp, engineCall, getOrgId } from '../components/utils.js';
2
2
  import { I } from '../components/icons.js';
3
3
  import { HelpButton } from '../components/help-button.js';
4
+ import { useOrgContext } from '../components/org-switcher.js';
4
5
 
5
6
  // ─── Constants ───────────────────────────────────────────
6
7
  var NODE_W = 200;
@@ -438,6 +439,8 @@ export function TaskPipelinePage() {
438
439
  injectCSS();
439
440
  var app = useApp();
440
441
  var toast = app.toast;
442
+ var orgCtx = useOrgContext();
443
+ var effectiveOrgId = orgCtx.selectedOrgId || effectiveOrgId;
441
444
  var _tasks = useState([]);
442
445
  var tasks = _tasks[0]; var setTasks = _tasks[1];
443
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: [] });
@@ -474,7 +477,7 @@ export function TaskPipelinePage() {
474
477
  Promise.all([
475
478
  engineCall('/task-pipeline?limit=200'),
476
479
  engineCall('/task-pipeline/stats'),
477
- engineCall('/agents?orgId=' + getOrgId()).catch(function() { return { agents: [] }; }),
480
+ engineCall('/agents?orgId=' + effectiveOrgId).catch(function() { return { agents: [] }; }),
478
481
  ]).then(function(res) {
479
482
  setTasks(res[0]?.tasks || []);
480
483
  setStats(res[1] || stats);
@@ -486,7 +489,7 @@ export function TaskPipelinePage() {
486
489
  setAgentMap(map);
487
490
  }).catch(function(err) { console.error('[TaskPipeline]', err); })
488
491
  .finally(function() { setLoading(false); });
489
- }, []);
492
+ }, [effectiveOrgId]);
490
493
 
491
494
  // SSE
492
495
  useEffect(function() {
@@ -1074,6 +1077,7 @@ export function AgentTaskPipeline(props) {
1074
1077
  }
1075
1078
 
1076
1079
  return h(Fragment, null,
1080
+ h(orgCtx.Switcher),
1077
1081
  active.length > 0 && h('div', { style: { marginBottom: 12 } },
1078
1082
  h('div', { style: { fontSize: 11, fontWeight: 600, color: STATUS_COLORS.in_progress, marginBottom: 6, display: 'flex', alignItems: 'center', gap: 4 } },
1079
1083
  h('div', { style: { width: 6, height: 6, borderRadius: '50%', background: STATUS_COLORS.in_progress, animation: 'flowPulse 2s infinite' } }),
@@ -2,8 +2,11 @@ import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, buil
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';
5
+ import { useOrgContext } from '../components/org-switcher.js';
5
6
 
6
7
  export function WorkforcePage() {
8
+ var orgCtx = useOrgContext();
9
+ var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
7
10
  const { toast } = useApp();
8
11
  const [tab, setTab] = useState('overview');
9
12
  const [status, setStatus] = useState(null);
@@ -44,7 +47,7 @@ export function WorkforcePage() {
44
47
  setSchedules(schedulesRes.schedules || []);
45
48
  setBudgetData(budgetRes);
46
49
  setClockRecords(recordsRes.records || []);
47
- engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
50
+ engineCall('/agents?orgId=' + effectiveOrgId).then(d => setAgents(d.agents || [])).catch(() => {});
48
51
  } catch (err) { toast('Failed to load workforce data', 'error'); }
49
52
  setLoading(false);
50
53
  };
@@ -251,6 +254,7 @@ export function WorkforcePage() {
251
254
  var _tip = { marginTop: 12, padding: 12, background: 'var(--bg-secondary, #1e293b)', borderRadius: 'var(--radius, 8px)', fontSize: 13 };
252
255
 
253
256
  return h('div', { className: 'page-inner' },
257
+ h(orgCtx.Switcher),
254
258
  h('div', { className: 'page-header' },
255
259
  h('h1', { style: { display: 'flex', alignItems: 'center' } }, 'Workforce Management', h(HelpButton, { label: 'Workforce Management' },
256
260
  h('p', null, 'Manage your agents like employees — set work schedules, assign tasks, track budgets, and monitor clock-in/out history.'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.301",
3
+ "version": "0.5.302",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,96 @@
1
+ import { h, useState, useEffect, Fragment, apiCall } from './utils.js';
2
+ import { I } from './icons.js';
3
+
4
+ /**
5
+ * OrgContextSwitcher — Global org context picker for multi-tenant pages.
6
+ *
7
+ * Props:
8
+ * onOrgChange(orgId, org) — called when org selection changes
9
+ * selectedOrgId — currently selected org ID ('' = my org)
10
+ * style — optional container style override
11
+ * showLabel — show "Viewing:" label (default true)
12
+ *
13
+ * The component loads client_organizations from the API and renders a
14
+ * compact dropdown that switches between "My Organization" and client orgs.
15
+ */
16
+ export function OrgContextSwitcher(props) {
17
+ var onOrgChange = props.onOrgChange;
18
+ var selectedOrgId = props.selectedOrgId || '';
19
+ var showLabel = props.showLabel !== false;
20
+ var style = props.style || {};
21
+
22
+ var _orgs = useState([]);
23
+ var orgs = _orgs[0]; var setOrgs = _orgs[1];
24
+ var _loaded = useState(false);
25
+ var loaded = _loaded[0]; var setLoaded = _loaded[1];
26
+
27
+ useEffect(function() {
28
+ apiCall('/organizations').then(function(d) {
29
+ setOrgs(d.organizations || []);
30
+ setLoaded(true);
31
+ }).catch(function() { setLoaded(true); });
32
+ }, []);
33
+
34
+ // Don't render if no client orgs exist
35
+ if (loaded && orgs.length === 0) return null;
36
+ if (!loaded) return null;
37
+
38
+ var selectedOrg = orgs.find(function(o) { return o.id === selectedOrgId; });
39
+
40
+ return h('div', {
41
+ style: Object.assign({
42
+ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 14px',
43
+ background: 'var(--bg-tertiary)', borderRadius: 'var(--radius, 8px)',
44
+ marginBottom: 16, fontSize: 13
45
+ }, style)
46
+ },
47
+ showLabel && h('span', { style: { color: 'var(--text-muted)', fontWeight: 600, whiteSpace: 'nowrap' } }, I.building(), ' Viewing:'),
48
+ h('select', {
49
+ value: selectedOrgId,
50
+ onChange: function(e) {
51
+ var id = e.target.value;
52
+ var org = orgs.find(function(o) { return o.id === id; });
53
+ onOrgChange(id, org || null);
54
+ },
55
+ style: {
56
+ padding: '6px 10px', borderRadius: 6, border: '1px solid var(--border)',
57
+ background: 'var(--bg-card)', color: 'var(--text)', fontSize: 13,
58
+ cursor: 'pointer', fontWeight: 600, flex: 1, maxWidth: 300
59
+ }
60
+ },
61
+ h('option', { value: '' }, 'My Organization'),
62
+ orgs.filter(function(o) { return o.is_active !== false; }).map(function(o) {
63
+ return h('option', { key: o.id, value: o.id }, o.name + (o.billing_rate_per_agent > 0 ? ' (' + (o.currency || 'USD') + ' ' + parseFloat(o.billing_rate_per_agent).toFixed(0) + '/agent)' : ''));
64
+ })
65
+ ),
66
+ selectedOrg && h('span', { style: { fontSize: 11, color: 'var(--text-muted)' } },
67
+ selectedOrg.contact_name ? selectedOrg.contact_name : '',
68
+ selectedOrg.contact_email ? ' \u2022 ' + selectedOrg.contact_email : ''
69
+ )
70
+ );
71
+ }
72
+
73
+ /**
74
+ * useOrgContext — Hook that provides org switching state.
75
+ * Returns [selectedOrgId, selectedOrg, onOrgChange, OrgSwitcher component]
76
+ */
77
+ export function useOrgContext() {
78
+ var _sel = useState('');
79
+ var selectedOrgId = _sel[0]; var setSelectedOrgId = _sel[1];
80
+ var _org = useState(null);
81
+ var selectedOrg = _org[0]; var setSelectedOrg = _org[1];
82
+
83
+ var onOrgChange = function(id, org) {
84
+ setSelectedOrgId(id);
85
+ setSelectedOrg(org);
86
+ };
87
+
88
+ var Switcher = function(extraProps) {
89
+ return h(OrgContextSwitcher, Object.assign({
90
+ selectedOrgId: selectedOrgId,
91
+ onOrgChange: onOrgChange
92
+ }, extraProps || {}));
93
+ };
94
+
95
+ return { selectedOrgId: selectedOrgId, selectedOrg: selectedOrg, onOrgChange: onOrgChange, Switcher: Switcher };
96
+ }
@@ -3,6 +3,7 @@ import { I } from '../components/icons.js';
3
3
  import { E } from '../assets/icons/emoji-icons.js';
4
4
  import { CULTURES, LANGUAGES, PersonaForm } from '../components/persona-fields.js';
5
5
  import { HelpButton } from '../components/help-button.js';
6
+ import { useOrgContext } from '../components/org-switcher.js';
6
7
 
7
8
  // ════════════════════════════════════════════════════════════
8
9
  // DEPLOY MODAL
@@ -1127,6 +1128,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
1127
1128
  export function AgentsPage({ onSelectAgent }) {
1128
1129
  const app = useApp();
1129
1130
  const toast = app.toast;
1131
+ var orgCtx = useOrgContext();
1130
1132
  const [agents, setAgents] = useState([]);
1131
1133
  const [creating, setCreating] = useState(false);
1132
1134
 
@@ -1138,9 +1140,13 @@ export function AgentsPage({ onSelectAgent }) {
1138
1140
  if (allowedAgents !== '*' && Array.isArray(allowedAgents)) {
1139
1141
  all = all.filter(a => allowedAgents.indexOf(a.id) >= 0);
1140
1142
  }
1143
+ // Filter by selected org context
1144
+ if (orgCtx.selectedOrgId) {
1145
+ all = all.filter(a => a.client_org_id === orgCtx.selectedOrgId);
1146
+ }
1141
1147
  setAgents(all);
1142
1148
  }).catch(() => {});
1143
- useEffect(() => { load(); }, []);
1149
+ useEffect(() => { load(); }, [orgCtx.selectedOrgId]);
1144
1150
 
1145
1151
  // Delete moved to agent detail overview tab with triple confirmation
1146
1152
 
@@ -1149,6 +1155,7 @@ export function AgentsPage({ onSelectAgent }) {
1149
1155
  var _tip = { marginTop: 12, padding: 12, background: 'var(--bg-secondary, #1e293b)', borderRadius: 'var(--radius, 8px)', fontSize: 13 };
1150
1156
 
1151
1157
  return h(Fragment, null,
1158
+ h(orgCtx.Switcher),
1152
1159
  h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 } },
1153
1160
  h('div', null, h('h1', { style: { fontSize: 20, fontWeight: 700, display: 'flex', alignItems: 'center' } }, 'Agents', h(HelpButton, { label: 'Agents' },
1154
1161
  h('p', null, 'Your AI workforce. Each agent has its own email identity, personality, skills, permissions, and deployment target.'),
@@ -1,8 +1,11 @@
1
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
  import { HelpButton } from '../components/help-button.js';
4
+ import { useOrgContext } from '../components/org-switcher.js';
4
5
 
5
6
  export function ApprovalsPage() {
7
+ var orgCtx = useOrgContext();
8
+ var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
6
9
  const { toast } = useApp();
7
10
  const [pending, setPending] = useState([]);
8
11
  const [history, setHistory] = useState([]);
@@ -13,7 +16,7 @@ export function ApprovalsPage() {
13
16
  const load = () => {
14
17
  engineCall('/approvals/pending').then(d => setPending(d.requests || [])).catch(() => {});
15
18
  engineCall('/approvals/history?limit=50').then(d => setHistory(d.requests || [])).catch(() => {});
16
- engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
19
+ engineCall('/agents?orgId=' + effectiveOrgId).then(d => setAgents(d.agents || [])).catch(() => {});
17
20
  };
18
21
  useEffect(() => { load(); }, []);
19
22
 
@@ -33,6 +36,7 @@ export function ApprovalsPage() {
33
36
  var _tip = { marginTop: 12, padding: 12, background: 'var(--bg-secondary, #1e293b)', borderRadius: 'var(--radius, 8px)', fontSize: 13 };
34
37
 
35
38
  return h(Fragment, null,
39
+ h(orgCtx.Switcher),
36
40
  h('div', { style: { marginBottom: 20 } },
37
41
  h('h1', { style: { fontSize: 20, fontWeight: 700, display: 'flex', alignItems: 'center' } }, 'Approvals', h(HelpButton, { label: 'Approvals' },
38
42
  h('p', null, 'The human-in-the-loop checkpoint. When agents attempt sensitive actions (based on your permission settings), they pause and wait for your approval here.'),
@@ -2,6 +2,7 @@ import { h, useState, useEffect, Fragment, buildAgentEmailMap, buildAgentDataMap
2
2
  import { I } from '../components/icons.js';
3
3
  import { DetailModal } from '../components/modal.js';
4
4
  import { HelpButton } from '../components/help-button.js';
5
+ import { useOrgContext } from '../components/org-switcher.js';
5
6
 
6
7
  export function SetupChecklist({ onNavigate }) {
7
8
  const [status, setStatus] = useState(null);
@@ -46,6 +47,8 @@ export function SetupChecklist({ onNavigate }) {
46
47
  }
47
48
 
48
49
  export function DashboardPage() {
50
+ var orgCtx = useOrgContext();
51
+ var effectiveOrgId = orgCtx.selectedOrgId || effectiveOrgId;
49
52
  const [stats, setStats] = useState(null);
50
53
  const [agents, setAgents] = useState([]);
51
54
  const [events, setEvents] = useState([]);
@@ -58,9 +61,9 @@ export function DashboardPage() {
58
61
  useEffect(() => {
59
62
  apiCall('/stats').then(setStats).catch(() => {});
60
63
  apiCall('/agents').then(d => setAgents(d.agents || d || [])).catch(() => {});
61
- engineCall('/agents?orgId=' + getOrgId()).then(d => setEngineAgents(d.agents || [])).catch(() => {});
64
+ engineCall('/agents?orgId=' + effectiveOrgId).then(d => setEngineAgents(d.agents || [])).catch(() => {});
62
65
  engineCall('/activity/events?limit=10').then(d => setEvents(d.events || [])).catch(() => {});
63
- }, []);
66
+ }, [effectiveOrgId]);
64
67
 
65
68
  // Merge admin + engine agents; engine agents (appended last) win in the data map
66
69
  var mergedForMap = [].concat(agents, engineAgents);
@@ -73,6 +76,7 @@ export function DashboardPage() {
73
76
  var _tip = { marginTop: 12, padding: 12, background: 'var(--bg-secondary, #1e293b)', borderRadius: 'var(--radius, 8px)', fontSize: 13 };
74
77
 
75
78
  return h(Fragment, null,
79
+ h(orgCtx.Switcher),
76
80
  h(SetupChecklist, { onNavigate: function(pg) { if (navTo) navTo(pg); } }),
77
81
  h('div', { className: 'stat-grid' },
78
82
  h('div', { className: 'stat-card' }, h('div', { className: 'stat-label', style: { display: 'flex', alignItems: 'center' } }, 'Total Agents', h(HelpButton, { label: 'Total Agents' },
@@ -1,6 +1,7 @@
1
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
  import { HelpButton } from '../components/help-button.js';
4
+ import { useOrgContext } from '../components/org-switcher.js';
4
5
 
5
6
  // ─── Constants ──────────────────────────────────────────
6
7
 
@@ -93,6 +94,8 @@ function EmptyState(props) {
93
94
  // ─── Main Page ──────────────────────────────────────────
94
95
 
95
96
  export function GuardrailsPage() {
97
+ var orgCtx = useOrgContext();
98
+ var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
96
99
  var app = useApp();
97
100
  var toast = app.toast;
98
101
  var tab = useState('overview');
@@ -101,7 +104,7 @@ export function GuardrailsPage() {
101
104
  var _ag = useState([]);
102
105
  var agents = _ag[0]; var setAgents = _ag[1];
103
106
  useEffect(function() {
104
- engineCall('/agents?orgId=' + getOrgId()).then(function(d) { setAgents(d.agents || []); }).catch(function() {});
107
+ engineCall('/agents?orgId=' + effectiveOrgId).then(function(d) { setAgents(d.agents || []); }).catch(function() {});
105
108
  }, []);
106
109
 
107
110
  var TABS = [
@@ -164,8 +167,8 @@ function OverviewTab(props) {
164
167
  var load = function() {
165
168
  setLoading(true);
166
169
  Promise.all([
167
- engineCall('/guardrails/interventions?orgId=' + getOrgId() + '&limit=10').catch(function() { return { interventions: [] }; }),
168
- engineCall('/policies?orgId=' + getOrgId()).catch(function() { return { policies: [] }; }),
170
+ engineCall('/guardrails/interventions?orgId=' + effectiveOrgId + '&limit=10').catch(function() { return { interventions: [] }; }),
171
+ engineCall('/policies?orgId=' + effectiveOrgId).catch(function() { return { policies: [] }; }),
169
172
  engineCall('/onboarding/org/default').catch(function() { return { progress: [] }; }),
170
173
  ]).then(function(res) {
171
174
  setInterventions(res[0].interventions || []);
@@ -203,6 +206,7 @@ function OverviewTab(props) {
203
206
  var typeColor = function(t) { return t === 'kill' ? '#ef4444' : t === 'pause' ? '#f59e0b' : t === 'resume' ? '#15803d' : '#0ea5e9'; };
204
207
 
205
208
  return h(Fragment, null,
209
+ h(orgCtx.Switcher),
206
210
  // Quick action bar
207
211
  h('div', { className: 'card', style: { marginBottom: 16 } },
208
212
  h('div', { className: 'card-body', style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' } },
@@ -282,17 +286,17 @@ function PoliciesTab() {
282
286
  var editPolicy = _edit[0]; var setEditPolicy = _edit[1];
283
287
  var _exp = useState(null);
284
288
  var expanded = _exp[0]; var setExpanded = _exp[1];
285
- var _form = useState({ orgId: getOrgId(), name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
289
+ var _form = useState({ orgId: effectiveOrgId, name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
286
290
  var form = _form[0]; var setForm = _form[1];
287
291
 
288
292
  var load = function() {
289
- engineCall('/policies?orgId=' + getOrgId()).then(function(d) { setPolicies(d.policies || []); }).catch(function() {});
293
+ engineCall('/policies?orgId=' + effectiveOrgId).then(function(d) { setPolicies(d.policies || []); }).catch(function() {});
290
294
  };
291
295
  useEffect(load, []);
292
296
 
293
297
  var openCreate = function() {
294
298
  setEditPolicy(null);
295
- setForm({ orgId: getOrgId(), name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
299
+ setForm({ orgId: effectiveOrgId, name: '', category: 'code_of_conduct', description: '', content: '', priority: 0, enforcement: 'mandatory', appliesTo: ['*'], tags: [], enabled: true });
296
300
  setShowModal(true);
297
301
  };
298
302
  var openEdit = function(p) {
@@ -314,7 +318,7 @@ function PoliciesTab() {
314
318
  .catch(function(e) { toast(e.message, 'error'); });
315
319
  };
316
320
  var applyDefaults = function() {
317
- engineCall('/policies/templates/apply', { method: 'POST', body: JSON.stringify({ orgId: getOrgId(), createdBy: 'admin' }) })
321
+ engineCall('/policies/templates/apply', { method: 'POST', body: JSON.stringify({ orgId: effectiveOrgId, createdBy: 'admin' }) })
318
322
  .then(function(d) { toast('Applied ' + (d.policies ? d.policies.length : 0) + ' default templates', 'success'); load(); })
319
323
  .catch(function(e) { toast(e.message, 'error'); });
320
324
  };
@@ -451,7 +455,7 @@ function OnboardingTab(props) {
451
455
 
452
456
  var initiate = function() {
453
457
  if (!initAgentId) { toast('Enter an agent ID', 'error'); return; }
454
- engineCall('/onboarding/initiate/' + initAgentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
458
+ engineCall('/onboarding/initiate/' + initAgentId, { method: 'POST', body: JSON.stringify({ orgId: effectiveOrgId }) })
455
459
  .then(function() { toast('Onboarding initiated', 'success'); setInitAgentId(''); load(); })
456
460
  .catch(function(e) { toast(e.message, 'error'); });
457
461
  };
@@ -461,7 +465,7 @@ function OnboardingTab(props) {
461
465
  .catch(function(e) { toast(e.message, 'error'); });
462
466
  };
463
467
  var checkChanges = function() {
464
- engineCall('/onboarding/check-changes', { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
468
+ engineCall('/onboarding/check-changes', { method: 'POST', body: JSON.stringify({ orgId: effectiveOrgId }) })
465
469
  .then(function(d) {
466
470
  var stale = d.staleAgents || [];
467
471
  if (stale.length === 0) { toast('All agents up to date', 'success'); }
@@ -555,7 +559,7 @@ function MemoryTab(props) {
555
559
  var showCreate = _show[0]; var setShowCreate = _show[1];
556
560
  var _exp = useState(null);
557
561
  var expanded = _exp[0]; var setExpanded = _exp[1];
558
- var _form = useState({ agentId: '', orgId: getOrgId(), category: 'org_knowledge', title: '', content: '', source: 'admin', importance: 'normal', tags: [] });
562
+ var _form = useState({ agentId: '', orgId: effectiveOrgId, category: 'org_knowledge', title: '', content: '', source: 'admin', importance: 'normal', tags: [] });
559
563
  var form = _form[0]; var setForm = _form[1];
560
564
 
561
565
  var loadMemories = function(aid) {
@@ -762,13 +766,13 @@ function RulesTab(props) {
762
766
  var _showAnomaly = useState(false);
763
767
  var showAnomalyModal = _showAnomaly[0]; var setShowAnomalyModal = _showAnomaly[1];
764
768
  var _form = useState({
765
- orgId: getOrgId(), name: '', description: '', category: 'anomaly', ruleType: 'threshold',
769
+ orgId: effectiveOrgId, name: '', description: '', category: 'anomaly', ruleType: 'threshold',
766
770
  conditions: { threshold: 10, windowMinutes: 60 },
767
771
  action: 'alert', severity: 'medium', cooldownMinutes: 15, enabled: true
768
772
  });
769
773
  var form = _form[0]; var setForm = _form[1];
770
774
  var _anomalyForm = useState({
771
- orgId: getOrgId(), name: '', ruleType: 'error_rate',
775
+ orgId: effectiveOrgId, name: '', ruleType: 'error_rate',
772
776
  config: { maxErrorsPerHour: 50, windowMinutes: 60 }, action: 'pause', enabled: true
773
777
  });
774
778
  var anomalyForm = _anomalyForm[0]; var setAnomalyForm = _anomalyForm[1];
@@ -777,9 +781,9 @@ function RulesTab(props) {
777
781
 
778
782
  var load = function() {
779
783
  Promise.all([
780
- engineCall('/guardrails/rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
781
- engineCall('/anomaly-rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
782
- engineCall('/guardrails/interventions?orgId=' + getOrgId() + '&limit=50').catch(function() { return { interventions: [] }; }),
784
+ engineCall('/guardrails/rules?orgId=' + effectiveOrgId).catch(function() { return { rules: [] }; }),
785
+ engineCall('/anomaly-rules?orgId=' + effectiveOrgId).catch(function() { return { rules: [] }; }),
786
+ engineCall('/guardrails/interventions?orgId=' + effectiveOrgId + '&limit=50').catch(function() { return { interventions: [] }; }),
783
787
  ]).then(function(res) {
784
788
  setRules(res[0].rules || []);
785
789
  setAnomalyRules(res[1].rules || []);
@@ -791,7 +795,7 @@ function RulesTab(props) {
791
795
  // Guardrail rules CRUD
792
796
  var openCreateRule = function() {
793
797
  setEditRule(null);
794
- setForm({ orgId: getOrgId(), name: '', description: '', category: 'anomaly', ruleType: 'threshold', conditions: { threshold: 10, windowMinutes: 60 }, action: 'alert', severity: 'medium', cooldownMinutes: 15, enabled: true });
798
+ setForm({ orgId: effectiveOrgId, name: '', description: '', category: 'anomaly', ruleType: 'threshold', conditions: { threshold: 10, windowMinutes: 60 }, action: 'alert', severity: 'medium', cooldownMinutes: 15, enabled: true });
795
799
  setShowModal(true);
796
800
  };
797
801
  var openEditRule = function(r) {
@@ -1,8 +1,11 @@
1
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
  import { HelpButton } from '../components/help-button.js';
4
+ import { useOrgContext } from '../components/org-switcher.js';
4
5
 
5
6
  export function JournalPage() {
7
+ var orgCtx = useOrgContext();
8
+ var effectiveOrgId = orgCtx.selectedOrgId || getOrgId();
6
9
  const { toast } = useApp();
7
10
  const [entries, setEntries] = useState([]);
8
11
  const [total, setTotal] = useState(0);
@@ -11,9 +14,9 @@ export function JournalPage() {
11
14
  const [agents, setAgents] = useState([]);
12
15
 
13
16
  const load = () => {
14
- engineCall('/journal?orgId=' + getOrgId() + '&limit=50').then(d => { setEntries(d.entries || []); setTotal(d.total || 0); }).catch(() => {});
17
+ engineCall('/journal?orgId=' + effectiveOrgId + '&limit=50').then(d => { setEntries(d.entries || []); setTotal(d.total || 0); }).catch(() => {});
15
18
  engineCall('/journal/stats/default').then(d => setStats(d)).catch(() => {});
16
- engineCall('/agents?orgId=' + getOrgId()).then(d => setAgents(d.agents || [])).catch(() => {});
19
+ engineCall('/agents?orgId=' + effectiveOrgId).then(d => setAgents(d.agents || [])).catch(() => {});
17
20
  };
18
21
  useEffect(load, []);
19
22
 
@@ -29,6 +32,7 @@ export function JournalPage() {
29
32
  var _tip = { marginTop: 12, padding: 12, background: 'var(--bg-secondary, #1e293b)', borderRadius: 'var(--radius, 8px)', fontSize: 13 };
30
33
 
31
34
  return h('div', { className: 'page-inner' },
35
+ h(orgCtx.Switcher),
32
36
  h('div', { className: 'page-header' }, h('h1', { style: { display: 'flex', alignItems: 'center' } }, 'Action Journal', h(HelpButton, { label: 'Action Journal' },
33
37
  h('p', null, 'A tamper-proof log of every action agents have taken. Think of it as an audit trail — every tool call, every side effect, recorded with full context.'),
34
38
  h('h4', { style: _h4 }, 'Why it matters'),