handle labels in resources too

This commit is contained in:
Fred KISSIE
2026-05-11 18:30:23 +02:00
parent a0759a79a1
commit 549e1ead1d
2 changed files with 88 additions and 25 deletions

View File

@@ -1,7 +1,9 @@
import { import {
db, db,
labels,
resourceHeaderAuth, resourceHeaderAuth,
resourceHeaderAuthExtendedCompatibility, resourceHeaderAuthExtendedCompatibility,
resourceLabels,
resourcePassword, resourcePassword,
resourcePincode, resourcePincode,
resources, resources,
@@ -9,8 +11,11 @@ import {
sites, sites,
targetHealthCheck, targetHealthCheck,
targets, targets,
userResources userResources,
type Label
} from "@server/db"; } from "@server/db";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
import response from "@server/lib/response"; import response from "@server/lib/response";
import logger from "@server/logger"; import logger from "@server/logger";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
@@ -154,10 +159,11 @@ export type ResourceWithTargets = {
siteNiceId: string; siteNiceId: string;
online?: boolean; // undefined for local sites online?: boolean; // undefined for local sites
}>; }>;
labels?: Array<Pick<Label, "color" | "labelId" | "name">>;
}; };
function queryResourcesBase() { function queryResourcesBase(isLabelFeatureEnabled: boolean) {
return db let query = db
.select({ .select({
resourceId: resources.resourceId, resourceId: resources.resourceId,
name: resources.name, name: resources.name,
@@ -203,8 +209,18 @@ function queryResourcesBase() {
.leftJoin( .leftJoin(
targetHealthCheck, targetHealthCheck,
eq(targetHealthCheck.targetId, targets.targetId) eq(targetHealthCheck.targetId, targets.targetId)
);
if (isLabelFeatureEnabled) {
query = query
.leftJoin(
resourceLabels,
eq(resourceLabels.resourceId, resources.resourceId)
) )
.groupBy( .leftJoin(labels, eq(labels.labelId, resourceLabels.labelId));
}
return query.groupBy(
resources.resourceId, resources.resourceId,
resourcePassword.passwordId, resourcePassword.passwordId,
resourcePincode.pincodeId, resourcePincode.pincodeId,
@@ -288,6 +304,11 @@ export async function listResources(
); );
} }
const isLabelFeatureEnabled = await isLicensedOrSubscribed(
orgId,
tierMatrix.labels
);
let accessibleResources: Array<{ resourceId: number }>; let accessibleResources: Array<{ resourceId: number }>;
if (req.user) { if (req.user) {
accessibleResources = await db accessibleResources = await db
@@ -369,8 +390,7 @@ export async function listResources(
conditions.push(inArray(resources.resourceId, resourcesWithSite)); conditions.push(inArray(resources.resourceId, resourcesWithSite));
} }
if (query) { if (query) {
conditions.push( const queryList = [
or(
like( like(
sql`LOWER(${resources.name})`, sql`LOWER(${resources.name})`,
"%" + query.toLowerCase() + "%" "%" + query.toLowerCase() + "%"
@@ -383,11 +403,21 @@ export async function listResources(
sql`LOWER(${resources.fullDomain})`, sql`LOWER(${resources.fullDomain})`,
"%" + query.toLowerCase() + "%" "%" + query.toLowerCase() + "%"
) )
];
if (isLabelFeatureEnabled) {
queryList.push(
like(
sql`LOWER(${labels.name})`,
"%" + query.toLowerCase() + "%"
) )
); );
} }
const baseQuery = queryResourcesBase().where(and(...conditions)); conditions.push(or(...queryList));
}
const baseQuery = queryResourcesBase(isLabelFeatureEnabled).where(and(...conditions));
// we need to add `as` so that drizzle filters the result as a subquery // we need to add `as` so that drizzle filters the result as a subquery
const countQuery = db.$count(baseQuery.as("filtered_resources")); const countQuery = db.$count(baseQuery.as("filtered_resources"));
@@ -407,6 +437,35 @@ export async function listResources(
]); ]);
const resourceIdList = rows.map((row) => row.resourceId); const resourceIdList = rows.map((row) => row.resourceId);
let labelsForResources: Array<{
labelId: number;
name: string;
color: string;
resourceId: number;
}> = [];
if (isLabelFeatureEnabled) {
labelsForResources =
resourceIdList.length === 0
? []
: await db
.select({
labelId: labels.labelId,
name: labels.name,
color: labels.color,
resourceId: resourceLabels.resourceId
})
.from(labels)
.innerJoin(
resourceLabels,
eq(resourceLabels.labelId, labels.labelId)
)
.where(
inArray(resourceLabels.resourceId, resourceIdList)
);
}
const allResourceTargets = const allResourceTargets =
resourceIdList.length === 0 resourceIdList.length === 0
? [] ? []
@@ -458,7 +517,10 @@ export async function listResources(
headerAuthId: row.headerAuthId, headerAuthId: row.headerAuthId,
health: row.health ?? null, health: row.health ?? null,
targets: [], targets: [],
sites: [] sites: [],
labels: labelsForResources.filter(
(l) => l.resourceId === row.resourceId
)
}; };
map.set(row.resourceId, entry); map.set(row.resourceId, entry);
} }

View File

@@ -111,6 +111,7 @@ export default async function ProxyResourcesPage(
protocol: resource.protocol, protocol: resource.protocol,
proxyPort: resource.proxyPort, proxyPort: resource.proxyPort,
http: resource.http, http: resource.http,
labels: resource.labels,
authState: !resource.http authState: !resource.http
? "none" ? "none"
: resource.sso || : resource.sso ||