label filter column

This commit is contained in:
Fred KISSIE
2026-05-26 22:45:41 +02:00
parent fd1813f3a7
commit 91883397e6
2 changed files with 54 additions and 7 deletions
+40 -2
View File
@@ -123,7 +123,27 @@ const listResourcesSchema = z.object({
type: "integer", type: "integer",
description: description:
"When set, only resources that have at least one target on this site are returned" "When set, only resources that have at least one target on this site are returned"
}) }),
labels: z
.preprocess((val) => {
if (val === undefined || val === null || val === "") {
return undefined;
}
if (Array.isArray(val)) {
return val;
}
// the array is returned as this
if (typeof val === "string") {
return val.split(",");
}
return undefined;
}, z.array(z.string()))
.optional()
.catch([])
.openapi({
type: "array",
description: "Filter by resource labels"
})
}); });
// grouped by resource with targets[]) // grouped by resource with targets[])
@@ -261,7 +281,8 @@ export async function listResources(
healthStatus, healthStatus,
sort_by, sort_by,
order, order,
siteId siteId,
labels: labelFilter
} = parsedQuery.data; } = parsedQuery.data;
const parsedParams = listResourcesParamsSchema.safeParse(req.params); const parsedParams = listResourcesParamsSchema.safeParse(req.params);
@@ -379,6 +400,23 @@ export async function listResources(
.where(and(eq(sites.orgId, orgId), eq(sites.siteId, siteId))); .where(and(eq(sites.orgId, orgId), eq(sites.siteId, siteId)));
conditions.push(inArray(resources.resourceId, resourcesWithSite)); conditions.push(inArray(resources.resourceId, resourcesWithSite));
} }
if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) {
conditions.push(
inArray(
resources.resourceId,
db
.select({ id: resourceLabels.resourceId })
.from(resourceLabels)
.innerJoin(
labels,
eq(labels.labelId, resourceLabels.labelId)
)
.where(inArray(labels.name, labelFilter))
)
);
}
if (query) { if (query) {
const q = "%" + query.toLowerCase() + "%"; const q = "%" + query.toLowerCase() + "%";
const queryList = [ const queryList = [
+14 -5
View File
@@ -72,6 +72,7 @@ import { ControlledDataTable } from "./ui/controlled-data-table";
import UptimeMiniBar from "./UptimeMiniBar"; import UptimeMiniBar from "./UptimeMiniBar";
import { LabelsSelector, type SelectedLabel } from "./labels-selector"; import { LabelsSelector, type SelectedLabel } from "./labels-selector";
import { LabelBadge } from "./label-badge"; import { LabelBadge } from "./label-badge";
import { LabelColumnFilterButton } from "./LabelColumnFilterButton";
export type TargetHealth = { export type TargetHealth = {
targetId: number; targetId: number;
@@ -640,9 +641,15 @@ export default function ProxyResourcesTable({
id: "labels", id: "labels",
accessorKey: "labels", accessorKey: "labels",
header: () => ( header: () => (
<span className="p-3 text-end w-full inline-block"> <LabelColumnFilterButton
{t("labels")} orgId={orgId}
</span> selectedValues={searchParams.getAll("labels")}
onSelectedValuesChange={(value) =>
handleFilterChange("labels", value)
}
label={t("labels")}
className="p-3"
/>
), ),
cell: ({ row }: { row: { original: ResourceRow } }) => ( cell: ({ row }: { row: { original: ResourceRow } }) => (
<ResourceLabelCell resource={row.original} orgId={orgId} /> <ResourceLabelCell resource={row.original} orgId={orgId} />
@@ -655,13 +662,15 @@ export default function ProxyResourcesTable({
function handleFilterChange( function handleFilterChange(
column: string, column: string,
value: string | undefined | null value: string | undefined | null | string[]
) { ) {
searchParams.delete(column); searchParams.delete(column);
searchParams.delete("page"); searchParams.delete("page");
if (value) { if (typeof value === "string") {
searchParams.set(column, value); searchParams.set(column, value);
} else if (value) {
value.forEach((val) => searchParams.append(column, val));
} }
filter({ filter({
searchParams searchParams