From 1fc40b301743d54967cdc8acdffdf9ae2dc0856a Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Wed, 4 Feb 2026 03:42:05 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20filter=20by=20auth=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/routers/resource/listResources.ts | 72 ++++++++++++++- src/components/ProxyResourcesTable.tsx | 107 ++++++++--------------- 2 files changed, 107 insertions(+), 72 deletions(-) diff --git a/server/routers/resource/listResources.ts b/server/routers/resource/listResources.ts index a60d27e6..a9c4d88c 100644 --- a/server/routers/resource/listResources.ts +++ b/server/routers/resource/listResources.ts @@ -17,7 +17,18 @@ import { import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; -import { sql, eq, or, inArray, and, count, ilike } from "drizzle-orm"; +import { + sql, + eq, + or, + inArray, + and, + count, + ilike, + asc, + not, + isNull +} from "drizzle-orm"; import logger from "@server/logger"; import { fromZodError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; @@ -48,7 +59,7 @@ const listResourcesSchema = z.object({ .optional() .catch(undefined), authState: z - .enum(["protected", "not_protected"]) + .enum(["protected", "not_protected", "none"]) .optional() .catch(undefined) }); @@ -277,9 +288,63 @@ export async function listResources( conditions = and(conditions, eq(resources.enabled, enabled)); } + if (typeof authState !== "undefined") { + switch (authState) { + case "none": + conditions = and(conditions, eq(resources.http, false)); + break; + case "protected": + conditions = and( + conditions, + or( + eq(resources.sso, true), + eq(resources.emailWhitelistEnabled, true), + not(isNull(resourceHeaderAuth.headerAuthId)), + not(isNull(resourcePincode.pincodeId)), + not(isNull(resourcePassword.passwordId)) + ) + ); + break; + case "not_protected": + conditions = and( + conditions, + not(eq(resources.sso, true)), + not(eq(resources.emailWhitelistEnabled, true)), + isNull(resourceHeaderAuth.headerAuthId), + isNull(resourcePincode.pincodeId), + isNull(resourcePassword.passwordId) + ); + break; + } + } + const countQuery: any = db .select({ count: count() }) .from(resources) + .leftJoin( + resourcePassword, + eq(resourcePassword.resourceId, resources.resourceId) + ) + .leftJoin( + resourcePincode, + eq(resourcePincode.resourceId, resources.resourceId) + ) + .leftJoin( + resourceHeaderAuth, + eq(resourceHeaderAuth.resourceId, resources.resourceId) + ) + .leftJoin( + resourceHeaderAuthExtendedCompatibility, + eq( + resourceHeaderAuthExtendedCompatibility.resourceId, + resources.resourceId + ) + ) + .leftJoin(targets, eq(targets.resourceId, resources.resourceId)) + .leftJoin( + targetHealthCheck, + eq(targetHealthCheck.targetId, targets.targetId) + ) .where(conditions); const baseQuery = queryResourcesBase(); @@ -287,7 +352,8 @@ export async function listResources( const rows: JoinedRow[] = await baseQuery .where(conditions) .limit(pageSize) - .offset(pageSize * (page - 1)); + .offset(pageSize * (page - 1)) + .orderBy(asc(resources.resourceId)); // avoids TS issues with reduce/never[] const map = new Map(); diff --git a/src/components/ProxyResourcesTable.tsx b/src/components/ProxyResourcesTable.tsx index 20eabc4d..f57601b0 100644 --- a/src/components/ProxyResourcesTable.tsx +++ b/src/components/ProxyResourcesTable.tsx @@ -185,23 +185,24 @@ export default function ProxyResourcesTable({ }; async function toggleResourceEnabled(val: boolean, resourceId: number) { - await api - .post>( + try { + await api.post>( `resource/${resourceId}`, { enabled: val } - ) - .catch((e) => { - toast({ - variant: "destructive", - title: t("resourcesErrorUpdate"), - description: formatAxiosError( - e, - t("resourcesErrorUpdateDescription") - ) - }); + ); + router.refresh(); + } catch (e) { + toast({ + variant: "destructive", + title: t("resourcesErrorUpdate"), + description: formatAxiosError( + e, + t("resourcesErrorUpdateDescription") + ) }); + } } function TargetStatusCell({ targets }: { targets?: TargetHealth[] }) { @@ -313,38 +314,14 @@ export default function ProxyResourcesTable({ accessorKey: "name", enableHiding: false, friendlyName: t("name"), - header: ({ column }) => { - return ( - - ); - } + header: () => {t("name")} }, { id: "niceId", accessorKey: "nice", friendlyName: t("identifier"), enableHiding: true, - header: ({ column }) => { - return ( - - ); - }, + header: () => {t("identifier")}, cell: ({ row }) => { return {row.original.nice || "-"}; } @@ -370,19 +347,7 @@ export default function ProxyResourcesTable({ id: "status", accessorKey: "status", friendlyName: t("status"), - header: ({ column }) => { - return ( - - ); - }, + header: () => {t("status")}, cell: ({ row }) => { const resourceRow = row.original; return ; @@ -430,19 +395,23 @@ export default function ProxyResourcesTable({ { accessorKey: "authState", friendlyName: t("authentication"), - header: ({ column }) => { - return ( - - ); - }, + header: () => ( + + handleFilterChange("authState", value) + } + searchPlaceholder={t("searchPlaceholder")} + emptyMessage={t("emptySearchOptions")} + label={t("authentication")} + className="p-3" + /> + ), cell: ({ row }) => { const resourceRow = row.original; return ( @@ -487,16 +456,16 @@ export default function ProxyResourcesTable({ ), cell: ({ row }) => ( - toggleResourceEnabled(val, row.original.id) + startTransition(() => + toggleResourceEnabled(val, row.original.id) + ) } /> )