mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-31 04:56:43 +00:00
Merge branch 'dev' of github.com:fosrl/pangolin into dev
This commit is contained in:
@@ -113,6 +113,16 @@ const listResourcesSchema = z.object({
|
||||
enum: ["no_targets", "healthy", "degraded", "offline", "unknown"],
|
||||
description:
|
||||
"Filter resources based on health status of their targets. `healthy` means all targets are healthy. `degraded` means at least one target is unhealthy, but not all are unhealthy. `offline` means all targets are unhealthy. `unknown` means all targets have unknown health status. `no_targets` means the resource has no targets."
|
||||
}),
|
||||
siteId: z.coerce
|
||||
.number<string>()
|
||||
.int()
|
||||
.positive()
|
||||
.optional()
|
||||
.openapi({
|
||||
type: "integer",
|
||||
description:
|
||||
"When set, only resources that have at least one target on this site are returned"
|
||||
})
|
||||
});
|
||||
|
||||
@@ -141,6 +151,12 @@ export type ResourceWithTargets = {
|
||||
healthStatus: "healthy" | "unhealthy" | "unknown" | null;
|
||||
siteName: string | null;
|
||||
}>;
|
||||
sites: Array<{
|
||||
siteId: number;
|
||||
siteName: string;
|
||||
siteNiceId: string;
|
||||
online: boolean;
|
||||
}>;
|
||||
};
|
||||
|
||||
function queryResourcesBase() {
|
||||
@@ -240,7 +256,8 @@ export async function listResources(
|
||||
query,
|
||||
healthStatus,
|
||||
sort_by,
|
||||
order
|
||||
order,
|
||||
siteId
|
||||
} = parsedQuery.data;
|
||||
|
||||
const parsedParams = listResourcesParamsSchema.safeParse(req.params);
|
||||
@@ -361,6 +378,18 @@ export async function listResources(
|
||||
if (typeof healthStatus !== "undefined") {
|
||||
conditions.push(eq(resources.health, healthStatus));
|
||||
}
|
||||
if (siteId != null) {
|
||||
const resourcesWithSite = db
|
||||
.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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const baseQuery = queryResourcesBase().where(and(...conditions));
|
||||
@@ -390,12 +419,15 @@ export async function listResources(
|
||||
.select({
|
||||
targetId: targets.targetId,
|
||||
resourceId: targets.resourceId,
|
||||
siteId: targets.siteId,
|
||||
ip: targets.ip,
|
||||
port: targets.port,
|
||||
enabled: targets.enabled,
|
||||
healthStatus: targetHealthCheck.hcHealth,
|
||||
hcEnabled: targetHealthCheck.hcEnabled,
|
||||
siteName: sites.name
|
||||
siteName: sites.name,
|
||||
siteNiceId: sites.niceId,
|
||||
siteOnline: sites.online
|
||||
})
|
||||
.from(targets)
|
||||
.where(inArray(targets.resourceId, resourceIdList))
|
||||
@@ -427,7 +459,8 @@ export async function listResources(
|
||||
enabled: row.enabled,
|
||||
domainId: row.domainId,
|
||||
headerAuthId: row.headerAuthId,
|
||||
targets: []
|
||||
targets: [],
|
||||
sites: []
|
||||
};
|
||||
map.set(row.resourceId, entry);
|
||||
}
|
||||
@@ -437,6 +470,33 @@ export async function listResources(
|
||||
);
|
||||
}
|
||||
|
||||
for (const entry of map.values()) {
|
||||
const raw = allResourceTargets.filter(
|
||||
(t) => t.resourceId === entry.resourceId
|
||||
);
|
||||
const siteById = new Map<
|
||||
number,
|
||||
{
|
||||
siteId: number;
|
||||
siteName: string;
|
||||
siteNiceId: string;
|
||||
online: boolean;
|
||||
}
|
||||
>();
|
||||
for (const t of raw) {
|
||||
if (typeof t.siteId !== "number" || siteById.has(t.siteId)) {
|
||||
continue;
|
||||
}
|
||||
siteById.set(t.siteId, {
|
||||
siteId: t.siteId,
|
||||
siteName: t.siteName ?? "",
|
||||
siteNiceId: t.siteNiceId ?? "",
|
||||
online: Boolean(t.siteOnline)
|
||||
});
|
||||
}
|
||||
entry.sites = Array.from(siteById.values());
|
||||
}
|
||||
|
||||
const resourcesList: ResourceWithTargets[] = Array.from(map.values());
|
||||
|
||||
return response<ListResourcesResponse>(res, {
|
||||
|
||||
@@ -4,7 +4,7 @@ import logger from "@server/logger";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import type { PaginatedResponse } from "@server/types/Pagination";
|
||||
import { and, asc, desc, eq, like, or, sql } from "drizzle-orm";
|
||||
import { and, asc, desc, eq, inArray, like, or, sql } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
@@ -68,6 +68,16 @@ const listAllSiteResourcesByOrgQuerySchema = z.object({
|
||||
enum: ["asc", "desc"],
|
||||
default: "asc",
|
||||
description: "Sort order"
|
||||
}),
|
||||
siteId: z.coerce
|
||||
.number<string>()
|
||||
.int()
|
||||
.positive()
|
||||
.optional()
|
||||
.openapi({
|
||||
type: "integer",
|
||||
description:
|
||||
"When set, only site resources associated with this site (via network) are returned"
|
||||
})
|
||||
});
|
||||
|
||||
@@ -199,10 +209,31 @@ export async function listAllSiteResourcesByOrg(
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
const { page, pageSize, query, mode, sort_by, order } =
|
||||
const { page, pageSize, query, mode, sort_by, order, siteId } =
|
||||
parsedQuery.data;
|
||||
|
||||
const conditions = [and(eq(siteResources.orgId, orgId))];
|
||||
|
||||
if (siteId != null) {
|
||||
const resourcesForSite = db
|
||||
.select({ id: siteResources.siteResourceId })
|
||||
.from(siteResources)
|
||||
.innerJoin(
|
||||
siteNetworks,
|
||||
eq(siteResources.networkId, siteNetworks.networkId)
|
||||
)
|
||||
.innerJoin(sites, eq(siteNetworks.siteId, sites.siteId))
|
||||
.where(
|
||||
and(
|
||||
eq(siteResources.orgId, orgId),
|
||||
eq(sites.orgId, orgId),
|
||||
eq(sites.siteId, siteId)
|
||||
)
|
||||
);
|
||||
conditions.push(
|
||||
inArray(siteResources.siteResourceId, resourcesForSite)
|
||||
);
|
||||
}
|
||||
if (query) {
|
||||
conditions.push(
|
||||
or(
|
||||
|
||||
Reference in New Issue
Block a user