Update Uptime API and Dashboard to support additional timespan options and improve time formatting

This commit is contained in:
headlessdev 2025-04-24 14:06:02 +02:00
parent 4e64701ddf
commit 08cce9fd24
2 changed files with 56 additions and 41 deletions

View File

@ -12,22 +12,27 @@ const getTimeRange = (timespan: number) => {
switch (timespan) { switch (timespan) {
case 1: case 1:
return { return {
start: new Date(now.getTime() - 30 * 60 * 1000), start: new Date(now.getTime() - 60 * 60 * 1000),
interval: 'minute' interval: 'minute'
}; };
case 2: case 2:
return { return {
start: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000), start: new Date(now.getTime() - 24 * 60 * 60 * 1000),
interval: '3hour' interval: 'hour'
}; };
case 3: case 3:
return {
start: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000),
interval: 'day'
};
case 4:
return { return {
start: new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000), start: new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000),
interval: 'day' interval: 'day'
}; };
default: default:
return { return {
start: new Date(now.getTime() - 30 * 60 * 1000), start: new Date(now.getTime() - 60 * 60 * 1000),
interval: 'minute' interval: 'minute'
}; };
} }
@ -38,23 +43,31 @@ const generateIntervals = (timespan: number) => {
now.setSeconds(0, 0); now.setSeconds(0, 0);
switch (timespan) { switch (timespan) {
case 1: case 1: // 1 hour - 60 one-minute intervals
return Array.from({ length: 30 }, (_, i) => { return Array.from({ length: 60 }, (_, i) => {
const d = new Date(now); const d = new Date(now);
d.setMinutes(d.getMinutes() - i); d.setMinutes(d.getMinutes() - i);
d.setSeconds(0, 0); d.setSeconds(0, 0);
return d; return d;
}); });
case 2: case 2: // 1 day - 24 one-hour intervals
return Array.from({ length: 56 }, (_, i) => { return Array.from({ length: 24 }, (_, i) => {
const d = new Date(now); const d = new Date(now);
d.setHours(d.getHours() - (i * 3)); d.setHours(d.getHours() - i);
d.setMinutes(0, 0, 0); d.setMinutes(0, 0, 0);
return d; return d;
}); });
case 3: case 3: // 7 days
return Array.from({ length: 7 }, (_, i) => {
const d = new Date(now);
d.setDate(d.getDate() - i);
d.setHours(0, 0, 0, 0);
return d;
});
case 4: // 30 days
return Array.from({ length: 30 }, (_, i) => { return Array.from({ length: 30 }, (_, i) => {
const d = new Date(now); const d = new Date(now);
d.setDate(d.getDate() - i); d.setDate(d.getDate() - i);
@ -70,14 +83,14 @@ const generateIntervals = (timespan: number) => {
const getIntervalKey = (date: Date, timespan: number) => { const getIntervalKey = (date: Date, timespan: number) => {
const d = new Date(date); const d = new Date(date);
switch (timespan) { switch (timespan) {
case 1: case 1: // 1 hour - minute intervals
d.setSeconds(0, 0); d.setSeconds(0, 0);
return d.toISOString(); return d.toISOString();
case 2: case 2: // 1 day - hour intervals
d.setHours(Math.floor(d.getHours() / 3) * 3);
d.setMinutes(0, 0, 0); d.setMinutes(0, 0, 0);
return d.toISOString(); return d.toISOString();
case 3: case 3: // 7 days - day intervals
case 4: // 30 days - day intervals
d.setHours(0, 0, 0, 0); d.setHours(0, 0, 0, 0);
return d.toISOString(); return d.toISOString();
default: default:

View File

@ -34,14 +34,18 @@ const timeFormats = {
minute: '2-digit', minute: '2-digit',
hour12: false hour12: false
}), }),
2: (timestamp: string) => { 2: (timestamp: string) =>
const start = new Date(timestamp); new Date(timestamp).toLocaleTimeString([], {
const end = new Date(start.getTime() + 3 * 60 * 60 * 1000); hour: '2-digit',
return `${start.toLocaleDateString([], { day: '2-digit', month: 'short' })} minute: '2-digit',
${start.getHours().toString().padStart(2, '0')}:00 - hour12: false
${end.getHours().toString().padStart(2, '0')}:00`; }),
},
3: (timestamp: string) => 3: (timestamp: string) =>
new Date(timestamp).toLocaleDateString([], {
day: '2-digit',
month: 'short'
}),
4: (timestamp: string) =>
new Date(timestamp).toLocaleDateString([], { new Date(timestamp).toLocaleDateString([], {
day: '2-digit', day: '2-digit',
month: 'short' month: 'short'
@ -49,9 +53,10 @@ const timeFormats = {
}; };
const minBoxWidths = { const minBoxWidths = {
1: 24, 1: 20,
2: 24, 2: 20,
3: 24 3: 24,
4: 24
}; };
interface UptimeData { interface UptimeData {
@ -72,7 +77,7 @@ interface PaginationData {
export default function Uptime() { export default function Uptime() {
const [data, setData] = useState<UptimeData[]>([]); const [data, setData] = useState<UptimeData[]>([]);
const [timespan, setTimespan] = useState<1 | 2 | 3>(1); const [timespan, setTimespan] = useState<1 | 2 | 3 | 4>(1);
const [pagination, setPagination] = useState<PaginationData>({ const [pagination, setPagination] = useState<PaginationData>({
currentPage: 1, currentPage: 1,
totalPages: 1, totalPages: 1,
@ -153,7 +158,7 @@ export default function Uptime() {
<Select <Select
value={String(timespan)} value={String(timespan)}
onValueChange={(v) => { onValueChange={(v) => {
setTimespan(Number(v) as 1 | 2 | 3); setTimespan(Number(v) as 1 | 2 | 3 | 4);
setPagination(prev => ({...prev, currentPage: 1})); setPagination(prev => ({...prev, currentPage: 1}));
}} }}
disabled={isLoading} disabled={isLoading}
@ -162,9 +167,10 @@ export default function Uptime() {
<SelectValue placeholder="Select timespan" /> <SelectValue placeholder="Select timespan" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="1">Last 30 minutes</SelectItem> <SelectItem value="1">Last 1 hour</SelectItem>
<SelectItem value="2">Last 7 days</SelectItem> <SelectItem value="2">Last 1 day</SelectItem>
<SelectItem value="3">Last 30 days</SelectItem> <SelectItem value="3">Last 7 days</SelectItem>
<SelectItem value="4">Last 30 days</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
@ -219,18 +225,14 @@ export default function Uptime() {
> >
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<p className="font-medium"> <p className="font-medium">
{timespan === 2 ? ( {new Date(entry.timestamp).toLocaleString([], {
timeFormats[2](entry.timestamp)
) : (
new Date(entry.timestamp).toLocaleString([], {
year: 'numeric', year: 'numeric',
month: 'short', month: 'short',
day: 'numeric', day: timespan > 2 ? 'numeric' : undefined,
hour: '2-digit', hour: '2-digit',
minute: timespan === 3 ? undefined : '2-digit', minute: timespan === 1 ? '2-digit' : undefined,
hour12: false hour12: false
}) })}
)}
</p> </p>
<p> <p>
{entry.missing {entry.missing