+ )
+ }
+ data={results?.Results?.RoleMappingResults}
+ simpleColumns={["RoleName", "GroupName", "GroupId", "Status", "Message"]}
+ />
+ >
+ )}
+
{results?.Results?.Memberships?.filter(
(membership) => membership?.["@odata.type"] === "#microsoft.graph.group",
).length > 0 && (
diff --git a/src/components/CippTable/CippDataTable.js b/src/components/CippTable/CippDataTable.js
index 284579c2b60d..1d902eb64f90 100644
--- a/src/components/CippTable/CippDataTable.js
+++ b/src/components/CippTable/CippDataTable.js
@@ -24,6 +24,7 @@ import { CippApiDialog } from '../CippComponents/CippApiDialog'
import { getCippError } from '../../utils/get-cipp-error'
import { Box } from '@mui/system'
import { useSettings } from '../../hooks/use-settings'
+import { parseCippDate } from '../../utils/parse-cipp-date'
import { isEqual } from 'lodash' // Import lodash for deep comparison
import { useLicenseBackfill } from '../../hooks/use-license-backfill'
@@ -84,8 +85,8 @@ const SORTING_FNS = {
dateTimeNullsLast: (a, b, id) => {
const aRaw = getRowValueByColumnId(a, id)
const bRaw = getRowValueByColumnId(b, id)
- const aDate = aRaw ? new Date(aRaw) : null
- const bDate = bRaw ? new Date(bRaw) : null
+ const aDate = aRaw ? parseCippDate(aRaw) : null
+ const bDate = bRaw ? parseCippDate(bRaw) : null
const aTime = aDate && !Number.isNaN(aDate.getTime()) ? aDate.getTime() : null
const bTime = bDate && !Number.isNaN(bDate.getTime()) ? bDate.getTime() : null
diff --git a/src/components/CippWizard/CippWizardOffboarding.jsx b/src/components/CippWizard/CippWizardOffboarding.jsx
index 990cb9d35b11..2fc5947c22bf 100644
--- a/src/components/CippWizard/CippWizardOffboarding.jsx
+++ b/src/components/CippWizard/CippWizardOffboarding.jsx
@@ -12,9 +12,13 @@ import CippWizardStepButtons from './CippWizardStepButtons'
import CippFormComponent from '../CippComponents/CippFormComponent'
import { CippFormCondition } from '../CippComponents/CippFormCondition'
import { useWatch } from 'react-hook-form'
-import { useEffect, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { Grid } from '@mui/system'
import { useSettings } from '../../hooks/use-settings'
+import { ApiGetCall } from '../../api/ApiCall'
+
+// Shared mailboxes are capped at 50 GiB without a license; warn at 49 GiB.
+const SHARED_MAILBOX_WARN_BYTES = 49 * 1024 ** 3
export const CippWizardOffboarding = (props) => {
const { postUrl, formControl, onPreviousStep, onNextStep, currentStep } = props
@@ -24,6 +28,40 @@ export const CippWizardOffboarding = (props) => {
const userSettingsDefaults = useSettings().userSettingsDefaults
const disableForwarding = useWatch({ control: formControl.control, name: 'disableForwarding' })
const deleteUser = useWatch({ control: formControl.control, name: 'DeleteUser' })
+ const convertToShared = useWatch({ control: formControl.control, name: 'ConvertToShared' })
+
+ // Pull cached mailbox sizes (storageUsedInBytes, keyed by UPN) only when relevant
+ const mailboxUsage = ApiGetCall({
+ url: '/api/ListMailboxes',
+ data: { tenantFilter: currentTenant?.value, UseReportDB: true },
+ queryKey: `OffboardingMailboxUsage-${currentTenant?.value}`,
+ waiting: !!convertToShared && !!currentTenant?.value && selectedUsers?.length > 0,
+ })
+
+ // Selected mailboxes whose cached size would exceed the shared-mailbox limit
+ const oversizedMailboxes = useMemo(() => {
+ if (!convertToShared || !mailboxUsage.isSuccess || !Array.isArray(mailboxUsage.data)) {
+ return []
+ }
+ const selectedUpns = (selectedUsers || []).map((u) =>
+ (u?.value ?? u)?.toString().toLowerCase(),
+ )
+ return mailboxUsage.data
+ .filter((mb) => {
+ const upn = mb?.UPN?.toString().toLowerCase()
+ const bytes = Number(mb?.storageUsedInBytes)
+ return (
+ upn &&
+ selectedUpns.includes(upn) &&
+ Number.isFinite(bytes) &&
+ bytes >= SHARED_MAILBOX_WARN_BYTES
+ )
+ })
+ .map((mb) => ({
+ upn: mb.UPN,
+ sizeGB: (Number(mb.storageUsedInBytes) / 1024 ** 3).toFixed(1),
+ }))
+ }, [convertToShared, mailboxUsage.isSuccess, mailboxUsage.data, selectedUsers])
useEffect(() => {
if (selectedUsers.length >= 3) {
@@ -383,6 +421,21 @@ export const CippWizardOffboarding = (props) => {
formControl={formControl}
/>
+ {convertToShared && oversizedMailboxes.length > 0 && (
+