Skip to content

Commit 6fc297d

Browse files
authored
Merge pull request #58 from KelvinTegelaar/main
[pull] main from KelvinTegelaar:main
2 parents 43eb765 + a1b6204 commit 6fc297d

24 files changed

Lines changed: 914 additions & 162 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cipp",
3-
"version": "10.8.4",
3+
"version": "10.8.5",
44
"author": "CIPP Contributors",
55
"homepage": "https://cipp.app/",
66
"bugs": {

public/version.json

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

src/components/CippAllTenants/AllTenantsDashboard.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { useAllTenantsDashboard } from './useAllTenantsDashboard'
1414
import {
1515
AllTenantsBandHeading,
1616
AllTenantsBarList,
17+
AllTenantsCacheList,
1718
AllTenantsMeterList,
1819
AllTenantsRowList,
1920
AllTenantsTrendChart,
@@ -578,7 +579,7 @@ export const AllTenantsDashboard = () => {
578579
</Stack>
579580
</Grid>
580581
<Grid size={{ xs: 12, md: 8 }}>
581-
<AllTenantsRowList
582+
<AllTenantsCacheList
582583
rows={cache.staleTenants}
583584
isFetching={countsApi.isLoading || tenants.isLoading}
584585
emptyText="Every tenant was cached within the last 30 hours."

src/components/CippAllTenants/AllTenantsPrimitives.jsx

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import {
22
Box,
3+
ButtonBase,
34
Card,
45
Chip,
6+
Collapse,
57
LinearProgress,
68
Skeleton,
79
Stack,
810
Tooltip,
911
Typography,
1012
} from '@mui/material'
13+
import { ExpandMore } from '@mui/icons-material'
1114
import { useTheme } from '@mui/material/styles'
1215
import Link from 'next/link'
16+
import { useState } from 'react'
17+
import { parseCippDate } from '../../utils/parse-cipp-date'
1318
import {
1419
Area,
1520
AreaChart,
@@ -246,6 +251,162 @@ export const AllTenantsRowList = ({ rows = [], isFetching, emptyText = 'Nothing
246251
)
247252
}
248253

254+
// Same 72-hour boundary the summary line uses, so a row reading "Oldest collection 60 hours old"
255+
// never expands to a collection labelled "3 days ago".
256+
const formatAge = (hours) => {
257+
if (hours >= 72) return `${Math.round(hours / 24)} days ago`
258+
if (hours >= 1) return `${Math.round(hours)} hours ago`
259+
return 'under an hour ago'
260+
}
261+
262+
/**
263+
* The cache freshness worklist: one row per tenant that is behind, expandable to the collections
264+
* holding it back and when each last ran.
265+
*
266+
* Scrolls rather than truncating. When a whole collection group fails estate-wide the affected
267+
* tenants number in the dozens, and the previous five-row cut said "stale" without ever saying which
268+
* collection or how stale — which is the only part you can act on.
269+
*/
270+
export const AllTenantsCacheList = ({
271+
rows = [],
272+
isFetching,
273+
emptyText = 'Nothing to report',
274+
maxHeight = 296,
275+
}) => {
276+
const [expanded, setExpanded] = useState(null)
277+
278+
if (isFetching) {
279+
return (
280+
<Stack spacing={0.5}>
281+
{[0, 1, 2].map((key) => (
282+
<Skeleton key={key} variant="rounded" height={48} />
283+
))}
284+
</Stack>
285+
)
286+
}
287+
288+
if (!rows.length) {
289+
return (
290+
<Typography variant="body2" color="text.secondary" sx={{ py: 2, textAlign: 'center' }}>
291+
{emptyText}
292+
</Typography>
293+
)
294+
}
295+
296+
return (
297+
<Stack spacing={0.5} sx={{ maxHeight, overflowY: 'auto', pr: 0.5 }}>
298+
{rows.map((row, index) => {
299+
const key = row.domain ?? `${row.name}-${index}`
300+
const isOpen = expanded === key
301+
const collections = row.collections ?? []
302+
const canExpand = collections.length > 0
303+
304+
const header = (
305+
<Stack
306+
direction="row"
307+
alignItems="center"
308+
spacing={1.5}
309+
sx={{ px: 1.25, py: 1.25, width: '100%' }}
310+
>
311+
<Box sx={{ flex: 1, minWidth: 0, textAlign: 'left' }}>
312+
<Typography variant="subtitle2" component="div" noWrap title={row.name}>
313+
{row.name}
314+
</Typography>
315+
{row.detail && (
316+
<Typography
317+
variant="caption"
318+
component="div"
319+
color="text.secondary"
320+
noWrap
321+
title={row.detail}
322+
>
323+
{row.detail}
324+
</Typography>
325+
)}
326+
</Box>
327+
{canExpand && (
328+
<>
329+
<Chip
330+
size="small"
331+
variant="outlined"
332+
color={CHIP_COLOR[row.severity] ?? 'default'}
333+
label={`${collections.length} stale`}
334+
sx={{ flexShrink: 0 }}
335+
/>
336+
<ExpandMore
337+
fontSize="small"
338+
sx={{
339+
flexShrink: 0,
340+
color: 'text.secondary',
341+
transform: isOpen ? 'rotate(180deg)' : 'none',
342+
transition: 'transform 150ms',
343+
}}
344+
/>
345+
</>
346+
)}
347+
</Stack>
348+
)
349+
350+
return (
351+
<Box
352+
key={key}
353+
sx={{
354+
borderRadius: 1,
355+
borderLeft: 3,
356+
borderLeftColor: severityColor(row.severity),
357+
backgroundColor: 'action.hover',
358+
}}
359+
>
360+
{canExpand ? (
361+
<ButtonBase
362+
onClick={() => setExpanded(isOpen ? null : key)}
363+
aria-expanded={isOpen}
364+
sx={{ width: '100%', display: 'block', borderRadius: 1 }}
365+
>
366+
{header}
367+
</ButtonBase>
368+
) : (
369+
header
370+
)}
371+
<Collapse in={isOpen} unmountOnExit>
372+
<Stack spacing={0.25} sx={{ px: 1.25, pb: 1.25 }}>
373+
{collections.map((collection) => (
374+
<Stack
375+
key={collection.type}
376+
direction="row"
377+
alignItems="baseline"
378+
spacing={1}
379+
sx={{ justifyContent: 'space-between' }}
380+
>
381+
<Typography
382+
variant="caption"
383+
component="div"
384+
noWrap
385+
title={collection.type}
386+
sx={{ minWidth: 0 }}
387+
>
388+
{collection.type}
389+
</Typography>
390+
<Typography
391+
variant="caption"
392+
component="div"
393+
color="text.secondary"
394+
sx={{ flexShrink: 0, fontVariantNumeric: 'tabular-nums' }}
395+
>
396+
{parseCippDate(collection.lastRefresh).toLocaleString()} ·{' '}
397+
{formatAge(collection.ageHours)}
398+
</Typography>
399+
</Stack>
400+
))}
401+
</Stack>
402+
</Collapse>
403+
</Box>
404+
)
405+
})}
406+
</Stack>
407+
)
408+
}
409+
249410
/** Labelled percentage meters, for pass-rate style measures. */
250411
export const AllTenantsMeterList = ({ meters = [], isFetching }) => {
251412
if (isFetching) {

0 commit comments

Comments
 (0)