dont show site online status for local sites

This commit is contained in:
miloschwartz
2026-04-29 12:35:08 -07:00
parent f03389a9a0
commit a029b107ae
6 changed files with 64 additions and 33 deletions

View File

@@ -152,7 +152,7 @@ export type ResourceWithTargets = {
siteId: number;
siteName: string;
siteNiceId: string;
online: boolean;
online?: boolean; // undefined for local sites
}>;
};
@@ -383,12 +383,8 @@ export async function listResources(
.select({ resourceId: targets.resourceId })
.from(targets)
.innerJoin(sites, eq(targets.siteId, sites.siteId))
.where(
and(eq(sites.orgId, orgId), eq(sites.siteId, siteId))
);
conditions.push(
inArray(resources.resourceId, resourcesWithSite)
);
.where(and(eq(sites.orgId, orgId), eq(sites.siteId, siteId)));
conditions.push(inArray(resources.resourceId, resourcesWithSite));
}
const baseQuery = queryResourcesBase().where(and(...conditions));
@@ -426,7 +422,8 @@ export async function listResources(
hcEnabled: targetHealthCheck.hcEnabled,
siteName: sites.name,
siteNiceId: sites.niceId,
siteOnline: sites.online
siteOnline: sites.online,
siteType: sites.type
})
.from(targets)
.where(inArray(targets.resourceId, resourceIdList))
@@ -481,18 +478,19 @@ export async function listResources(
siteId: number;
siteName: string;
siteNiceId: string;
online: boolean;
online?: boolean;
}
>();
for (const t of raw) {
if (typeof t.siteId !== "number" || siteById.has(t.siteId)) {
continue;
}
const isLocal = t.siteType === "local";
siteById.set(t.siteId, {
siteId: t.siteId,
siteName: t.siteName ?? "",
siteNiceId: t.siteNiceId ?? "",
online: Boolean(t.siteOnline)
online: isLocal ? undefined : Boolean(t.siteOnline)
});
}
entry.sites = Array.from(siteById.values());

View File

@@ -31,7 +31,9 @@ let staleNewtVersion: string | null = null;
async function getLatestNewtVersion(): Promise<string | null> {
try {
const cachedVersion = await cache.get<string>("cache:latestNewtVersion");
const cachedVersion = await cache.get<string>(
"cache:latestNewtVersion"
);
if (cachedVersion) {
return cachedVersion;
}
@@ -226,7 +228,10 @@ function querySitesBase() {
);
}
type SiteWithUpdateAvailable = Awaited<ReturnType<typeof querySitesBase>>[0] & {
type SiteRowBase = Awaited<ReturnType<typeof querySitesBase>>[0];
type SiteWithUpdateAvailable = Omit<SiteRowBase, "online"> & {
online?: SiteRowBase["online"]; // undefined for local sites
newtUpdateAvailable?: boolean;
};
@@ -338,7 +343,9 @@ export async function listSites(
// we need to add `as` so that drizzle filters the result as a subquery
const countQuery = db.$count(
querySitesBase().where(and(...conditions)).as("filtered_sites")
querySitesBase()
.where(and(...conditions))
.as("filtered_sites")
);
const siteListQuery = baseQuery
@@ -397,9 +404,13 @@ export async function listSites(
);
}
const sitesPayload = sitesWithUpdates.map((site) =>
site.type === "local" ? { ...site, online: undefined } : site
);
return response<ListSitesResponse>(res, {
data: {
sites: sitesWithUpdates,
sites: sitesPayload,
pagination: {
total: totalCount,
pageSize,

View File

@@ -16,10 +16,10 @@ export type ResourceSiteRow = {
siteId: number;
siteName: string;
siteNiceId: string;
online: boolean;
online?: boolean | null;
};
type AggregateSitesStatus = "allOnline" | "partial" | "allOffline";
type AggregateSitesStatus = "allOnline" | "partial" | "allOffline" | "unknown";
function aggregateSitesStatus(
resourceSites: ResourceSiteRow[]
@@ -27,8 +27,17 @@ function aggregateSitesStatus(
if (resourceSites.length === 0) {
return "allOffline";
}
const onlineCount = resourceSites.filter((rs) => rs.online).length;
if (onlineCount === resourceSites.length) return "allOnline";
const knownStatuses = resourceSites
.map((rs) => rs.online)
.filter((status): status is boolean => typeof status === "boolean");
if (knownStatuses.length === 0) {
return "unknown";
}
const onlineCount = knownStatuses.filter(Boolean).length;
if (onlineCount === knownStatuses.length) return "allOnline";
if (onlineCount > 0) return "partial";
return "allOffline";
}
@@ -40,8 +49,10 @@ function aggregateStatusDotClass(status: AggregateSitesStatus): string {
case "partial":
return "bg-yellow-500";
case "allOffline":
default:
return "bg-neutral-500";
case "unknown":
default:
return "bg-transparent";
}
}
@@ -84,6 +95,7 @@ export function ResourceSitesStatusCell({
<DropdownMenuContent align="start" className="min-w-56">
{resourceSites.map((site) => {
const isOnline = site.online;
const hasKnownStatus = typeof isOnline === "boolean";
return (
<DropdownMenuItem key={site.siteId} asChild>
<Link
@@ -94,7 +106,9 @@ export function ResourceSitesStatusCell({
<div
className={cn(
"h-2 w-2 shrink-0 rounded-full",
isOnline
!hasKnownStatus
? "bg-transparent"
: isOnline
? "bg-green-500"
: "bg-neutral-500"
)}
@@ -106,12 +120,16 @@ export function ResourceSitesStatusCell({
<span
className={cn(
"shrink-0 capitalize",
isOnline
hasKnownStatus && isOnline
? "text-green-600"
: "text-muted-foreground"
)}
>
{isOnline ? t("online") : t("offline")}
{!hasKnownStatus
? t("resourcesTableUnknown")
: isOnline
? t("online")
: t("offline")}
</span>
</Link>
</DropdownMenuItem>

View File

@@ -60,7 +60,7 @@ export type SiteRow = {
type: "newt" | "wireguard" | "local";
newtVersion?: string;
newtUpdateAvailable?: boolean;
online: boolean;
online?: boolean | null;
address?: string;
exitNodeName?: string;
exitNodeEndpoint?: string;

View File

@@ -111,11 +111,13 @@ export function MultiSitesSelector({
<span className="min-w-0 flex-1 truncate">
{site.name}
</span>
<SiteOnlineStatus
type={site.type}
online={site.online}
t={t}
/>
{site.online != null && (
<SiteOnlineStatus
type={site.type}
online={site.online}
t={t}
/>
)}
</div>
</CommandItem>
))}

View File

@@ -124,11 +124,13 @@ export function SitesSelector({
<span className="min-w-0 flex-1 truncate">
{site.name}
</span>
<SiteOnlineStatus
type={site.type}
online={site.online}
t={t}
/>
{site.online != null && (
<SiteOnlineStatus
type={site.type}
online={site.online}
t={t}
/>
)}
</div>
</CommandItem>
))}