Skip to content

Commit de6a125

Browse files
Merge pull request KelvinTegelaar#5007 from KelvinTegelaar/dev
Dev to hotfix
2 parents c925e7d + 41ff35e commit de6a125

File tree

6 files changed

+262
-29
lines changed

6 files changed

+262
-29
lines changed

public/version.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "8.7.1"
3-
}
2+
"version": "8.7.2"
3+
}

src/components/CippComponents/CippCentralSearch.jsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ async function loadTabOptions() {
8888
*/
8989
function filterItemsByPermissionsAndRoles(items, userPermissions, userRoles) {
9090
return items.filter((item) => {
91-
// Check roles if specified
92-
if (item.roles && item.roles.length > 0) {
93-
const hasRole = item.roles.some((requiredRole) => userRoles.includes(requiredRole));
94-
if (!hasRole) {
95-
return false;
96-
}
97-
}
98-
9991
// Check permissions with pattern matching support
10092
if (item.permissions && item.permissions.length > 0) {
10193
const hasPermission = userPermissions?.some((userPerm) => {

src/layouts/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ export const nativeMenuItems = [
744744
"Tenant.Application.*",
745745
"Tenant.DomainAnalyser.*",
746746
"Exchange.Mailbox.*",
747+
"CIPP.Scheduler.*",
747748
],
748749
items: [
749750
{

src/layouts/index.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,6 @@ export const Layout = (props) => {
114114
const filterItemsByRole = (items) => {
115115
return items
116116
.map((item) => {
117-
// role
118-
if (item.roles && item.roles.length > 0) {
119-
const hasRole = item.roles.some((requiredRole) => userRoles.includes(requiredRole));
120-
if (!hasRole) {
121-
return null;
122-
}
123-
}
124-
125117
// Check permission with pattern matching support
126118
if (item.permissions && item.permissions.length > 0) {
127119
const hasPermission = userPermissions?.some((userPerm) => {

src/pages/endpoint/applications/list/index.js

Lines changed: 163 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
11
import { Layout as DashboardLayout } from "/src/layouts/index.js";
22
import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx";
33
import { CippApiDialog } from "/src/components/CippComponents/CippApiDialog.jsx";
4-
import { GlobeAltIcon, TrashIcon, UserIcon } from "@heroicons/react/24/outline";
4+
import { GlobeAltIcon, TrashIcon, UserIcon, UserGroupIcon } from "@heroicons/react/24/outline";
55
import { LaptopMac, Sync } from "@mui/icons-material";
66
import { CippApplicationDeployDrawer } from "/src/components/CippComponents/CippApplicationDeployDrawer";
77
import { Button, Box } from "@mui/material";
88
import { useSettings } from "/src/hooks/use-settings.js";
99
import { useDialog } from "/src/hooks/use-dialog.js";
1010

11+
const assignmentIntentOptions = [
12+
{ label: "Required", value: "Required" },
13+
{ label: "Available", value: "Available" },
14+
{ label: "Available without enrollment", value: "AvailableWithoutEnrollment" },
15+
{ label: "Uninstall", value: "Uninstall" },
16+
];
17+
18+
const assignmentModeOptions = [
19+
{ label: "Replace existing assignments", value: "replace" },
20+
{ label: "Append to existing assignments", value: "append" },
21+
];
22+
23+
const getAppAssignmentSettingsType = (odataType) => {
24+
if (!odataType || typeof odataType !== "string") {
25+
return undefined;
26+
}
27+
28+
return odataType.replace("#microsoft.graph.", "").replace(/App$/i, "");
29+
};
30+
1131
const Page = () => {
1232
const pageTitle = "Applications";
1333
const syncDialog = useDialog();
@@ -22,7 +42,28 @@ const Page = () => {
2242
AssignTo: "!AllUsers",
2343
ID: "id",
2444
},
25-
confirmText: "Are you sure you want to assign this app to all users?",
45+
fields: [
46+
{
47+
type: "radio",
48+
name: "Intent",
49+
label: "Assignment intent",
50+
options: assignmentIntentOptions,
51+
defaultValue: "Required",
52+
validators: { required: "Select an assignment intent" },
53+
helperText:
54+
"Available assigns to Company Portal, Required installs automatically, Uninstall removes the app, Available without enrollment exposes it without device enrollment.",
55+
},
56+
{
57+
type: "radio",
58+
name: "assignmentMode",
59+
label: "Assignment mode",
60+
options: assignmentModeOptions,
61+
defaultValue: "replace",
62+
helperText:
63+
"Replace will overwrite existing assignments. Append keeps current assignments and adds/overwrites only for the selected groups/intents.",
64+
},
65+
],
66+
confirmText: 'Are you sure you want to assign "[displayName]" to all users?',
2667
icon: <UserIcon />,
2768
color: "info",
2869
},
@@ -34,7 +75,28 @@ const Page = () => {
3475
AssignTo: "!AllDevices",
3576
ID: "id",
3677
},
37-
confirmText: "Are you sure you want to assign this app to all devices?",
78+
fields: [
79+
{
80+
type: "radio",
81+
name: "Intent",
82+
label: "Assignment intent",
83+
options: assignmentIntentOptions,
84+
defaultValue: "Required",
85+
validators: { required: "Select an assignment intent" },
86+
helperText:
87+
"Available assigns to Company Portal, Required installs automatically, Uninstall removes the app, Available without enrollment exposes it without device enrollment.",
88+
},
89+
{
90+
type: "radio",
91+
name: "assignmentMode",
92+
label: "Assignment mode",
93+
options: assignmentModeOptions,
94+
defaultValue: "replace",
95+
helperText:
96+
"Replace will overwrite existing assignments. Append keeps current assignments and adds/overwrites only for the selected groups/intents.",
97+
},
98+
],
99+
confirmText: 'Are you sure you want to assign "[displayName]" to all devices?',
38100
icon: <LaptopMac />,
39101
color: "info",
40102
},
@@ -43,21 +105,112 @@ const Page = () => {
43105
type: "POST",
44106
url: "/api/ExecAssignApp",
45107
data: {
46-
AssignTo: "!Both",
108+
AssignTo: "!AllDevicesAndUsers",
47109
ID: "id",
48110
},
49-
confirmText: "Are you sure you want to assign this app to all users and devices?",
111+
fields: [
112+
{
113+
type: "radio",
114+
name: "Intent",
115+
label: "Assignment intent",
116+
options: assignmentIntentOptions,
117+
defaultValue: "Required",
118+
validators: { required: "Select an assignment intent" },
119+
helperText:
120+
"Available assigns to Company Portal, Required installs automatically, Uninstall removes the app, Available without enrollment exposes it without device enrollment.",
121+
},
122+
{
123+
type: "radio",
124+
name: "assignmentMode",
125+
label: "Assignment mode",
126+
options: assignmentModeOptions,
127+
defaultValue: "replace",
128+
helperText:
129+
"Replace will overwrite existing assignments. Append keeps current assignments and adds/overwrites only for the selected groups/intents.",
130+
},
131+
],
132+
confirmText: 'Are you sure you want to assign "[displayName]" to all users and devices?',
50133
icon: <GlobeAltIcon />,
51134
color: "info",
52135
},
136+
{
137+
label: "Assign to Custom Group",
138+
type: "POST",
139+
url: "/api/ExecAssignApp",
140+
icon: <UserGroupIcon />,
141+
color: "info",
142+
confirmText: 'Select the target groups and intent for "[displayName]".',
143+
fields: [
144+
{
145+
type: "autoComplete",
146+
name: "groupTargets",
147+
label: "Group(s)",
148+
multiple: true,
149+
creatable: false,
150+
allowResubmit: true,
151+
validators: { required: "Please select at least one group" },
152+
api: {
153+
url: "/api/ListGraphRequest",
154+
dataKey: "Results",
155+
queryKey: `ListAppAssignmentGroups-${tenant}`,
156+
labelField: (group) =>
157+
group.id ? `${group.displayName} (${group.id})` : group.displayName,
158+
valueField: "id",
159+
addedField: {
160+
description: "description",
161+
},
162+
data: {
163+
Endpoint: "groups",
164+
manualPagination: true,
165+
$select: "id,displayName,description",
166+
$orderby: "displayName",
167+
$top: 999,
168+
$count: true,
169+
},
170+
},
171+
},
172+
{
173+
type: "radio",
174+
name: "assignmentIntent",
175+
label: "Assignment intent",
176+
options: assignmentIntentOptions,
177+
defaultValue: "Required",
178+
validators: { required: "Select an assignment intent" },
179+
helperText:
180+
"Available assigns to Company Portal, Required installs automatically, Uninstall removes the app, Available without enrollment exposes it without device enrollment.",
181+
},
182+
{
183+
type: "radio",
184+
name: "assignmentMode",
185+
label: "Assignment mode",
186+
options: assignmentModeOptions,
187+
defaultValue: "replace",
188+
helperText:
189+
"Replace will overwrite existing assignments. Append keeps current assignments and adds/overwrites only for the selected groups/intents.",
190+
},
191+
],
192+
customDataformatter: (row, action, formData) => {
193+
const selectedGroups = Array.isArray(formData?.groupTargets) ? formData.groupTargets : [];
194+
const tenantFilterValue = tenant === "AllTenants" && row?.Tenant ? row.Tenant : tenant;
195+
return {
196+
tenantFilter: tenantFilterValue,
197+
ID: row?.id,
198+
GroupIds: selectedGroups.map((group) => group.value).filter(Boolean),
199+
GroupNames: selectedGroups.map((group) => group.label).filter(Boolean),
200+
Intent: formData?.assignmentIntent || "Required",
201+
AssignmentMode: formData?.assignmentMode || "replace",
202+
AppType: getAppAssignmentSettingsType(row?.["@odata.type"]),
203+
};
204+
},
205+
},
53206
{
54207
label: "Delete Application",
55208
type: "POST",
56209
url: "/api/RemoveApp",
57210
data: {
58211
ID: "id",
59212
},
60-
confirmText: "Are you sure you want to delete this application?",
213+
confirmText: 'Are you sure you want to delete "[displayName]"?',
61214
icon: <TrashIcon />,
62215
color: "danger",
63216
},
@@ -83,8 +236,10 @@ const Page = () => {
83236
const simpleColumns = [
84237
"displayName",
85238
"publishingState",
86-
"installCommandLine",
87-
"uninstallCommandLine",
239+
"isAssigned",
240+
"lastModifiedDateTime",
241+
"createdDateTime",
242+
"applicableDeviceType",
88243
];
89244

90245
return (

src/pages/tenant/manage/applied-standards.js

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ const Page = () => {
6464

6565
const templateDetails = ApiGetCall({
6666
url: `/api/listStandardTemplates`,
67-
queryKey: `listStandardTemplates-reports`,
67+
data: {
68+
templateId: templateId,
69+
},
70+
queryKey: `listStandardTemplates-reports-${templateId}`,
6871
});
6972

7073
// Normalize template data structure to always work with an array
@@ -408,6 +411,92 @@ const Page = () => {
408411
}
409412
}
410413
});
414+
} else if (standardKey === "GroupTemplate") {
415+
// GroupTemplate structure has groupTemplate array and action array at the top level
416+
const groupTemplates = standardConfig.groupTemplate || [];
417+
const actions = standardConfig.action || [];
418+
const standardId = `standards.GroupTemplate`;
419+
const standardInfo = standards.find((s) => s.name === standardId);
420+
421+
// Find the tenant's value for this template
422+
const currentTenantStandard = currentTenantData.find(
423+
(s) => s.standardId === standardId
424+
);
425+
const standardObject = currentTenantObj?.[standardId];
426+
const directStandardValue = standardObject?.Value;
427+
let isCompliant = false;
428+
429+
// For GroupTemplate, the value is true if compliant
430+
if (directStandardValue === true) {
431+
isCompliant = true;
432+
} else if (currentTenantStandard?.value) {
433+
isCompliant = currentTenantStandard.value === true;
434+
}
435+
436+
// Build a list of all group names with their types
437+
const groupList = groupTemplates
438+
.map((groupTemplate) => {
439+
const rawGroupType = (
440+
groupTemplate.rawData?.groupType || "generic"
441+
).toLowerCase();
442+
let prettyGroupType = "Generic";
443+
444+
if (rawGroupType.includes("dynamicdistribution")) {
445+
prettyGroupType = "Dynamic Distribution Group";
446+
} else if (rawGroupType.includes("dynamic")) {
447+
prettyGroupType = "Dynamic Security Group";
448+
} else if (rawGroupType.includes("azurerole")) {
449+
prettyGroupType = "Azure Role-Assignable Group";
450+
} else if (
451+
rawGroupType.includes("m365") ||
452+
rawGroupType.includes("unified") ||
453+
rawGroupType.includes("microsoft")
454+
) {
455+
prettyGroupType = "Microsoft 365 Group";
456+
} else if (
457+
rawGroupType.includes("distribution") ||
458+
rawGroupType.includes("mail")
459+
) {
460+
prettyGroupType = "Distribution Group";
461+
} else if (
462+
rawGroupType.includes("security") ||
463+
rawGroupType === "mail-enabled security"
464+
) {
465+
prettyGroupType = "Security Group";
466+
} else if (rawGroupType.includes("generic")) {
467+
prettyGroupType = "Security Group";
468+
}
469+
470+
const groupName =
471+
groupTemplate.label || groupTemplate.rawData?.displayName || "Unknown Group";
472+
return `- ${groupName} (${prettyGroupType})`;
473+
})
474+
.join("\n");
475+
476+
// Create a single standard entry for all groups
477+
const templateSettings = {
478+
Groups: groupList,
479+
};
480+
481+
allStandards.push({
482+
standardId,
483+
standardName: `Group Templates`,
484+
currentTenantValue:
485+
standardObject !== undefined
486+
? {
487+
Value: directStandardValue,
488+
LastRefresh: standardObject?.LastRefresh,
489+
}
490+
: currentTenantStandard?.value,
491+
standardValue: templateSettings,
492+
complianceStatus: isCompliant ? "Compliant" : "Non-Compliant",
493+
complianceDetails: standardInfo?.docsDescription || standardInfo?.helpText || "",
494+
standardDescription: standardInfo?.helpText || "",
495+
standardImpact: standardInfo?.impact || "Medium Impact",
496+
standardImpactColour: standardInfo?.impactColour || "warning",
497+
templateName: selectedTemplate?.templateName || "Standard Template",
498+
templateActions: actions,
499+
});
411500
} else {
412501
// Regular handling for other standards
413502
const standardId = `standards.${standardKey}`;
@@ -1129,14 +1218,18 @@ const Page = () => {
11291218
typeof standard.standardValue === "object" &&
11301219
Object.keys(standard.standardValue).length > 0 ? (
11311220
Object.entries(standard.standardValue).map(([key, value]) => (
1132-
<Box key={key} sx={{ display: "flex", mb: 0.5 }}>
1221+
<Box key={key} sx={{ mb: 0.5 }}>
11331222
<Typography
11341223
variant="body2"
11351224
sx={{ fontWeight: "medium", mr: 1 }}
11361225
>
11371226
{key}:
11381227
</Typography>
1139-
<Typography variant="body2">
1228+
<Typography
1229+
variant="body2"
1230+
component="div"
1231+
sx={{ whiteSpace: "pre-line", mt: 0.5 }}
1232+
>
11401233
{typeof value === "object" && value !== null
11411234
? value?.label || JSON.stringify(value)
11421235
: value === true

0 commit comments

Comments
 (0)