diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index 97317c62e..63941a3f4 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -680,7 +680,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/folders/project-environments", + url: "/:workspaceId/folders/environment-folder-tree", config: { rateLimit: readLimit }, diff --git a/backend/src/services/secret-folder/secret-folder-fns.ts b/backend/src/services/secret-folder/secret-folder-fns.ts new file mode 100644 index 000000000..a3783a1b9 --- /dev/null +++ b/backend/src/services/secret-folder/secret-folder-fns.ts @@ -0,0 +1,17 @@ +import { TSecretFolders } from "@app/db/schemas"; +import { InternalServerError } from "@app/lib/errors"; + +export const buildFolderPath = ( + folder: TSecretFolders, + foldersMap: Record, + depth: number = 0 +): string => { + if (depth > 20) { + throw new InternalServerError({ message: "Maximum folder depth of 20 exceeded" }); + } + if (!folder.parentId) { + return depth === 0 ? "/" : ""; + } + + return `${buildFolderPath(foldersMap[folder.parentId], foldersMap, depth + 1)}/${folder.name}`; +}; diff --git a/backend/src/services/secret-folder/secret-folder-service.ts b/backend/src/services/secret-folder/secret-folder-service.ts index 1cc275cad..7afbb290f 100644 --- a/backend/src/services/secret-folder/secret-folder-service.ts +++ b/backend/src/services/secret-folder/secret-folder-service.ts @@ -2,12 +2,13 @@ import { ForbiddenError, subject } from "@casl/ability"; import path from "path"; import { v4 as uuidv4, validate as uuidValidate } from "uuid"; -import { ActionProjectType, TSecretFolders, TSecretFoldersInsert } from "@app/db/schemas"; +import { ActionProjectType, TSecretFoldersInsert } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { OrderByDirection, OrgServiceActor } from "@app/lib/types"; +import { buildFolderPath } from "@app/services/secret-folder/secret-folder-fns"; import { TProjectDALFactory } from "../project/project-dal"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; @@ -608,14 +609,7 @@ export const secretFolderServiceFactory = ({ const foldersWithPath = relevantFolders.map((folder) => ({ ...folder, - path: folder.parentId - ? (function buildPath(f: TSecretFolders): string { - if (!f.parentId) { - return ""; - } - return `${buildPath(foldersMap[f.parentId])}/${f.name}`; - })(folder) - : "/" + path: buildFolderPath(folder, foldersMap) })); return [env.slug, { ...env, folders: foldersWithPath }]; diff --git a/frontend/src/components/permissions/AccessTree/AccessTree.tsx b/frontend/src/components/permissions/AccessTree/AccessTree.tsx index adc2d8868..609a39c4b 100644 --- a/frontend/src/components/permissions/AccessTree/AccessTree.tsx +++ b/frontend/src/components/permissions/AccessTree/AccessTree.tsx @@ -29,8 +29,6 @@ import { useAccessTree } from "./hooks"; import { FolderNode, RoleNode } from "./nodes"; import { ViewMode } from "./types"; -import "@xyflow/react/dist/style.css"; - export type AccessTreeProps = { permissions: MongoAbility; }; @@ -63,7 +61,7 @@ const AccessTreeContent = ({ permissions }: AccessTreeProps) => { duration: 1000, maxZoom: 1 }); - }, 5); + }, 1); }, [fitView, nodes, edges, getViewport()]); const handleToggleModalView = () => diff --git a/frontend/src/components/permissions/AccessTree/hooks/index.ts b/frontend/src/components/permissions/AccessTree/hooks/index.ts index 7de33cb14..5d843909e 100644 --- a/frontend/src/components/permissions/AccessTree/hooks/index.ts +++ b/frontend/src/components/permissions/AccessTree/hooks/index.ts @@ -22,7 +22,7 @@ export const useAccessTree = (permissions: MongoAbility([]); const [edges, setEdges] = useEdgesState([]); const [subject, setSubject] = useState(ProjectPermissionSub.Secrets); - const [environment, setEnvironment] = useState(currentWorkspace.environments[0].slug); + const [environment, setEnvironment] = useState(currentWorkspace.environments[0]?.slug ?? ""); const { data: environmentsFolders, isPending } = useListProjectEnvironmentsFolders( currentWorkspace.id ); diff --git a/frontend/src/components/permissions/AccessTree/nodes/FolderNode/FolderNode.tsx b/frontend/src/components/permissions/AccessTree/nodes/FolderNode/FolderNode.tsx index 2b049fc04..0c680264e 100644 --- a/frontend/src/components/permissions/AccessTree/nodes/FolderNode/FolderNode.tsx +++ b/frontend/src/components/permissions/AccessTree/nodes/FolderNode/FolderNode.tsx @@ -48,6 +48,7 @@ export const FolderNode = ({ return ( when: {Object.entries(rule.conditions).map(([key, condition]) => ( -
    +
      {Object.entries(condition as object).map(([operator, value]) => ( -
    • +
    • {camelCaseToSpaces(key)} {" "} diff --git a/frontend/src/components/permissions/AccessTree/utils/createFolderNode.ts b/frontend/src/components/permissions/AccessTree/utils/createFolderNode.ts index 58764d5f7..9ccbfc604 100644 --- a/frontend/src/components/permissions/AccessTree/utils/createFolderNode.ts +++ b/frontend/src/components/permissions/AccessTree/utils/createFolderNode.ts @@ -150,7 +150,7 @@ export const createFolderNode = ({ }) ); - let height = 84; + let height: number; switch (subject) { case ProjectPermissionSub.DynamicSecrets: diff --git a/frontend/src/hooks/api/secretFolders/queries.tsx b/frontend/src/hooks/api/secretFolders/queries.tsx index afc71434d..44fa22759 100644 --- a/frontend/src/hooks/api/secretFolders/queries.tsx +++ b/frontend/src/hooks/api/secretFolders/queries.tsx @@ -56,7 +56,7 @@ export const useListProjectEnvironmentsFolders = ( queryKey: folderQueryKeys.getProjectEnvironmentsFolders(projectId), queryFn: async () => { const { data } = await apiRequest.get( - `/api/v1/workspace/${projectId}/folders/project-environments` + `/api/v1/workspace/${projectId}/folders/environment-folder-tree` ); return data; }, diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index e2114636e..088d28250 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -10,6 +10,7 @@ import { NotFoundPage } from "./pages/public/NotFoundPage/NotFoundPage"; // Import the generated route tree import { routeTree } from "./routeTree.gen"; +import "@xyflow/react/dist/style.css"; import "nprogress/nprogress.css"; import "react-toastify/dist/ReactToastify.css"; import "@fortawesome/fontawesome-svg-core/styles.css";