Show account names and roles on cards from scheduled scans
Cards from scheduled scans of editor-saved profiles showed the account's
GUID as its name and no Elev/Ansat badge: the profile editor stored bare
id strings, the scheduler passes them straight to run_scan, and run_scan
normalised them to displayName=<id>, userRole="other". Before 1.7.10 the
scan-start profile overwrite kept repairing profiles to named objects,
which is why this surfaced now.
- run_scan: _enrich_bare_users() looks bare accounts up in the directory
(list_users, falling back to lookup_user) for name and role.
- M365Connector.build_role_sku_map(): the SKU map /api/users built inline,
now shared so cards and the account list classify roles identically.
lookup_user() also returns assignedLicenses.
- Profile editor saves {id, displayName, userRole} (manual accounts keep
email/manual), like the 💾 save.
- _accountPill: an account_name equal to account_id counts as missing;
name and role are filled from the loaded user list, so existing cards
display correctly without a rescan.
- Excel export: the scan's account-name map no longer breaks on bare id
strings (.get() on a str raised and dropped the whole map).
Tests: tests/test_account_names.py (10); the run_scan test fails on the
old engine with "Collecting emails — guid-henrik…".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c55db48894
commit
20156ffc93
8 files changed
+283
-37
No files matched your search
+18
-7
@@ -437,8 +437,9 @@ function _openEditorForProfile(profile) {
|
||||
const accountRows = S._allUsers.map(u => {
|
||||
// Only check if the user was explicitly saved — default to unchecked like the main window
|
||||
const checked = isSaved(u) ? 'checked' : '';
|
||||
const manualAttrs = u.manual
|
||||
? ` data-manual="1" data-name="${_esc(u.displayName || '')}" data-email="${_esc(u.email || '')}"` : '';
|
||||
// data-name lets the save keep the display name with the id (see _pmgmtSaveFullEdit)
|
||||
const manualAttrs = ` data-name="${_esc(u.displayName || '')}"` + (u.manual
|
||||
? ` data-manual="1" data-email="${_esc(u.email || '')}"` : '');
|
||||
const platBadge = u.platform === 'both' ? '<span style="font-size:9px;padding:1px 5px;border-radius:10px;background:linear-gradient(90deg,#E6F1FB 50%,#EAF3DE 50%);color:#1a4a1a;font-weight:500;border:0.5px solid #b5d4b5">M365+GWS</span>'
|
||||
: (u.platform || 'm365') === 'google' ? '<span style="font-size:9px;padding:1px 5px;border-radius:10px;background:#EAF3DE;color:#3B6D11;font-weight:500">GWS</span>'
|
||||
: '<span style="font-size:9px;padding:1px 5px;border-radius:10px;background:#E6F1FB;color:#185FA5;font-weight:500">M365</span>';
|
||||
@@ -550,8 +551,9 @@ function _unresolvedAccountRows(savedList) {
|
||||
const label = (typeof u === 'object' && u.displayName) || id.replace(/^(manual|google):/, '');
|
||||
const badge = isManual ? t('m365_profile_acct_manual', 'Manual')
|
||||
: t('m365_profile_acct_unresolved', 'Not loaded');
|
||||
const manualAttrs = _isManualEntry(u) && typeof u === 'object'
|
||||
? ` data-manual="1" data-name="${_esc(u.displayName || '')}" data-email="${_esc(u.email || '')}"` : '';
|
||||
const savedName = typeof u === 'object' && u.displayName && u.displayName !== id ? u.displayName : '';
|
||||
const manualAttrs = (savedName ? ` data-name="${_esc(savedName)}"` : '') + (isManual && typeof u === 'object'
|
||||
? ` data-manual="1" data-email="${_esc(u.email || '')}"` : '');
|
||||
return `<label class="pmgmt-acct-row" data-uid="${_esc(id)}" data-role="${_esc((typeof u === 'object' && u.userRole) || 'other')}"><input type="checkbox" checked data-uid="${_esc(id)}"${manualAttrs}><span style="flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${_esc(id)}">${_esc(label)}</span><span style="font-size:9px;padding:1px 5px;border-radius:10px;background:#D3D1C7;color:#444441">${_esc(badge)}</span></label>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -737,9 +739,18 @@ async function _pmgmtSaveFullEdit() {
|
||||
const allSources = m365Sources.concat(effectiveGoogleSources).concat(effectiveFileSources);
|
||||
let user_ids = Array.from(document.querySelectorAll('#pmgmtAcctList input[type=checkbox]:checked'))
|
||||
.filter(cb => cb.dataset.uid)
|
||||
.map(cb => cb.dataset.manual
|
||||
? {id: cb.dataset.uid, displayName: cb.dataset.name || '', email: cb.dataset.email || '', manual: true}
|
||||
: cb.dataset.uid);
|
||||
.map(cb => {
|
||||
// Save name + role with the id (same shape as 💾 / getSelectedUsers()):
|
||||
// scheduled scans pass these straight to the scan, and a bare id became
|
||||
// the card's "name" with no Elev/Ansat badge.
|
||||
const role = cb.closest('label')?.dataset.role || 'other';
|
||||
if (cb.dataset.manual) {
|
||||
return {id: cb.dataset.uid, displayName: cb.dataset.name || '', email: cb.dataset.email || '',
|
||||
userRole: role, manual: true};
|
||||
}
|
||||
return cb.dataset.name ? {id: cb.dataset.uid, displayName: cb.dataset.name, userRole: role}
|
||||
: cb.dataset.uid;
|
||||
});
|
||||
// "all" profile opened before users loaded: there were no rows to tick, so keep "all"
|
||||
if (window._pmgmtSavedAll && !S._allUsers.length && !user_ids.length) user_ids = 'all';
|
||||
const updated = {
|
||||
|
||||
Reference in new issue
Block a user