@agenticmail/enterprise 0.5.380 → 0.5.381
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/package.json +1 -1
- package/dist/dashboard/org-switcher.js +0 -156
package/package.json
CHANGED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { h, useState, useEffect, useCallback, useRef, Fragment, apiCall, useApp } from './utils.js';
|
|
2
|
-
import { I } from './icons.js';
|
|
3
|
-
|
|
4
|
-
// ─── Global org cache (shared across all switcher instances) ────────
|
|
5
|
-
var _orgCache = { orgs: null, loading: false, listeners: [], lastFetch: 0 };
|
|
6
|
-
var ORG_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
7
|
-
|
|
8
|
-
function getOrgsFromCache(forceRefresh) {
|
|
9
|
-
var now = Date.now();
|
|
10
|
-
// Return cached if fresh
|
|
11
|
-
if (!forceRefresh && _orgCache.orgs && (now - _orgCache.lastFetch) < ORG_CACHE_TTL) {
|
|
12
|
-
return Promise.resolve(_orgCache.orgs);
|
|
13
|
-
}
|
|
14
|
-
// Already loading — wait for it
|
|
15
|
-
if (_orgCache.loading) {
|
|
16
|
-
return new Promise(function(resolve) {
|
|
17
|
-
_orgCache.listeners.push(resolve);
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
// Fetch
|
|
21
|
-
_orgCache.loading = true;
|
|
22
|
-
return apiCall('/organizations').then(function(d) {
|
|
23
|
-
var list = d.organizations || [];
|
|
24
|
-
_orgCache.orgs = list;
|
|
25
|
-
_orgCache.lastFetch = Date.now();
|
|
26
|
-
_orgCache.loading = false;
|
|
27
|
-
// Notify waiters
|
|
28
|
-
var listeners = _orgCache.listeners;
|
|
29
|
-
_orgCache.listeners = [];
|
|
30
|
-
listeners.forEach(function(fn) { fn(list); });
|
|
31
|
-
return list;
|
|
32
|
-
}).catch(function() {
|
|
33
|
-
_orgCache.loading = false;
|
|
34
|
-
_orgCache.orgs = _orgCache.orgs || [];
|
|
35
|
-
var listeners = _orgCache.listeners;
|
|
36
|
-
_orgCache.listeners = [];
|
|
37
|
-
listeners.forEach(function(fn) { fn(_orgCache.orgs || []); });
|
|
38
|
-
return _orgCache.orgs || [];
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Invalidate org cache (call after creating/deleting orgs) */
|
|
43
|
-
export function invalidateOrgCache() {
|
|
44
|
-
_orgCache.orgs = null;
|
|
45
|
-
_orgCache.lastFetch = 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* OrgContextSwitcher — Global org context picker for multi-tenant pages.
|
|
50
|
-
*
|
|
51
|
-
* If the current user has a clientOrgId, the switcher is LOCKED to that org
|
|
52
|
-
* (they can only see their org's data). Owners/admins can switch freely.
|
|
53
|
-
*
|
|
54
|
-
* Uses a global cache so /organizations is only fetched once across all pages.
|
|
55
|
-
*/
|
|
56
|
-
export function OrgContextSwitcher(props) {
|
|
57
|
-
var onOrgChange = props.onOrgChange;
|
|
58
|
-
var selectedOrgId = props.selectedOrgId || '';
|
|
59
|
-
var showLabel = props.showLabel !== false;
|
|
60
|
-
var style = props.style || {};
|
|
61
|
-
|
|
62
|
-
var app = useApp();
|
|
63
|
-
var user = app.user || {};
|
|
64
|
-
var userOrgId = user.clientOrgId || null;
|
|
65
|
-
var isLocked = !!userOrgId && user.role !== 'owner' && user.role !== 'admin';
|
|
66
|
-
|
|
67
|
-
var _orgs = useState(_orgCache.orgs || []);
|
|
68
|
-
var orgs = _orgs[0]; var setOrgs = _orgs[1];
|
|
69
|
-
var _loaded = useState(!!_orgCache.orgs);
|
|
70
|
-
var loaded = _loaded[0]; var setLoaded = _loaded[1];
|
|
71
|
-
|
|
72
|
-
useEffect(function() {
|
|
73
|
-
// If already cached, use immediately (no API call)
|
|
74
|
-
if (_orgCache.orgs && (Date.now() - _orgCache.lastFetch) < ORG_CACHE_TTL) {
|
|
75
|
-
setOrgs(_orgCache.orgs);
|
|
76
|
-
setLoaded(true);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
getOrgsFromCache(false).then(function(list) {
|
|
80
|
-
setOrgs(list);
|
|
81
|
-
setLoaded(true);
|
|
82
|
-
});
|
|
83
|
-
}, []);
|
|
84
|
-
|
|
85
|
-
// Don't render if no client orgs and user isn't org-bound
|
|
86
|
-
if (loaded && orgs.length === 0 && !userOrgId) return null;
|
|
87
|
-
if (!loaded) return null;
|
|
88
|
-
|
|
89
|
-
var effectiveId = isLocked ? userOrgId : selectedOrgId;
|
|
90
|
-
var selectedOrg = orgs.find(function(o) { return o.id === effectiveId; });
|
|
91
|
-
|
|
92
|
-
return h('div', {
|
|
93
|
-
style: Object.assign({
|
|
94
|
-
display: 'flex', alignItems: 'center', gap: 10, padding: '8px 14px',
|
|
95
|
-
background: 'var(--bg-tertiary)', border: '1px solid var(--border)',
|
|
96
|
-
borderRadius: 'var(--radius, 8px)',
|
|
97
|
-
marginBottom: 16, fontSize: 13
|
|
98
|
-
}, style)
|
|
99
|
-
},
|
|
100
|
-
showLabel && h('span', { style: { color: 'var(--text-muted)', fontWeight: 600, whiteSpace: 'nowrap' } }, I.building(), ' Viewing:'),
|
|
101
|
-
isLocked
|
|
102
|
-
? h('div', { style: { fontWeight: 600, fontSize: 13, color: 'var(--text)', display: 'flex', alignItems: 'center', gap: 6 } },
|
|
103
|
-
selectedOrg ? selectedOrg.name : 'Your Organization',
|
|
104
|
-
h('span', { className: 'badge badge-neutral', style: { fontSize: 10 } }, 'Locked')
|
|
105
|
-
)
|
|
106
|
-
: h('select', {
|
|
107
|
-
value: selectedOrgId,
|
|
108
|
-
onChange: function(e) {
|
|
109
|
-
var id = e.target.value;
|
|
110
|
-
var org = orgs.find(function(o) { return o.id === id; });
|
|
111
|
-
onOrgChange(id, org || null);
|
|
112
|
-
},
|
|
113
|
-
style: {
|
|
114
|
-
padding: '6px 10px', borderRadius: 6, border: '1px solid var(--border)',
|
|
115
|
-
background: 'var(--bg-card)', color: 'var(--text)', fontSize: 13,
|
|
116
|
-
cursor: 'pointer', fontWeight: 600, flex: 1, maxWidth: 300
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
h('option', { value: '' }, 'My Organization'),
|
|
120
|
-
orgs.filter(function(o) { return o.is_active !== false; }).map(function(o) {
|
|
121
|
-
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)' : ''));
|
|
122
|
-
})
|
|
123
|
-
),
|
|
124
|
-
selectedOrg && h('span', { style: { fontSize: 11, color: 'var(--text-muted)' } },
|
|
125
|
-
selectedOrg.contact_name ? selectedOrg.contact_name : '',
|
|
126
|
-
selectedOrg.contact_email ? ' \u2022 ' + selectedOrg.contact_email : ''
|
|
127
|
-
),
|
|
128
|
-
// Impersonation banner
|
|
129
|
-
app.impersonating && h('span', { className: 'badge badge-warning', style: { fontSize: 10, marginLeft: 'auto' } }, 'Impersonating: ' + (user.name || user.email))
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* useOrgContext — Hook that provides org switching state.
|
|
135
|
-
* Auto-selects the user's client org if they are org-bound.
|
|
136
|
-
*/
|
|
137
|
-
export function useOrgContext() {
|
|
138
|
-
var app = useApp();
|
|
139
|
-
var user = app.user || {};
|
|
140
|
-
var userClientOrgId = user.clientOrgId || null;
|
|
141
|
-
var isLocked = !!userClientOrgId && user.role !== 'owner' && user.role !== 'admin';
|
|
142
|
-
// If user is org-bound (locked), always use their clientOrgId regardless of selectedOrgId
|
|
143
|
-
var selectedOrgId = isLocked ? userClientOrgId : (app.selectedOrgId || '');
|
|
144
|
-
var selectedOrg = app.selectedOrg || null;
|
|
145
|
-
var onOrgChange = app.onOrgChange || function() {};
|
|
146
|
-
|
|
147
|
-
// Stable Switcher reference
|
|
148
|
-
var Switcher = useCallback(function(extraProps) {
|
|
149
|
-
return h(OrgContextSwitcher, Object.assign({
|
|
150
|
-
selectedOrgId: selectedOrgId,
|
|
151
|
-
onOrgChange: onOrgChange
|
|
152
|
-
}, extraProps || {}));
|
|
153
|
-
}, [selectedOrgId, onOrgChange]);
|
|
154
|
-
|
|
155
|
-
return { selectedOrgId: selectedOrgId, selectedOrg: selectedOrg, onOrgChange: onOrgChange, Switcher: Switcher };
|
|
156
|
-
}
|