@agenticmail/enterprise 0.5.295 → 0.5.296
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/dashboard/pages/users.js +87 -18
- package/package.json +1 -1
- package/src/dashboard/pages/users.js +87 -18
|
@@ -210,6 +210,88 @@ function PermissionEditor({ userId, userName, currentPerms, pageRegistry, onSave
|
|
|
210
210
|
);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// ─── Inline Permission Picker (for create modal) ──
|
|
214
|
+
|
|
215
|
+
function InlinePermissionPicker({ permissions, pageRegistry, onChange }) {
|
|
216
|
+
var [expandedPage, setExpandedPage] = useState(null);
|
|
217
|
+
|
|
218
|
+
// Resolve grants from permissions
|
|
219
|
+
var grants = permissions === '*' ? (function() { var a = {}; Object.keys(pageRegistry).forEach(function(p) { a[p] = true; }); return a; })() : (permissions || {});
|
|
220
|
+
|
|
221
|
+
var togglePage = function(pid) {
|
|
222
|
+
var next = Object.assign({}, grants);
|
|
223
|
+
if (next[pid]) { delete next[pid]; if (expandedPage === pid) setExpandedPage(null); }
|
|
224
|
+
else { next[pid] = true; }
|
|
225
|
+
onChange(Object.keys(next).length === Object.keys(pageRegistry).length ? '*' : next);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
var toggleTab = function(pid, tabId) {
|
|
229
|
+
var next = Object.assign({}, grants);
|
|
230
|
+
var current = next[pid];
|
|
231
|
+
var allTabs = Object.keys(pageRegistry[pid].tabs || {});
|
|
232
|
+
if (current === true) {
|
|
233
|
+
var remaining = allTabs.filter(function(t) { return t !== tabId; });
|
|
234
|
+
next[pid] = remaining.length > 0 ? remaining : true;
|
|
235
|
+
} else if (Array.isArray(current)) {
|
|
236
|
+
var idx = current.indexOf(tabId);
|
|
237
|
+
if (idx >= 0) {
|
|
238
|
+
var arr = current.filter(function(t) { return t !== tabId; });
|
|
239
|
+
if (arr.length === 0) delete next[pid];
|
|
240
|
+
else next[pid] = arr;
|
|
241
|
+
} else {
|
|
242
|
+
var newArr = current.concat([tabId]);
|
|
243
|
+
next[pid] = newArr.length === allTabs.length ? true : newArr;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
onChange(Object.keys(next).length === Object.keys(pageRegistry).length && Object.values(next).every(function(v) { return v === true; }) ? '*' : next);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
var isTabChecked = function(pid, tabId) {
|
|
250
|
+
var g = grants[pid];
|
|
251
|
+
if (!g) return false;
|
|
252
|
+
if (g === true) return true;
|
|
253
|
+
return Array.isArray(g) && g.indexOf(tabId) >= 0;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
var sections = { overview: 'Overview', management: 'Management', administration: 'Administration' };
|
|
257
|
+
var grouped = {};
|
|
258
|
+
Object.keys(pageRegistry).forEach(function(pid) { var s = pageRegistry[pid].section; if (!grouped[s]) grouped[s] = []; grouped[s].push(pid); });
|
|
259
|
+
|
|
260
|
+
return h('div', { style: { maxHeight: 250, overflowY: 'auto', border: '1px solid var(--border)', borderRadius: 6, marginTop: 8 } },
|
|
261
|
+
Object.keys(sections).map(function(sKey) {
|
|
262
|
+
var pids = grouped[sKey] || [];
|
|
263
|
+
if (!pids.length) return null;
|
|
264
|
+
return h(Fragment, { key: sKey },
|
|
265
|
+
h('div', { style: { fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)', padding: '8px 10px 2px' } }, sections[sKey]),
|
|
266
|
+
pids.map(function(pid) {
|
|
267
|
+
var page = pageRegistry[pid];
|
|
268
|
+
var checked = !!grants[pid];
|
|
269
|
+
var hasTabs = page.tabs && Object.keys(page.tabs).length > 0;
|
|
270
|
+
var isExpanded = expandedPage === pid;
|
|
271
|
+
return h(Fragment, { key: pid },
|
|
272
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px', fontSize: 12, cursor: 'pointer', background: checked ? 'var(--bg-tertiary)' : 'transparent' }, onClick: function(e) {
|
|
273
|
+
if (e.target.closest && e.target.closest('[data-expand]')) return;
|
|
274
|
+
togglePage(pid);
|
|
275
|
+
} },
|
|
276
|
+
h('input', { type: 'checkbox', checked: checked, readOnly: true, style: { width: 14, height: 14, accentColor: 'var(--primary)', cursor: 'pointer' } }),
|
|
277
|
+
h('span', { style: { flex: 1 } }, page.label),
|
|
278
|
+
hasTabs && checked && h('button', { 'data-expand': true, className: 'btn btn-ghost', style: { padding: '0 4px', minWidth: 0, fontSize: 10, lineHeight: 1 }, onClick: function(e) { e.stopPropagation(); setExpandedPage(isExpanded ? null : pid); } },
|
|
279
|
+
isExpanded ? I.chevronDown() : I.chevronRight()
|
|
280
|
+
)
|
|
281
|
+
),
|
|
282
|
+
hasTabs && isExpanded && checked && Object.keys(page.tabs).map(function(tabId) {
|
|
283
|
+
return h('div', { key: tabId, style: { display: 'flex', alignItems: 'center', gap: 8, padding: '3px 10px 3px 34px', fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer' }, onClick: function() { toggleTab(pid, tabId); } },
|
|
284
|
+
h('input', { type: 'checkbox', checked: isTabChecked(pid, tabId), readOnly: true, style: { width: 13, height: 13, accentColor: 'var(--primary)', cursor: 'pointer' } }),
|
|
285
|
+
h('span', null, page.tabs[tabId])
|
|
286
|
+
);
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
213
295
|
// ─── Users Page ────────────────────────────────────
|
|
214
296
|
|
|
215
297
|
export function UsersPage() {
|
|
@@ -357,24 +439,11 @@ export function UsersPage() {
|
|
|
357
439
|
h('button', { type: 'button', className: 'btn btn-ghost btn-sm', onClick: function() { setShowCreatePerms(!showCreatePerms); }, style: { fontSize: 11 } }, showCreatePerms ? 'Hide' : 'Customize')
|
|
358
440
|
),
|
|
359
441
|
!showCreatePerms && h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginTop: 4 } }, 'Full access (default). Click "Customize" to restrict.'),
|
|
360
|
-
showCreatePerms && pageRegistry && h(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return h('div', { key: pid, style: { display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px', fontSize: 12, cursor: 'pointer' }, onClick: function() {
|
|
366
|
-
setForm(function(f) {
|
|
367
|
-
var current = f.permissions === '*' ? (function() { var a = {}; Object.keys(pageRegistry).forEach(function(p) { a[p] = true; }); return a; })() : Object.assign({}, f.permissions);
|
|
368
|
-
if (current[pid]) { delete current[pid]; } else { current[pid] = true; }
|
|
369
|
-
if (Object.keys(current).length === Object.keys(pageRegistry).length) return Object.assign({}, f, { permissions: '*' });
|
|
370
|
-
return Object.assign({}, f, { permissions: current });
|
|
371
|
-
});
|
|
372
|
-
} },
|
|
373
|
-
h('input', { type: 'checkbox', checked: checked, readOnly: true, style: { width: 14, height: 14, accentColor: 'var(--primary)' } }),
|
|
374
|
-
h('span', null, page.label)
|
|
375
|
-
);
|
|
376
|
-
})
|
|
377
|
-
)
|
|
442
|
+
showCreatePerms && pageRegistry && h(InlinePermissionPicker, {
|
|
443
|
+
permissions: form.permissions,
|
|
444
|
+
pageRegistry: pageRegistry,
|
|
445
|
+
onChange: function(p) { setForm(function(f) { return Object.assign({}, f, { permissions: p }); }); }
|
|
446
|
+
})
|
|
378
447
|
),
|
|
379
448
|
(form.role === 'owner' || form.role === 'admin') && h('div', { style: { marginTop: 8, padding: 8, background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 11, color: 'var(--info)' } },
|
|
380
449
|
'Owner and Admin roles always have full access to all pages.'
|
package/package.json
CHANGED
|
@@ -210,6 +210,88 @@ function PermissionEditor({ userId, userName, currentPerms, pageRegistry, onSave
|
|
|
210
210
|
);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// ─── Inline Permission Picker (for create modal) ──
|
|
214
|
+
|
|
215
|
+
function InlinePermissionPicker({ permissions, pageRegistry, onChange }) {
|
|
216
|
+
var [expandedPage, setExpandedPage] = useState(null);
|
|
217
|
+
|
|
218
|
+
// Resolve grants from permissions
|
|
219
|
+
var grants = permissions === '*' ? (function() { var a = {}; Object.keys(pageRegistry).forEach(function(p) { a[p] = true; }); return a; })() : (permissions || {});
|
|
220
|
+
|
|
221
|
+
var togglePage = function(pid) {
|
|
222
|
+
var next = Object.assign({}, grants);
|
|
223
|
+
if (next[pid]) { delete next[pid]; if (expandedPage === pid) setExpandedPage(null); }
|
|
224
|
+
else { next[pid] = true; }
|
|
225
|
+
onChange(Object.keys(next).length === Object.keys(pageRegistry).length ? '*' : next);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
var toggleTab = function(pid, tabId) {
|
|
229
|
+
var next = Object.assign({}, grants);
|
|
230
|
+
var current = next[pid];
|
|
231
|
+
var allTabs = Object.keys(pageRegistry[pid].tabs || {});
|
|
232
|
+
if (current === true) {
|
|
233
|
+
var remaining = allTabs.filter(function(t) { return t !== tabId; });
|
|
234
|
+
next[pid] = remaining.length > 0 ? remaining : true;
|
|
235
|
+
} else if (Array.isArray(current)) {
|
|
236
|
+
var idx = current.indexOf(tabId);
|
|
237
|
+
if (idx >= 0) {
|
|
238
|
+
var arr = current.filter(function(t) { return t !== tabId; });
|
|
239
|
+
if (arr.length === 0) delete next[pid];
|
|
240
|
+
else next[pid] = arr;
|
|
241
|
+
} else {
|
|
242
|
+
var newArr = current.concat([tabId]);
|
|
243
|
+
next[pid] = newArr.length === allTabs.length ? true : newArr;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
onChange(Object.keys(next).length === Object.keys(pageRegistry).length && Object.values(next).every(function(v) { return v === true; }) ? '*' : next);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
var isTabChecked = function(pid, tabId) {
|
|
250
|
+
var g = grants[pid];
|
|
251
|
+
if (!g) return false;
|
|
252
|
+
if (g === true) return true;
|
|
253
|
+
return Array.isArray(g) && g.indexOf(tabId) >= 0;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
var sections = { overview: 'Overview', management: 'Management', administration: 'Administration' };
|
|
257
|
+
var grouped = {};
|
|
258
|
+
Object.keys(pageRegistry).forEach(function(pid) { var s = pageRegistry[pid].section; if (!grouped[s]) grouped[s] = []; grouped[s].push(pid); });
|
|
259
|
+
|
|
260
|
+
return h('div', { style: { maxHeight: 250, overflowY: 'auto', border: '1px solid var(--border)', borderRadius: 6, marginTop: 8 } },
|
|
261
|
+
Object.keys(sections).map(function(sKey) {
|
|
262
|
+
var pids = grouped[sKey] || [];
|
|
263
|
+
if (!pids.length) return null;
|
|
264
|
+
return h(Fragment, { key: sKey },
|
|
265
|
+
h('div', { style: { fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)', padding: '8px 10px 2px' } }, sections[sKey]),
|
|
266
|
+
pids.map(function(pid) {
|
|
267
|
+
var page = pageRegistry[pid];
|
|
268
|
+
var checked = !!grants[pid];
|
|
269
|
+
var hasTabs = page.tabs && Object.keys(page.tabs).length > 0;
|
|
270
|
+
var isExpanded = expandedPage === pid;
|
|
271
|
+
return h(Fragment, { key: pid },
|
|
272
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px', fontSize: 12, cursor: 'pointer', background: checked ? 'var(--bg-tertiary)' : 'transparent' }, onClick: function(e) {
|
|
273
|
+
if (e.target.closest && e.target.closest('[data-expand]')) return;
|
|
274
|
+
togglePage(pid);
|
|
275
|
+
} },
|
|
276
|
+
h('input', { type: 'checkbox', checked: checked, readOnly: true, style: { width: 14, height: 14, accentColor: 'var(--primary)', cursor: 'pointer' } }),
|
|
277
|
+
h('span', { style: { flex: 1 } }, page.label),
|
|
278
|
+
hasTabs && checked && h('button', { 'data-expand': true, className: 'btn btn-ghost', style: { padding: '0 4px', minWidth: 0, fontSize: 10, lineHeight: 1 }, onClick: function(e) { e.stopPropagation(); setExpandedPage(isExpanded ? null : pid); } },
|
|
279
|
+
isExpanded ? I.chevronDown() : I.chevronRight()
|
|
280
|
+
)
|
|
281
|
+
),
|
|
282
|
+
hasTabs && isExpanded && checked && Object.keys(page.tabs).map(function(tabId) {
|
|
283
|
+
return h('div', { key: tabId, style: { display: 'flex', alignItems: 'center', gap: 8, padding: '3px 10px 3px 34px', fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer' }, onClick: function() { toggleTab(pid, tabId); } },
|
|
284
|
+
h('input', { type: 'checkbox', checked: isTabChecked(pid, tabId), readOnly: true, style: { width: 13, height: 13, accentColor: 'var(--primary)', cursor: 'pointer' } }),
|
|
285
|
+
h('span', null, page.tabs[tabId])
|
|
286
|
+
);
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
213
295
|
// ─── Users Page ────────────────────────────────────
|
|
214
296
|
|
|
215
297
|
export function UsersPage() {
|
|
@@ -357,24 +439,11 @@ export function UsersPage() {
|
|
|
357
439
|
h('button', { type: 'button', className: 'btn btn-ghost btn-sm', onClick: function() { setShowCreatePerms(!showCreatePerms); }, style: { fontSize: 11 } }, showCreatePerms ? 'Hide' : 'Customize')
|
|
358
440
|
),
|
|
359
441
|
!showCreatePerms && h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginTop: 4 } }, 'Full access (default). Click "Customize" to restrict.'),
|
|
360
|
-
showCreatePerms && pageRegistry && h(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return h('div', { key: pid, style: { display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px', fontSize: 12, cursor: 'pointer' }, onClick: function() {
|
|
366
|
-
setForm(function(f) {
|
|
367
|
-
var current = f.permissions === '*' ? (function() { var a = {}; Object.keys(pageRegistry).forEach(function(p) { a[p] = true; }); return a; })() : Object.assign({}, f.permissions);
|
|
368
|
-
if (current[pid]) { delete current[pid]; } else { current[pid] = true; }
|
|
369
|
-
if (Object.keys(current).length === Object.keys(pageRegistry).length) return Object.assign({}, f, { permissions: '*' });
|
|
370
|
-
return Object.assign({}, f, { permissions: current });
|
|
371
|
-
});
|
|
372
|
-
} },
|
|
373
|
-
h('input', { type: 'checkbox', checked: checked, readOnly: true, style: { width: 14, height: 14, accentColor: 'var(--primary)' } }),
|
|
374
|
-
h('span', null, page.label)
|
|
375
|
-
);
|
|
376
|
-
})
|
|
377
|
-
)
|
|
442
|
+
showCreatePerms && pageRegistry && h(InlinePermissionPicker, {
|
|
443
|
+
permissions: form.permissions,
|
|
444
|
+
pageRegistry: pageRegistry,
|
|
445
|
+
onChange: function(p) { setForm(function(f) { return Object.assign({}, f, { permissions: p }); }); }
|
|
446
|
+
})
|
|
378
447
|
),
|
|
379
448
|
(form.role === 'owner' || form.role === 'admin') && h('div', { style: { marginTop: 8, padding: 8, background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 11, color: 'var(--info)' } },
|
|
380
449
|
'Owner and Admin roles always have full access to all pages.'
|