Skip to content

Commit d4718db

Browse files
Merge pull request #1871 from rvdwegen/dev
Add tenant offboarding feature
2 parents 9692d8f + c5603ae commit d4718db

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

src/_nav.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ const _nav = [
137137
name: 'Enterprise Applications',
138138
to: '/tenant/administration/enterprise-apps',
139139
},
140+
{
141+
component: CNavItem,
142+
name: 'Tenant Offboarding',
143+
to: '/tenant/administration/tenant-offboarding-wizard',
144+
},
140145
],
141146
},
142147
{

src/adminRoutes.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const GDAPRelationships = React.lazy(() =>
1111
import('./views/tenant/administration/ListGDAPRelationships'),
1212
)
1313
const appapproval = React.lazy(() => import('src/views/cipp/AppApproval'))
14+
const TenantOffboardingWizard = React.lazy(() =>
15+
import('src/views/tenant/administration/tenant-offboarding-wizard'),
16+
)
1417

1518
const adminRoutes = [
1619
{ path: '/cipp', name: 'CIPP' },
@@ -38,6 +41,11 @@ const adminRoutes = [
3841
{ path: '/tenant/administration/appapproval', name: 'App Approval', component: appapproval },
3942
{ path: '/tenant/administration/gdap-status', name: 'GDAP Status', component: GDAPStatus },
4043
{ path: '/tenant/standards/apply-standard', name: 'Apply Standard', component: ApplyStandard },
44+
{
45+
path: '/tenant/administration/tenant-offboarding-wizard',
46+
name: 'Tenant Offboarding',
47+
component: TenantOffboardingWizard,
48+
},
4149
]
4250

4351
export default adminRoutes

src/routes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const DeployGroupTemplates = React.lazy(() =>
2323
const GeoIPLookup = React.lazy(() => import('src/views/tenant/administration/GeoIPLookup'))
2424

2525
const TenantLookup = React.lazy(() => import('src/views/tenant/administration/TenantLookup'))
26+
2627
const GroupTemplates = React.lazy(() => import('src/views/identity/administration/GroupTemplates'))
2728

2829
const EditGroup = React.lazy(() => import('src/views/identity/administration/EditGroup'))
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import React from 'react'
2+
import { CCallout, CCol, CListGroup, CListGroupItem, CRow, CSpinner } from '@coreui/react'
3+
import { Field, FormSpy } from 'react-final-form'
4+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
5+
import { faExclamationTriangle, faTimes, faCheck } from '@fortawesome/free-solid-svg-icons'
6+
import { useSelector } from 'react-redux'
7+
import { CippWizard } from 'src/components/layout'
8+
import PropTypes from 'prop-types'
9+
import { RFFCFormCheck, RFFCFormInput, RFFCFormSwitch, RFFSelectSearch } from 'src/components/forms'
10+
import { TenantSelector } from 'src/components/utilities'
11+
import { useLazyGenericPostRequestQuery } from 'src/store/api/app'
12+
13+
const Error = ({ name }) => (
14+
<Field
15+
name={name}
16+
subscription={{ touched: true, error: true }}
17+
render={({ meta: { touched, error } }) =>
18+
touched && error ? (
19+
<CCallout color="danger">
20+
<FontAwesomeIcon icon={faExclamationTriangle} color="danger" />
21+
{error}
22+
</CCallout>
23+
) : null
24+
}
25+
/>
26+
)
27+
28+
Error.propTypes = {
29+
name: PropTypes.string.isRequired,
30+
}
31+
32+
const TenantOffboardingWizard = () => {
33+
const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName)
34+
const currentSettings = useSelector((state) => state.app)
35+
const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery()
36+
37+
const handleSubmit = async (values) => {
38+
const shippedValues = {
39+
TenantFilter: tenantDomain,
40+
RemoveCSPGuestUsers: values.RemoveCSPGuestUsers ? values.RemoveCSPGuestUsers : '',
41+
RemoveMultitenantCSPApps: values.RemoveMultitenantCSPApps
42+
? values.RemoveMultitenantCSPApps
43+
: '',
44+
TerminateGDAP: values.TerminateGDAP ? values.TerminateGDAP : '',
45+
TerminateContract: values.TerminateContract ? values.TerminateContract : '',
46+
}
47+
48+
//alert(JSON.stringify(values, null, 2))
49+
genericPostRequest({ path: '/api/ExecOffboardTenant', values: shippedValues })
50+
}
51+
52+
return (
53+
<CippWizard
54+
initialValues={currentSettings.offboardingDefaults}
55+
onSubmit={handleSubmit}
56+
wizardTitle="Tenant Offboarding Wizard"
57+
>
58+
<CippWizard.Page
59+
title="Tenant Choice"
60+
description="Choose the tenant to offboard"
61+
>
62+
{console.log(currentSettings.offboardingDefaults)}
63+
<center>
64+
<h3 className="text-primary">Step 1</h3>
65+
<h5 className="card-title mb-4">Choose a tenant</h5>
66+
</center>
67+
<hr className="my-4" />
68+
<Field name="tenantFilter">{(props) => <TenantSelector />}</Field>
69+
<hr className="my-4" />
70+
</CippWizard.Page>
71+
<CippWizard.Page
72+
initialvalues={currentSettings.tenantOffboardingDefaults}
73+
title="Tenant Offboarding Settings"
74+
description="Select the tenant offboarding actions you wish to take."
75+
>
76+
<center>
77+
<h3 className="text-primary">Step 2</h3>
78+
<h5>Choose tenant offboarding options</h5>
79+
</center>
80+
<hr className="my-4" />
81+
<div className="mb-2">
82+
<CRow>
83+
<CCol className="mb-3" md={6}>
84+
<RFFCFormSwitch
85+
name="RemoveCSPGuestUsers"
86+
label="Remove all guest users originating from the CSP tenant."
87+
/>
88+
<RFFCFormSwitch
89+
name="RemoveMultitenantCSPApps"
90+
label="Remove all multitenant applications originating from CSP tenant (including CIPP-SAM)."
91+
/>
92+
<RFFCFormSwitch
93+
name="TerminateGDAP"
94+
label="Terminate all active GDAP relationships (will send email to tenant admins and contacts)."
95+
/>
96+
<RFFCFormSwitch
97+
name="TerminateContract"
98+
label="Terminate contract relationship (reseller, etc)."
99+
/>
100+
</CCol>
101+
</CRow>
102+
</div>
103+
<hr className="my-4" />
104+
</CippWizard.Page>
105+
<CippWizard.Page title="Review and Confirm" description="Confirm the settings to apply">
106+
<center>
107+
<h3 className="text-primary">Step 3</h3>
108+
<h5 className="mb-4">Confirm and apply</h5>
109+
<hr className="my-4" />
110+
</center>
111+
<div className="mb-2">
112+
{postResults.isFetching && (
113+
<CCallout color="info">
114+
<CSpinner>Loading</CSpinner>
115+
</CCallout>
116+
)}
117+
{postResults.isSuccess && (
118+
<>
119+
<CCallout color="success">
120+
{postResults.data.Results.map((message, idx) => {
121+
return <li key={idx}>{message}</li>
122+
})}
123+
</CCallout>
124+
<CCallout color="danger">
125+
{postResults.data.Errors.map((message, idx) => {
126+
return <li key={idx}>{message}</li>
127+
})}
128+
</CCallout>
129+
</>
130+
)}
131+
{!postResults.isSuccess && (
132+
<FormSpy>
133+
{(props) => (
134+
<>
135+
<CRow>
136+
<CCol md={{ span: 6, offset: 3 }}>
137+
<CCallout color="danger">
138+
<FontAwesomeIcon icon={faExclamationTriangle} color="danger" />
139+
These actions are irreversible!
140+
</CCallout>
141+
<CListGroup flush>
142+
<CListGroupItem className="d-flex justify-content-between align-items-center">
143+
<h5 className="mb-0">Selected Tenant:</h5>
144+
{tenantDomain}
145+
</CListGroupItem>
146+
</CListGroup>
147+
<hr />
148+
</CCol>
149+
</CRow>
150+
<CRow>
151+
<CCol md={{ span: 6, offset: 3 }}>
152+
<CListGroup flush>
153+
<CListGroupItem className="d-flex justify-content-between align-items-center">
154+
Remove all guest users originating from the CSP tenant
155+
<FontAwesomeIcon
156+
color="#f77f00"
157+
size="lg"
158+
icon={props.values.RemoveCSPGuestUsers ? faCheck : faTimes}
159+
/>
160+
</CListGroupItem>
161+
<CListGroupItem className="d-flex justify-content-between align-items-center">
162+
Remove all multitenant applications originating from CSP tenant
163+
<FontAwesomeIcon
164+
color="#f77f00"
165+
size="lg"
166+
icon={props.values.RemoveMultitenantApps ? faCheck : faTimes}
167+
/>
168+
</CListGroupItem>
169+
<CListGroupItem className="d-flex justify-content-between align-items-center">
170+
Terminate all active GDAP relationships
171+
<FontAwesomeIcon
172+
color="#f77f00"
173+
size="lg"
174+
icon={props.values.TerminateGDAP ? faCheck : faTimes}
175+
/>
176+
</CListGroupItem>
177+
<CListGroupItem className="d-flex justify-content-between align-items-center">
178+
Terminate contract relationship
179+
<FontAwesomeIcon
180+
color="#f77f00"
181+
size="lg"
182+
icon={props.values.TerminateContract ? faCheck : faTimes}
183+
/>
184+
</CListGroupItem>
185+
</CListGroup>
186+
<hr />
187+
</CCol>
188+
</CRow>
189+
</>
190+
)}
191+
</FormSpy>
192+
)}
193+
</div>
194+
<hr className="my-4" />
195+
</CippWizard.Page>
196+
</CippWizard>
197+
)
198+
}
199+
200+
export default TenantOffboardingWizard

0 commit comments

Comments
 (0)