Skip to content

Commit 40996cf

Browse files
authored
Merge pull request #19 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 161b2bd + a79f672 commit 40996cf

6 files changed

Lines changed: 266 additions & 7 deletions

File tree

src/components/CippComponents/CippAppTemplateDrawer.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ export const CippAppTemplateDrawer = ({
614614
{ value: "oneNote", label: "OneNote" },
615615
{ value: "outlook", label: "Outlook" },
616616
{ value: "powerPoint", label: "PowerPoint" },
617+
{ value: "publisher", label: "Publisher" },
617618
{ value: "teams", label: "Teams" },
618619
{ value: "word", label: "Word" },
619620
{ value: "lync", label: "Skype For Business" },
@@ -835,4 +836,4 @@ export const CippAppTemplateDrawer = ({
835836
</CippOffCanvas>
836837
</>
837838
);
838-
};
839+
};

src/components/CippComponents/CippApplicationDeployDrawer.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ export const CippApplicationDeployDrawer = ({
689689
{ value: "oneNote", label: "OneNote" },
690690
{ value: "outlook", label: "Outlook" },
691691
{ value: "powerPoint", label: "PowerPoint" },
692+
{ value: "publisher", label: "Publisher" },
692693
{ value: "teams", label: "Teams" },
693694
{ value: "word", label: "Word" },
694695
{ value: "lync", label: "Skype For Business" },

src/components/CippWizard/CippWizardVacationActions.jsx

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { CippFormCondition } from '../CippComponents/CippFormCondition'
1616
import { CippFormUserSelector } from '../CippComponents/CippFormUserSelector'
1717
import { useWatch } from 'react-hook-form'
1818
import { ApiGetCall } from '../../api/ApiCall'
19+
import { getCippValidator } from '../../utils/get-cipp-validator'
1920

2021
export const CippWizardVacationActions = (props) => {
2122
const { postUrl, formControl, onPreviousStep, onNextStep, currentStep, lastStep } = props
@@ -25,12 +26,14 @@ export const CippWizardVacationActions = (props) => {
2526

2627
const enableCA = useWatch({ control: formControl.control, name: 'enableCAExclusion' })
2728
const enableMailbox = useWatch({ control: formControl.control, name: 'enableMailboxPermissions' })
29+
const enableForwarding = useWatch({ control: formControl.control, name: 'enableForwarding' })
2830
const enableOOO = useWatch({ control: formControl.control, name: 'enableOOO' })
29-
const atLeastOneEnabled = enableCA || enableMailbox || enableOOO
31+
const atLeastOneEnabled = enableCA || enableMailbox || enableForwarding || enableOOO
3032

3133
const users = useWatch({ control: formControl.control, name: 'Users' })
3234
const firstUser = Array.isArray(users) && users.length > 0 ? users[0] : null
3335
const firstUserUpn = firstUser?.addedFields?.userPrincipalName || firstUser?.value || null
36+
const forwardOption = useWatch({ control: formControl.control, name: 'forwardOption' })
3437

3538
const oooData = ApiGetCall({
3639
url: '/api/ListOoO',
@@ -41,6 +44,41 @@ export const CippWizardVacationActions = (props) => {
4144

4245
const isFetchingOOO = oooData.isFetching
4346

47+
const forwardingUsers = ApiGetCall({
48+
url: '/api/ListGraphRequest',
49+
data: {
50+
Endpoint: 'users',
51+
tenantFilter: tenantDomain,
52+
$select: 'id,displayName,userPrincipalName,mail',
53+
$top: 999,
54+
},
55+
queryKey: `VacationForwardingUsers-${tenantDomain}`,
56+
waiting: !!(enableForwarding && tenantDomain),
57+
})
58+
59+
const forwardingContacts = ApiGetCall({
60+
url: '/api/ListGraphRequest',
61+
data: {
62+
Endpoint: 'contacts',
63+
tenantFilter: tenantDomain,
64+
$select: 'displayName,mail,mailNickname',
65+
$top: 999,
66+
},
67+
queryKey: `VacationForwardingContacts-${tenantDomain}`,
68+
waiting: !!(enableForwarding && tenantDomain),
69+
})
70+
71+
const internalAddressOptions = [
72+
...((forwardingUsers.data?.Results || []).map((user) => ({
73+
value: user.userPrincipalName,
74+
label: `${user.displayName} (${user.userPrincipalName}) - User`,
75+
})) || []),
76+
...((forwardingContacts.data?.Results || []).map((contact) => ({
77+
value: contact.mail || contact.emailAddress,
78+
label: `${contact.displayName} (${contact.mail || contact.emailAddress}) - Contact`,
79+
})) || []),
80+
]
81+
4482
useEffect(() => {
4583
if (oooData.isSuccess && oooData.data) {
4684
const currentInternal = formControl.getValues('oooInternalMessage')
@@ -71,7 +109,13 @@ export const CippWizardVacationActions = (props) => {
71109
formControl.setValue('oooDeclineMeetingMessage', oooData.data.DeclineMeetingMessage)
72110
}
73111
}
74-
}, [oooData.isSuccess, oooData.data])
112+
}, [oooData.isSuccess, oooData.data, formControl])
113+
114+
useEffect(() => {
115+
if (enableForwarding && !forwardOption) {
116+
formControl.setValue('forwardOption', 'internalAddress')
117+
}
118+
}, [enableForwarding, forwardOption, formControl])
75119

76120
return (
77121
<Stack spacing={4}>
@@ -318,6 +362,120 @@ export const CippWizardVacationActions = (props) => {
318362
</CardContent>
319363
</Card>
320364

365+
{/* Mail Forwarding Section */}
366+
<Card variant="outlined">
367+
<CardHeader
368+
title="Mail Forwarding"
369+
subheader="Forward email to another recipient during the vacation period"
370+
/>
371+
<Divider />
372+
<CardContent>
373+
<Stack spacing={2}>
374+
<CippFormComponent
375+
type="switch"
376+
name="enableForwarding"
377+
label="Enable Mail Forwarding"
378+
formControl={formControl}
379+
/>
380+
381+
<CippFormCondition
382+
formControl={formControl}
383+
field="enableForwarding"
384+
compareType="is"
385+
compareValue={true}
386+
clearOnHide={false}
387+
>
388+
<Grid container spacing={2}>
389+
<Grid size={{ xs: 12 }}>
390+
<Alert severity="info" sx={{ mb: 1 }}>
391+
Vacation mode will enable forwarding at the start date and disable forwarding
392+
again at the end date. Existing forwarding settings are not restored after the
393+
vacation ends.
394+
</Alert>
395+
</Grid>
396+
<Grid size={{ xs: 12 }}>
397+
<CippFormComponent
398+
type="radio"
399+
name="forwardOption"
400+
formControl={formControl}
401+
options={[
402+
{ label: 'Forward to Internal Address', value: 'internalAddress' },
403+
{
404+
label: 'Forward to External Address (Tenant must allow this)',
405+
value: 'ExternalAddress',
406+
},
407+
]}
408+
/>
409+
</Grid>
410+
411+
<CippFormCondition
412+
formControl={formControl}
413+
field="forwardOption"
414+
compareType="is"
415+
compareValue="internalAddress"
416+
>
417+
<Grid size={{ xs: 12 }}>
418+
<CippFormComponent
419+
type="autoComplete"
420+
label={
421+
tenantDomain
422+
? `Forward to user or contact in ${tenantDomain}`
423+
: 'Select a tenant first'
424+
}
425+
name="forwardInternal"
426+
multiple={false}
427+
options={internalAddressOptions}
428+
formControl={formControl}
429+
creatable={false}
430+
disabled={!tenantDomain}
431+
validators={{
432+
validate: (option) => {
433+
if (!option?.value && !option) {
434+
return 'Forwarding target is required'
435+
}
436+
return true
437+
},
438+
}}
439+
required={true}
440+
/>
441+
</Grid>
442+
</CippFormCondition>
443+
444+
<CippFormCondition
445+
formControl={formControl}
446+
field="forwardOption"
447+
compareType="is"
448+
compareValue="ExternalAddress"
449+
>
450+
<Grid size={{ xs: 12 }}>
451+
<CippFormComponent
452+
type="textField"
453+
label="External Email Address"
454+
name="forwardExternal"
455+
formControl={formControl}
456+
validators={{
457+
required: 'Email is required',
458+
validate: (value) => getCippValidator(value, 'email'),
459+
}}
460+
required={true}
461+
/>
462+
</Grid>
463+
</CippFormCondition>
464+
465+
<Grid size={{ xs: 12 }}>
466+
<CippFormComponent
467+
type="switch"
468+
label="Keep a Copy of the Forwarded Mail in the Source Mailbox"
469+
name="forwardKeepCopy"
470+
formControl={formControl}
471+
/>
472+
</Grid>
473+
</Grid>
474+
</CippFormCondition>
475+
</Stack>
476+
</CardContent>
477+
</Card>
478+
321479
{/* Out of Office Section */}
322480
<Card variant="outlined">
323481
<CardHeader

src/components/CippWizard/CippWizardVacationConfirmation.jsx

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@ export const CippWizardVacationConfirmation = (props) => {
1313

1414
const caExclusion = ApiPostCall({ relatedQueryKeys: ["VacationMode"] });
1515
const mailboxVacation = ApiPostCall({ relatedQueryKeys: ["VacationMode"] });
16+
const forwardingVacation = ApiPostCall({ relatedQueryKeys: ["VacationMode"] });
1617
const oooVacation = ApiPostCall({ relatedQueryKeys: ["VacationMode"] });
1718

1819
const tenantFilter = values.tenantFilter?.value || values.tenantFilter;
19-
const isSubmitting = caExclusion.isPending || mailboxVacation.isPending || oooVacation.isPending;
20-
const hasSubmitted = caExclusion.isSuccess || mailboxVacation.isSuccess || oooVacation.isSuccess;
20+
const isSubmitting =
21+
caExclusion.isPending ||
22+
mailboxVacation.isPending ||
23+
forwardingVacation.isPending ||
24+
oooVacation.isPending;
25+
const hasSubmitted =
26+
caExclusion.isSuccess ||
27+
mailboxVacation.isSuccess ||
28+
forwardingVacation.isSuccess ||
29+
oooVacation.isSuccess;
2130

2231
const handleSubmit = () => {
2332
if (values.enableCAExclusion) {
@@ -57,6 +66,32 @@ export const CippWizardVacationConfirmation = (props) => {
5766
});
5867
}
5968

69+
if (values.enableForwarding) {
70+
const forwardingData = {
71+
tenantFilter,
72+
Users: values.Users,
73+
forwardOption: values.forwardOption,
74+
KeepCopy: values.forwardKeepCopy || false,
75+
startDate: values.startDate,
76+
endDate: values.endDate,
77+
reference: values.reference || null,
78+
postExecution: values.postExecution || [],
79+
};
80+
81+
if (values.forwardOption === "internalAddress") {
82+
forwardingData.ForwardInternal = values.forwardInternal;
83+
}
84+
85+
if (values.forwardOption === "ExternalAddress") {
86+
forwardingData.ForwardExternal = values.forwardExternal;
87+
}
88+
89+
forwardingVacation.mutate({
90+
url: "/api/ExecScheduleForwardingVacation",
91+
data: forwardingData,
92+
});
93+
}
94+
6095
if (values.enableOOO) {
6196
const oooData = {
6297
tenantFilter,
@@ -97,6 +132,18 @@ export const CippWizardVacationConfirmation = (props) => {
97132
return users.map((u) => u.label || u.value || u).join(", ");
98133
};
99134

135+
const formatForwardingTarget = () => {
136+
if (values.forwardOption === "internalAddress") {
137+
return values.forwardInternal?.label || values.forwardInternal?.value || values.forwardInternal || "Not set";
138+
}
139+
140+
if (values.forwardOption === "ExternalAddress") {
141+
return values.forwardExternal || "Not set";
142+
}
143+
144+
return "Not set";
145+
};
146+
100147
return (
101148
<Stack spacing={3}>
102149
{/* Summary */}
@@ -148,8 +195,13 @@ export const CippWizardVacationConfirmation = (props) => {
148195

149196
{/* Enabled Actions */}
150197
{(() => {
151-
const enabledCount = [values.enableCAExclusion, values.enableMailboxPermissions, values.enableOOO].filter(Boolean).length;
152-
const mdSize = enabledCount >= 3 ? 4 : enabledCount === 2 ? 6 : 12;
198+
const enabledCount = [
199+
values.enableCAExclusion,
200+
values.enableMailboxPermissions,
201+
values.enableForwarding,
202+
values.enableOOO,
203+
].filter(Boolean).length;
204+
const mdSize = enabledCount >= 4 ? 3 : enabledCount === 3 ? 4 : enabledCount === 2 ? 6 : 12;
153205
return (
154206
<Grid container spacing={3}>
155207
{values.enableCAExclusion && (
@@ -225,6 +277,42 @@ export const CippWizardVacationConfirmation = (props) => {
225277
</Grid>
226278
)}
227279

280+
{values.enableForwarding && (
281+
<Grid size={{ md: mdSize, xs: 12 }}>
282+
<Card variant="outlined" sx={{ height: "100%" }}>
283+
<CardHeader
284+
title="Mail Forwarding"
285+
action={<Chip label="Enabled" color="primary" size="small" />}
286+
/>
287+
<Divider />
288+
<CardContent>
289+
<Stack spacing={1}>
290+
<div>
291+
<Typography variant="subtitle2" color="text.secondary">
292+
Destination
293+
</Typography>
294+
<Typography variant="body2">{formatForwardingTarget()}</Typography>
295+
</div>
296+
<div>
297+
<Typography variant="subtitle2" color="text.secondary">
298+
Forwarding Type
299+
</Typography>
300+
<Typography variant="body2">
301+
{values.forwardOption === "ExternalAddress" ? "External Address" : "Internal Address"}
302+
</Typography>
303+
</div>
304+
<div>
305+
<Typography variant="subtitle2" color="text.secondary">
306+
Keep Copy
307+
</Typography>
308+
<Typography variant="body2">{values.forwardKeepCopy ? "Yes" : "No"}</Typography>
309+
</div>
310+
</Stack>
311+
</CardContent>
312+
</Card>
313+
</Grid>
314+
)}
315+
228316
{values.enableOOO && (
229317
<Grid size={{ md: mdSize, xs: 12 }}>
230318
<Card variant="outlined" sx={{ height: "100%" }}>
@@ -287,6 +375,7 @@ export const CippWizardVacationConfirmation = (props) => {
287375
{/* API Results */}
288376
{values.enableCAExclusion && <CippApiResults apiObject={caExclusion} />}
289377
{values.enableMailboxPermissions && <CippApiResults apiObject={mailboxVacation} />}
378+
{values.enableForwarding && <CippApiResults apiObject={forwardingVacation} />}
290379
{values.enableOOO && <CippApiResults apiObject={oooVacation} />}
291380

292381
{/* Navigation + Custom Submit */}

src/pages/identity/administration/vacation-mode/add/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ const Page = () => {
7676
includeCalendar: false,
7777
calendarPermission: null,
7878
canViewPrivateItems: false,
79+
enableForwarding: false,
80+
forwardOption: 'internalAddress',
81+
forwardInternal: null,
82+
forwardExternal: '',
83+
forwardKeepCopy: false,
7984
enableOOO: false,
8085
oooInternalMessage: null,
8186
oooExternalMessage: null,

src/pages/identity/administration/vacation-mode/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ const Page = () => {
6060
value: [{ id: "Name", value: "Mailbox Vacation" }],
6161
type: "column",
6262
},
63+
{
64+
filterName: "Mail Forwarding",
65+
value: [{ id: "Name", value: "Forwarding Vacation" }],
66+
type: "column",
67+
},
6368
{
6469
filterName: "Out of Office",
6570
value: [{ id: "Name", value: "OOO Vacation" }],

0 commit comments

Comments
 (0)