Skip to content

Commit b73d1b6

Browse files
committed
allow showing public ip in internet connectivity tooltip
1 parent ce158e7 commit b73d1b6

File tree

12 files changed

+163
-14
lines changed

12 files changed

+163
-14
lines changed

backend/src/routes/health.route.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ healthRoute.get('/', async (req: Request, res: Response): Promise<void> => {
5050

5151
// For HTTP health checks (default)
5252
const response = await axios.get(url, {
53-
timeout: 5000,
53+
timeout: 10000, // Increased to 10 seconds to handle slower services
5454
httpsAgent,
5555
responseType: 'text',
5656
validateStatus: () => true // Accept any HTTP status code
@@ -65,3 +65,16 @@ healthRoute.get('/', async (req: Request, res: Response): Promise<void> => {
6565
res.json({ status: 'offline' });
6666
}
6767
});
68+
69+
// Endpoint to get public IP address
70+
healthRoute.get('/public-ip', async (req: Request, res: Response): Promise<void> => {
71+
try {
72+
const response = await axios.get('https://api.ipify.org?format=json', {
73+
timeout: 5000
74+
});
75+
res.json({ ip: response.data.ip });
76+
} catch (error) {
77+
console.error('Failed to fetch public IP:', error);
78+
res.status(500).json({ error: 'Failed to fetch public IP' });
79+
}
80+
});

backend/src/types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export type Config = {
3939
lastSeenVersion?: string;
4040
notes?: Note[];
4141
themeColor?: string;
42+
showInternetIndicator?: boolean;
43+
showPublicIP?: boolean;
4244
}
4345

4446
export type Note = {

frontend/src/api/dash-api.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,8 @@ export class DashApi {
589589
params: { url, type: healthCheckType },
590590
// Don't send credentials for health checks to avoid auth issues
591591
withCredentials: false,
592-
// Add timeout to prevent long-running requests
593-
timeout: 5000
592+
// Increased timeout to handle slower services
593+
timeout: 12000
594594
});
595595
return res.data.status;
596596
} catch (error) {
@@ -615,6 +615,19 @@ export class DashApi {
615615
}
616616
}
617617

618+
public static async getPublicIP(): Promise<string | null> {
619+
try {
620+
const res = await axios.get(`${BACKEND_URL}/api/health/public-ip`, {
621+
withCredentials: false,
622+
timeout: 5000
623+
});
624+
return res.data.ip;
625+
} catch (error) {
626+
console.error('Failed to fetch public IP:', error);
627+
return null;
628+
}
629+
}
630+
618631
public static async uploadBackgroundImage(file: File): Promise<UploadImageResponse | null> {
619632
try {
620633
const formData = new FormData();
@@ -2142,7 +2155,7 @@ export class DashApi {
21422155

21432156
public static async nzbgetResumeDownload(itemId: string, nzbId?: string): Promise<boolean> {
21442157
try {
2145-
const res = await axios.post(`${BACKEND_URL}/api/nzbget/resume`,
2158+
const res = await axios.post(`${BACKEND_URL}/api/nzbget/resume`,
21462159
{ nzbId }, // Send nzbId in request body
21472160
{
21482161
params: { itemId },
@@ -2158,7 +2171,7 @@ export class DashApi {
21582171

21592172
public static async nzbgetPauseDownload(itemId: string, nzbId?: string): Promise<boolean> {
21602173
try {
2161-
const res = await axios.post(`${BACKEND_URL}/api/nzbget/pause`,
2174+
const res = await axios.post(`${BACKEND_URL}/api/nzbget/pause`,
21622175
{ nzbId }, // Send nzbId in request body
21632176
{
21642177
params: { itemId },

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ interface SystemMonitorWidgetProps {
2626
showDiskUsage?: boolean;
2727
showSystemInfo?: boolean;
2828
showInternetStatus?: boolean;
29+
showPublicIP?: boolean;
2930
};
3031
editMode?: boolean;
3132
}
@@ -48,6 +49,7 @@ export const SystemMonitorWidget = ({ config, editMode }: SystemMonitorWidgetPro
4849
const [errorMessage, setErrorMessage] = useState<string | null>(null);
4950
const [isLoading, setIsLoading] = useState(false);
5051
const [internetTooltipOpen, setInternetTooltipOpen] = useState(false);
52+
const [publicIP, setPublicIP] = useState<string | null>(null);
5153

5254
const { internetStatus } = useInternetStatus();
5355

@@ -61,6 +63,7 @@ export const SystemMonitorWidget = ({ config, editMode }: SystemMonitorWidgetPro
6163
const showDiskUsage = config?.showDiskUsage !== false;
6264
const showSystemInfo = config?.showSystemInfo !== false;
6365
const showInternetStatus = config?.showInternetStatus !== false;
66+
const showPublicIP = config?.showPublicIP || false;
6467

6568
const isMobile = useIsMobile();
6669

@@ -438,6 +441,19 @@ export const SystemMonitorWidget = ({ config, editMode }: SystemMonitorWidgetPro
438441
};
439442
}, [internetTooltipOpen]);
440443

444+
// Fetch public IP when showPublicIP is enabled
445+
useEffect(() => {
446+
if (showPublicIP && internetStatus === 'online') {
447+
const fetchPublicIP = async () => {
448+
const ip = await DashApi.getPublicIP();
449+
setPublicIP(ip);
450+
};
451+
fetchPublicIP();
452+
} else {
453+
setPublicIP(null);
454+
}
455+
}, [showPublicIP, internetStatus]);
456+
441457
// Determine layout styles based on dual widget position
442458
const containerStyles = {
443459
width: '100%',
@@ -519,7 +535,18 @@ export const SystemMonitorWidget = ({ config, editMode }: SystemMonitorWidgetPro
519535
onClick={(e) => e.stopPropagation()}
520536
>
521537
<Tooltip
522-
title={internetStatus === 'online' ? 'Internet Connected' : internetStatus === 'offline' ? 'No Internet Connection' : 'Checking Internet...'}
538+
title={
539+
<Box>
540+
<Typography variant='body2'>
541+
{internetStatus === 'online' ? 'Internet Connected' : internetStatus === 'offline' ? 'No Internet Connection' : 'Checking Internet...'}
542+
</Typography>
543+
{showPublicIP && publicIP && internetStatus === 'online' && (
544+
<Typography variant='caption' sx={{ display: 'block', mt: 0.5 }}>
545+
IP: {publicIP}
546+
</Typography>
547+
)}
548+
</Box>
549+
}
523550
arrow
524551
placement='left'
525552
open={internetTooltipOpen}

frontend/src/components/forms/AddEditForm/AddEditForm.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
192192
gauges: [data.gauge1, data.gauge2, data.gauge3],
193193
showDiskUsage: data.showDiskUsage !== false, // Default to true
194194
showSystemInfo: data.showSystemInfo !== false, // Default to true
195-
showInternetStatus: data.showInternetStatus !== false // Default to true
195+
showInternetStatus: data.showInternetStatus !== false, // Default to true
196+
showPublicIP: data.showPublicIP || false
196197
};
197198

198199
// Add network interface to config if a network gauge is included
@@ -469,6 +470,7 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
469470
showDiskUsage: data.top_showDiskUsage,
470471
showSystemInfo: data.top_showSystemInfo,
471472
showInternetStatus: data.top_showInternetStatus,
473+
showPublicIP: data.top_showPublicIP,
472474
selectedDisks: data.top_selectedDisks,
473475
showIcons: data.top_showIcons,
474476
showMountPath: data.top_showMountPath,
@@ -501,6 +503,7 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
501503
showDiskUsage: data.bottom_showDiskUsage,
502504
showSystemInfo: data.bottom_showSystemInfo,
503505
showInternetStatus: data.bottom_showInternetStatus,
506+
showPublicIP: data.bottom_showPublicIP,
504507
selectedDisks: data.bottom_selectedDisks,
505508
showIcons: data.bottom_showIcons,
506509
showMountPath: data.bottom_showMountPath,

frontend/src/components/forms/AddEditForm/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type FormValues = {
2020
showDiskUsage?: boolean;
2121
showSystemInfo?: boolean;
2222
showInternetStatus?: boolean;
23+
showPublicIP?: boolean;
2324
// Disk monitor widget
2425
selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
2526
showIcons?: boolean;
@@ -105,6 +106,7 @@ export type FormValues = {
105106
top_showDiskUsage?: boolean;
106107
top_showSystemInfo?: boolean;
107108
top_showInternetStatus?: boolean;
109+
top_showPublicIP?: boolean;
108110
top_selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
109111
top_showIcons?: boolean;
110112
top_showMountPath?: boolean;
@@ -135,6 +137,7 @@ export type FormValues = {
135137
bottom_showDiskUsage?: boolean;
136138
bottom_showSystemInfo?: boolean;
137139
bottom_showInternetStatus?: boolean;
140+
bottom_showPublicIP?: boolean;
138141
bottom_selectedDisks?: Array<{ mount: string; customName: string; showMountPath?: boolean }>;
139142
bottom_showIcons?: boolean;
140143
bottom_showMountPath?: boolean;

frontend/src/components/forms/AddEditForm/useExistingItem.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ export const useExistingItem = ({ existingItem, formContext, setCustomIconFile }
220220
showDiskUsage: existingItem?.config?.showDiskUsage !== false, // Default to true
221221
showSystemInfo: existingItem?.config?.showSystemInfo !== false, // Default to true
222222
showInternetStatus: existingItem?.config?.showInternetStatus !== false, // Default to true
223+
showPublicIP: existingItem?.config?.showPublicIP || false,
223224

224225
// Disk monitor widget values
225226
selectedDisks: existingItem?.type === ITEM_TYPE.DISK_MONITOR_WIDGET ? (existingItem?.config?.selectedDisks || []) : [],
@@ -241,6 +242,7 @@ export const useExistingItem = ({ existingItem, formContext, setCustomIconFile }
241242
top_showDiskUsage: true,
242243
top_showSystemInfo: true,
243244
top_showInternetStatus: true,
245+
top_showPublicIP: false,
244246
top_selectedDisks: [],
245247
top_showIcons: true,
246248
top_layout: '2x2',
@@ -268,6 +270,7 @@ export const useExistingItem = ({ existingItem, formContext, setCustomIconFile }
268270
bottom_showDiskUsage: true,
269271
bottom_showSystemInfo: true,
270272
bottom_showInternetStatus: true,
273+
bottom_showPublicIP: false,
271274
bottom_selectedDisks: [],
272275
bottom_showIcons: true,
273276
bottom_layout: '2x2',
@@ -318,6 +321,7 @@ export const useExistingItem = ({ existingItem, formContext, setCustomIconFile }
318321
formContext.setValue('top_showDiskUsage', topConfig.showDiskUsage !== false);
319322
formContext.setValue('top_showSystemInfo', topConfig.showSystemInfo !== false);
320323
formContext.setValue('top_showInternetStatus', topConfig.showInternetStatus !== false);
324+
formContext.setValue('top_showPublicIP', topConfig.showPublicIP || false);
321325
}
322326

323327
// Handle top disk monitor widget
@@ -390,6 +394,7 @@ export const useExistingItem = ({ existingItem, formContext, setCustomIconFile }
390394
formContext.setValue('bottom_showDiskUsage', bottomConfig.showDiskUsage !== false);
391395
formContext.setValue('bottom_showSystemInfo', bottomConfig.showSystemInfo !== false);
392396
formContext.setValue('bottom_showInternetStatus', bottomConfig.showInternetStatus !== false);
397+
formContext.setValue('bottom_showPublicIP', bottomConfig.showPublicIP || false);
393398
}
394399

395400
// Handle bottom disk monitor widget

frontend/src/components/forms/SettingsForm.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type FormValues = {
3535
searchProviderId: string;
3636
searchProvider?: SearchProvider;
3737
showInternetIndicator: boolean;
38+
showPublicIP: boolean;
3839
themeColor: string;
3940
configFile?: File | null;
4041
appIconFiles?: File[] | null;
@@ -304,6 +305,7 @@ export const SettingsForm = () => {
304305
: ''
305306
},
306307
showInternetIndicator: config?.showInternetIndicator !== false, // Default to true
308+
showPublicIP: config?.showPublicIP || false,
307309
themeColor: config?.themeColor || '#734CDE',
308310
configFile: null,
309311
appIconFiles: null
@@ -319,6 +321,7 @@ export const SettingsForm = () => {
319321
const searchProviderName = formContext.watch('searchProvider.name', '');
320322
const searchProviderUrl = formContext.watch('searchProvider.url', '');
321323
const showInternetIndicator = formContext.watch('showInternetIndicator', true);
324+
const showPublicIP = formContext.watch('showPublicIP', false);
322325
const themeColor = formContext.watch('themeColor', '#734CDE');
323326
const configFile = formContext.watch('configFile', null);
324327
const appIconFiles = formContext.watch('appIconFiles', null);
@@ -376,6 +379,9 @@ export const SettingsForm = () => {
376379
// Internet indicator change
377380
if (showInternetIndicator !== (config?.showInternetIndicator !== false)) return true;
378381

382+
// Show public IP change
383+
if (showPublicIP !== (config?.showPublicIP || false)) return true;
384+
379385
// Theme color change
380386
if (themeColor !== (config?.themeColor || '#734CDE')) return true;
381387

@@ -422,6 +428,7 @@ export const SettingsForm = () => {
422428
searchProviderName,
423429
searchProviderUrl,
424430
showInternetIndicator,
431+
showPublicIP,
425432
themeColor,
426433
config
427434
]);
@@ -457,6 +464,10 @@ export const SettingsForm = () => {
457464
updatedConfig.showInternetIndicator = data.showInternetIndicator;
458465
}
459466

467+
if (data.showPublicIP !== undefined) {
468+
updatedConfig.showPublicIP = data.showPublicIP;
469+
}
470+
460471
// Handle theme color
461472
if (data.themeColor && data.themeColor !== config?.themeColor) {
462473
updatedConfig.themeColor = data.themeColor;
@@ -587,6 +598,7 @@ export const SettingsForm = () => {
587598
url: refreshedConfig?.searchProvider?.url || ''
588599
},
589600
showInternetIndicator: refreshedConfig?.showInternetIndicator !== false,
601+
showPublicIP: refreshedConfig?.showPublicIP || false,
590602
themeColor: refreshedConfig?.themeColor || '#734CDE',
591603
appIconFiles: null
592604
});
@@ -799,6 +811,17 @@ export const SettingsForm = () => {
799811
/>
800812
</Box>
801813

814+
<Typography variant='body1' sx={{
815+
alignSelf: 'center',
816+
fontSize: { xs: '0.875rem', sm: '1rem' }
817+
}}>Show Public IP in Tooltip</Typography>
818+
<Box sx={{ display: 'flex', alignItems: 'center' }}>
819+
<CheckboxElement
820+
name='showPublicIP'
821+
sx={{ color: 'text.primary' }}
822+
/>
823+
</Box>
824+
802825
{searchEnabled && (
803826
<>
804827
<Typography variant='body1' sx={{

0 commit comments

Comments
 (0)