Skip to content

Commit c07da99

Browse files
Merge branch 'dev' into DynamicM365
2 parents 9ef8a55 + 5d14889 commit c07da99

File tree

15 files changed

+887
-568
lines changed

15 files changed

+887
-568
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cipp",
3-
"version": "7.1.3",
3+
"version": "8.0.3",
44
"author": "CIPP Contributors",
55
"homepage": "https://cipp.app/",
66
"bugs": {
@@ -112,4 +112,4 @@
112112
"eslint": "9.22.0",
113113
"eslint-config-next": "15.2.2"
114114
}
115-
}
115+
}

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.0.1"
3-
}
2+
"version": "8.0.3"
3+
}

src/components/CippComponents/CippAppPermissionBuilder.jsx

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,14 @@ const CippAppPermissionBuilder = ({
7070
setExpanded(newExpanded ? panel : false);
7171
};
7272

73+
const deprecatedServicePrincipals = ["00000002-0000-0000-c000-000000000000"];
74+
7375
const currentSelectedSp = useWatch({ control: formControl.control, name: "servicePrincipal" });
76+
77+
// Check if selected service principal is in the deprecated list
78+
const isDeprecatedSp =
79+
currentSelectedSp && deprecatedServicePrincipals.includes(currentSelectedSp.value);
80+
7481
const {
7582
data: servicePrincipals = [],
7683
isSuccess: spSuccess,
@@ -739,22 +746,31 @@ const CippAppPermissionBuilder = ({
739746
</Grid>
740747
<Grid item>
741748
<Stack direction="row" spacing={1}>
742-
<Tooltip title="Add Service Principal">
749+
<Tooltip
750+
title={
751+
isDeprecatedSp
752+
? "This service principal is deprecated and cannot be added"
753+
: "Add Service Principal"
754+
}
755+
>
743756
<div
744757
onClick={(e) => {
745-
setSelectedApp([
746-
...selectedApp,
747-
servicePrincipals?.Results?.find(
748-
(sp) => sp.appId === currentSelectedSp.value
749-
),
750-
]);
751-
formControl.setValue("servicePrincipal", null);
758+
// Only add if not deprecated
759+
if (!isDeprecatedSp) {
760+
setSelectedApp([
761+
...selectedApp,
762+
servicePrincipals?.Results?.find(
763+
(sp) => sp.appId === currentSelectedSp.value
764+
),
765+
]);
766+
formControl.setValue("servicePrincipal", null);
767+
}
752768
}}
753769
>
754770
<Button
755771
variant="contained"
756772
component={!currentSelectedSp?.value ? "span" : undefined}
757-
disabled={!currentSelectedSp?.value}
773+
disabled={!currentSelectedSp?.value || isDeprecatedSp}
758774
>
759775
<SvgIcon fontSize="small">
760776
<PlusIcon />
@@ -894,6 +910,17 @@ const CippAppPermissionBuilder = ({
894910
</Grid>
895911
)}
896912

913+
{isDeprecatedSp && (
914+
<Grid container sx={{ my: 3 }}>
915+
<Grid size={{ xl: 8, xs: 12 }}>
916+
<Alert color="error" icon={<WarningAmberOutlined />}>
917+
{currentSelectedSp.label} is deprecated and cannot be added. Please select a
918+
different service principal.
919+
</Alert>
920+
</Grid>
921+
</Grid>
922+
)}
923+
897924
{newPermissions?.MissingPermissions &&
898925
newPermissions?.Type === "Table" &&
899926
Object.keys(newPermissions?.MissingPermissions).length > 0 && (

src/components/CippComponents/CippMailboxPermissionsDialog.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const CippMailboxPermissionsDialog = ({ formHook }) => {
2525
});
2626

2727
return (
28-
<Stack spacing={3} sx={{ mt: 1 }}>
28+
<Stack spacing={2} sx={{ mt: 1 }}>
2929
<Box>
3030
<CippFormComponent
3131
type="autoComplete"
@@ -40,16 +40,17 @@ const CippMailboxPermissionsDialog = ({ formHook }) => {
4040
})) || []
4141
}
4242
/>
43-
{fullAccess && (
43+
</Box>
44+
{fullAccess?.length > 0 && (
45+
<Box sx={{ pl: 0.5 }}>
4446
<CippFormComponent
4547
type="switch"
4648
label="Enable Automapping"
47-
name="permissions.AutoMapping"
49+
name="permissions.AutoMap"
4850
formControl={formHook}
49-
sx={{ mt: 0.5, ml: 0.5 }}
5051
/>
51-
)}
52-
</Box>
52+
</Box>
53+
)}
5354
<Box>
5455
<CippFormComponent
5556
type="autoComplete"

src/components/CippFormPages/CippExchangeSettingsForm.jsx

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,31 @@ const CippExchangeSettingsForm = (props) => {
2929
const [expandedPanel, setExpandedPanel] = useState(null);
3030
const [relatedQueryKeys, setRelatedQueryKeys] = useState([]);
3131

32+
// Watch the Auto Reply State value
33+
const autoReplyState = useWatch({
34+
control: formControl.control,
35+
name: "ooo.AutoReplyState",
36+
});
37+
38+
// Calculate if date fields should be disabled
39+
const areDateFieldsDisabled = autoReplyState?.value !== "Scheduled";
40+
41+
useEffect(() => {
42+
console.log('Auto Reply State changed:', {
43+
autoReplyState,
44+
areDateFieldsDisabled,
45+
fullFormValues: formControl.getValues()
46+
});
47+
}, [autoReplyState]);
48+
49+
// Add debug logging for form values
50+
useEffect(() => {
51+
const subscription = formControl.watch((value, { name, type }) => {
52+
console.log('Form value changed:', { name, type, value });
53+
});
54+
return () => subscription.unsubscribe();
55+
}, [formControl]);
56+
3257
const handleExpand = (panel) => {
3358
setExpandedPanel((prev) => (prev === panel ? null : panel));
3459
};
@@ -199,20 +224,36 @@ const CippExchangeSettingsForm = (props) => {
199224
/>
200225
</Grid>
201226
<Grid item size={6}>
202-
<CippFormComponent
203-
type="datePicker"
204-
label="Start Date/Time"
205-
name="ooo.StartTime"
206-
formControl={formControl}
207-
/>
227+
<Tooltip
228+
title={areDateFieldsDisabled ? "Scheduling is only available when Auto Reply State is set to Scheduled" : ""}
229+
placement="bottom"
230+
>
231+
<Box>
232+
<CippFormComponent
233+
type="datePicker"
234+
label="Start Date/Time"
235+
name="ooo.StartTime"
236+
formControl={formControl}
237+
disabled={areDateFieldsDisabled}
238+
/>
239+
</Box>
240+
</Tooltip>
208241
</Grid>
209242
<Grid item size={6}>
210-
<CippFormComponent
211-
type="datePicker"
212-
label="End Date/Time"
213-
name="ooo.EndTime"
214-
formControl={formControl}
215-
/>
243+
<Tooltip
244+
title={areDateFieldsDisabled ? "Scheduling is only available when Auto Reply State is set to Scheduled" : ""}
245+
placement="bottom"
246+
>
247+
<Box>
248+
<CippFormComponent
249+
type="datePicker"
250+
label="End Date/Time"
251+
name="ooo.EndTime"
252+
formControl={formControl}
253+
disabled={areDateFieldsDisabled}
254+
/>
255+
</Box>
256+
</Tooltip>
216257
</Grid>
217258
<Grid item size={12}>
218259
<CippFormComponent

src/components/CippStandards/CippStandardAccordion.jsx

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ const CippStandardAccordion = ({
9393
handleRemoveStandard,
9494
handleAddMultipleStandard,
9595
formControl,
96+
editMode = false,
9697
}) => {
9798
const [configuredState, setConfiguredState] = useState({});
9899
const [filter, setFilter] = useState("all");
@@ -188,46 +189,48 @@ const CippStandardAccordion = ({
188189

189190
// Initialize when watchedValues are available
190191
useEffect(() => {
191-
// Only run initialization if we have watchedValues and they contain data
192-
if (!watchedValues || Object.keys(watchedValues).length === 0) {
193-
return;
194-
}
195-
196-
// Prevent re-initialization if we already have configuration state
197-
const hasConfigState = Object.keys(configuredState).length > 0;
198-
if (hasConfigState) {
199-
return;
200-
}
201-
202-
console.log("Initializing configuration state from template values");
203-
const initial = {};
204-
const initialConfigured = {};
205-
206-
// For each standard, get its current values and determine if it's configured
207-
Object.keys(selectedStandards).forEach((standardName) => {
208-
const currentValues = _.get(watchedValues, standardName);
209-
if (!currentValues) return;
210-
211-
initial[standardName] = _.cloneDeep(currentValues);
192+
if (editMode) {
193+
// Only run initialization if we have watchedValues and they contain data
194+
if (!watchedValues || Object.keys(watchedValues).length === 0) {
195+
return;
196+
}
212197

213-
const baseStandardName = standardName.split("[")[0];
214-
const standard = providedStandards.find((s) => s.name === baseStandardName);
215-
if (standard) {
216-
initialConfigured[standardName] = isStandardConfigured(
217-
standardName,
218-
standard,
219-
currentValues
220-
);
198+
// Prevent re-initialization if we already have configuration state
199+
const hasConfigState = Object.keys(configuredState).length > 0;
200+
if (hasConfigState) {
201+
return;
221202
}
222-
});
223203

224-
// Store both the initial values and set them as current saved values
225-
setOriginalValues(initial);
226-
setSavedValues(initial);
227-
setConfiguredState(initialConfigured);
228-
// Only depend on watchedValues and selectedStandards to avoid infinite loops
229-
// eslint-disable-next-line react-hooks/exhaustive-deps
230-
}, [watchedValues, selectedStandards]);
204+
console.log("Initializing configuration state from template values");
205+
const initial = {};
206+
const initialConfigured = {};
207+
208+
// For each standard, get its current values and determine if it's configured
209+
Object.keys(selectedStandards).forEach((standardName) => {
210+
const currentValues = _.get(watchedValues, standardName);
211+
if (!currentValues) return;
212+
213+
initial[standardName] = _.cloneDeep(currentValues);
214+
215+
const baseStandardName = standardName.split("[")[0];
216+
const standard = providedStandards.find((s) => s.name === baseStandardName);
217+
if (standard) {
218+
initialConfigured[standardName] = isStandardConfigured(
219+
standardName,
220+
standard,
221+
currentValues
222+
);
223+
}
224+
});
225+
226+
// Store both the initial values and set them as current saved values
227+
setOriginalValues(initial);
228+
setSavedValues(initial);
229+
setConfiguredState(initialConfigured);
230+
// Only depend on watchedValues and selectedStandards to avoid infinite loops
231+
// eslint-disable-next-line react-hooks/exhaustive-deps
232+
}
233+
}, [watchedValues, selectedStandards, editMode]);
231234

232235
// Save changes for a standard
233236
const handleSave = (standardName, standard, current) => {
@@ -519,6 +522,9 @@ const CippStandardAccordion = ({
519522
// Get current values and check if they differ from saved values
520523
const current = _.get(watchedValues, standardName);
521524
const saved = _.get(savedValues, standardName) || {};
525+
console.log(`Current values for ${standardName}:`, current);
526+
console.log(`Saved values for ${standardName}:`, saved);
527+
522528
const hasUnsaved = !_.isEqual(current, saved);
523529

524530
// Check if all required fields are filled
@@ -609,7 +615,7 @@ const CippStandardAccordion = ({
609615
const canSave = hasAction && requiredFieldsFilled && hasUnsaved;
610616

611617
console.log(
612-
`Standard: ${standardName}, Action Required: ${actionRequired}, Has Action: ${hasAction}, Required Fields Filled: ${requiredFieldsFilled}, Can Save: ${canSave}`
618+
`Standard: ${standardName}, Action Required: ${actionRequired}, Has Action: ${hasAction}, Required Fields Filled: ${requiredFieldsFilled}, Unsaved Changes: ${hasUnsaved}, Can Save: ${canSave}`
613619
);
614620

615621
return (
@@ -760,7 +766,7 @@ const CippStandardAccordion = ({
760766
</Grid>
761767
</Box>
762768
<Divider sx={{ mt: 2 }} />
763-
<Box sx={{ px: 3 , py: 2 }}>
769+
<Box sx={{ px: 3, py: 2 }}>
764770
<Stack direction="row" justifyContent="flex-end" spacing={1}>
765771
<Button
766772
variant="outlined"

src/components/CippStandards/CippStandardsSideBar.jsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,24 @@ const CippStandardsSideBar = ({
6464
formControl,
6565
createDialog,
6666
edit,
67+
onSaveSuccess,
6768
}) => {
6869
const [currentStep, setCurrentStep] = useState(0);
6970
const [savedItem, setSavedItem] = useState(null);
7071
const dialogAfterEffect = (id) => {
7172
setSavedItem(id);
73+
74+
// Reset form's dirty state to prevent unsaved changes warning
75+
if (formControl && formControl.reset) {
76+
// Get current values and reset the form with them to clear dirty state
77+
const currentValues = formControl.getValues();
78+
formControl.reset(currentValues);
79+
}
80+
81+
// Call the onSaveSuccess callback if provided
82+
if (typeof onSaveSuccess === "function") {
83+
onSaveSuccess();
84+
}
7285
};
7386

7487
const watchForm = useWatch({ control: formControl.control });
@@ -276,6 +289,7 @@ CippStandardsSideBar.propTypes = {
276289
).isRequired,
277290
updatedAt: PropTypes.string,
278291
formControl: PropTypes.object.isRequired,
292+
onSaveSuccess: PropTypes.func,
279293
};
280294

281295
export default CippStandardsSideBar;

src/components/PrivateRoute.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ export const PrivateRoute = ({ children, routeType }) => {
1818
});
1919

2020
// Check if the session is still loading before determining authentication status
21-
if (session.isLoading || apiRoles.isLoading) {
21+
if (
22+
session.isLoading ||
23+
apiRoles.isLoading ||
24+
(apiRoles.isFetching && (apiRoles.data === null || apiRoles.data === undefined))
25+
) {
2226
return <LoadingPage />;
2327
}
2428

0 commit comments

Comments
 (0)