Skip to content

Commit b79e088

Browse files
authored
Merge branch 'KelvinTegelaar:main' into main
2 parents f6b1335 + a9fadb8 commit b79e088

30 files changed

Lines changed: 689 additions & 244 deletions

File tree

.github/workflows/Close_Stale_Issues_and_PRs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ jobs:
1313
stale-issue-message: 'This issue is stale because it has been open 10 days with no activity. We will close this issue soon. If you want this feature implemented you can contribute it. See: https://docs.cipp.app/dev-documentation/contributing-to-the-code . Please notify the team if you are working on this yourself.'
1414
close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.'
1515
stale-issue-label: 'no-activity'
16-
exempt-issue-labels: 'planned,bug'
16+
exempt-issue-labels: 'planned,bug,roadmap'
1717
days-before-stale: 9
1818
days-before-close: 5

public/version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "7.5.1"
2+
"version": "7.5.3"
33
}

src/components/CippCards/CippExchangeInfoCard.jsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ export const CippExchangeInfoCard = (props) => {
2929
{ name: "ActiveSync", enabled: exchangeData?.MailboxActiveSyncEnabled },
3030
];
3131

32+
// Define mailbox hold types array
33+
const holds = [
34+
{ name: "Compliance Tag Hold", enabled: exchangeData?.ComplianceTagHold },
35+
{ name: "Retention Hold", enabled: exchangeData?.RetentionHold },
36+
{ name: "Litigation Hold", enabled: exchangeData?.LitigationHold },
37+
{ name: "In-Place Hold", enabled: exchangeData?.InPlaceHold },
38+
{ name: "eDiscovery Hold", enabled: exchangeData?.EDiscoveryHold },
39+
{ name: "Purview Retention Hold", enabled: exchangeData?.PurviewRetentionHold },
40+
{ name: "Excluded from Org-Wide Hold", enabled: exchangeData?.ExcludedFromOrgWideHold },
41+
];
42+
3243
return (
3344
<Card {...other}>
3445
<CardHeader
@@ -164,14 +175,27 @@ export const CippExchangeInfoCard = (props) => {
164175
)
165176
}
166177
/>
178+
{/* Combine all mailbox hold types into a single PropertyListItem */}
167179
<PropertyListItem
168180
divider
169-
label="Litigation Hold"
181+
label="Mailbox Holds"
170182
value={
171183
isLoading ? (
172-
<Skeleton variant="text" width={60} />
184+
<Skeleton variant="text" width={200} />
173185
) : (
174-
getCippFormatting(exchangeData?.LitigationHold, "LitigationHold")
186+
<div>
187+
{holds.map((hold) => (
188+
<Chip
189+
key={hold.name}
190+
label={hold.name}
191+
icon={hold.enabled ? <CheckIcon /> : <CloseIcon />}
192+
color={hold.enabled ? "success" : "default"}
193+
variant="outlined"
194+
size="small"
195+
sx={{ mr: 1, mb: 1 }}
196+
/>
197+
))}
198+
</div>
175199
)
176200
}
177201
/>

src/components/CippCards/CippUniversalSearch.jsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,60 @@ export const CippUniversalSearch = React.forwardRef(
6767

6868
CippUniversalSearch.displayName = "CippUniversalSearch";
6969

70-
const Results = ({ items = [], searchValue }) => (
71-
<Grid container spacing={2} mt={2}>
72-
{items.slice(0, 9).map((item, key) => (
73-
<Grid item xs={12} sm={6} md={4} key={key}>
74-
<ResultsRow match={item} searchValue={searchValue} />
70+
const Results = ({ items = [], searchValue }) => {
71+
const [currentPage, setCurrentPage] = useState(1);
72+
const resultsPerPage = 9; // Number of results per page
73+
const totalResults = items.length; // Total number of results
74+
const totalPages = Math.ceil(totalResults / resultsPerPage); // Total pages
75+
76+
// Calculate the results to display for the current page
77+
const startIndex = (currentPage - 1) * resultsPerPage;
78+
const endIndex = startIndex + resultsPerPage;
79+
const displayedResults = items.slice(startIndex, endIndex);
80+
81+
const handleNextPage = () => {
82+
if (currentPage < totalPages) {
83+
setCurrentPage(currentPage + 1);
84+
}
85+
};
86+
87+
const handlePreviousPage = () => {
88+
if (currentPage > 1) {
89+
setCurrentPage(currentPage - 1);
90+
}
91+
};
92+
93+
return (
94+
<>
95+
<Typography variant="body2" color="textSecondary" mt={2}>
96+
{totalResults} results (Page {currentPage} of {totalPages})
97+
</Typography>
98+
<Grid container spacing={2} mt={2}>
99+
{displayedResults.map((item, key) => (
100+
<Grid item xs={12} sm={6} md={4} key={key}>
101+
<ResultsRow match={item} searchValue={searchValue} />
102+
</Grid>
103+
))}
75104
</Grid>
76-
))}
77-
</Grid>
78-
);
105+
<Box display="flex" justifyContent="space-between" mt={2}>
106+
<Button
107+
variant="outlined"
108+
disabled={currentPage === 1}
109+
onClick={handlePreviousPage}
110+
>
111+
Previous
112+
</Button>
113+
<Button
114+
variant="outlined"
115+
disabled={currentPage === totalPages}
116+
onClick={handleNextPage}
117+
>
118+
Next
119+
</Button>
120+
</Box>
121+
</>
122+
);
123+
};
79124

80125
const ResultsRow = ({ match, searchValue }) => {
81126
const highlightMatch = (text) => {
@@ -118,7 +163,7 @@ const ResultsRow = ({ match, searchValue }) => {
118163
href={`identity/administration/users/user?tenantFilter=${
119164
currentTenantInfo.data?.find((tenant) => tenant.customerId === match._tenantId)
120165
?.defaultDomainName || match._tenantId
121-
}&userId=${match.userPrincipalName}`}
166+
}&userId=${match.id}`}
122167
variant="outlined"
123168
color="primary"
124169
size="small"

src/components/CippComponents/CippApiDialog.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export const CippApiDialog = (props) => {
295295
return getNestedValue(row, key) || `[${key}]`;
296296
});
297297

298-
if (linkWithRowData.startsWith("/")) {
298+
if (linkWithRowData.startsWith("/") && !api?.external) {
299299
// Internal link navigation
300300
setLinkClicked(true);
301301
router.push(linkWithRowData, undefined, { shallow: true });

src/components/CippComponents/CippCentralSearch.jsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ export const CippCentralSearch = ({ handleClose, open }) => {
9696
label="Search any menu item or page in CIPP"
9797
onChange={handleChange}
9898
onKeyDown={handleKeyDown}
99+
onFocus={(event) => {
100+
// Select all text on focus if there's content
101+
if (event.target.value) {
102+
event.target.select();
103+
}
104+
}}
99105
value={searchValue}
100106
autoFocus
101107
/>
@@ -106,10 +112,7 @@ export const CippCentralSearch = ({ handleClose, open }) => {
106112
<Grid container spacing={2} mt={2}>
107113
{filteredItems.map((item, index) => (
108114
<Grid item xs={12} sm={12} md={12} key={index}>
109-
<Card
110-
variant="outlined"
111-
sx={{ height: "100%" }}
112-
>
115+
<Card variant="outlined" sx={{ height: "100%" }}>
113116
<CardActionArea
114117
onClick={() => handleCardClick(item.path)}
115118
aria-label={`Navigate to ${item.title}`}

src/components/CippComponents/CippCustomVariables.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const CippCustomVariables = ({ id }) => {
6464
url: "/api/ExecCippReplacemap",
6565
data: {
6666
Action: "!AddEdit",
67-
customerId: id,
67+
tenantId: id,
6868
},
6969
relatedQueryKeys: [`CustomVariables_${id}`],
7070
},
@@ -77,7 +77,7 @@ const CippCustomVariables = ({ id }) => {
7777
data: {
7878
Action: "Delete",
7979
RowKey: "RowKey",
80-
customerId: id,
80+
tenantId: id,
8181
},
8282
relatedQueryKeys: [`CustomVariables_${id}`],
8383
multiPost: false,
@@ -100,7 +100,7 @@ const CippCustomVariables = ({ id }) => {
100100
title={id === "AllTenants" ? "Global Variables" : "Custom Variables"}
101101
actions={actions}
102102
api={{
103-
url: `/api/ExecCippReplacemap?Action=List&customerId=${id}`,
103+
url: `/api/ExecCippReplacemap?Action=List&tenantId=${id}`,
104104
dataKey: "Results",
105105
}}
106106
simpleColumns={["RowKey", "Value"]}
@@ -147,7 +147,7 @@ const CippCustomVariables = ({ id }) => {
147147
api={{
148148
type: "POST",
149149
url: "/api/ExecCippReplacemap",
150-
data: { Action: "AddEdit", customerId: id },
150+
data: { Action: "AddEdit", tenantId: id },
151151
relatedQueryKeys: [`CustomVariables_${id}`],
152152
}}
153153
/>

src/components/CippComponents/CippExchangeActions.jsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
Outbox,
1515
NotificationImportant,
1616
DataUsage,
17+
MailLock,
1718
} from "@mui/icons-material";
1819

1920
export const CippExchangeActions = () => {
@@ -187,6 +188,21 @@ export const CippExchangeActions = () => {
187188
},
188189
],
189190
},
191+
{
192+
label: "Set Retention Hold",
193+
type: "POST",
194+
url: "/api/ExecSetRetentionHold",
195+
data: { UPN: "UPN", Identity: "Id" },
196+
confirmText: "What do you want to set Retention Hold to?",
197+
icon: <MailLock />,
198+
fields: [
199+
{
200+
type: "switch",
201+
name: "disable",
202+
label: "Disable Retention Hold",
203+
},
204+
],
205+
},
190206
{
191207
label: "Set Mailbox Locale",
192208
type: "POST",

src/components/CippComponents/CippTenantSelector.jsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const CippTenantSelector = (props) => {
6666
}, [currentTenant?.value]);
6767

6868
useEffect(() => {
69-
if (tenant && currentTenant?.value && currentTenant?.value !== 'AllTenants') {
69+
if (tenant && currentTenant?.value && currentTenant?.value !== "AllTenants") {
7070
tenantDetails.refetch();
7171
}
7272
}, [tenant, offcanvasVisible]);
@@ -85,6 +85,7 @@ export const CippTenantSelector = (props) => {
8585
defaultDomainName: matchingTenant.defaultDomainName,
8686
displayName: matchingTenant.displayName,
8787
customerId: matchingTenant.customerId,
88+
initialDomainName: matchingTenant.initialDomainName,
8889
},
8990
}
9091
: {
@@ -192,12 +193,12 @@ export const CippTenantSelector = (props) => {
192193
actions={[
193194
{
194195
label: "M365 Admin Portal",
195-
link: `https://admin.microsoft.com/Partner/BeginClientSession.aspx?CTID=${currentTenant?.addedFields?.customerId}&CSDEST=o365admincenter`,
196+
link: `https://admin.cloud.microsoft/?delegatedOrg=${currentTenant?.addedFields?.initialDomainName}`,
196197
icon: <GlobeAltIcon />,
197198
},
198199
{
199200
label: "Exchange Portal",
200-
link: `https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=${currentTenant?.value}`,
201+
link: `https://admin.cloud.microsoft/exchange?delegatedOrg=${currentTenant?.addedFields?.initialDomainName}`,
201202
icon: <Mail />,
202203
},
203204
{
@@ -207,7 +208,7 @@ export const CippTenantSelector = (props) => {
207208
},
208209
{
209210
label: "Teams Portal",
210-
link: `https://admin.teams.microsoft.com/?delegatedOrg=${currentTenant?.value}`,
211+
link: `https://admin.teams.microsoft.com/?delegatedOrg=${currentTenant?.addedFields?.initialDomainName}`,
211212
icon: <FilePresent />,
212213
},
213214
{
@@ -222,8 +223,9 @@ export const CippTenantSelector = (props) => {
222223
},
223224
{
224225
label: "SharePoint Portal",
225-
link: `https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=${currentTenant?.addedFields?.customerId}&CSDEST=SharePoint`,
226+
link: `/api/ListSharePointAdminUrl?tenantFilter=${currentTenant?.value}`,
226227
icon: <Share />,
228+
external: true,
227229
},
228230
{
229231
label: "Security Portal",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, { useState } from "react";
2+
import { Box, Link } from "@mui/material";
3+
4+
export const CollapsibleChipList = ({ children, maxItems = 4 }) => {
5+
const [expanded, setExpanded] = useState(false);
6+
const childArray = React.Children.toArray(children);
7+
const hasMoreItems = childArray.length > maxItems;
8+
9+
const toggleExpanded = (e) => {
10+
e.preventDefault();
11+
setExpanded(!expanded);
12+
};
13+
14+
return (
15+
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5, alignItems: "center" }}>
16+
{expanded ? childArray : childArray.slice(0, maxItems)}
17+
18+
{hasMoreItems && (
19+
<Link
20+
href="#"
21+
onClick={toggleExpanded}
22+
sx={{ ml: 0.5, fontSize: "0.8rem", whiteSpace: "nowrap" }}
23+
>
24+
{expanded ? "Show less" : `+${childArray.length - maxItems} more`}
25+
</Link>
26+
)}
27+
</Box>
28+
);
29+
};

0 commit comments

Comments
 (0)