Skip to content

Commit 4995dea

Browse files
committed
feat: Enhance SharePoint site management
1 parent 696f42a commit 4995dea

4 files changed

Lines changed: 333 additions & 39 deletions

File tree

src/components/CippComponents/CippEditSitePropertiesForm.jsx

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const LOCK_STATE_OPTIONS = [
3838
// prefills the form so submitting without changes is a no-op write of current values.
3939
export const CippEditSitePropertiesForm = ({ formHook, row, tenantFilter }) => {
4040
const siteRow = Array.isArray(row) ? row[0] : row
41+
// Group-connected sites only accept sharing level, link defaults, lock state and storage
42+
// quota; SPO rejects Title, domain restrictions, anonymous-link override and version policy.
43+
const isGroupSite = siteRow?.rootWebTemplate === 'Group'
4144
const propsApi = ApiGetCall({
4245
url: '/api/ListSiteProperties',
4346
data: {
@@ -99,10 +102,24 @@ export const CippEditSitePropertiesForm = ({ formHook, row, tenantFilter }) => {
99102

100103
return (
101104
<Stack spacing={1.5}>
102-
<Typography variant="subtitle2">General</Typography>
103-
<CippFormComponent type="textField" name="Title" label="Site Name" formControl={formHook} />
104-
105-
<Divider />
105+
{isGroupSite && (
106+
<Alert severity="info">
107+
Group-connected (Team) site: only the sharing level, default link settings, lock state
108+
and storage limits can be managed here. Rename the site by renaming its M365 group.
109+
</Alert>
110+
)}
111+
{!isGroupSite && (
112+
<>
113+
<Typography variant="subtitle2">General</Typography>
114+
<CippFormComponent
115+
type="textField"
116+
name="Title"
117+
label="Site Name"
118+
formControl={formHook}
119+
/>
120+
<Divider />
121+
</>
122+
)}
106123
<Typography variant="subtitle2">External Sharing</Typography>
107124
<CippFormComponent
108125
type="autoComplete"
@@ -131,15 +148,17 @@ export const CippEditSitePropertiesForm = ({ formHook, row, tenantFilter }) => {
131148
options={LINK_PERMISSION_OPTIONS}
132149
formControl={formHook}
133150
/>
134-
<CippFormComponent
135-
type="autoComplete"
136-
name="SharingDomainRestrictionMode"
137-
label="Domain Restriction"
138-
multiple={false}
139-
creatable={false}
140-
options={DOMAIN_MODE_OPTIONS}
141-
formControl={formHook}
142-
/>
151+
{!isGroupSite && (
152+
<CippFormComponent
153+
type="autoComplete"
154+
name="SharingDomainRestrictionMode"
155+
label="Domain Restriction"
156+
multiple={false}
157+
creatable={false}
158+
options={DOMAIN_MODE_OPTIONS}
159+
formControl={formHook}
160+
/>
161+
)}
143162
<CippFormCondition
144163
field="SharingDomainRestrictionMode"
145164
compareType="valueEq"
@@ -166,12 +185,14 @@ export const CippEditSitePropertiesForm = ({ formHook, row, tenantFilter }) => {
166185
formControl={formHook}
167186
/>
168187
</CippFormCondition>
169-
<CippFormComponent
170-
type="switch"
171-
name="OverrideTenantAnonymousLinkExpirationPolicy"
172-
label="Override tenant anonymous link expiration"
173-
formControl={formHook}
174-
/>
188+
{!isGroupSite && (
189+
<CippFormComponent
190+
type="switch"
191+
name="OverrideTenantAnonymousLinkExpirationPolicy"
192+
label="Override tenant anonymous link expiration"
193+
formControl={formHook}
194+
/>
195+
)}
175196
<CippFormCondition
176197
field="OverrideTenantAnonymousLinkExpirationPolicy"
177198
compareType="is"
@@ -214,18 +235,22 @@ export const CippEditSitePropertiesForm = ({ formHook, row, tenantFilter }) => {
214235
formControl={formHook}
215236
/>
216237

217-
<Divider />
218-
<Typography variant="subtitle2">File Version Policy</Typography>
219-
<CippFormComponent
220-
type="switch"
221-
name="InheritVersionPolicyFromTenant"
222-
label="Inherit version policy from tenant"
223-
formControl={formHook}
224-
/>
238+
{!isGroupSite && (
239+
<>
240+
<Divider />
241+
<Typography variant="subtitle2">File Version Policy</Typography>
242+
<CippFormComponent
243+
type="switch"
244+
name="InheritVersionPolicyFromTenant"
245+
label="Inherit version policy from tenant"
246+
formControl={formHook}
247+
/>
248+
</>
249+
)}
225250
<CippFormCondition
226251
field="InheritVersionPolicyFromTenant"
227252
compareType="is"
228-
compareValue={false}
253+
compareValue={isGroupSite ? '__never__' : false}
229254
formControl={formHook}
230255
>
231256
<CippFormComponent
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material'
2+
import { RestoreFromTrash } from '@mui/icons-material'
3+
import { CippDataTable } from '../CippTable/CippDataTable'
4+
import { usePermissions } from '../../hooks/use-permissions'
5+
6+
// Custom-component action dialog: lists a site's recycle bin (first + second stage) and
7+
// restores selected items via ExecRestoreRecycleBinItems.
8+
export const CippSiteRecycleBinDialog = ({
9+
row,
10+
tenantFilter,
11+
drawerVisible,
12+
setDrawerVisible,
13+
}) => {
14+
const siteRow = Array.isArray(row) ? row[0] : row
15+
const siteUrl = siteRow?.webUrl
16+
const tenant = siteRow?.Tenant ?? tenantFilter
17+
const { checkPermissions } = usePermissions()
18+
const canRestore = checkPermissions(['Sharepoint.SiteRecycleBin.ReadWrite'])
19+
20+
const actions = [
21+
{
22+
label: 'Restore Item',
23+
type: 'POST',
24+
icon: <RestoreFromTrash />,
25+
url: '/api/ExecRestoreRecycleBinItems',
26+
data: {
27+
Ids: 'Id',
28+
ItemNames: 'LeafName',
29+
// Literal values: these keys do not exist on the recycle bin rows, so the
30+
// action data mapper passes them through as-is.
31+
SiteUrl: siteUrl,
32+
tenantFilter: tenant,
33+
},
34+
confirmText: 'Restore [LeafName] from the recycle bin?',
35+
condition: () => canRestore,
36+
multiPost: false,
37+
},
38+
]
39+
40+
return (
41+
<Dialog fullWidth maxWidth="lg" open={!!drawerVisible} onClose={() => setDrawerVisible(false)}>
42+
<DialogTitle>
43+
Recycle Bin{siteRow?.displayName ? ` — ${siteRow.displayName}` : ''}
44+
</DialogTitle>
45+
<DialogContent dividers>
46+
<CippDataTable
47+
noCard={true}
48+
title="Deleted Items"
49+
queryKey={`SiteRecycleBin-${siteUrl}`}
50+
api={{
51+
url: '/api/ListSiteRecycleBin',
52+
data: {
53+
SiteUrl: siteUrl,
54+
tenantFilter: tenant,
55+
},
56+
dataKey: 'Results',
57+
}}
58+
actions={actions}
59+
simpleColumns={[
60+
'LeafName',
61+
'DirName',
62+
'ItemType',
63+
'ItemState',
64+
'Size',
65+
'DeletedByName',
66+
'DeletedDate',
67+
]}
68+
/>
69+
</DialogContent>
70+
<DialogActions>
71+
<Button color="inherit" onClick={() => setDrawerVisible(false)}>
72+
Close
73+
</Button>
74+
</DialogActions>
75+
</Dialog>
76+
)
77+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Layout as DashboardLayout } from '../../../layouts/index.js'
2+
import { usePermissions } from '../../../hooks/use-permissions'
3+
import { CippTablePage } from '../../../components/CippComponents/CippTablePage.jsx'
4+
import { Button } from '@mui/material'
5+
import { ArrowBack, RestoreFromTrash } from '@mui/icons-material'
6+
import Link from 'next/link'
7+
8+
const Page = () => {
9+
const { checkPermissions } = usePermissions()
10+
const canWriteSite = checkPermissions(['Sharepoint.Site.ReadWrite'])
11+
12+
const actions = [
13+
{
14+
label: 'Restore Site',
15+
type: 'POST',
16+
icon: <RestoreFromTrash />,
17+
url: '/api/ExecRestoreDeletedSite',
18+
data: {
19+
SiteUrl: 'Url',
20+
},
21+
confirmText:
22+
'Restore [Url] from the tenant recycle bin? Large sites can take a while to finish restoring.',
23+
condition: () => canWriteSite,
24+
multiPost: false,
25+
},
26+
]
27+
28+
return (
29+
<CippTablePage
30+
title="Deleted SharePoint Sites"
31+
apiUrl="/api/ListDeletedSites"
32+
apiDataKey="Results"
33+
queryKey="ListDeletedSites"
34+
actions={actions}
35+
simpleColumns={[
36+
'Name',
37+
'Url',
38+
'Status',
39+
'DeletionTime',
40+
'DaysRemaining',
41+
'StorageMaximumLevel',
42+
]}
43+
cardButton={
44+
<Button component={Link} href="/teams-share/sharepoint" startIcon={<ArrowBack />}>
45+
Back to Sites
46+
</Button>
47+
}
48+
/>
49+
)
50+
}
51+
52+
Page.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>
53+
54+
export default Page

0 commit comments

Comments
 (0)