Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 85 additions & 17 deletions src/components/CippComponents/CippBreadcrumbNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ export const CippBreadcrumbNav = () => {
const titleCheckCountRef = useRef(0);
const titleCheckIntervalRef = useRef(null);

// Helper function to filter out unnecessary query parameters
const getCleanQueryParams = (query) => {
const cleaned = { ...query };
// Remove tenantFilter if it's "AllTenants" or not explicitly needed
if (cleaned.tenantFilter === "AllTenants" || cleaned.tenantFilter === undefined) {
delete cleaned.tenantFilter;
}
return cleaned;
};

// Helper function to clean page titles
const cleanPageTitle = (title) => {
if (!title) return title;
// Remove AllTenants and any surrounding separators
return title
.replace(/\s*-\s*AllTenants\s*/, "")
.replace(/AllTenants\s*-\s*/, "")
.replace(/AllTenants/, "")
.trim();
};

// Load tab options on mount
useEffect(() => {
loadTabOptions().then(setTabOptions);
Expand Down Expand Up @@ -109,6 +130,9 @@ export const CippBreadcrumbNav = () => {
pageTitle = parts.slice(0, -1).join(" - ").trim();
}

// Clean AllTenants from title
pageTitle = cleanPageTitle(pageTitle);

// Skip if title is empty, generic, or error page
if (
!pageTitle ||
Expand Down Expand Up @@ -155,7 +179,10 @@ export const CippBreadcrumbNav = () => {
if (samePath && !sameTitle) {
// Same URL but title changed - update the entry
const updated = [...prevHistory];
updated[prevHistory.length - 1] = currentPage;
updated[prevHistory.length - 1] = {
...currentPage,
query: getCleanQueryParams(currentPage.query),
};
if (titleCheckIntervalRef.current) {
clearInterval(titleCheckIntervalRef.current);
titleCheckIntervalRef.current = null;
Expand All @@ -173,7 +200,11 @@ export const CippBreadcrumbNav = () => {

// URL not in history (except possibly as last entry which we handled) - add as new entry
if (existingIndex === -1) {
const newHistory = [...prevHistory, currentPage];
const cleanedCurrentPage = {
...currentPage,
query: getCleanQueryParams(currentPage.query),
};
const newHistory = [...prevHistory, cleanedCurrentPage];

// Keep only the last MAX_HISTORY_STORAGE pages
const trimmedHistory =
Expand All @@ -192,7 +223,10 @@ export const CippBreadcrumbNav = () => {
titleCheckIntervalRef.current = null;
}
const updated = prevHistory.slice(0, existingIndex + 1);
updated[existingIndex] = currentPage;
updated[existingIndex] = {
...currentPage,
query: getCleanQueryParams(currentPage.query),
};
return updated;
});
};
Expand All @@ -211,9 +245,10 @@ export const CippBreadcrumbNav = () => {
const handleBreadcrumbClick = (index) => {
const page = history[index];
if (page) {
const cleanedQuery = getCleanQueryParams(page.query);
router.push({
pathname: page.path,
query: page.query,
query: cleanedQuery,
});
}
};
Expand Down Expand Up @@ -247,15 +282,18 @@ export const CippBreadcrumbNav = () => {
return;
}

const pageTitle = document.title.replace(" - CIPP", "").trim();
let pageTitle = document.title.replace(" - CIPP", "").trim();
const parts = pageTitle.split(" - ");
const cleanTitle =
parts.length > 1 && parts[parts.length - 1].includes(".")
? parts.slice(0, -1).join(" - ").trim()
: pageTitle;

if (cleanTitle && cleanTitle !== "CIPP" && !cleanTitle.toLowerCase().includes("loading")) {
setCurrentPageTitle(cleanTitle);
// Clean AllTenants from title
const finalTitle = cleanPageTitle(cleanTitle);

if (finalTitle && finalTitle !== "CIPP" && !finalTitle.toLowerCase().includes("loading")) {
setCurrentPageTitle(finalTitle);
// Stop checking once we have a valid title
if (hierarchicalTitleCheckRef.current) {
clearInterval(hierarchicalTitleCheckRef.current);
Expand Down Expand Up @@ -316,11 +354,11 @@ export const CippBreadcrumbNav = () => {

// Check if this item matches the current path
if (item.path && pathsMatch(item.path, currentPath)) {
// If this is the current page, include current query params
// If this is the current page, include current query params (cleaned)
if (item.path === currentPath) {
const lastItem = currentBreadcrumb[currentBreadcrumb.length - 1];
if (lastItem) {
lastItem.query = { ...router.query };
lastItem.query = getCleanQueryParams(router.query);
}
}
return currentBreadcrumb;
Expand All @@ -339,6 +377,32 @@ export const CippBreadcrumbNav = () => {

let result = findPathInMenu(nativeMenuItems);

// If we found a menu item, check if the current path matches any tab
// If so, tabOptions wins and we use its label
if (result.length > 0 && tabOptions.length > 0) {
const normalizedCurrentPath = currentPath.replace(/\/$/, "");

// Check if current path matches any tab (exact match)
const matchingTab = tabOptions.find((tab) => {
const normalizedTabPath = tab.path.replace(/\/$/, "");
return normalizedTabPath === normalizedCurrentPath;
});

if (matchingTab) {
// Tab matches the current path - use tab's label instead of config's
result = result.map((item, idx) => {
if (idx === result.length - 1) {
return {
...item,
title: matchingTab.title,
type: "tab",
};
}
return item;
});
}
}

// If not found in main menu, check if it's a tab page
if (result.length === 0 && tabOptions.length > 0) {
const normalizedCurrentPath = currentPath.replace(/\/$/, "");
Expand Down Expand Up @@ -395,12 +459,12 @@ export const CippBreadcrumbNav = () => {
if (basePagePath.length > 0) {
result = basePagePath;

// Add the tab as the final breadcrumb with current query params
// Add the tab as the final breadcrumb with current query params (cleaned)
result.push({
title: matchingTab.title,
path: matchingTab.path,
type: "tab",
query: { ...router.query }, // Include current query params for tab page
query: getCleanQueryParams(router.query), // Include current query params for tab page
});
}
}
Expand All @@ -411,7 +475,10 @@ export const CippBreadcrumbNav = () => {
const lastItem = result[result.length - 1];
if (lastItem.path && lastItem.path !== currentPath && currentPath.startsWith(lastItem.path)) {
// Use the tracked page title if available, otherwise fall back to document.title
const tabTitle = currentPageTitle || document.title.replace(" - CIPP", "").trim();
let tabTitle = currentPageTitle || document.title.replace(" - CIPP", "").trim();

// Clean AllTenants from title
tabTitle = cleanPageTitle(tabTitle);

// Add tab as an additional breadcrumb item
if (
Expand All @@ -423,7 +490,7 @@ export const CippBreadcrumbNav = () => {
title: tabTitle,
path: currentPath,
type: "tab",
query: { ...router.query }, // Include current query params
query: getCleanQueryParams(router.query), // Include current query params (cleaned)
});
}
}
Expand All @@ -435,10 +502,11 @@ export const CippBreadcrumbNav = () => {
// Handle click for hierarchical breadcrumbs
const handleHierarchicalClick = (path, query) => {
if (path) {
if (query && Object.keys(query).length > 0) {
const cleanedQuery = getCleanQueryParams(query);
if (cleanedQuery && Object.keys(cleanedQuery).length > 0) {
router.push({
pathname: path,
query: query,
query: cleanedQuery,
});
} else {
router.push(path);
Expand Down Expand Up @@ -478,7 +546,7 @@ export const CippBreadcrumbNav = () => {
title,
path,
type: "fallback",
query: index === pathSegments.length - 1 ? { ...router.query } : {},
query: index === pathSegments.length - 1 ? getCleanQueryParams(router.query) : {},
};
});

Expand All @@ -488,7 +556,7 @@ export const CippBreadcrumbNav = () => {
currentPageTitle !== "CIPP" &&
!currentPageTitle.toLowerCase().includes("loading")
) {
breadcrumbs[breadcrumbs.length - 1].title = currentPageTitle;
breadcrumbs[breadcrumbs.length - 1].title = cleanPageTitle(currentPageTitle);
}
}
}
Expand Down
18 changes: 13 additions & 5 deletions src/components/CippComponents/CippFormCondition.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const CippFormCondition = (props) => {

if (
field === undefined ||
compareValue === undefined ||
(compareValue === undefined && compareType !== "hasValue") ||
children === undefined ||
formControl === undefined
) {
Expand Down Expand Up @@ -148,10 +148,18 @@ export const CippFormCondition = (props) => {
watcher.length >= compareValue
);
case "hasValue":
return (
(watcher !== undefined && watcher !== null && watcher !== "") ||
(watcher?.value !== undefined && watcher?.value !== null && watcher?.value !== "")
);
// Check watchedValue (the extracted value based on propertyName)
// For simple values (strings, numbers)
if (watchedValue === undefined || watchedValue === null || watchedValue === "") {
return false;
}
// If it's an array, check if it has elements
if (Array.isArray(watchedValue)) {
return watchedValue.length > 0;
}
console.log("watched value:", watchedValue);
// For any other truthy value (objects, numbers, strings), consider it as having a value
return true;
case "labelEq":
return Array.isArray(watcher) && watcher.some((item) => item?.label === compareValue);
case "labelContains":
Expand Down
42 changes: 1 addition & 41 deletions src/components/CippStandards/CippStandardsSideBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,34 +144,12 @@ const CippStandardsSideBar = ({
}

// Filter out current template if editing
console.log("Duplicate detection debug:", {
edit,
currentGUID: watchForm.GUID,
allTemplates: driftValidationApi.data?.map((t) => ({
GUID: t.GUID,
standardId: t.standardId,
standardName: t.standardName,
})),
});

const existingTemplates = driftValidationApi.data.filter((template) => {
const shouldInclude =
edit && watchForm.GUID ? template.standardId !== watchForm.GUID : true;
console.log(
`Template ${template.standardId} (${template.standardName}): shouldInclude=${shouldInclude}, currentGUID=${watchForm.GUID}`
);
return shouldInclude;
});

console.log(
"Filtered templates:",
existingTemplates?.map((t) => ({
GUID: t.GUID,
standardId: t.standardId,
standardName: t.standardName,
}))
);

// Get tenant groups data
const groups = tenantGroupsApi.data?.Results || [];

Expand All @@ -198,45 +176,27 @@ const CippStandardsSideBar = ({
});

// Check for conflicts with unique templates
console.log("Checking conflicts with unique templates:", uniqueTemplates);
console.log("Selected tenant list:", selectedTenantList);

for (const templateId in uniqueTemplates) {
const template = uniqueTemplates[templateId];
const templateTenants = template.tenants;

console.log(
`Checking template ${templateId} (${template.standardName}) with tenants:`,
templateTenants
);

const hasConflict = selectedTenantList.some((selectedTenant) => {
// Check if any template tenant matches the selected tenant
const conflict = templateTenants.some((templateTenant) => {
if (selectedTenant === "AllTenants" || templateTenant === "AllTenants") {
console.log(
`Conflict found: ${selectedTenant} vs ${templateTenant} (AllTenants match)`
);
return true;
}
const match = selectedTenant === templateTenant;
if (match) {
console.log(`Conflict found: ${selectedTenant} vs ${templateTenant} (exact match)`);
}
return match;
});
return conflict;
});

console.log(`Template ${templateId} has conflict: ${hasConflict}`);

if (hasConflict) {
conflicts.push(template.standardName || "Unknown Template");
}
}

console.log("Final conflicts:", conflicts);

if (conflicts.length > 0) {
setDriftError(
`This template has tenants that are assigned to another Drift Template. You can only assign one Drift Template to each tenant. Please check the ${conflicts.join(
Expand Down Expand Up @@ -556,7 +516,7 @@ const CippStandardsSideBar = ({
title="Add Standard"
api={{
confirmText: isDriftMode
? "This template will automatically every hour to detect drift. Are you sure you want to apply this Drift Template?"
? "This template will automatically every 12 hours to detect drift. Are you sure you want to apply this Drift Template?"
: watchForm.runManually
? "Are you sure you want to apply this standard? This template has been set to never run on a schedule. After saving the template you will have to run it manually."
: "Are you sure you want to apply this standard? This will apply the template and run every 3 hours.",
Expand Down
5 changes: 1 addition & 4 deletions src/data/standards.json
Original file line number Diff line number Diff line change
Expand Up @@ -5056,10 +5056,7 @@
"queryKey": "ListIntuneTemplates-tag-autcomplete",
"url": "/api/ListIntuneTemplates?mode=Tag",
"labelField": "label",
"valueField": "value",
"addedField": {
"templates": "templates"
}
"valueField": "value"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export const nativeMenuItems = [
items: [
{
title: "Standards Management",
path: "/tenant/standards/list-standards",
path: "/tenant/standards/alignment",
permissions: ["Tenant.Standards.*"],
},
{
Expand Down
10 changes: 2 additions & 8 deletions src/pages/endpoint/MEM/devices/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,7 @@ const Page = () => {
GUID: "id",
Action: "resetPasscode",
},
condition: (row) =>
row.operatingSystem === "iOS" ||
row.operatingSystem === "macOS" ||
row.operatingSystem === "Android",
condition: (row) => row.operatingSystem === "Android",
confirmText:
"Are you sure you want to reset the passcode for [deviceName]? A new passcode will be generated and displayed.",
},
Expand All @@ -194,10 +191,7 @@ const Page = () => {
GUID: "id",
Action: "removeDevicePasscode",
},
condition: (row) =>
row.operatingSystem === "iOS" ||
row.operatingSystem === "macOS" ||
row.operatingSystem === "Android",
condition: (row) => row.operatingSystem === "iOS",
confirmText:
"Are you sure you want to remove the passcode from [deviceName]? This will remove the device passcode requirement.",
},
Expand Down
2 changes: 1 addition & 1 deletion src/pages/tenant/administration/tenants/groups/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const Page = () => {
dynamicRules: formattedDynamicRules,
});
}
}, [groupDetails.isSuccess, groupDetails.data]);
}, [groupDetails.isSuccess, groupDetails.data, id]);

const customDataFormatter = (values) => {
const formattedData = {
Expand Down
Loading