diff --git a/internal/hub/probes.go b/internal/hub/probes.go
index bea0b2e1..a7d2e0d4 100644
--- a/internal/hub/probes.go
+++ b/internal/hub/probes.go
@@ -1,9 +1,12 @@
package hub
import (
+ "time"
+
"github.com/henrygd/beszel/internal/entities/probe"
"github.com/henrygd/beszel/internal/hub/systems"
"github.com/pocketbase/pocketbase/core"
+ "github.com/pocketbase/pocketbase/tools/types"
)
// generateProbeID creates a stable hash ID for a probe based on its configuration and the system it belongs to.
@@ -107,11 +110,14 @@ func probeConfigFromRecord(record *core.Record) *probe.Config {
// setProbeResultFields stores the latest probe result values on the record.
func setProbeResultFields(record *core.Record, result probe.Result) {
+ now := time.Now().UTC()
+ nowString := now.Format(types.DefaultDateLayout)
record.Set("res", result.Get(0))
record.Set("resAvg1h", result.Get(1))
record.Set("resMin1h", result.Get(2))
record.Set("resMax1h", result.Get(3))
record.Set("loss1h", result.Get(4))
+ record.Set("updated", nowString)
}
// copyProbeToNewRecord creates a new record with the same field values as the old one.
diff --git a/internal/hub/systems/system.go b/internal/hub/systems/system.go
index f09da46a..d378addb 100644
--- a/internal/hub/systems/system.go
+++ b/internal/hub/systems/system.go
@@ -327,12 +327,13 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
return !strings.Contains(filterQuery, "system") || strings.Contains(filterQuery, systemId)
})
+ now := time.Now().UTC()
+ nowMilli := now.UnixMilli()
+ nowString := now.Format(types.DefaultDateLayout)
var db dbx.Builder
- var nowString string
var updateQuery *dbx.Query
if !realtimeActive {
db = app.DB()
- nowString = time.Now().UTC().Format(types.DefaultDateLayout)
sql := fmt.Sprintf("UPDATE %s SET res={:res}, resMin1h={:resMin1h}, resMax1h={:resMax1h}, resAvg1h={:resAvg1h}, loss1h={:loss1h}, updated={:updated} WHERE id={:id}", collectionName)
updateQuery = db.NewQuery(sql)
}
@@ -349,6 +350,7 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
record.Set("resMin1h", values.Get(2))
record.Set("resMax1h", values.Get(3))
record.Set("loss1h", values.Get(4))
+ record.Set("updated", nowString)
err = app.SaveNoValidate(record)
}
default:
@@ -375,6 +377,7 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
record.Set("system", systemId)
record.Set("stats", data)
record.Set("type", "1m")
+ record.Set("created", nowMilli)
err = app.SaveNoValidate(record)
default:
var statsJson types.JSONRaw
@@ -384,7 +387,7 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
"system": systemId,
"stats": statsJson,
"type": "1m",
- "created": nowString,
+ "created": nowMilli,
}).Execute()
}
}
diff --git a/internal/site/src/components/network-probes-table/network-probes-columns.tsx b/internal/site/src/components/network-probes-table/network-probes-columns.tsx
index f5c5a5e0..cec104a8 100644
--- a/internal/site/src/components/network-probes-table/network-probes-columns.tsx
+++ b/internal/site/src/components/network-probes-table/network-probes-columns.tsx
@@ -226,7 +226,10 @@ export function getProbeColumns(
header: ({ column }) => ,
cell: ({ getValue }) => {
const timestamp = getValue() as number
- return {hourWithSeconds(new Date(timestamp).toISOString())}
+ if (!timestamp) {
+ return -
+ }
+ return {hourWithSeconds(timestamp)}
},
},
{
diff --git a/internal/site/src/components/routes/system/chart-data.ts b/internal/site/src/components/routes/system/chart-data.ts
index 041aaa94..d8691b1c 100644
--- a/internal/site/src/components/routes/system/chart-data.ts
+++ b/internal/site/src/components/routes/system/chart-data.ts
@@ -48,13 +48,14 @@ export async function getStats {
const lastCached = cachedStats?.at(-1)?.created as number
return await pb.collection(collection).getFullList({
filter: pb.filter("system={:id} && created > {:created} && type={:type}", {
id: systemId,
- created: getPbTimestamp(chartTime, lastCached ? new Date(lastCached + 1000) : undefined),
+ created: getPbTimestamp(chartTime, lastCached ? new Date(lastCached + 1000) : undefined, createdIsNumber),
type: chartTimeData[chartTime].type,
}),
fields: "created,stats",
diff --git a/internal/site/src/lib/api.ts b/internal/site/src/lib/api.ts
index 79f4b127..edc8beb6 100644
--- a/internal/site/src/lib/api.ts
+++ b/internal/site/src/lib/api.ts
@@ -54,8 +54,11 @@ export async function updateUserSettings() {
}
}
-export function getPbTimestamp(timeString: ChartTimes, d?: Date) {
+export function getPbTimestamp(timeString: ChartTimes, d?: Date, createdIsNumber?: boolean) {
d ||= chartTimeData[timeString].getOffset(new Date())
+ if (createdIsNumber) {
+ return d.getTime()
+ }
const year = d.getUTCFullYear()
const month = String(d.getUTCMonth() + 1).padStart(2, "0")
const day = String(d.getUTCDate()).padStart(2, "0")
diff --git a/internal/site/src/lib/use-network-probes.ts b/internal/site/src/lib/use-network-probes.ts
index 99ed95fa..06406a5b 100644
--- a/internal/site/src/lib/use-network-probes.ts
+++ b/internal/site/src/lib/use-network-probes.ts
@@ -196,7 +196,7 @@ export function useNetworkProbesData(props: UseNetworkProbesProps) {
}
}
- getStats("network_probe_stats", systemId, chartTime, cachedProbeStats).then(
+ getStats("network_probe_stats", systemId, chartTime, cachedProbeStats, true).then(
(probeStats) => {
// If another request has been made since this one, ignore the results
if (requestId !== statsRequestId.current) {
diff --git a/internal/site/src/lib/utils.ts b/internal/site/src/lib/utils.ts
index d7900bcc..ee6ef525 100644
--- a/internal/site/src/lib/utils.ts
+++ b/internal/site/src/lib/utils.ts
@@ -72,7 +72,7 @@ export const formatShortDate = (timestamp: string) => {
return shortDateFormatter.format(new Date(timestamp))
}
-export const hourWithSeconds = (timestamp: string) => {
+export const hourWithSeconds = (timestamp: string | number) => {
return hourWithSecondsFormatter.format(new Date(timestamp))
}
@@ -111,17 +111,18 @@ export const updateFavicon = (() => {
- ${downCount > 0 &&
- `
+ ${
+ downCount > 0 &&
+ `
${downCount}
`
- }
+ }
`
const blob = new Blob([svg], { type: "image/svg+xml" })
const url = URL.createObjectURL(blob)
- ; (document.querySelector("link[rel='icon']") as HTMLLinkElement).href = url
+ ;(document.querySelector("link[rel='icon']") as HTMLLinkElement).href = url
}
})()
@@ -365,12 +366,12 @@ export function formatDuration(
.join(" ")
}
-/** Parse semver string into major, minor, and patch numbers
+/** Parse semver string into major, minor, and patch numbers
* @example
* const semVer = "1.2.3"
* const { major, minor, patch } = parseSemVer(semVer)
* console.log(major, minor, patch) // 1, 2, 3
-*/
+ */
export const parseSemVer = (semVer = ""): SemVer => {
// if (semVer.startsWith("v")) {
// semVer = semVer.slice(1)
@@ -452,7 +453,12 @@ export function secondsToString(seconds: number, unit: "hour" | "minute" | "day"
const countString = count.toLocaleString()
switch (unit) {
case "minute":
- return plural(count, { one: `${countString} minute`, few: `${countString} minutes`, many: `${countString} minutes`, other: `${countString} minutes` })
+ return plural(count, {
+ one: `${countString} minute`,
+ few: `${countString} minutes`,
+ many: `${countString} minutes`,
+ other: `${countString} minutes`,
+ })
case "hour":
return plural(count, { one: `${countString} hour`, other: `${countString} hours` })
case "day":
@@ -469,4 +475,4 @@ export function secondsToUptimeString(seconds: number): string {
} else {
return secondsToString(seconds, "day")
}
-}
\ No newline at end of file
+}