Skip to content

Commit 79d3ffb

Browse files
authored
Merge pull request #1138 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 50d8caf + 4d59a15 commit 79d3ffb

2 files changed

Lines changed: 78 additions & 17 deletions

File tree

src/pages/identity/administration/users/user/exchange.jsx

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ const Page = () => {
197197
const aliasApiConfig = {
198198
type: "POST",
199199
url: "/api/EditUserAliases",
200-
relatedQueryKeys: `ListUsers-${userId}`,
200+
relatedQueryKeys: [`ListUsers-${userId}`, `Mailbox-${userId}`],
201201
confirmText: "Add the specified proxy addresses to this user?",
202202
customDataformatter: (row, action, formData) => {
203203
return {
@@ -1259,8 +1259,8 @@ const Page = () => {
12591259
},
12601260
confirmText: "Are you sure you want to make this the primary proxy address?",
12611261
multiPost: false,
1262-
relatedQueryKeys: `ListUsers-${userId}`,
1263-
condition: (row) => row && row.Type !== "Primary",
1262+
relatedQueryKeys: [`ListUsers-${userId}`, `Mailbox-${userId}`],
1263+
condition: (row) => row && row.Type === "Alias",
12641264
},
12651265
{
12661266
label: "Remove Proxy Address",
@@ -1274,28 +1274,73 @@ const Page = () => {
12741274
},
12751275
confirmText: "Are you sure you want to remove this proxy address?",
12761276
multiPost: false,
1277-
relatedQueryKeys: `ListUsers-${userId}`,
1278-
condition: (row) => row && row.Type !== "Primary",
1277+
relatedQueryKeys: [`ListUsers-${userId}`, `Mailbox-${userId}`],
1278+
condition: (row) => row && row.Type === "Alias",
12791279
},
12801280
];
12811281

1282+
// Merge Entra ID proxyAddresses (fast, primary source) with the mailbox EmailAddresses
1283+
// from Exchange so forward-sync drift between the two directories is visible.
1284+
const graphProxyAddresses = (graphUserRequest.data?.[0]?.proxyAddresses || []).filter(
1285+
(address) => typeof address === "string",
1286+
);
1287+
// Mailbox serializes as an array with one element
1288+
const mailboxDetails = [].concat(userRequest.data?.[0]?.Mailbox || [])[0];
1289+
const exchangeProxyAddresses = []
1290+
.concat(mailboxDetails?.EmailAddresses || [])
1291+
.filter((address) => typeof address === "string");
1292+
// Only assess sync when Exchange returned addresses; a mailbox always has at least a primary
1293+
const exchangeAddressesLoaded = userRequest.isSuccess && exchangeProxyAddresses.length > 0;
1294+
const proxyAddressType = (address) =>
1295+
address.startsWith("SMTP:") ? "Primary" : address.startsWith("smtp:") ? "Alias" : address.split(":")[0];
1296+
const proxyAddressRows = (() => {
1297+
const rows = new Map();
1298+
graphProxyAddresses.forEach((address) => {
1299+
rows.set(address.toLowerCase(), { Address: address, inGraph: true, inExchange: false });
1300+
});
1301+
exchangeProxyAddresses.forEach((address) => {
1302+
const existing = rows.get(address.toLowerCase());
1303+
if (existing) {
1304+
existing.inExchange = true;
1305+
} else {
1306+
rows.set(address.toLowerCase(), { Address: address, inGraph: false, inExchange: true });
1307+
}
1308+
});
1309+
return [...rows.values()].map((row) => ({
1310+
Address: row.Address,
1311+
Type: proxyAddressType(row.Address),
1312+
Source: !exchangeAddressesLoaded
1313+
? "Checking"
1314+
: row.inGraph && row.inExchange
1315+
? "Entra ID & Exchange"
1316+
: row.inGraph
1317+
? "Entra ID only"
1318+
: "Exchange only",
1319+
}));
1320+
})();
1321+
const mismatchedAddresses = exchangeAddressesLoaded
1322+
? proxyAddressRows.filter((row) => row.Source !== "Entra ID & Exchange")
1323+
: [];
1324+
12821325
const proxyAddressesCard = [
12831326
{
12841327
id: 1,
12851328
cardLabelBox: {
12861329
cardLabelBoxHeader: graphUserRequest.isFetching ? (
12871330
<CircularProgress size="25px" color="inherit" />
1288-
) : graphUserRequest.data?.[0]?.proxyAddresses?.length > 1 ? (
1331+
) : mismatchedAddresses.length === 0 && graphUserRequest.data?.[0]?.proxyAddresses?.length > 1 ? (
12891332
<Check />
12901333
) : (
12911334
<Error />
12921335
),
12931336
},
12941337
text: "Proxy Addresses",
12951338
subtext:
1296-
graphUserRequest.data?.[0]?.proxyAddresses?.length > 1
1297-
? "Proxy addresses are configured for this user"
1298-
: "No proxy addresses configured for this user",
1339+
mismatchedAddresses.length > 0
1340+
? `${mismatchedAddresses.length} address(es) only exist in one of Entra ID or Exchange - Microsoft may still be propagating recent changes`
1341+
: graphUserRequest.data?.[0]?.proxyAddresses?.length > 1
1342+
? "Proxy addresses are configured for this user"
1343+
: "No proxy addresses configured for this user",
12991344
statusColor: "green.main",
13001345
cardLabelBoxActions: (
13011346
<Button
@@ -1311,14 +1356,13 @@ const Page = () => {
13111356
table: {
13121357
title: "Proxy Addresses",
13131358
hideTitle: true,
1314-
data:
1315-
graphUserRequest.data?.[0]?.proxyAddresses?.map((address) => ({
1316-
Address: address,
1317-
Type: typeof address === "string" && address.startsWith("SMTP:") ? "Primary" : "Alias",
1318-
})) || [],
1319-
refreshFunction: () => graphUserRequest.refetch(),
1359+
data: proxyAddressRows,
1360+
refreshFunction: () => {
1361+
graphUserRequest.refetch();
1362+
userRequest.refetch();
1363+
},
13201364
isFetching: graphUserRequest.isFetching,
1321-
simpleColumns: ["Address", "Type"],
1365+
simpleColumns: ["Address", "Type", "Source"],
13221366
actions: proxyAddressActions,
13231367
offCanvas: {
13241368
children: (data) => {
@@ -1335,6 +1379,10 @@ const Page = () => {
13351379
label: "Type",
13361380
value: data.Type,
13371381
},
1382+
{
1383+
label: "Source",
1384+
value: data.Source,
1385+
},
13381386
]}
13391387
actionItems={proxyAddressActions}
13401388
/>

src/pages/tenant/manage/drift.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ const ManageDriftPage = () => {
186186
if (item.deniedDeviations && Array.isArray(item.deniedDeviations)) {
187187
acc.deniedDeviationsList.push(...item.deniedDeviations.filter((dev) => dev !== null))
188188
}
189+
if (item.licenseMissingDeviations && Array.isArray(item.licenseMissingDeviations)) {
190+
acc.licenseMissingDeviationsList.push(
191+
...item.licenseMissingDeviations.filter((dev) => dev !== null)
192+
)
193+
}
189194

190195
// Extract compliant standards from ComparisonDetails in driftSettings
191196
if (
@@ -301,6 +306,7 @@ const ManageDriftPage = () => {
301306
acceptedDeviations: [],
302307
customerSpecificDeviationsList: [],
303308
deniedDeviationsList: [],
309+
licenseMissingDeviationsList: [],
304310
alignedStandards: [],
305311
latestDataCollection: null,
306312
}
@@ -1134,9 +1140,16 @@ const ManageDriftPage = () => {
11341140
'denied'
11351141
)
11361142
const alignedStandardItems = createDeviationItems(processedDriftData.alignedStandards, 'aligned')
1143+
const licenseMissingDeviationItems = createDeviationItems(
1144+
processedDriftData.licenseMissingDeviationsList,
1145+
'skipped'
1146+
)
11371147

11381148
// Separate items by their actual status
1139-
const licenseSkippedItems = deviationItems.filter((item) => item.isLicenseSkipped)
1149+
const licenseSkippedItems = [
1150+
...licenseMissingDeviationItems,
1151+
...deviationItems.filter((item) => item.isLicenseSkipped),
1152+
]
11401153
const compliantFromDeviations = deviationItems.filter((item) => item.isActuallyCompliant)
11411154
const actualDeviationItems = deviationItems.filter(
11421155
(item) => !item.isLicenseSkipped && !item.isActuallyCompliant

0 commit comments

Comments
 (0)