mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 18:29:07 +00:00
move resource type filter to backend
This commit is contained in:
@@ -59,7 +59,16 @@ export const registerPamResourceRouter = async (server: FastifyZodProvider) => {
|
|||||||
limit: z.coerce.number().min(1).max(100).default(100),
|
limit: z.coerce.number().min(1).max(100).default(100),
|
||||||
orderBy: z.nativeEnum(PamResourceOrderBy).default(PamResourceOrderBy.Name),
|
orderBy: z.nativeEnum(PamResourceOrderBy).default(PamResourceOrderBy.Name),
|
||||||
orderDirection: z.nativeEnum(OrderByDirection).default(OrderByDirection.ASC),
|
orderDirection: z.nativeEnum(OrderByDirection).default(OrderByDirection.ASC),
|
||||||
search: z.string().trim().optional()
|
search: z.string().trim().optional(),
|
||||||
|
filterResourceTypes: z
|
||||||
|
.string()
|
||||||
|
.transform((val) =>
|
||||||
|
val
|
||||||
|
.split(",")
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -70,7 +79,7 @@ export const registerPamResourceRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { projectId, limit, offset, search, orderBy, orderDirection } = req.query;
|
const { projectId, limit, offset, search, orderBy, orderDirection, filterResourceTypes } = req.query;
|
||||||
|
|
||||||
const { resources, totalCount } = await server.services.pamResource.list({
|
const { resources, totalCount } = await server.services.pamResource.list({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -82,7 +91,8 @@ export const registerPamResourceRouter = async (server: FastifyZodProvider) => {
|
|||||||
offset,
|
offset,
|
||||||
search,
|
search,
|
||||||
orderBy,
|
orderBy,
|
||||||
orderDirection
|
orderDirection,
|
||||||
|
filterResourceTypes
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export const pamResourceDALFactory = (db: TDbClient) => {
|
|||||||
limit,
|
limit,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
orderBy = PamResourceOrderBy.Name,
|
orderBy = PamResourceOrderBy.Name,
|
||||||
orderDirection = OrderByDirection.ASC
|
orderDirection = OrderByDirection.ASC,
|
||||||
|
filterResourceTypes
|
||||||
}: {
|
}: {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
search?: string;
|
search?: string;
|
||||||
@@ -39,6 +40,7 @@ export const pamResourceDALFactory = (db: TDbClient) => {
|
|||||||
offset?: number;
|
offset?: number;
|
||||||
orderBy?: PamResourceOrderBy;
|
orderBy?: PamResourceOrderBy;
|
||||||
orderDirection?: OrderByDirection;
|
orderDirection?: OrderByDirection;
|
||||||
|
filterResourceTypes?: string[];
|
||||||
},
|
},
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
@@ -57,6 +59,10 @@ export const pamResourceDALFactory = (db: TDbClient) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filterResourceTypes && filterResourceTypes.length) {
|
||||||
|
void query.whereIn(`${TableName.PamResource}.resourceType`, filterResourceTypes);
|
||||||
|
}
|
||||||
|
|
||||||
const countQuery = query.clone().count("*", { as: "count" }).first();
|
const countQuery = query.clone().count("*", { as: "count" }).first();
|
||||||
|
|
||||||
void query.select(selectAllTableCols(TableName.PamResource));
|
void query.select(selectAllTableCols(TableName.PamResource));
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export const useListPamResources = (
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
placeholderData: (prev) => prev,
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export type TListPamResourcesDTO = {
|
|||||||
orderBy?: PamResourceOrderBy;
|
orderBy?: PamResourceOrderBy;
|
||||||
orderDirection?: OrderByDirection;
|
orderDirection?: OrderByDirection;
|
||||||
search?: string;
|
search?: string;
|
||||||
|
filterResourceTypes?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreatePamResourceDTO = Pick<
|
export type TCreatePamResourceDTO = Pick<
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ import { PamDeleteResourceModal } from "./PamDeleteResourceModal";
|
|||||||
import { PamResourceRow } from "./PamResourceRow";
|
import { PamResourceRow } from "./PamResourceRow";
|
||||||
import { PamUpdateResourceModal } from "./PamUpdateResourceModal";
|
import { PamUpdateResourceModal } from "./PamUpdateResourceModal";
|
||||||
|
|
||||||
type Filters = {
|
type PamResourceFilter = {
|
||||||
resourceType: PamResourceType[];
|
resourceTypes: PamResourceType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -80,8 +80,8 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
from: ROUTE_PATHS.Pam.ResourcesPage.id
|
from: ROUTE_PATHS.Pam.ResourcesPage.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const [filters, setFilters] = useState<Filters>({
|
const [filter, setFilter] = useState<PamResourceFilter>({
|
||||||
resourceType: []
|
resourceTypes: []
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -114,7 +114,8 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
limit: perPage,
|
limit: perPage,
|
||||||
search: debouncedSearch,
|
search: debouncedSearch,
|
||||||
orderBy,
|
orderBy,
|
||||||
orderDirection
|
orderDirection,
|
||||||
|
filterResourceTypes: filter.resourceTypes.length ? filter.resourceTypes.join(",") : undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
const resources = data?.resources || [];
|
const resources = data?.resources || [];
|
||||||
@@ -125,7 +126,7 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
resources.filter((resource) => {
|
resources.filter((resource) => {
|
||||||
const { name, resourceType } = resource;
|
const { name, resourceType } = resource;
|
||||||
|
|
||||||
if (filters.resourceType.length && !filters.resourceType.includes(resourceType)) {
|
if (filter.resourceTypes.length && !filter.resourceTypes.includes(resourceType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +137,7 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
resourceType.toLowerCase().includes(searchValue)
|
resourceType.toLowerCase().includes(searchValue)
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
[resources, search, filters]
|
[resources, search, filter]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSort = (column: PamResourceOrderBy) => {
|
const handleSort = (column: PamResourceOrderBy) => {
|
||||||
@@ -155,7 +156,7 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
const getColSortIcon = (col: PamResourceOrderBy) =>
|
const getColSortIcon = (col: PamResourceOrderBy) =>
|
||||||
orderDirection === OrderByDirection.DESC && orderBy === col ? faArrowUp : faArrowDown;
|
orderDirection === OrderByDirection.DESC && orderBy === col ? faArrowUp : faArrowDown;
|
||||||
|
|
||||||
const isTableFiltered = Boolean(filters.resourceType.length);
|
const isTableFiltered = Boolean(filter.resourceTypes.length);
|
||||||
const isContentEmpty = !filteredResources.length;
|
const isContentEmpty = !filteredResources.length;
|
||||||
const isSearchEmpty = isContentEmpty && (Boolean(search) || isTableFiltered);
|
const isSearchEmpty = isContentEmpty && (Boolean(search) || isTableFiltered);
|
||||||
|
|
||||||
@@ -192,43 +193,38 @@ export const PamResourcesTable = ({ projectId }: Props) => {
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="max-h-[70vh] thin-scrollbar overflow-y-auto" align="end">
|
<DropdownMenuContent className="max-h-[70vh] thin-scrollbar overflow-y-auto" align="end">
|
||||||
<DropdownMenuLabel>Resource Type</DropdownMenuLabel>
|
<DropdownMenuLabel>Resource Type</DropdownMenuLabel>
|
||||||
{resources.length ? (
|
{Object.entries(PAM_RESOURCE_TYPE_MAP).map(([type, { name, image }]) => {
|
||||||
[...new Set(resources.map(({ resourceType }) => resourceType))].map((type) => {
|
const resourceType = type as PamResourceType;
|
||||||
const { name, image } = PAM_RESOURCE_TYPE_MAP[type];
|
return (
|
||||||
|
<DropdownMenuItem
|
||||||
return (
|
onClick={(e) => {
|
||||||
<DropdownMenuItem
|
e.preventDefault();
|
||||||
onClick={(e) => {
|
setFilter((prev) => ({
|
||||||
e.preventDefault();
|
...prev,
|
||||||
setFilters((prev) => ({
|
resourceTypes: prev.resourceTypes.includes(resourceType)
|
||||||
...prev,
|
? prev.resourceTypes.filter((a) => a !== resourceType)
|
||||||
resourceType: prev.resourceType.includes(type)
|
: [...prev.resourceTypes, resourceType]
|
||||||
? prev.resourceType.filter((a) => a !== type)
|
}));
|
||||||
: [...prev.resourceType, type]
|
}}
|
||||||
}));
|
key={resourceType}
|
||||||
}}
|
icon={
|
||||||
key={type}
|
filter.resourceTypes.includes(resourceType) && (
|
||||||
icon={
|
<FontAwesomeIcon className="text-primary" icon={faCheckCircle} />
|
||||||
filters.resourceType.includes(type) && (
|
)
|
||||||
<FontAwesomeIcon className="text-primary" icon={faCheckCircle} />
|
}
|
||||||
)
|
iconPos="right"
|
||||||
}
|
>
|
||||||
iconPos="right"
|
<div className="flex items-center gap-2">
|
||||||
>
|
<img
|
||||||
<div className="flex items-center gap-2">
|
alt={`${name} resource type`}
|
||||||
<img
|
src={`/images/integrations/${image}`}
|
||||||
alt={`${name} resource type`}
|
className="h-4 w-4"
|
||||||
src={`/images/integrations/${image}`}
|
/>
|
||||||
className="h-4 w-4"
|
<span>{name}</span>
|
||||||
/>
|
</div>
|
||||||
<span>{name}</span>
|
</DropdownMenuItem>
|
||||||
</div>
|
);
|
||||||
</DropdownMenuItem>
|
})}
|
||||||
);
|
|
||||||
})
|
|
||||||
) : (
|
|
||||||
<DropdownMenuItem isDisabled>No Resources</DropdownMenuItem>
|
|
||||||
)}
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
<OrgPermissionCan
|
<OrgPermissionCan
|
||||||
|
|||||||
Reference in New Issue
Block a user