mirror of
https://github.com/henrygd/beszel.git
synced 2026-05-06 10:51:50 +02:00
updates
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
package hub
|
package hub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/henrygd/beszel/internal/entities/probe"
|
"github.com/henrygd/beszel/internal/entities/probe"
|
||||||
"github.com/henrygd/beszel/internal/hub/systems"
|
"github.com/henrygd/beszel/internal/hub/systems"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"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.
|
// 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.
|
// setProbeResultFields stores the latest probe result values on the record.
|
||||||
func setProbeResultFields(record *core.Record, result probe.Result) {
|
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("res", result.Get(0))
|
||||||
record.Set("resAvg1h", result.Get(1))
|
record.Set("resAvg1h", result.Get(1))
|
||||||
record.Set("resMin1h", result.Get(2))
|
record.Set("resMin1h", result.Get(2))
|
||||||
record.Set("resMax1h", result.Get(3))
|
record.Set("resMax1h", result.Get(3))
|
||||||
record.Set("loss1h", result.Get(4))
|
record.Set("loss1h", result.Get(4))
|
||||||
|
record.Set("updated", nowString)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyProbeToNewRecord creates a new record with the same field values as the old one.
|
// copyProbeToNewRecord creates a new record with the same field values as the old one.
|
||||||
|
|||||||
@@ -327,12 +327,13 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
|
|||||||
return !strings.Contains(filterQuery, "system") || strings.Contains(filterQuery, systemId)
|
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 db dbx.Builder
|
||||||
var nowString string
|
|
||||||
var updateQuery *dbx.Query
|
var updateQuery *dbx.Query
|
||||||
if !realtimeActive {
|
if !realtimeActive {
|
||||||
db = app.DB()
|
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)
|
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)
|
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("resMin1h", values.Get(2))
|
||||||
record.Set("resMax1h", values.Get(3))
|
record.Set("resMax1h", values.Get(3))
|
||||||
record.Set("loss1h", values.Get(4))
|
record.Set("loss1h", values.Get(4))
|
||||||
|
record.Set("updated", nowString)
|
||||||
err = app.SaveNoValidate(record)
|
err = app.SaveNoValidate(record)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -375,6 +377,7 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
|
|||||||
record.Set("system", systemId)
|
record.Set("system", systemId)
|
||||||
record.Set("stats", data)
|
record.Set("stats", data)
|
||||||
record.Set("type", "1m")
|
record.Set("type", "1m")
|
||||||
|
record.Set("created", nowMilli)
|
||||||
err = app.SaveNoValidate(record)
|
err = app.SaveNoValidate(record)
|
||||||
default:
|
default:
|
||||||
var statsJson types.JSONRaw
|
var statsJson types.JSONRaw
|
||||||
@@ -384,7 +387,7 @@ func updateNetworkProbesRecords(app core.App, data map[string]probe.Result, syst
|
|||||||
"system": systemId,
|
"system": systemId,
|
||||||
"stats": statsJson,
|
"stats": statsJson,
|
||||||
"type": "1m",
|
"type": "1m",
|
||||||
"created": nowString,
|
"created": nowMilli,
|
||||||
}).Execute()
|
}).Execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,10 @@ export function getProbeColumns(
|
|||||||
header: ({ column }) => <HeaderButton column={column} name={t`Updated`} Icon={ClockIcon} />,
|
header: ({ column }) => <HeaderButton column={column} name={t`Updated`} Icon={ClockIcon} />,
|
||||||
cell: ({ getValue }) => {
|
cell: ({ getValue }) => {
|
||||||
const timestamp = getValue() as number
|
const timestamp = getValue() as number
|
||||||
return <span className="ms-1.5 tabular-nums">{hourWithSeconds(new Date(timestamp).toISOString())}</span>
|
if (!timestamp) {
|
||||||
|
return <span className="ms-1.5 text-muted-foreground">-</span>
|
||||||
|
}
|
||||||
|
return <span className="ms-1.5 tabular-nums">{hourWithSeconds(timestamp)}</span>
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,13 +48,14 @@ export async function getStats<T extends SystemStatsRecord | ContainerStatsRecor
|
|||||||
collection: string,
|
collection: string,
|
||||||
systemId: string,
|
systemId: string,
|
||||||
chartTime: ChartTimes,
|
chartTime: ChartTimes,
|
||||||
cachedStats?: { created: string | number | null }[]
|
cachedStats?: { created: string | number | null }[],
|
||||||
|
createdIsNumber?: boolean
|
||||||
): Promise<T[]> {
|
): Promise<T[]> {
|
||||||
const lastCached = cachedStats?.at(-1)?.created as number
|
const lastCached = cachedStats?.at(-1)?.created as number
|
||||||
return await pb.collection<T>(collection).getFullList({
|
return await pb.collection<T>(collection).getFullList({
|
||||||
filter: pb.filter("system={:id} && created > {:created} && type={:type}", {
|
filter: pb.filter("system={:id} && created > {:created} && type={:type}", {
|
||||||
id: systemId,
|
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,
|
type: chartTimeData[chartTime].type,
|
||||||
}),
|
}),
|
||||||
fields: "created,stats",
|
fields: "created,stats",
|
||||||
|
|||||||
@@ -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())
|
d ||= chartTimeData[timeString].getOffset(new Date())
|
||||||
|
if (createdIsNumber) {
|
||||||
|
return d.getTime()
|
||||||
|
}
|
||||||
const year = d.getUTCFullYear()
|
const year = d.getUTCFullYear()
|
||||||
const month = String(d.getUTCMonth() + 1).padStart(2, "0")
|
const month = String(d.getUTCMonth() + 1).padStart(2, "0")
|
||||||
const day = String(d.getUTCDate()).padStart(2, "0")
|
const day = String(d.getUTCDate()).padStart(2, "0")
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export function useNetworkProbesData(props: UseNetworkProbesProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getStats<NetworkProbeStatsRecord>("network_probe_stats", systemId, chartTime, cachedProbeStats).then(
|
getStats<NetworkProbeStatsRecord>("network_probe_stats", systemId, chartTime, cachedProbeStats, true).then(
|
||||||
(probeStats) => {
|
(probeStats) => {
|
||||||
// If another request has been made since this one, ignore the results
|
// If another request has been made since this one, ignore the results
|
||||||
if (requestId !== statsRequestId.current) {
|
if (requestId !== statsRequestId.current) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const formatShortDate = (timestamp: string) => {
|
|||||||
return shortDateFormatter.format(new Date(timestamp))
|
return shortDateFormatter.format(new Date(timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hourWithSeconds = (timestamp: string) => {
|
export const hourWithSeconds = (timestamp: string | number) => {
|
||||||
return hourWithSecondsFormatter.format(new Date(timestamp))
|
return hourWithSecondsFormatter.format(new Date(timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,8 @@ export const updateFavicon = (() => {
|
|||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<path fill="url(#gradient)" d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/>
|
<path fill="url(#gradient)" d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/>
|
||||||
${downCount > 0 &&
|
${
|
||||||
|
downCount > 0 &&
|
||||||
`
|
`
|
||||||
<circle cx="40" cy="50" r="22" fill="#f00"/>
|
<circle cx="40" cy="50" r="22" fill="#f00"/>
|
||||||
<text x="40" y="60" font-size="34" text-anchor="middle" fill="#fff" font-family="Arial" font-weight="bold">${downCount}</text>
|
<text x="40" y="60" font-size="34" text-anchor="middle" fill="#fff" font-family="Arial" font-weight="bold">${downCount}</text>
|
||||||
@@ -452,7 +453,12 @@ export function secondsToString(seconds: number, unit: "hour" | "minute" | "day"
|
|||||||
const countString = count.toLocaleString()
|
const countString = count.toLocaleString()
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case "minute":
|
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":
|
case "hour":
|
||||||
return plural(count, { one: `${countString} hour`, other: `${countString} hours` })
|
return plural(count, { one: `${countString} hour`, other: `${countString} hours` })
|
||||||
case "day":
|
case "day":
|
||||||
|
|||||||
Reference in New Issue
Block a user