diff --git a/.github/workflows/auto_comments.yml b/.github/workflows/auto_comments.yml
index 9a7664c9007c..89a9908a6748 100644
--- a/.github/workflows/auto_comments.yml
+++ b/.github/workflows/auto_comments.yml
@@ -17,7 +17,7 @@ jobs:
# 1) If the comment includes '!notasponsor', delete it using GitHub Script
- name: Delete !notasponsor comment
if: contains(github.event.comment.body, '!notasponsor')
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/pr_check.yml b/.github/workflows/pr_check.yml
index 15b52ecd4e82..ea36ac1e82f7 100644
--- a/.github/workflows/pr_check.yml
+++ b/.github/workflows/pr_check.yml
@@ -25,7 +25,7 @@ jobs:
github.event.pull_request.head.repo.fork == true &&
((github.event.pull_request.head.ref == 'main' || github.event.pull_request.head.ref == 'master') ||
(github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master'))
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 647f3571b4c2..3622dc676b7c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -35,6 +35,13 @@
"cwd": "${cwd}",
"script": ". '${cwd}\\Tools\\Start-CIPPDevEmulators.ps1'"
},
+ {
+ "type": "PowerShell",
+ "name": "Launch in Windows Terminal with Offloading Proc and HTTP only workers",
+ "request": "launch",
+ "cwd": "${cwd}",
+ "script": ". '${cwd}\\Tools\\Start-CippOffloadSimulation.ps1'"
+ },
{
"type": "PowerShell",
"name": "Launch in Kitty Terminal",
diff --git a/Tools/Start-CippDevEmulators.ps1 b/Tools/Start-CippDevEmulators.ps1
index 2b5d4a4a7ac6..ecf6855fe1e5 100644
--- a/Tools/Start-CippDevEmulators.ps1
+++ b/Tools/Start-CippDevEmulators.ps1
@@ -22,7 +22,7 @@ $apiCommand = @'
try {
# Use a stable local identity so timer node selection treats this as the catch-all host.
$env:WEBSITE_SITE_NAME = "cipp"
- $env:CIPP_PROCESSOR = "true"
+ $env:CIPP_PROCESSOR = "false"
$env:AzureFunctionsWebHost__hostid = "cipp-single"
# Ensure prior offload simulation env overrides do not disable triggers in this shell.
@@ -42,5 +42,11 @@ try {
$frontendCommand = 'try { npm run dev } catch { Write-Error $_.Exception.Message } finally { Read-Host "Press Enter to exit" }'
$swaCommand = 'try { npm run start-swa } catch { Write-Error $_.Exception.Message } finally { Read-Host "Press Enter to exit" }'
+# Encode commands to avoid parsing issues with multi-line strings
+$azuriteEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($azuriteCommand))
+$apiEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($apiCommand))
+$frontendEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($frontendCommand))
+$swaEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($swaCommand))
+
# Start Windows Terminal with all tabs
-wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -c $azuriteCommand`; new-tab --title 'FunctionApp' -d $ApiPath pwsh -c $apiCommand`; new-tab --title 'CIPP Frontend' -d $FrontendPath pwsh -c $frontendCommand`; new-tab --title 'SWA' -d $FrontendPath pwsh -c $swaCommand
+wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -EncodedCommand $azuriteEncoded`; new-tab --title 'FunctionApp' -d $ApiPath pwsh -EncodedCommand $apiEncoded`; new-tab --title 'CIPP Frontend' -d $FrontendPath pwsh -EncodedCommand $frontendEncoded`; new-tab --title 'SWA' -d $FrontendPath pwsh -EncodedCommand $swaEncoded
diff --git a/package.json b/package.json
index 35da2539bbdb..07dae7f34412 100644
--- a/package.json
+++ b/package.json
@@ -31,11 +31,11 @@
"@emotion/styled": "11.14.1",
"@heroicons/react": "2.2.0",
"@monaco-editor/react": "^4.6.0",
- "@mui/icons-material": "7.3.7",
+ "@mui/icons-material": "7.3.10",
"@mui/lab": "7.0.0-beta.17",
- "@mui/material": "7.3.7",
- "@mui/system": "7.3.2",
- "@mui/x-date-pickers": "^8.27.2",
+ "@mui/material": "7.3.10",
+ "@mui/system": "7.3.10",
+ "@mui/x-date-pickers": "^9.0.2",
"@musement/iso-duration": "^1.0.0",
"@nivo/core": "^0.99.0",
"@nivo/sankey": "^0.99.0",
@@ -51,12 +51,12 @@
"@tiptap/extension-image": "^3.20.5",
"@tiptap/extension-table": "^3.19.0",
"@tiptap/pm": "^3.22.3",
- "@tiptap/react": "^3.4.1",
+ "@tiptap/react": "^3.20.5",
"@tiptap/starter-kit": "^3.20.5",
"@uiw/react-json-view": "^2.0.0-alpha.41",
"@vvo/tzdb": "^6.198.0",
"apexcharts": "5.10.4",
- "axios": "1.14.0",
+ "axios": "1.15.0",
"date-fns": "4.1.0",
"diff": "^8.0.3",
"eml-parse-js": "^1.2.0-beta.0",
@@ -100,7 +100,7 @@
"react-redux": "9.2.0",
"react-syntax-highlighter": "^16.1.0",
"react-time-ago": "^7.3.3",
- "react-virtuoso": "^4.18.3",
+ "react-virtuoso": "^4.18.5",
"react-window": "^2.2.7",
"recharts": "^3.7.0",
"redux": "5.0.1",
diff --git a/src/components/CippComponents/AppApprovalTemplateForm.jsx b/src/components/CippComponents/AppApprovalTemplateForm.jsx
index e58add0e6945..20db0c4c48cd 100644
--- a/src/components/CippComponents/AppApprovalTemplateForm.jsx
+++ b/src/components/CippComponents/AppApprovalTemplateForm.jsx
@@ -19,9 +19,76 @@ const AppApprovalTemplateForm = ({
refetchKey,
hideSubmitButton = false, // New prop to hide the submit button when used in a drawer
}) => {
+ const forbiddenManifestProperties = ["keyCredentials", "passwordCredentials"];
const [selectedPermissionSet, setSelectedPermissionSet] = useState(null);
const [permissionsLoaded, setPermissionsLoaded] = useState(false);
const [permissionSetDrawerVisible, setPermissionSetDrawerVisible] = useState(false);
+ const [manifestSanitizeMessage, setManifestSanitizeMessage] = useState(null);
+
+ const getManifestValidationError = (manifest) => {
+ if (!manifest.displayName) {
+ return "Application manifest must include a 'displayName' property";
+ }
+
+ if (manifest.signInAudience && manifest.signInAudience !== "AzureADMyOrg") {
+ return "signInAudience must be null, undefined, or 'AzureADMyOrg' for security reasons";
+ }
+
+ const presentForbiddenProperties = forbiddenManifestProperties.filter(
+ (propertyName) => Object.prototype.hasOwnProperty.call(manifest, propertyName)
+ );
+ if (presentForbiddenProperties.length > 0) {
+ return `Remove unsupported manifest properties: ${presentForbiddenProperties.join(", ")}.`;
+ }
+
+ return null;
+ };
+
+ const handleSanitizeManifest = () => {
+ const currentManifest = formControl.getValues("applicationManifest");
+
+ if (!currentManifest) {
+ setManifestSanitizeMessage({
+ severity: "warning",
+ text: "Paste a manifest first, then use cleanup.",
+ });
+ return;
+ }
+
+ try {
+ const parsedManifest = JSON.parse(currentManifest);
+ const removedProperties = forbiddenManifestProperties.filter((propertyName) =>
+ Object.prototype.hasOwnProperty.call(parsedManifest, propertyName)
+ );
+
+ if (removedProperties.length === 0) {
+ setManifestSanitizeMessage({
+ severity: "info",
+ text: "No forbidden sections found. Your manifest is already clean.",
+ });
+ return;
+ }
+
+ removedProperties.forEach((propertyName) => {
+ delete parsedManifest[propertyName];
+ });
+
+ formControl.setValue("applicationManifest", JSON.stringify(parsedManifest, null, 2), {
+ shouldDirty: true,
+ shouldValidate: true,
+ });
+
+ setManifestSanitizeMessage({
+ severity: "success",
+ text: `Removed forbidden sections: ${removedProperties.join(", ")}.`,
+ });
+ } catch (error) {
+ setManifestSanitizeMessage({
+ severity: "error",
+ text: "Manifest JSON is invalid. Fix the JSON and try cleanup again.",
+ });
+ }
+ };
// Watch for app type selection changes
const selectedAppType = useWatch({
@@ -40,6 +107,28 @@ const AppApprovalTemplateForm = ({
name: "applicationManifest",
});
+ const getForbiddenManifestPropertiesPresent = (manifestValue) => {
+ if (!manifestValue) {
+ return [];
+ }
+
+ try {
+ const manifest = JSON.parse(manifestValue);
+ return forbiddenManifestProperties.filter((propertyName) =>
+ Object.prototype.hasOwnProperty.call(manifest, propertyName)
+ );
+ } catch {
+ return [];
+ }
+ };
+
+ const forbiddenPropertiesInCurrentManifest =
+ selectedAppType === "ApplicationManifest"
+ ? getForbiddenManifestPropertiesPresent(selectedApplicationManifest)
+ : [];
+ const showSanitizeManifestButton = forbiddenPropertiesInCurrentManifest.length > 0;
+ const isTemplateFormValid = formControl?.formState?.isValid ?? false;
+
// Watch for app selection changes to update template name
const selectedApp = useWatch({
control: formControl?.control,
@@ -236,6 +325,22 @@ const AppApprovalTemplateForm = ({
}
}, [isEditing, isCopy, templateData]);
+ useEffect(() => {
+ if (!formControl) {
+ return;
+ }
+
+ formControl.trigger();
+ }, [
+ formControl,
+ selectedAppType,
+ selectedApplicationManifest,
+ selectedApp,
+ selectedGalleryTemplate,
+ selectedPermissionSetValue,
+ templateData,
+ ]);
+
// Handle form submission
const handleSubmit = (data) => {
let appDisplayName, appId, galleryTemplateId, applicationManifest;
@@ -249,11 +354,12 @@ const AppApprovalTemplateForm = ({
try {
applicationManifest = JSON.parse(data.applicationManifest);
- // Validate signInAudience - only allow null/undefined or "AzureADMyOrg"
- if (
- applicationManifest.signInAudience &&
- applicationManifest.signInAudience !== "AzureADMyOrg"
- ) {
+ const manifestValidationError = getManifestValidationError(applicationManifest);
+ if (manifestValidationError) {
+ setManifestSanitizeMessage({
+ severity: "error",
+ text: manifestValidationError,
+ });
return; // Don't submit if validation fails
}
@@ -481,24 +587,27 @@ const AppApprovalTemplateForm = ({
validate: (value) => {
try {
const manifest = JSON.parse(value);
-
- // Check for minimum required property
- if (!manifest.displayName) {
- return "Application manifest must include a 'displayName' property";
- }
-
- // Validate signInAudience if present
- if (manifest.signInAudience && manifest.signInAudience !== "AzureADMyOrg") {
- return "signInAudience must be null, undefined, or 'AzureADMyOrg' for security reasons";
- }
-
- return true;
+ return getManifestValidationError(manifest) ?? true;
} catch (e) {
return "Invalid JSON format";
}
},
}}
/>
+
+ {showSanitizeManifestButton && (
+
+
+
+ )}
+ {manifestSanitizeMessage && (
+
+ {manifestSanitizeMessage.text}
+
+ )}
+
{isEditing ? "Update Template" : "Create Template"}
diff --git a/src/components/CippComponents/CippAppApprovalTemplateDrawer.jsx b/src/components/CippComponents/CippAppApprovalTemplateDrawer.jsx
index 95526d194495..5315e080eb5a 100644
--- a/src/components/CippComponents/CippAppApprovalTemplateDrawer.jsx
+++ b/src/components/CippComponents/CippAppApprovalTemplateDrawer.jsx
@@ -144,7 +144,7 @@ export const CippAppApprovalTemplateDrawer = ({
variant="contained"
color="primary"
onClick={formControl.handleSubmit(handleSubmit)}
- disabled={updatePermissions.isPending}
+ disabled={updatePermissions.isPending || !formControl.formState.isValid}
>
{updatePermissions.isPending
? isEditMode
diff --git a/src/components/CippComponents/CippRestoreWizard.jsx b/src/components/CippComponents/CippRestoreWizard.jsx
index e2218d4d7e88..a539ccf16770 100644
--- a/src/components/CippComponents/CippRestoreWizard.jsx
+++ b/src/components/CippComponents/CippRestoreWizard.jsx
@@ -44,6 +44,7 @@ const TABLE_LABELS = {
AppPermissions: "App Permissions",
CommunityRepos: "Community Repositories",
Config: "CIPP Configuration",
+ CustomPowershellScripts: "Custom PowerShell/Test Scripts",
CustomData: "Custom Data",
CustomRoles: "Custom Roles",
Domains: "Domains",
diff --git a/src/components/CippSettings/CippPermissionCheck.jsx b/src/components/CippSettings/CippPermissionCheck.jsx
index 575f95cae5e1..ea5e20b8acc9 100644
--- a/src/components/CippSettings/CippPermissionCheck.jsx
+++ b/src/components/CippSettings/CippPermissionCheck.jsx
@@ -112,6 +112,17 @@ const CippPermissionCheck = (props) => {
);
};
+ const responseData = executeCheck?.error?.response?.data;
+ const responseText =
+ typeof responseData === "string" ? responseData : responseData ? JSON.stringify(responseData) : "";
+ const shouldShowApiResponse = responseText.includes(
+ "Access to this CIPP API endpoint is not allowed",
+ );
+ const checkErrorMessage =
+ shouldShowApiResponse
+ ? responseText
+ : `Failed to load ${type} check. Please try refreshing the page.`;
+
return (
<>
{
>
{executeCheck.isError && !importReport && (
- Failed to load {type} check. Please try refreshing the page.
+ {checkErrorMessage}
)}
{(executeCheck.isSuccess || executeCheck.isLoading) && (
diff --git a/src/components/CippSettings/CippRoleAddEdit.jsx b/src/components/CippSettings/CippRoleAddEdit.jsx
index 4c02bf71e673..757215cd0f49 100644
--- a/src/components/CippSettings/CippRoleAddEdit.jsx
+++ b/src/components/CippSettings/CippRoleAddEdit.jsx
@@ -103,6 +103,24 @@ export const CippRoleAddEdit = ({ selectedRole }) => {
return regex.test(value);
};
+ const getFunctionDescriptionText = (description) => {
+ if (!description) return null;
+
+ if (Array.isArray(description)) {
+ return description?.[0]?.Text || description?.[0]?.text || null;
+ }
+
+ if (typeof description === "string") {
+ return description;
+ }
+
+ if (typeof description === "object") {
+ return description?.Text || description?.text || null;
+ }
+
+ return null;
+ };
+
const getBaseRolePermissions = (role) => {
const roleConfig = cippRoles[role];
if (!roleConfig) return {};
@@ -434,7 +452,7 @@ export const CippRoleAddEdit = ({ selectedRole }) => {
const apiFunction = apiPermissions[cat][obj][type][api];
items.push({
name: apiFunction.Name,
- description: apiFunction.Description?.[0]?.Text || null,
+ description: getFunctionDescriptionText(apiFunction.Description),
});
}
return (
@@ -593,7 +611,9 @@ export const CippRoleAddEdit = ({ selectedRole }) => {
Object.keys(apiPermissions[cat][obj][type]).forEach(
(apiKey) => {
const apiFunction = apiPermissions[cat][obj][type][apiKey];
- const descriptionText = apiFunction.Description?.[0]?.Text;
+ const descriptionText = getFunctionDescriptionText(
+ apiFunction.Description
+ );
allEndpoints.push({
label: descriptionText
? `${apiFunction.Name} - ${descriptionText}`
diff --git a/src/components/CippWizard/CippGDAPTenantOnboarding.jsx b/src/components/CippWizard/CippGDAPTenantOnboarding.jsx
index 4c5dc48a77cc..6357c5642eb5 100644
--- a/src/components/CippWizard/CippGDAPTenantOnboarding.jsx
+++ b/src/components/CippWizard/CippGDAPTenantOnboarding.jsx
@@ -45,11 +45,7 @@ export const CippGDAPTenantOnboarding = (props) => {
});
const relationshipList = ApiGetCall({
- url: "/api/ListGraphRequest",
- data: {
- TenantFilter: "",
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- },
+ url: "/api/ListGDAPRelationships",
queryKey: "GDAPRelationshipOnboarding-wizard",
});
diff --git a/src/data/GDAPRoles.json b/src/data/GDAPRoles.json
index 7a92b58f95bc..df827501cdeb 100644
--- a/src/data/GDAPRoles.json
+++ b/src/data/GDAPRoles.json
@@ -814,5 +814,13 @@
"IsSystem": true,
"Name": "Customer Delegated Admin Relationship Administrator",
"ObjectId": "fc8ad4e2-40e4-4724-8317-bcda7503ecbf"
+ },
+ {
+ "ExtensionData": {},
+ "Description": "Assign the AI Administrator role to users who need to manage all aspects of Microsoft 365 Copilot, AI-related enterprise services, copilot agents, and view usage reports and service health dashboards.",
+ "IsEnabled": true,
+ "IsSystem": true,
+ "Name": "AI Administrator",
+ "ObjectId": "d2562ede-74db-457e-a7b6-544e236ebb61"
}
]
diff --git a/src/pages/500.js b/src/pages/500.js
index d25c3b9e761d..623609b2d974 100644
--- a/src/pages/500.js
+++ b/src/pages/500.js
@@ -1,23 +1,75 @@
-import { Box, Container, Stack, Typography } from "@mui/material";
-import { Grid } from "@mui/system";
-import Head from "next/head";
-import { CippImageCard } from "../components/CippCards/CippImageCard.jsx";
-import { Layout as DashboardLayout } from "../layouts/index.js";
-import { useEffect } from "react";
-import { useRouter } from "next/router.js";
+import { Box, Button, Container, Stack, Typography } from '@mui/material'
+import { Grid } from '@mui/system'
+import Head from 'next/head'
+import { CippImageCard } from '../components/CippCards/CippImageCard.jsx'
+import { Layout as DashboardLayout } from '../layouts/index.js'
+import { useEffect } from 'react'
+import { useRouter } from 'next/router.js'
+import { ErrorBoundary } from 'react-error-boundary'
+
+// Minimal fallback if DashboardLayout itself crashes — breaks the infinite loop
+const MinimalErrorFallback = ({ error, resetErrorBoundary, outerError }) => {
+ const handleClearCacheAndReload = () => {
+ if (typeof window !== 'undefined') {
+ Object.keys(localStorage).forEach((key) => {
+ if (key.startsWith('REACT_QUERY_OFFLINE_CACHE')) {
+ localStorage.removeItem(key)
+ }
+ })
+ }
+ window.location.reload(true)
+ }
+
+ return (
+
+
+
+ Error 500 - Something went wrong
+ Oh no! It seems something went wrong.
+
+ {outerError?.message || error?.message}
+
+
+
+
+
+
+
+
+ )
+}
const Error500 = (props) => {
//when we browse away from the page we want to reset the error boundary
//this will prevent the error from showing on other pages
- const router = useRouter();
+ const router = useRouter()
useEffect(() => {
return () => {
- props.resetErrorBoundary();
- };
- }, [router]);
+ props.resetErrorBoundary()
+ }
+ }, [router])
return (
- <>
+ (
+
+ )}
+ >
500 - Error
@@ -26,17 +78,17 @@ const Error500 = (props) => {
sx={{
flexGrow: 1,
py: 4,
- height: "80vh",
+ height: '80vh',
}}
>
-
+
{
text={
<>
Oh no! It seems something went wrong.
- {props.error.message}
+ {props.error?.message}
You can use the button below to try again.
>
}
title="Error 500 - Something went wrong"
- linkText={"Try again"}
+ linkText={'Try again'}
onButtonClick={() => props.resetErrorBoundary()}
/>
@@ -59,8 +111,8 @@ const Error500 = (props) => {
- >
- );
-};
+
+ )
+}
-export default Error500;
+export default Error500
diff --git a/src/pages/onboardingv2.js b/src/pages/onboardingv2.js
index 59f101d6f8f8..3046798627ac 100644
--- a/src/pages/onboardingv2.js
+++ b/src/pages/onboardingv2.js
@@ -13,52 +13,64 @@ import { CippDirectTenantDeploy } from "../components/CippWizard/CippDirectTenan
import { CippGDAPTenantSetup } from "../components/CippWizard/CippGDAPTenantSetup.jsx";
import { CippGDAPTenantOnboarding } from "../components/CippWizard/CippGDAPTenantOnboarding.jsx";
import { BuildingOfficeIcon, CloudIcon, CpuChipIcon } from "@heroicons/react/24/outline";
+import { useRouter } from "next/router";
const Page = () => {
+ const router = useRouter();
+ const selectedOptionQuery = router.query?.selectedOption;
+ const deepLinkedOption = Array.isArray(selectedOptionQuery)
+ ? selectedOptionQuery[0]
+ : selectedOptionQuery;
+ const setupOptions = [
+ {
+ description:
+ "Choose this option if this is your first setup, or if you'd like to redo the previous setup.",
+ icon: ,
+ label: "First Setup",
+ value: "FirstSetup",
+ },
+ {
+ description: "Choose this option if you would like to add a tenant to your environment.",
+ icon: ,
+ label: "Add a tenant",
+ value: "AddTenant",
+ },
+ {
+ description:
+ "Choose this option if you want to setup which application registration is used to connect to your tenants.",
+ icon: ,
+ label: "Create a new application registration for me and connect to my tenants",
+ value: "CreateApp",
+ },
+ {
+ description: "I would like to refresh my token or replace the account I've used.",
+ icon: ,
+ label: "Refresh Tokens for existing application registration",
+ value: "UpdateTokens",
+ },
+ {
+ description:
+ "I have an existing application and would like to manually enter my token, or update them. This is only recommended for advanced users.",
+ icon: ,
+ label: "Manually enter credentials",
+ value: "Manual",
+ },
+ ];
+
+ const hasDeepLinkedOption =
+ typeof deepLinkedOption === "string" &&
+ setupOptions.some((option) => option.value === deepLinkedOption);
+
const steps = [
{
description: "Onboarding",
component: CippWizardOptionsList,
+ hideStepWhen: () => hasDeepLinkedOption,
componentProps: {
title: "Select your setup method",
subtext: `This wizard will guide you through setting up CIPPs access to your client tenants. If this is your first time setting up CIPP you will want to choose the option "Create application for me and connect to my tenants",`,
valuesKey: "SyncTool",
- options: [
- {
- description:
- "Choose this option if this is your first setup, or if you'd like to redo the previous setup.",
- icon: ,
- label: "First Setup",
- value: "FirstSetup",
- },
- {
- description:
- "Choose this option if you would like to add a tenant to your environment.",
- icon: ,
- label: "Add a tenant",
- value: "AddTenant",
- },
- {
- description:
- "Choose this option if you want to setup which application registration is used to connect to your tenants.",
- icon: ,
- label: "Create a new application registration for me and connect to my tenants",
- value: "CreateApp",
- },
- {
- description: "I would like to refresh my token or replace the account I've used.",
- icon: ,
- label: "Refresh Tokens for existing application registration",
- value: "UpdateTokens",
- },
- {
- description:
- "I have an existing application and would like to manually enter my token, or update them. This is only recommended for advanced users.",
- icon: ,
- label: "Manually enter credentials",
- value: "Manual",
- },
- ],
+ options: setupOptions,
},
},
{
@@ -137,6 +149,7 @@ const Page = () => {
steps={steps}
wizardTitle="Setup Wizard"
postUrl={"/api/ExecCombinedSetup"}
+ initialState={hasDeepLinkedOption ? { selectedOption: deepLinkedOption } : undefined}
/>
>
);
diff --git a/src/pages/tenant/gdap-management/index.js b/src/pages/tenant/gdap-management/index.js
index 9aafd4a40531..25e1a1308489 100644
--- a/src/pages/tenant/gdap-management/index.js
+++ b/src/pages/tenant/gdap-management/index.js
@@ -19,18 +19,16 @@ import CippButtonCard from "../../../components/CippCards/CippButtonCard";
import { WizardSteps } from "../../../components/CippWizard/wizard-steps";
import Link from "next/link";
import { CippHead } from "../../../components/CippComponents/CippHead";
+import { usePermissions } from "../../../hooks/use-permissions";
const Page = () => {
const [createDefaults, setCreateDefaults] = useState(false);
const [activeStep, setActiveStep] = useState(0);
+ const { checkRoles } = usePermissions();
+ const canViewGdapChecks = checkRoles(["CIPP.AppSettings.Read"]);
const relationships = ApiGetCallWithPagination({
- url: "/api/ListGraphRequest",
- data: {
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- tenantFilter: "",
- $top: 300,
- },
+ url: "/api/ListGDAPRelationships",
queryKey: "ListGDAPRelationships",
});
@@ -167,46 +165,50 @@ const Page = () => {
}
variant="contained"
>
Add a Tenant
-
-
-
-
-
-
-
-
+ {canViewGdapChecks && (
+ <>
+
+
+
+
+
+
+
+
+ >
+ )}
);
diff --git a/src/pages/tenant/gdap-management/offboarding.js b/src/pages/tenant/gdap-management/offboarding.js
index d9486f775c25..aa6cddc87d0d 100644
--- a/src/pages/tenant/gdap-management/offboarding.js
+++ b/src/pages/tenant/gdap-management/offboarding.js
@@ -22,60 +22,46 @@ const Page = () => {
return vendor.vendorTenantId;
})
.join(",");
- const vendorGraphFilter = `appOwnerOrganizationId in (${vendorFilter})`;
const tenantId = useWatch({
control: formControl.control,
name: "tenantFilter",
});
const gdapRelationships = ApiGetCall({
- url: "/api/ListGraphRequest",
- data: {
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- tenantFilter: "",
- $top: 300,
- },
+ url: "/api/ListGDAPRelationships",
queryKey: "ListGDAPRelationship",
});
const cspContracts = ApiGetCall({
- url: "/api/ListGraphRequest",
- data: {
- Endpoint: "contracts",
- tenantFilter: "",
- $top: 300,
- },
+ url: "/api/ListGDAPContracts",
queryKey: "ListContracts",
});
const mspApps = ApiGetCall({
- url: "/api/ListGraphRequest",
+ url: "/api/ListGDAPServicePrincipals",
data: {
- Endpoint: "servicePrincipals",
- TenantFilter: tenantId?.value,
- $filter: `appOwnerOrganizationId eq %partnertenantid%`,
- $select: "id,displayName,appId,appOwnerOrganizationId",
- $count: true,
+ tenantFilter: tenantId?.value,
+ ownerType: "partner",
},
queryKey: "ListMSPApps-" + tenantId?.value,
+ waiting: Boolean(tenantId?.value),
});
const vendorApps = ApiGetCallWithPagination({
- url: "/api/ListGraphRequest",
+ url: "/api/ListGDAPServicePrincipals",
data: {
- Endpoint: "servicePrincipals",
- TenantFilter: tenantId?.value,
- $filter: vendorGraphFilter,
- $select: "id,displayName,appId,appOwnerOrganizationId",
- $count: true,
+ tenantFilter: tenantId?.value,
+ ownerType: "vendor",
+ vendorTenantIds: vendorFilter,
},
queryKey: "ListVendorApps-" + tenantId?.value,
+ waiting: Boolean(tenantId?.value),
});
return (
<>
{
label="Select Tenant to Offboard"
type="autoComplete"
api={{
- url: "/api/ExecExcludeTenant",
- data: {
- ListAll: true,
- },
- queryKey: "ListAllTenants",
+ url: "/api/ListOffboardTenants",
+ queryKey: "ListOffboardTenants",
labelField: (tenant) => {
return `${tenant.displayName} (${tenant.defaultDomainName})`;
},
@@ -205,13 +188,11 @@ const Page = () => {
label="Vendor Applications to Remove"
type="autoComplete"
api={{
- url: "/api/ListGraphRequest",
+ url: "/api/ListGDAPServicePrincipals",
data: {
- Endpoint: "servicePrincipals",
- TenantFilter: tenantId.value,
- $filter: vendorGraphFilter,
- $select: "id,displayName,appId,appOwnerOrganizationId",
- $count: true,
+ tenantFilter: tenantId.value,
+ ownerType: "vendor",
+ vendorTenantIds: vendorFilter,
},
dataKey: "Results",
queryKey: "ListVendorApps-" + tenantId.value,
diff --git a/src/pages/tenant/gdap-management/onboarding/start.js b/src/pages/tenant/gdap-management/onboarding/start.js
index c2908d22a467..c5cf9cf5da3a 100644
--- a/src/pages/tenant/gdap-management/onboarding/start.js
+++ b/src/pages/tenant/gdap-management/onboarding/start.js
@@ -49,11 +49,7 @@ const Page = () => {
});
const relationshipList = ApiGetCall({
- url: "/api/ListGraphRequest",
- data: {
- TenantFilter: "",
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- },
+ url: "/api/ListGDAPRelationships",
queryKey: "GDAPRelationshipOnboarding",
});
const onboardingList = ApiGetCallWithPagination({
@@ -317,10 +313,7 @@ const Page = () => {
label="Select GDAP Relationship"
type="autoComplete"
api={{
- url: "/api/ListGraphRequest",
- data: {
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- },
+ url: "/api/ListGDAPRelationships",
excludeTenantFilter: true,
queryKey: "GDAPRelationships",
dataKey: "Results",
diff --git a/src/pages/tenant/gdap-management/relationships/index.js b/src/pages/tenant/gdap-management/relationships/index.js
index 8c3c3da01bc0..f3a3e4f441a7 100644
--- a/src/pages/tenant/gdap-management/relationships/index.js
+++ b/src/pages/tenant/gdap-management/relationships/index.js
@@ -4,8 +4,6 @@ import tabOptions from "../tabOptions";
import CippTablePage from "../../../../components/CippComponents/CippTablePage";
import CippGdapActions from "../../../../components/CippComponents/CippGdapActions";
-const pageTitle = "GDAP Relationships";
-
const actions = CippGdapActions();
const simpleColumns = [
@@ -47,20 +45,12 @@ const offCanvas = {
extendedInfoFields: simpleColumns,
};
-const apiUrl = "/api/ListGraphRequest";
-const apiData = {
- Endpoint: "tenantRelationships/delegatedAdminRelationships",
- tenantFilter: "",
- $top: 300,
-};
-
const Page = () => {
return (
{
const [relationshipData, setRelationshipData] = useState({});
const relationshipRequest = ApiGetCall({
- url: `/api/ListGraphRequest?Endpoint=tenantRelationships/delegatedAdminRelationships/${id}`,
+ url: `/api/ListGDAPRelationships?id=${id}`,
queryKey: `ListRelationships-${id}`,
});
diff --git a/src/pages/tenant/gdap-management/relationships/relationship/mappings.js b/src/pages/tenant/gdap-management/relationships/relationship/mappings.js
index 3ec708b70c66..b9669e3f725f 100644
--- a/src/pages/tenant/gdap-management/relationships/relationship/mappings.js
+++ b/src/pages/tenant/gdap-management/relationships/relationship/mappings.js
@@ -12,7 +12,7 @@ const Page = () => {
const { id } = router.query;
const relationshipRequest = ApiGetCall({
- url: `/api/ListGraphRequest?Endpoint=tenantRelationships/delegatedAdminRelationships/${id}`,
+ url: `/api/ListGDAPRelationships?id=${id}`,
queryKey: `ListRelationships-${id}`,
});
diff --git a/src/utils/get-cipp-error.js b/src/utils/get-cipp-error.js
index 4b38df2af676..105ced73caf2 100644
--- a/src/utils/get-cipp-error.js
+++ b/src/utils/get-cipp-error.js
@@ -16,7 +16,7 @@ export const getCippError = (data) => {
if (data.response?.data?.Results) {
return data.response.data.Results;
}
-
+
if (data.response?.data) {
return data.response.data;
}
diff --git a/src/utils/get-cipp-license-translation.js b/src/utils/get-cipp-license-translation.js
index 0397585d927a..321379fc6785 100644
--- a/src/utils/get-cipp-license-translation.js
+++ b/src/utils/get-cipp-license-translation.js
@@ -3,9 +3,18 @@ import M365LicensesAdditional from "../data/M365Licenses-additional.json";
import { getCachedLicense } from "./cipp-license-cache";
import licenseBackfillManager from "./cipp-license-backfill-manager";
+// Create a Map for O(1) lookups of GUID to Product_Display_Name
+const licenseByGuid = new Map();
+[...M365LicensesDefault, ...M365LicensesAdditional].forEach((entry) => {
+ if (entry.GUID) {
+ const key = entry.GUID.toLowerCase();
+ if (!licenseByGuid.has(key)) {
+ licenseByGuid.set(key, entry.Product_Display_Name);
+ }
+ }
+});
+
export const getCippLicenseTranslation = (licenseArray) => {
- //combine M365LicensesDefault and M365LicensesAdditional to one array
- const M365Licenses = [...M365LicensesDefault, ...M365LicensesAdditional];
let licenses = [];
let missingSkuIds = [];
@@ -24,17 +33,16 @@ export const getCippLicenseTranslation = (licenseArray) => {
licenseArray?.forEach((licenseAssignment) => {
let found = false;
- // First, check static JSON files
- for (let x = 0; x < M365Licenses.length; x++) {
- if (licenseAssignment.skuId === M365Licenses[x].GUID) {
- licenses.push(
- M365Licenses[x].Product_Display_Name
- ? M365Licenses[x].Product_Display_Name
- : licenseAssignment.skuPartNumber,
- );
- found = true;
- break;
- }
+ // First, check static JSON map (O(1) lookup)
+ const skuLower = licenseAssignment.skuId?.toLowerCase();
+ const displayName = skuLower ? licenseByGuid.get(skuLower) : undefined;
+ if (displayName) {
+ licenses.push(displayName);
+ found = true;
+ } else if (skuLower && licenseByGuid.has(skuLower)) {
+ // Entry exists but Product_Display_Name is falsy — fall back to skuPartNumber
+ licenses.push(licenseAssignment.skuPartNumber || licenseAssignment.skuId);
+ found = true;
}
// Second, check dynamic cache
diff --git a/src/utils/get-cipp-validator.js b/src/utils/get-cipp-validator.js
index e1db092ae1ad..f5541e0dc25c 100644
--- a/src/utils/get-cipp-validator.js
+++ b/src/utils/get-cipp-validator.js
@@ -41,7 +41,7 @@ export const getCippValidator = (value, type) => {
case "wildcardDomain":
return /^(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.\*)?$/.test(value) || /^(\*)?[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\*)?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/.test(value) || "This is not a valid domain pattern";
case "wildcardUrl":
- return /^(https?:\/\/)?(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.\*)?([\/\?\*][a-zA-Z0-9\-\.\~\*\/\?=&%]*)?$/.test(value) || "This is not a valid URL pattern";
+ return /^(https?:\/\/)?(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.\*)?([\/\?\*][a-zA-Z0-9\-\.\~\*\/\?=&%]*)?$/.test(value) || "This is not a valid URL pattern";
case "senderEntry":
return (
/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$/.test(value) ||
diff --git a/yarn.lock b/yarn.lock
index 052eb57111f7..717cf1e70089 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1368,17 +1368,17 @@
dependencies:
"@monaco-editor/loader" "^1.5.0"
-"@mui/core-downloads-tracker@^7.3.7":
- version "7.3.9"
- resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.9.tgz#d944e385f8f7f5e680e5ba479b39ff8602bd4939"
- integrity sha512-MOkOCTfbMJwLshlBCKJ59V2F/uaLYfmKnN76kksj6jlGUVdI25A9Hzs08m+zjBRdLv+sK7Rqdsefe8X7h/6PCw==
+"@mui/core-downloads-tracker@^7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.10.tgz#f6af0bbfa825f11849f5f190d984d6f8d5c0d961"
+ integrity sha512-vrOpWRmPJSuwLo23J62wggEm/jvGdzqctej+UOCtgDUz6nZJQuj3ByPccVyaa7eQmwAzUwKN56FQPMKkqbj1GA==
-"@mui/icons-material@7.3.7":
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-7.3.7.tgz#01a6019c552e27c7f8a3451bcb47171ede8b34ac"
- integrity sha512-3Q+ulAqG+A1+R4ebgoIs7AccaJhIGy+Xi/9OnvX376jQ6wcy+rz4geDGrxQxCGzdjOQr4Z3NgyFSZCz4T999lA==
+"@mui/icons-material@7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-7.3.10.tgz#f0d232ebe007b3a125a52c5c9e1bece43a83b57c"
+ integrity sha512-Au0ma4NSKGKNiimukj8UT/W1x2Qx6Qwn2RvFGykiSqVLYBNlIOPbjnIMvrwLGLu89EEpTVdu/ys/OduZR+tWqw==
dependencies:
- "@babel/runtime" "^7.28.4"
+ "@babel/runtime" "^7.28.6"
"@mui/lab@7.0.0-beta.17":
version "7.0.0-beta.17"
@@ -1392,16 +1392,16 @@
clsx "^2.1.1"
prop-types "^15.8.1"
-"@mui/material@7.3.7":
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.3.7.tgz#50fc9b9f8645a4d26a48d7c5f7fa0c9876a8c679"
- integrity sha512-6bdIxqzeOtBAj2wAsfhWCYyMKPLkRO9u/2o5yexcL0C3APqyy91iGSWgT3H7hg+zR2XgE61+WAu12wXPON8b6A==
+"@mui/material@7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.3.10.tgz#1c954b0e7aba220703afe07594388a69383c7363"
+ integrity sha512-cHvGOk2ZEfbQt3LnGe0ZKd/ETs9gsUpkW66DCO+GSjMZhpdKU4XsuIr7zJ/B/2XaN8ihxuzHfYAR4zPtCN4RYg==
dependencies:
- "@babel/runtime" "^7.28.4"
- "@mui/core-downloads-tracker" "^7.3.7"
- "@mui/system" "^7.3.7"
- "@mui/types" "^7.4.10"
- "@mui/utils" "^7.3.7"
+ "@babel/runtime" "^7.28.6"
+ "@mui/core-downloads-tracker" "^7.3.10"
+ "@mui/system" "^7.3.10"
+ "@mui/types" "^7.4.12"
+ "@mui/utils" "^7.3.10"
"@popperjs/core" "^2.11.8"
"@types/react-transition-group" "^4.4.12"
clsx "^2.1.1"
@@ -1410,7 +1410,16 @@
react-is "^19.2.3"
react-transition-group "^4.4.5"
-"@mui/private-theming@^7.3.2", "@mui/private-theming@^7.3.9":
+"@mui/private-theming@^7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-7.3.10.tgz#2e500959f39c7b305a30ff3f947f47dea9e8eac1"
+ integrity sha512-j3EZN+zOctxUISvJSmsEPo5o2F8zse4l5vRkBY+ps6UtnL6J7o14kUaI4w7gwo73id9e3cDNMVQK/9BVaMHVBw==
+ dependencies:
+ "@babel/runtime" "^7.28.6"
+ "@mui/utils" "^7.3.10"
+ prop-types "^15.8.1"
+
+"@mui/private-theming@^7.3.9":
version "7.3.9"
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-7.3.9.tgz#c785dc429b7ed62cf3952140be703cbe95704a13"
integrity sha512-ErIyRQvsiQEq7Yvcvfw9UDHngaqjMy9P3JDPnRAaKG5qhpl2C4tX/W1S4zJvpu+feihmZJStjIyvnv6KDbIrlw==
@@ -1419,7 +1428,19 @@
"@mui/utils" "^7.3.9"
prop-types "^15.8.1"
-"@mui/styled-engine@^7.3.2", "@mui/styled-engine@^7.3.9":
+"@mui/styled-engine@^7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.3.10.tgz#53e98c1fdeda972b5932c76f6a2a29faf33f0d11"
+ integrity sha512-WxE9SiF8xskAQqGjsp0poXCkCqsoXFEsSr0HBXfApmGHR+DBnXRp+z46Vsltg4gpPM4Z96DeAQRpeAOnhNg7Ng==
+ dependencies:
+ "@babel/runtime" "^7.28.6"
+ "@emotion/cache" "^11.14.0"
+ "@emotion/serialize" "^1.3.3"
+ "@emotion/sheet" "^1.4.0"
+ csstype "^3.2.3"
+ prop-types "^15.8.1"
+
+"@mui/styled-engine@^7.3.9":
version "7.3.9"
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.3.9.tgz#e425ca7b5cb559bde01b8fa4a7a842e9b5916f53"
integrity sha512-JqujWt5bX4okjUPGpVof/7pvgClqh7HvIbsIBIOOlCh2u3wG/Bwp4+E1bc1dXSwkrkp9WUAoNdI5HEC+5HKvMw==
@@ -1431,21 +1452,21 @@
csstype "^3.2.3"
prop-types "^15.8.1"
-"@mui/system@7.3.2":
- version "7.3.2"
- resolved "https://registry.yarnpkg.com/@mui/system/-/system-7.3.2.tgz#e838097fc6cb0a2e4c1822478950db89affb116a"
- integrity sha512-9d8JEvZW+H6cVkaZ+FK56R53vkJe3HsTpcjMUtH8v1xK6Y1TjzHdZ7Jck02mGXJsE6MQGWVs3ogRHTQmS9Q/rA==
+"@mui/system@7.3.10", "@mui/system@^7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/system/-/system-7.3.10.tgz#b8e668537605413be168a865d4e980c7d6747320"
+ integrity sha512-/sfPpdpJaQn7BSF+avjIdHSYmxHp0UOBYNxSG9QGKfMOD6sLANCpRPCnanq1Pe0lFf0NHkO2iUk0TNzdWC1USQ==
dependencies:
- "@babel/runtime" "^7.28.3"
- "@mui/private-theming" "^7.3.2"
- "@mui/styled-engine" "^7.3.2"
- "@mui/types" "^7.4.6"
- "@mui/utils" "^7.3.2"
+ "@babel/runtime" "^7.28.6"
+ "@mui/private-theming" "^7.3.10"
+ "@mui/styled-engine" "^7.3.10"
+ "@mui/types" "^7.4.12"
+ "@mui/utils" "^7.3.10"
clsx "^2.1.1"
- csstype "^3.1.3"
+ csstype "^3.2.3"
prop-types "^15.8.1"
-"@mui/system@^7.3.2", "@mui/system@^7.3.7":
+"@mui/system@^7.3.2":
version "7.3.9"
resolved "https://registry.yarnpkg.com/@mui/system/-/system-7.3.9.tgz#d8181dd9ad8c5e9afdf50eb7009062c506976ab1"
integrity sha512-aL1q9am8XpRrSabv9qWf5RHhJICJql34wnrc1nz0MuOglPRYF/liN+c8VqZdTvUn9qg+ZjRVbKf4sJVFfIDtmg==
@@ -1459,14 +1480,45 @@
csstype "^3.2.3"
prop-types "^15.8.1"
-"@mui/types@^7.4.10", "@mui/types@^7.4.12", "@mui/types@^7.4.6":
+"@mui/types@^7.4.12", "@mui/types@^7.4.6":
version "7.4.12"
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.4.12.tgz#e4eba37a7506419ea5c5e0604322ba82b271bf46"
integrity sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==
dependencies:
"@babel/runtime" "^7.28.6"
-"@mui/utils@^7.3.2", "@mui/utils@^7.3.5", "@mui/utils@^7.3.7", "@mui/utils@^7.3.9":
+"@mui/types@^9.0.0":
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/@mui/types/-/types-9.0.0.tgz#92d8c64e72cb863ee59108cb20cc476d648a3ab9"
+ integrity sha512-i1cuFCAWN44b3AJWO7mh7tuh1sqbQSeVr/94oG0TX5uXivac8XalgE4/6fQZcmGZigzbQ35IXxj/4jLpRIBYZg==
+ dependencies:
+ "@babel/runtime" "^7.29.2"
+
+"@mui/utils@9.0.0":
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-9.0.0.tgz#25b563ccbf537feba5f89c37a00cb8e6eea45ad0"
+ integrity sha512-bQcqyg/gjULUqTuyUjSAFr6LQGLvtkNtDbJerAtoUn9kGZ0hg5QJiN1PLHMLbeFpe3te1831uq7GFl2ITokGdg==
+ dependencies:
+ "@babel/runtime" "^7.29.2"
+ "@mui/types" "^9.0.0"
+ "@types/prop-types" "^15.7.15"
+ clsx "^2.1.1"
+ prop-types "^15.8.1"
+ react-is "^19.2.4"
+
+"@mui/utils@^7.3.10":
+ version "7.3.10"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-7.3.10.tgz#b74050131ca9022c0815d16f54f1a6d757ab343d"
+ integrity sha512-7y2eIfy0h7JPz+Yy4pS+wgV68d46PuuxDqKBN4Q8VlPQSsCAGwroMCV6xWyc7g9dvEp8ZNFsknc59GHWO+r6Ow==
+ dependencies:
+ "@babel/runtime" "^7.28.6"
+ "@mui/types" "^7.4.12"
+ "@types/prop-types" "^15.7.15"
+ clsx "^2.1.1"
+ prop-types "^15.8.1"
+ react-is "^19.2.3"
+
+"@mui/utils@^7.3.2", "@mui/utils@^7.3.9":
version "7.3.9"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-7.3.9.tgz#8af5093fc93c2e582fa3d047f561c7b690509bc2"
integrity sha512-U6SdZaGbfb65fqTsH3V5oJdFj9uYwyLE2WVuNvmbggTSDBb8QHrFsqY8BN3taK9t3yJ8/BPHD/kNvLNyjwM7Yw==
@@ -1478,26 +1530,26 @@
prop-types "^15.8.1"
react-is "^19.2.3"
-"@mui/x-date-pickers@^8.27.2":
- version "8.27.2"
- resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-8.27.2.tgz#5ada1fb3adffff3e0fd0fee7702fba7f770dca68"
- integrity sha512-06LFkHFRXJ2O9DMXtWAA3kY0jpbL7XH8iqa8L5cBlN+8bRx/UVLKlZYlhGv06C88jF9kuZWY1bUgrv/EoY/2Ww==
+"@mui/x-date-pickers@^9.0.2":
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-9.0.2.tgz#ac601e4655ce3017185d652f9f91a2914bb6e63a"
+ integrity sha512-rnyc2wFPnprTS5i8Lq9aX2Rlx+ZRvNZERTd7sPMErf/8HnMCYzxwErITbd+TuImlvo2vaLF1gNynqT8AJMusYw==
dependencies:
- "@babel/runtime" "^7.28.4"
- "@mui/utils" "^7.3.5"
- "@mui/x-internals" "8.26.0"
+ "@babel/runtime" "^7.28.6"
+ "@mui/utils" "9.0.0"
+ "@mui/x-internals" "^9.0.0"
"@types/react-transition-group" "^4.4.12"
clsx "^2.1.1"
prop-types "^15.8.1"
react-transition-group "^4.4.5"
-"@mui/x-internals@8.26.0":
- version "8.26.0"
- resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-8.26.0.tgz#49caacac954c29a1b10425c67418310ceb9c8cfa"
- integrity sha512-B9OZau5IQUvIxwpJZhoFJKqRpmWf5r0yMmSXjQuqb5WuqM755EuzWJOenY48denGoENzMLT8hQpA0hRTeU2IPA==
+"@mui/x-internals@^9.0.0":
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-9.0.0.tgz#8851a058e09b719690b4f398319805239e923855"
+ integrity sha512-E/4rdg69JjhyybpPGypCjAKSKLLnSdCFM+O6P/nkUg47+qt3uftxQEhjQO53rcn6ahHl6du/uNZ9BLgeY6kYxQ==
dependencies:
- "@babel/runtime" "^7.28.4"
- "@mui/utils" "^7.3.5"
+ "@babel/runtime" "^7.28.6"
+ "@mui/utils" "9.0.0"
reselect "^5.1.1"
use-sync-external-store "^1.6.0"
@@ -2147,10 +2199,10 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.20.5.tgz#b40e8e43db3123c5dee9864931f7f9ad1b1e07dc"
integrity sha512-hraiiWkF58n8Jy0Wl3OGwjCTrGWwZZxez/IlexrzKQ/nMFdjDpensZucWwu59zhAM9fqZwGSLDtCFuak03WKnA==
-"@tiptap/extension-bubble-menu@^3.20.4":
- version "3.20.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.20.4.tgz#e7e3c033a74d5dc67b1dac84346ee12e07d81b86"
- integrity sha512-EXywPlI8wjPcAb8ozymgVhjtMjFrnhtoyNTy8ZcObdpUi5CdO9j892Y7aPbKe5hLhlDpvJk7rMfir4FFKEmfng==
+"@tiptap/extension-bubble-menu@^3.20.5":
+ version "3.22.3"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.22.3.tgz#f94a3ac119b8576d040dc458d44b4200ad03e27b"
+ integrity sha512-Y6zQjh0ypDg32HWgICEvmPSKjGLr39k3aDxxt/H0uQEZSfw4smT0hxUyyyjVjx68C6t6MTnwdfz0hPI5lL68vQ==
dependencies:
"@floating-ui/dom" "^1.0.0"
@@ -2179,10 +2231,10 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.20.5.tgz#ea810297825b009c357559e66f5fd76e91e8c940"
integrity sha512-/lDG9OjvAv0ynmgFH17mt/GUeGT5bqu0iPW8JMgaRqlKawk+uUIv5SF5WkXS4SwxXih+hXdPEQD3PWZnxlQxAQ==
-"@tiptap/extension-floating-menu@^3.20.4":
- version "3.20.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.20.4.tgz#5b082cf500330f0a66f91a49c3a1a232038662a7"
- integrity sha512-AaPTFhoO8DBIElJyd/RTVJjkctvJuL+GHURX0npbtTxXq5HXbebVwf2ARNR7jMd/GThsmBaNJiGxZg4A2oeDqQ==
+"@tiptap/extension-floating-menu@^3.20.5":
+ version "3.22.3"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.22.3.tgz#c9a911b7784cb45d6f8e7260d77bf2015066e5a4"
+ integrity sha512-0f8b4KZ3XKai8GXWseIYJGdOfQr3evtFbBo3U08zy2aYzMMXWG0zEF7qe5/oiYp2aZ95edjjITnEceviTsZkIg==
"@tiptap/extension-gapcursor@^3.20.5":
version "3.20.5"
@@ -2295,17 +2347,17 @@
prosemirror-transform "^1.10.2"
prosemirror-view "^1.38.1"
-"@tiptap/react@^3.4.1":
- version "3.20.4"
- resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-3.20.4.tgz#b313ff5051e30de4476138e47802a67bfda8ca2e"
- integrity sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw==
+"@tiptap/react@^3.20.5":
+ version "3.20.5"
+ resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-3.20.5.tgz#6b2bd999470d9037fd9741ba598c9b3dc12f7759"
+ integrity sha512-in37o1Eo7JCflcHyK/SDfgkJBgX0LRN3LMk+NdLPTerRnC0zhGLQlpfBL4591TLTOUQde7QIrLv98smYO2mj+w==
dependencies:
"@types/use-sync-external-store" "^0.0.6"
fast-equals "^5.3.3"
use-sync-external-store "^1.4.0"
optionalDependencies:
- "@tiptap/extension-bubble-menu" "^3.20.4"
- "@tiptap/extension-floating-menu" "^3.20.4"
+ "@tiptap/extension-bubble-menu" "^3.20.5"
+ "@tiptap/extension-floating-menu" "^3.20.5"
"@tiptap/starter-kit@^3.20.5":
version "3.20.5"
@@ -3041,10 +3093,10 @@ axe-core@^4.10.0:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.1.tgz#052ff9b2cbf543f5595028b583e4763b40c78ea7"
integrity sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==
-axios@1.14.0:
- version "1.14.0"
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.14.0.tgz#7c29f4cf2ea91ef05018d5aa5399bf23ed3120eb"
- integrity sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==
+axios@1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.0.tgz#0fcee91ef03d386514474904b27863b2c683bf4f"
+ integrity sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==
dependencies:
follow-redirects "^1.15.11"
form-data "^4.0.5"
@@ -7010,6 +7062,11 @@ react-is@^19.2.3:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.4.tgz#a080758243c572ccd4a63386537654298c99d135"
integrity sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==
+react-is@^19.2.4:
+ version "19.2.5"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.5.tgz#7e7b54143e9313fed787b23fd4295d5a23872ad9"
+ integrity sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==
+
react-leaflet-markercluster@^5.0.0-rc.0:
version "5.0.0-rc.0"
resolved "https://registry.yarnpkg.com/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz#42b1b9786de565fe69ec95abc6ff3232713f5300"
@@ -7130,10 +7187,10 @@ react-virtualized-auto-sizer@^1.0.26:
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz#e9470ef6a778dc4f1d5fd76305fa2d8b610c357a"
integrity sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==
-react-virtuoso@^4.18.3:
- version "4.18.3"
- resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.18.3.tgz#12e69600c258bc6e6bd31c2516942ef08700deac"
- integrity sha512-fLz/peHAx4Eu0DLHurFEEI7Y6n5CqEoxBh04rgJM9yMuOJah2a9zWg/MUOmZLcp7zuWYorXq5+5bf3IRgkNvWg==
+react-virtuoso@^4.18.5:
+ version "4.18.5"
+ resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.18.5.tgz#450108e585c7a1124b995c7ea3cf367ed4857631"
+ integrity sha512-QDyNjyNEuurZG67SOmzYyxEkQYSyGmAMixOI6M15L/Q4CF39EgG+88y6DgZRo0q7rmy0HPx3Fj90I8/tPdnRCQ==
react-window@^2.2.7:
version "2.2.7"