Skip to content

Commit 0950166

Browse files
authored
Merge pull request #170 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 69a08e4 + 4263f4e commit 0950166

File tree

6 files changed

+124
-66
lines changed

6 files changed

+124
-66
lines changed

src/components/CippComponents/CippAppPermissionBuilder.jsx

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
AccordionSummary,
77
AccordionDetails,
88
Tooltip,
9-
Grid,
109
Alert,
1110
Skeleton,
1211
IconButton,
@@ -17,7 +16,7 @@ import {
1716
Tabs,
1817
Tab,
1918
} from "@mui/material";
20-
19+
import { Grid } from "@mui/system";
2120
import { ApiGetCall, ApiPostCall } from "/src/api/ApiCall";
2221
import { CippDataTable } from "../CippTable/CippDataTable";
2322
import { PlusIcon, ShieldCheckIcon, WrenchIcon } from "@heroicons/react/24/outline";
@@ -29,6 +28,7 @@ import {
2928
Error,
3029
ExpandMore,
3130
Save,
31+
Sync,
3232
TaskAlt,
3333
Undo,
3434
Upload,
@@ -76,6 +76,7 @@ const CippAppPermissionBuilder = ({
7676
isSuccess: spSuccess,
7777
isFetching: spFetching,
7878
isLoading: spLoading,
79+
refetch: refetchServicePrincipals,
7980
} = ApiGetCall({
8081
url: "/api/ExecServicePrincipals",
8182
queryKey: "execServicePrincipals",
@@ -366,6 +367,7 @@ const CippAppPermissionBuilder = ({
366367
},
367368
},
368369
});
370+
setExpanded("00000003-0000-0000-c000-000000000000"); // Automatically expand Microsoft Graph
369371
}
370372
} else if (!_.isEqual(currentPermissions, initialPermissions)) {
371373
setSelectedApp([]); // Avoid redundant updates
@@ -384,6 +386,11 @@ const CippAppPermissionBuilder = ({
384386
setNewPermissions(currentPermissions);
385387
setInitialPermissions(currentPermissions);
386388
setPermissionsImported(true);
389+
390+
// Automatically expand if only one service principal exists
391+
if (newApps.length === 1) {
392+
setExpanded(newApps[0].appId);
393+
}
387394
}
388395
}
389396
}, [
@@ -560,7 +567,7 @@ const CippAppPermissionBuilder = ({
560567
<>
561568
<Stack spacing={2}>
562569
<Grid container sx={{ display: "flex", alignItems: "center" }} spacing={2}>
563-
<Grid item xl={8} xs={12}>
570+
<Grid item size={{ xl: 8, xs: 12 }}>
564571
<CippFormComponent
565572
type="autoComplete"
566573
label="Application Permissions"
@@ -622,7 +629,7 @@ const CippAppPermissionBuilder = ({
622629
</Alert>
623630
)}
624631
<Grid container sx={{ display: "flex", alignItems: "center" }} spacing={2}>
625-
<Grid item xl={8} xs={12}>
632+
<Grid item size={{ xl: 8, xs: 12 }}>
626633
<CippFormComponent
627634
type="autoComplete"
628635
label="Delegated Permissions"
@@ -694,30 +701,40 @@ const CippAppPermissionBuilder = ({
694701
{spSuccess && (
695702
<>
696703
<Grid container>
697-
<Grid item xl={12} md={12} sx={{ mb: 3 }}>
704+
<Grid size={{ xl: 12, md: 12 }} sx={{ mb: 3 }}>
698705
<Grid
699706
container
700707
spacing={2}
701708
sx={{ display: "flex", alignItems: "center" }}
702709
justifyContent="space-between"
703710
>
704-
<Grid item xs={12} xl={8}>
705-
{servicePrincipals?.Metadata?.Success && (
706-
<CippFormComponent
707-
type="autoComplete"
708-
fullWidth
709-
label="Select a Service Principal or enter an AppId if not listed"
710-
name="servicePrincipal"
711-
createOption={true}
712-
onCreateOption={onCreateServicePrincipal}
713-
isFetching={spFetching}
714-
options={servicePrincipals?.Results.map((sp) => {
715-
return { label: `${sp.displayName} (${sp.appId})`, value: sp.appId };
716-
})}
717-
formControl={formControl}
718-
multiple={false}
719-
/>
720-
)}
711+
<Grid size={{ xl: 8, xs: 12 }}>
712+
<Stack direction="row" spacing={1}>
713+
{servicePrincipals?.Metadata?.Success && (
714+
<Box width="100%">
715+
<CippFormComponent
716+
type="autoComplete"
717+
fullWidth
718+
label="Select a Service Principal or enter an AppId if not listed"
719+
name="servicePrincipal"
720+
createOption={true}
721+
onCreateOption={onCreateServicePrincipal}
722+
isFetching={spFetching}
723+
options={servicePrincipals?.Results.map((sp) => {
724+
return { label: `${sp.displayName} (${sp.appId})`, value: sp.appId };
725+
})}
726+
formControl={formControl}
727+
multiple={false}
728+
/>
729+
</Box>
730+
)}
731+
<IconButton
732+
onClick={() => refetchServicePrincipals()}
733+
disabled={servicePrincipals.isFetching}
734+
>
735+
<Sync />
736+
</IconButton>
737+
</Stack>
721738
</Grid>
722739
<Grid item>
723740
<Stack direction="row" spacing={1}>
@@ -787,7 +804,7 @@ const CippAppPermissionBuilder = ({
787804
</Grid>
788805
<Grid
789806
item
790-
xs={12}
807+
size={12}
791808
sx={{
792809
mt: createServicePrincipal.isSuccess || createServicePrincipal.isPending ? 3 : 0,
793810
}}
@@ -802,7 +819,7 @@ const CippAppPermissionBuilder = ({
802819
}}
803820
>
804821
<Grid container>
805-
<Grid item xl={12}>
822+
<Grid item size={12}>
806823
<Typography variant="h4" sx={{ mb: 2 }}>
807824
Import Permission Manifest
808825
</Typography>
@@ -814,7 +831,7 @@ const CippAppPermissionBuilder = ({
814831
</Grid>
815832
</Grid>
816833
<Grid container>
817-
<Grid item xl={12}>
834+
<Grid item size={12}>
818835
<FileDropzone
819836
onDrop={onManifestImport}
820837
accept={{
@@ -834,12 +851,12 @@ const CippAppPermissionBuilder = ({
834851
{importedManifest && (
835852
<>
836853
<Grid container sx={{ mt: 2 }} spacing={2}>
837-
<Grid item xl={12}>
854+
<Grid item size={12}>
838855
<Alert color="success" icon={<TaskAlt />}>
839856
Manifest is valid. Click Import to apply the permissions.
840857
</Alert>
841858
</Grid>
842-
<Grid item xl={12}>
859+
<Grid item size={12}>
843860
<Button
844861
variant="contained"
845862
onClick={() => importManifest()}
@@ -854,7 +871,7 @@ const CippAppPermissionBuilder = ({
854871
</Grid>
855872
</Grid>
856873
<Grid container className="mt-3">
857-
<Grid item xl={12}>
874+
<Grid item size={12}>
858875
<h4>Preview</h4>
859876
<CippCodeBlock
860877
code={JSON.stringify(importedManifest, null, 2)}
@@ -868,7 +885,7 @@ const CippAppPermissionBuilder = ({
868885
</CippOffCanvas>
869886
{calloutMessage && (
870887
<Grid container sx={{ my: 3 }}>
871-
<Grid item xs={12} xl={8}>
888+
<Grid size={{ xl: 8, xs: 12 }}>
872889
<Alert variant="outlined" color="info" onClose={() => setCalloutMessage(null)}>
873890
{calloutMessage}
874891
</Alert>
@@ -880,7 +897,7 @@ const CippAppPermissionBuilder = ({
880897
newPermissions?.Type === "Table" &&
881898
Object.keys(newPermissions?.MissingPermissions).length > 0 && (
882899
<Grid container sx={{ width: "100%", mt: 3 }}>
883-
<Grid item xs={12} xl={8}>
900+
<Grid size={{ xl: 8, xs: 12 }}>
884901
<Alert
885902
color="warning"
886903
icon={<WarningAmberOutlined />}
@@ -1041,13 +1058,13 @@ const CippAppPermissionBuilder = ({
10411058
))}
10421059
</Box>
10431060
</Grid>
1044-
<Grid item xl={12} xs={12}>
1061+
<Grid size={{ xl: 12, xs: 12 }}>
10451062
<CippApiResults apiObject={updatePermissions} />
10461063
</Grid>
10471064
</Grid>
10481065

10491066
<Grid container sx={{ display: "flex", alignItems: "center" }}>
1050-
<Grid item xl={1} xs={12}>
1067+
<Grid item size={{ xl: 1, xs: 12 }}>
10511068
<Button
10521069
variant="contained"
10531070
startIcon={

src/components/CippSettings/CippGDAPResults.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ export const CippGDAPResults = (props) => {
103103
{propertyItems.length > 0 && (
104104
<CippPropertyList
105105
direction="row"
106-
isFetching={executeCheck?.isFetching}
106+
isFetching={!importReport && executeCheck?.isFetching}
107107
propertyItems={propertyItems}
108108
showDivider={false}
109109
layout
110110
/>
111111
)}
112112

113-
{executeCheck.isFetching ? (
113+
{!importReport && executeCheck.isFetching ? (
114114
<Skeleton variant="rectangular" height={100} sx={{ borderRadius: 1, ml: 3, mr: 1 }} />
115115
) : (
116116
<>
@@ -157,7 +157,7 @@ export const CippGDAPResults = (props) => {
157157
<>
158158
<CippDataTable
159159
title="GDAP Issues"
160-
isFetching={executeCheck.isFetching}
160+
isFetching={!importReport && executeCheck.isFetching}
161161
refreshFunction={executeCheck}
162162
data={results?.Results?.GDAPIssues}
163163
simpleColumns={["Tenant", "Type", "Issue", "Link"]}
@@ -169,7 +169,7 @@ export const CippGDAPResults = (props) => {
169169
<>
170170
<CippDataTable
171171
title="Missing Groups"
172-
isFetching={executeCheck.isFetching}
172+
isFetching={!importReport && executeCheck.isFetching}
173173
refreshFunction={executeCheck}
174174
data={results?.Results?.MissingGroups}
175175
simpleColumns={["Name", "Type"]}
@@ -183,7 +183,7 @@ export const CippGDAPResults = (props) => {
183183
<>
184184
<CippDataTable
185185
title="Group Memberships"
186-
isFetching={executeCheck.isFetching}
186+
isFetching={!importReport && executeCheck.isFetching}
187187
refreshFunction={executeCheck}
188188
data={results?.Results?.Memberships?.filter(
189189
(membership) => membership?.["@odata.type"] === "#microsoft.graph.group"
@@ -199,7 +199,7 @@ export const CippGDAPResults = (props) => {
199199
<>
200200
<CippDataTable
201201
title="Directory Roles"
202-
isFetching={executeCheck.isFetching}
202+
isFetching={!importReport && executeCheck.isFetching}
203203
refreshFunction={executeCheck}
204204
data={results?.Results?.Memberships?.filter(
205205
(membership) => membership?.["@odata.type"] === "#microsoft.graph.directoryRole"

src/components/CippSettings/CippPermissionReport.jsx

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Button, Stack, SvgIcon, Tooltip } from "@mui/material";
2-
import { Close, FileDownload, FileUpload } from "@mui/icons-material";
2+
import { Close, ContentPasteGo, FileDownload, FileUpload } from "@mui/icons-material";
33
import { ApiGetCall } from "../../api/ApiCall";
44
import { useDialog } from "../../hooks/use-dialog";
55
import { CippApiDialog } from "../CippComponents/CippApiDialog";
@@ -54,9 +54,9 @@ export const CippPermissionReport = (props) => {
5454
gdapReport.waiting = true;
5555
tenantReport.waiting = true;
5656
const report = {
57-
Permissions: permissionReport.data,
58-
GDAP: gdapReport.data,
59-
Tenants: tenantReport.data,
57+
Permissions: permissionReport?.data,
58+
GDAP: gdapReport?.data,
59+
Tenants: tenantReport?.data,
6060
};
6161

6262
const customerProps = [
@@ -75,12 +75,12 @@ export const CippPermissionReport = (props) => {
7575
if (formData.redactCustomerData) {
7676
report.Tenants.Results = report?.Tenants?.Results?.map((tenant) => {
7777
customerProps.forEach((prop) => {
78-
if (tenant[prop]) {
78+
if (tenant?.[prop]) {
7979
if (prop === "GDAPRoles") {
8080
tenant[prop] = tenant[prop].map((role) => {
81-
if (Array.isArray(role.Group)) {
82-
role.Group = role.Group.map((group) => group.split("@")[0]);
83-
} else {
81+
if (Array.isArray(role?.Group)) {
82+
role.Group = role.Group.map((group) => group?.split("@")[0]);
83+
} else if (role?.Group) {
8484
role.Group = role.Group.split("@")[0];
8585
}
8686
return role;
@@ -95,7 +95,7 @@ export const CippPermissionReport = (props) => {
9595

9696
report?.GDAP?.Results?.GDAPIssues?.map((issue) => {
9797
customerProps.forEach((prop) => {
98-
if (issue[prop]) {
98+
if (issue?.[prop]) {
9999
issue[prop] = redactString(issue[prop]);
100100
}
101101
});
@@ -104,7 +104,7 @@ export const CippPermissionReport = (props) => {
104104

105105
report?.Permissions?.Results?.CPVRefreshList?.map((cpv) => {
106106
customerProps.forEach((prop) => {
107-
if (cpv[prop]) {
107+
if (cpv?.[prop]) {
108108
cpv[prop] = redactString(cpv[prop]);
109109
}
110110
});
@@ -117,6 +117,11 @@ export const CippPermissionReport = (props) => {
117117
report.Permissions.Results.AccessTokenDetails[prop]
118118
);
119119
}
120+
if (report?.Permissions?.Results?.ApplicationTokenDetails?.[prop]) {
121+
report.Permissions.Results.ApplicationTokenDetails[prop] = redactString(
122+
report.Permissions.Results.ApplicationTokenDetails[prop]
123+
);
124+
}
120125
});
121126
}
122127

@@ -139,7 +144,7 @@ export const CippPermissionReport = (props) => {
139144
reader.onload = (e) => {
140145
const report = JSON.parse(e.target.result);
141146

142-
if (!report.Permissions || !report.GDAP || !report.Tenants) {
147+
if (!report?.Permissions && !report?.GDAP && !report?.Tenants) {
143148
setImportError("Invalid report format");
144149
return;
145150
}
@@ -151,6 +156,23 @@ export const CippPermissionReport = (props) => {
151156
e.target.value = null;
152157
};
153158

159+
const handleImportFromClipboard = async () => {
160+
try {
161+
const text = await navigator.clipboard.readText();
162+
const report = JSON.parse(text);
163+
164+
if (!report?.Permissions && !report?.GDAP && !report?.Tenants) {
165+
setImportError("Invalid report format");
166+
return;
167+
}
168+
setCurrentFile({ name: "Clipboard Data" });
169+
setImportReport(report);
170+
setImportError(false);
171+
} catch (error) {
172+
setImportError("Failed to read from clipboard");
173+
}
174+
};
175+
154176
return (
155177
<>
156178
<Stack direction="row" spacing={2}>
@@ -187,6 +209,19 @@ export const CippPermissionReport = (props) => {
187209
id="report-upload"
188210
/>
189211
</Button>
212+
<Button
213+
size="small"
214+
variant="contained"
215+
color="primary"
216+
onClick={handleImportFromClipboard}
217+
startIcon={
218+
<SvgIcon fontSize="small">
219+
<ContentPasteGo />
220+
</SvgIcon>
221+
}
222+
>
223+
Paste Report
224+
</Button>
190225
{importReport && (
191226
<Tooltip title="Close report">
192227
<Button

0 commit comments

Comments
 (0)