Skip to content

Commit 1cbf074

Browse files
committed
add disk monitor widget
1 parent a937c80 commit 1cbf074

File tree

5 files changed

+202
-97
lines changed

5 files changed

+202
-97
lines changed

frontend/src/components/dashboard/base-items/widgets/DiskMonitorWidget.tsx

Lines changed: 88 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ interface DiskMonitorWidgetProps {
2828
selectedDisks?: DiskSelection[];
2929
showIcons?: boolean;
3030
showMountPath?: boolean;
31+
showName?: boolean;
3132
layout?: '2x2' | '2x4' | '1x5';
3233
dualWidgetPosition?: 'top' | 'bottom';
3334
};
@@ -43,6 +44,7 @@ export const DiskMonitorWidget = ({ config, editMode }: DiskMonitorWidgetProps)
4344
// Get config options with defaults
4445
const selectedDisks = config?.selectedDisks || [];
4546
const showIcons = config?.showIcons !== false;
47+
const showName = config?.showName !== false;
4648
const isDualWidget = config?.dualWidgetPosition !== undefined;
4749
// Force 2x2 layout for dual widgets to maintain standard widget height
4850
const layout = isDualWidget ? '2x2' : (config?.layout || '2x2');
@@ -311,25 +313,55 @@ export const DiskMonitorWidget = ({ config, editMode }: DiskMonitorWidgetProps)
311313
padding: '0 !important', // Remove all default padding
312314
maxWidth: '100%',
313315
width: '100%',
316+
display: 'flex',
317+
flexDirection: 'column',
314318
...(layout === '2x4' || layout === '1x5' ? {
315319
minHeight: DUAL_WIDGET_CONTAINER_HEIGHT.sm
316320
} : {})
317321
}}>
318322
<Box sx={{
319-
display: 'flex',
320-
flexDirection: 'column',
321-
height: '100%',
323+
flex: 1,
322324
color: 'white',
323325
width: '100%',
324-
padding: 2
326+
padding: 2,
327+
display: 'flex',
328+
alignItems: 'center',
329+
justifyContent: 'center',
330+
position: 'relative'
325331
}}>
332+
333+
{/* Conditionally rendered title */}
334+
{showName && (
335+
<Box
336+
sx={{
337+
position: 'absolute',
338+
top: layout === '2x2' ? 0 : 2.5,
339+
left: 16,
340+
color: 'white',
341+
fontSize: '1.1rem',
342+
zIndex: 1,
343+
display: 'flex',
344+
alignItems: 'center',
345+
gap: 0.5
346+
}}
347+
>
348+
<PiHardDrivesFill size={18} color='white' />
349+
<Typography
350+
variant='h6'
351+
sx={{
352+
color: 'white',
353+
fontSize: '1.1rem',
354+
}}
355+
>
356+
Disk Monitor
357+
</Typography>
358+
</Box>
359+
)}
326360
{error ? (
327361
<Box sx={{
328362
display: 'flex',
329-
justifyContent: 'center',
330-
alignItems: 'center',
331363
flexDirection: 'column',
332-
flex: 1
364+
alignItems: 'center'
333365
}}>
334366
<Typography variant='body2' sx={{ textAlign: 'center', mb: 1 }}>
335367
Configuration Error
@@ -338,77 +370,61 @@ export const DiskMonitorWidget = ({ config, editMode }: DiskMonitorWidgetProps)
338370
{error}
339371
</Typography>
340372
</Box>
373+
) : (gridDisks.length === 0 || isLoading) ? (
374+
<Box sx={{
375+
color: 'rgba(255,255,255,0.5)',
376+
fontSize: '0.85rem'
377+
}}>
378+
{isLoading ? 'Loading disks...' : 'No disks configured'}
379+
</Box>
341380
) : (
342-
<>
343-
{/* Empty/Loading state - only show when no disks or loading */}
344-
{(gridDisks.length === 0 || isLoading) && (
345-
<Box sx={{
346-
display: 'flex',
347-
justifyContent: 'center',
348-
alignItems: 'center',
349-
color: 'rgba(255,255,255,0.5)',
350-
fontSize: '0.85rem',
351-
flex: 1
352-
}}>
353-
{isLoading ? 'Loading disks...' : 'No disks configured'}
354-
</Box>
355-
)}
356-
357-
{/* Disk items in grid - only show when not loading and has disks */}
358-
{!isLoading && gridDisks.length > 0 && (
359-
<Box sx={{
360-
display: 'flex',
361-
alignItems: 'center',
362-
justifyContent: 'center',
363-
flex: 1,
364-
width: '100%'
365-
}}>
366-
<Box sx={{
367-
width: '100%',
368-
maxWidth: '100%'
369-
}}>
370-
<Grid container spacing={layout === '2x2' ? 0.75 : layout === '2x4' ? 1 : 1.25} sx={{
371-
height: 'fit-content',
372-
width: '100%'
373-
}}>
374-
{gridDisks.map((disk, index) => {
375-
const getGridSize = () => {
376-
switch (layout) {
377-
case '2x2': return 6; // 2 columns
378-
case '2x4': return 6; // 2 columns
379-
case '1x5': return 12; // 1 column
380-
default: return 6;
381-
}
382-
};
381+
<Box sx={{
382+
width: '100%',
383+
height: layout === '2x4' || layout === '1x5' ? '100%' : 'auto',
384+
display: 'flex',
385+
alignItems: 'center',
386+
justifyContent: 'center',
387+
mt: 3
388+
}}>
389+
<Grid container spacing={layout === '2x2' ? 0.75 : 1} sx={{
390+
width: '100%',
391+
maxWidth: '100%'
392+
}}>
393+
{gridDisks.map((disk, index) => {
394+
const getGridSize = () => {
395+
switch (layout) {
396+
case '2x2': return 6; // 2 columns
397+
case '2x4': return 6; // 2 columns
398+
case '1x5': return 12; // 1 column
399+
default: return 6;
400+
}
401+
};
383402

384-
// Determine alignment based on position
385-
const getAlignment = () => {
386-
if (layout === '1x5') return 'flex-start'; // All left aligned for single column
403+
// Determine alignment based on position
404+
const getAlignment = () => {
405+
if (layout === '1x5') return 'flex-start'; // All left aligned for single column
387406

388-
// For 2-column layouts (2x2, 2x4)
389-
const isLeftColumn = index % 2 === 0;
390-
return isLeftColumn ? 'flex-start' : 'flex-end';
391-
};
407+
// For 2-column layouts (2x2, 2x4)
408+
const isLeftColumn = index % 2 === 0;
409+
return isLeftColumn ? 'flex-start' : 'flex-end';
410+
};
392411

393-
// Find the disk configuration
394-
const diskConfig = selectedDisks.find(d => d.mount === disk.mount) || { mount: disk.mount, customName: disk.customName };
412+
// Find the disk configuration
413+
const diskConfig = selectedDisks.find(d => d.mount === disk.mount) || { mount: disk.mount, customName: disk.customName };
395414

396-
return (
397-
<Grid key={disk.mount} size={getGridSize()} sx={{
398-
display: 'flex',
399-
justifyContent: getAlignment(),
400-
alignItems: 'stretch',
401-
minHeight: layout === '2x2' ? '60px' : layout === '1x5' ? '55px' : '70px'
402-
}}>
403-
<DiskItem disk={disk} diskConfig={diskConfig} />
404-
</Grid>
405-
);
406-
})}
415+
return (
416+
<Grid key={disk.mount} size={getGridSize()} sx={{
417+
display: 'flex',
418+
justifyContent: getAlignment(),
419+
alignItems: 'stretch',
420+
// minHeight: layout === '2x2' ? '60px' : layout === '1x5' ? '100%' : '100%'
421+
}}>
422+
<DiskItem disk={disk} diskConfig={diskConfig} />
407423
</Grid>
408-
</Box>
409-
</Box>
410-
)}
411-
</>
424+
);
425+
})}
426+
</Grid>
427+
</Box>
412428
)}
413429
</Box>
414430
</CardContent>

frontend/src/components/dashboard/base-items/widgets/DualWidget.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React from 'react';
33

44
import { AdGuardWidget } from './AdGuardWidget/AdGuardWidget';
55
import { DateTimeWidget } from './DateTimeWidget';
6+
import { DiskMonitorWidget } from './DiskMonitorWidget';
67
import { DualWidgetContainer } from './DualWidgetContainer';
78
import { PiholeWidget } from './PiholeWidget/PiholeWidget';
89
import { SystemMonitorWidget } from './SystemMonitorWidget/SystemMonitorWidget';
@@ -85,6 +86,14 @@ export const DualWidget: React.FC<DualWidgetProps> = ({
8586
config={widgetConfig.config}
8687
id={id ? `${id}-${position}` : undefined}
8788
/>;
89+
case ITEM_TYPE.DISK_MONITOR_WIDGET:
90+
return <DiskMonitorWidget
91+
config={{
92+
...widgetConfig.config,
93+
dualWidgetPosition: position
94+
}}
95+
editMode={editMode}
96+
/>;
8897
default:
8998
return (
9099
<Box
@@ -95,7 +104,7 @@ export const DualWidget: React.FC<DualWidgetProps> = ({
95104
justifyContent: 'center'
96105
}}
97106
>
98-
<Typography variant='body2' color='text.secondary'>
107+
<Typography variant='body2' color='text.primary'>
99108
Unknown widget type: {widgetConfig.type}
100109
</Typography>
101110
</Box>

frontend/src/components/forms/AddEditForm.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export type FormValues = {
6767
selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
6868
showIcons?: boolean;
6969
showMountPath?: boolean;
70+
showName?: boolean;
7071
layout?: '2x2' | '2x4' | '1x6';
7172
// DateTime widget
7273
timezone?: string;
@@ -144,6 +145,7 @@ export type FormValues = {
144145
top_selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
145146
top_showIcons?: boolean;
146147
top_showMountPath?: boolean;
148+
top_showName?: boolean;
147149
top_layout?: '2x2' | '2x4' | '1x6';
148150
top_piholeHost?: string;
149151
top_piholePort?: string;
@@ -172,6 +174,7 @@ export type FormValues = {
172174
bottom_selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
173175
bottom_showIcons?: boolean;
174176
bottom_showMountPath?: boolean;
177+
bottom_showName?: boolean;
175178
bottom_layout?: '2x2' | '2x4' | '1x6';
176179
bottom_piholeHost?: string;
177180
bottom_piholePort?: string;
@@ -1012,6 +1015,7 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
10121015
selectedDisks: data.top_selectedDisks,
10131016
showIcons: data.top_showIcons,
10141017
showMountPath: data.top_showMountPath,
1018+
showName: data.top_showName,
10151019
piholeHost: data.top_piholeHost,
10161020
piholePort: data.top_piholePort,
10171021
piholeSsl: data.top_piholeSsl,
@@ -1043,6 +1047,7 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
10431047
selectedDisks: data.bottom_selectedDisks,
10441048
showIcons: data.bottom_showIcons,
10451049
showMountPath: data.bottom_showMountPath,
1050+
showName: data.bottom_showName,
10461051
piholeHost: data.bottom_piholeHost,
10471052
piholePort: data.bottom_piholePort,
10481053
piholeSsl: data.bottom_piholeSsl,
@@ -1251,11 +1256,19 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
12511256
selectedDisks: data.selectedDisks,
12521257
showIcons: data.showIcons,
12531258
showMountPath: data.showMountPath,
1259+
showName: data.showName,
12541260
layout: data.layout
12551261
});
1262+
1263+
// Validate that at least one disk is selected
1264+
if (!data.selectedDisks || !Array.isArray(data.selectedDisks) || data.selectedDisks.length === 0) {
1265+
throw new Error('At least one disk must be selected for the Disk Monitor widget');
1266+
}
1267+
12561268
return {
12571269
selectedDisks: data.selectedDisks || [],
12581270
showIcons: data.showIcons !== false,
1271+
showName: data.showName !== false,
12591272
layout: data.layout || '2x2'
12601273
};
12611274
} else if (widgetType === ITEM_TYPE.PIHOLE_WIDGET) {

0 commit comments

Comments
 (0)