Skip to content

Commit f922f0b

Browse files
committed
show multiple changelogs in recently updated modal
1 parent 3e361cb commit f922f0b

File tree

3 files changed

+238
-104
lines changed

3 files changed

+238
-104
lines changed

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

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -565,39 +565,7 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
565565
setDisableMenuAnchor(null);
566566

567567
try {
568-
// Immediately update UI state for better responsiveness
569-
setIsBlocking(false);
570-
571-
// For timed disables, immediately set up the timer view
572-
if (seconds !== null) {
573-
const endTime = new Date();
574-
endTime.setSeconds(endTime.getSeconds() + seconds);
575-
setDisableEndTime(endTime);
576-
577-
// Calculate and set remaining time immediately
578-
const diffSec = seconds;
579-
const minutes = Math.floor(diffSec / 60);
580-
const secs = diffSec % 60;
581-
setRemainingTime(`${minutes}:${secs.toString().padStart(2, '0')}`);
582-
583-
// Update stats with timer
584-
setStats(prevStats => ({
585-
...prevStats,
586-
status: 'disabled',
587-
timer: seconds
588-
}));
589-
} else {
590-
// For indefinite disables, clear timer
591-
setDisableEndTime(null);
592-
setRemainingTime('');
593-
594-
// Update stats for indefinite disable
595-
setStats(prevStats => ({
596-
...prevStats,
597-
status: 'disabled',
598-
timer: null
599-
}));
600-
}
568+
// Don't update UI state here - wait for API call to complete
601569

602570
// Call the backend API to disable blocking
603571
const result = await DashApi.disablePihole(
@@ -612,13 +580,47 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
612580
);
613581

614582
if (result) {
583+
// Only update UI after successful API call
584+
setIsBlocking(false);
585+
586+
// For timed disables, set up the timer view
587+
if (seconds !== null) {
588+
const endTime = new Date();
589+
endTime.setSeconds(endTime.getSeconds() + seconds);
590+
setDisableEndTime(endTime);
591+
592+
// Calculate and set remaining time immediately
593+
const diffSec = seconds;
594+
const minutes = Math.floor(diffSec / 60);
595+
const secs = diffSec % 60;
596+
setRemainingTime(`${minutes}:${secs.toString().padStart(2, '0')}`);
597+
598+
// Update stats with timer
599+
setStats(prevStats => ({
600+
...prevStats,
601+
status: 'disabled',
602+
timer: seconds
603+
}));
604+
} else {
605+
// For indefinite disables, clear timer
606+
setDisableEndTime(null);
607+
setRemainingTime('');
608+
609+
// Update stats for indefinite disable
610+
setStats(prevStats => ({
611+
...prevStats,
612+
status: 'disabled',
613+
timer: null
614+
}));
615+
}
616+
615617
// For Pi-hole v6, trigger an immediate status check
616618
if (isPiholeV6) {
617619
checkPiholeStatus();
618620
} else {
619621
// For Pi-hole v5, handle the local timer
620622
if (seconds !== null) {
621-
// Clear any existing timer
623+
// Clear any existing timer
622624
if (disableTimer) {
623625
clearTimeout(disableTimer);
624626
}
@@ -643,7 +645,7 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
643645
throw new Error('Failed to disable Pi-hole blocking');
644646
}
645647
} catch (err: any) {
646-
// On error, revert UI state
648+
// Error handling remains the same
647649
setIsBlocking(true);
648650
setDisableEndTime(null);
649651
setRemainingTime('');
@@ -672,11 +674,14 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
672674

673675
// Handle enable blocking
674676
const handleEnableBlocking = useCallback(async () => {
677+
if (isDisablingBlocking) return; // Prevent action if we're already handling a state change
678+
679+
setIsDisablingBlocking(true); // Use the same lock for enable operations
680+
675681
try {
676682
setIsLoading(true);
677-
// Optimistically update UI
678-
setIsBlocking(true);
679683

684+
// Call API first, don't update UI state optimistically
680685
await DashApi.enablePihole({
681686
host: piholeConfig.host,
682687
port: piholeConfig.port,
@@ -685,6 +690,17 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
685690
password: piholeConfig.password
686691
});
687692

693+
// Only update UI after successful API call
694+
setIsBlocking(true);
695+
setDisableEndTime(null);
696+
setRemainingTime('');
697+
698+
// Clear any disable timer
699+
if (disableTimer) {
700+
clearTimeout(disableTimer);
701+
setDisableTimer(null);
702+
}
703+
688704
setIsLoading(false);
689705
// Fetch updated stats after enabling
690706
await checkPiholeStatus();
@@ -710,8 +726,10 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
710726
// Generic error
711727
setError(err.message || 'Failed to enable Pi-hole blocking');
712728
}
729+
} finally {
730+
setIsDisablingBlocking(false);
713731
}
714-
}, [piholeConfig, checkPiholeStatus]);
732+
}, [piholeConfig, checkPiholeStatus, disableTimer, isDisablingBlocking]);
715733

716734
// Clean up disable timer on unmount
717735
useEffect(() => {
@@ -995,6 +1013,7 @@ export const PiholeWidget = (props: { config?: PiholeWidgetConfig }) => {
9951013
height: 25,
9961014
fontSize: '0.7rem',
9971015
color: 'white',
1016+
minWidth: '80px', // Add fixed minimum width to prevent size changes
9981017
'&:hover': {
9991018
backgroundColor: 'rgba(255, 255, 255, 0.1)'
10001019
},

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,30 +213,32 @@ export const SystemMonitorWidget = ({ config }: SystemMonitorWidgetProps) => {
213213
width: '100%',
214214
height: '70%', // Use most of the gauge height
215215
pt: 0.5,
216-
ml: -5.75
216+
ml: -4.75
217217
}}>
218218
{/* Container for both rows with fixed width icon column */}
219219
<Box sx={{
220220
display: 'grid',
221-
gridTemplateColumns: '16px 1fr',
221+
gridTemplateColumns: '24px minmax(40px, 1fr)', // Fixed width for icon column and minimum width for text
222222
width: '80%', // Increased width for more text space
223-
gap: 0.25,
223+
gap: 0.2,
224224
alignItems: 'center'
225225
}}>
226226
{/* Upload row */}
227227
<Box sx={{
228228
display: 'flex',
229229
justifyContent: 'center',
230230
alignItems: 'center',
231-
height: '100%'
231+
height: '100%',
232+
width: '24px', // Fixed width
232233
}}>
233234
<ArrowUpward sx={{ color: 'text.primary', fontSize: { xs: 13, sm: 14, md: 17, lg: 17, xl: 18 } }} />
234235
</Box>
235236
<Box sx={{
236237
display: 'flex',
237238
justifyContent: 'flex-start',
238239
alignItems: 'center',
239-
width: '100%'
240+
width: '100%',
241+
minWidth: '40px' // Minimum width to prevent resizing
240242
}}>
241243
<Typography
242244
fontWeight='medium'
@@ -246,7 +248,7 @@ export const SystemMonitorWidget = ({ config }: SystemMonitorWidgetProps) => {
246248
lineHeight: 1.2,
247249
whiteSpace: 'nowrap',
248250
display: 'block',
249-
ml: { lg: 0.4 }
251+
250252
}}
251253
>
252254
{formatNumberForDisplay(uploadSpeed.value)} {uploadSpeed.unit.replace('/s', '')}
@@ -258,15 +260,17 @@ export const SystemMonitorWidget = ({ config }: SystemMonitorWidgetProps) => {
258260
display: 'flex',
259261
justifyContent: 'center',
260262
alignItems: 'center',
261-
height: '100%'
263+
height: '100%',
264+
width: '24px', // Fixed width
262265
}}>
263266
<ArrowDownward sx={{ color: 'text.primary', fontSize: { xs: 13, sm: 14, md: 17, lg: 17, xl: 18 } }} />
264267
</Box>
265268
<Box sx={{
266269
display: 'flex',
267270
justifyContent: 'flex-start',
268271
alignItems: 'center',
269-
width: '100%'
272+
width: '100%',
273+
minWidth: '40px' // Minimum width to prevent resizing
270274
}}>
271275
<Typography
272276
fontWeight='medium'
@@ -276,7 +280,6 @@ export const SystemMonitorWidget = ({ config }: SystemMonitorWidgetProps) => {
276280
lineHeight: 1.2,
277281
whiteSpace: 'nowrap',
278282
display: 'block',
279-
ml: { lg: 0.4 }
280283
}}
281284
>
282285
{formatNumberForDisplay(downloadSpeed.value)} {downloadSpeed.unit.replace('/s', '')}

0 commit comments

Comments
 (0)