Skip to content
This repository was archived by the owner on Jan 12, 2026. It is now read-only.

Commit 152691f

Browse files
authored
Merge branch 'KelvinTegelaar:main' into main
2 parents 23bdca3 + e7714a5 commit 152691f

File tree

190 files changed

+13265
-2640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+13265
-2640
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ app.log
3131

3232
# AI rules
3333
.*/rules
34+
AGENTS.md

.vscode/tasks.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
"type": "shell",
1111
"command": "azurite --location ../",
1212
"isBackground": true,
13+
"options": {
14+
"env": {
15+
"LC_ALL": "en-US.UTF-8",
16+
"LANG": "en-US"
17+
}
18+
},
1319
"problemMatcher": {
1420
"pattern": [
1521
{

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"Reshare",
3131
"Rewst",
3232
"Sherweb",
33+
"superadmin",
3334
"Syncro",
3435
"TERRL",
3536
"unconfigured",

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cipp",
3-
"version": "8.4.2",
3+
"version": "8.5.2",
44
"author": "CIPP Contributors",
55
"homepage": "https://cipp.app/",
66
"bugs": {
@@ -89,6 +89,8 @@
8989
"react-leaflet": "5.0.0",
9090
"react-leaflet-markercluster": "^5.0.0-rc.0",
9191
"react-markdown": "10.1.0",
92+
"rehype-raw": "^7.0.0",
93+
"remark-gfm": "^3.0.1",
9294
"react-media-hook": "^0.5.0",
9395
"react-papaparse": "^4.4.0",
9496
"react-quill": "^2.0.0",

public/permissionsList.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7969,5 +7969,25 @@
79697969
"userConsentDescription": "Allows the app to manage workforce integrations, to synchronize data from Microsoft Teams Shifts, on your behalf.",
79707970
"userConsentDisplayName": "Read and write workforce integrations",
79717971
"value": "WorkforceIntegration.ReadWrite.All"
7972+
},
7973+
{
7974+
"description": "Read and Modify Tenant-Acquired Telephone Number Details",
7975+
"displayName": "Read and Modify Tenant-Acquired Telephone Number Details",
7976+
"id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
7977+
"isEnabled": true,
7978+
"Origin": "Delegated",
7979+
"userConsentDescription": "Allows the app to read and modify your tenant's acquired telephone number details on behalf of the signed-in admin user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
7980+
"userConsentDisplayName": "Allows the app to read and modify your tenant's acquired telephone number details on behalf of the signed-in admin user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
7981+
"value": "TeamsTelephoneNumber.ReadWrite.All"
7982+
},
7983+
{
7984+
"description": "Read and Modify Tenant-Acquired Telephone Number Details",
7985+
"displayName": "Read and Modify Tenant-Acquired Telephone Number Details",
7986+
"id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
7987+
"isEnabled": true,
7988+
"Origin": "Application",
7989+
"userConsentDescription": "Allows the app to read your tenant's acquired telephone number details, without a signed-in user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
7990+
"userConsentDisplayName": "Allows the app to read your tenant's acquired telephone number details, without a signed-in user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
7991+
"value": "TeamsTelephoneNumber.ReadWrite.All"
79727992
}
79737993
]

public/version.json

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

src/api/ApiCall.jsx

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export function ApiGetCall(props) {
2121
refetchOnReconnect = true,
2222
keepPreviousData = false,
2323
refetchInterval = false,
24+
responseType = "json",
25+
convertToDataUrl = false,
2426
} = props;
2527
const queryClient = useQueryClient();
2628
const dispatch = useDispatch();
@@ -76,7 +78,25 @@ export function ApiGetCall(props) {
7678
if (relatedQueryKeys) {
7779
const clearKeys = Array.isArray(relatedQueryKeys) ? relatedQueryKeys : [relatedQueryKeys];
7880
setTimeout(() => {
79-
clearKeys.forEach((key) => {
81+
// Separate wildcard patterns from exact keys
82+
const wildcardPatterns = clearKeys
83+
.filter((key) => key.endsWith("*"))
84+
.map((key) => key.slice(0, -1));
85+
const exactKeys = clearKeys.filter((key) => !key.endsWith("*"));
86+
87+
// Use single predicate call for all wildcard patterns
88+
if (wildcardPatterns.length > 0) {
89+
queryClient.invalidateQueries({
90+
predicate: (query) => {
91+
if (!query.queryKey || !query.queryKey[0]) return false;
92+
const queryKeyStr = String(query.queryKey[0]);
93+
return wildcardPatterns.some((pattern) => queryKeyStr.startsWith(pattern));
94+
},
95+
});
96+
}
97+
98+
// Handle exact keys
99+
exactKeys.forEach((key) => {
80100
queryClient.invalidateQueries({ queryKey: [key] });
81101
});
82102
}, 1000);
@@ -89,19 +109,50 @@ export function ApiGetCall(props) {
89109
headers: {
90110
"Content-Type": "application/json",
91111
},
112+
responseType: responseType,
92113
});
114+
115+
let responseData = response.data;
116+
117+
// Convert blob to data URL if requested
118+
if (convertToDataUrl && responseType === "blob" && response.data) {
119+
responseData = await new Promise((resolve) => {
120+
const reader = new FileReader();
121+
reader.onloadend = () => resolve(reader.result);
122+
reader.readAsDataURL(response.data);
123+
});
124+
}
125+
93126
if (onResult) {
94-
onResult(response.data); // Emit each result as it arrives
127+
onResult(responseData); // Emit each result as it arrives
95128
}
96129
if (relatedQueryKeys) {
97130
const clearKeys = Array.isArray(relatedQueryKeys) ? relatedQueryKeys : [relatedQueryKeys];
98131
setTimeout(() => {
99-
clearKeys.forEach((key) => {
132+
// Separate wildcard patterns from exact keys
133+
const wildcardPatterns = clearKeys
134+
.filter((key) => key.endsWith("*"))
135+
.map((key) => key.slice(0, -1));
136+
const exactKeys = clearKeys.filter((key) => !key.endsWith("*"));
137+
138+
// Use single predicate call for all wildcard patterns
139+
if (wildcardPatterns.length > 0) {
140+
queryClient.invalidateQueries({
141+
predicate: (query) => {
142+
if (!query.queryKey || !query.queryKey[0]) return false;
143+
const queryKeyStr = String(query.queryKey[0]);
144+
return wildcardPatterns.some((pattern) => queryKeyStr.startsWith(pattern));
145+
},
146+
});
147+
}
148+
149+
// Handle exact keys
150+
exactKeys.forEach((key) => {
100151
queryClient.invalidateQueries({ queryKey: [key] });
101152
});
102153
}, 1000);
103154
}
104-
return response.data;
155+
return responseData;
105156
}
106157
},
107158
staleTime: staleTime,
@@ -117,6 +168,7 @@ export function ApiGetCall(props) {
117168

118169
export function ApiPostCall({ relatedQueryKeys, onResult }) {
119170
const queryClient = useQueryClient();
171+
120172
const mutation = useMutation({
121173
mutationFn: async (props) => {
122174
const { url, data, bulkRequest } = props;
@@ -144,9 +196,43 @@ export function ApiPostCall({ relatedQueryKeys, onResult }) {
144196
const clearKeys = Array.isArray(relatedQueryKeys) ? relatedQueryKeys : [relatedQueryKeys];
145197
setTimeout(() => {
146198
if (relatedQueryKeys === "*") {
199+
console.log("Invalidating all queries");
147200
queryClient.invalidateQueries();
148201
} else {
149-
clearKeys.forEach((key) => {
202+
// Separate wildcard patterns from exact keys
203+
const wildcardPatterns = clearKeys
204+
.filter((key) => key.endsWith("*"))
205+
.map((key) => key.slice(0, -1));
206+
const exactKeys = clearKeys.filter((key) => !key.endsWith("*"));
207+
208+
// Use single predicate call for all wildcard patterns
209+
if (wildcardPatterns.length > 0) {
210+
queryClient.invalidateQueries({
211+
predicate: (query) => {
212+
if (!query.queryKey || !query.queryKey[0]) return false;
213+
const queryKeyStr = String(query.queryKey[0]);
214+
const matches = wildcardPatterns.some((pattern) =>
215+
queryKeyStr.startsWith(pattern)
216+
);
217+
218+
// Debug logging for each query check
219+
if (matches) {
220+
console.log("Invalidating query:", {
221+
queryKey: query.queryKey,
222+
queryKeyStr,
223+
matchedPattern: wildcardPatterns.find((pattern) =>
224+
queryKeyStr.startsWith(pattern)
225+
),
226+
});
227+
}
228+
229+
return matches;
230+
},
231+
});
232+
}
233+
234+
// Handle exact keys
235+
exactKeys.forEach((key) => {
150236
queryClient.invalidateQueries({ queryKey: [key] });
151237
});
152238
}

src/components/CippCards/CippChartCard.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,15 @@ export const CippChartCard = ({
9393
title,
9494
actions,
9595
onClick,
96+
totalLabel = "Total",
97+
customTotal,
9698
}) => {
9799
const [range, setRange] = useState("Last 7 days");
98100
const [barSeries, setBarSeries] = useState([]);
99101
const chartOptions = useChartOptions(labels, chartType);
100102
chartSeries = chartSeries.filter((item) => item !== null);
101-
const total = chartSeries.reduce((acc, value) => acc + value, 0);
103+
const calculatedTotal = chartSeries.reduce((acc, value) => acc + value, 0);
104+
const total = customTotal !== undefined ? customTotal : calculatedTotal;
102105
useEffect(() => {
103106
if (chartType === "bar") {
104107
setBarSeries(
@@ -160,7 +163,7 @@ export const CippChartCard = ({
160163
>
161164
{labels.length > 0 && (
162165
<>
163-
<Typography variant="h5">Total</Typography>
166+
<Typography variant="h5">{totalLabel}</Typography>
164167
<Typography variant="h5">{isFetching ? "0" : total}</Typography>
165168
</>
166169
)}

0 commit comments

Comments
 (0)