Feat: persist project tree hierarchy

This commit is contained in:
MangoPig
2026-06-24 01:28:50 +01:00
parent 5b9e14b442
commit 5758074f6f
9 changed files with 489 additions and 111 deletions
@@ -79,6 +79,68 @@ func (routes apiRoutes) handleCreateProjectFolder(w http.ResponseWriter, r *http
})
}
func (routes apiRoutes) handleProjectTreeFolders(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Project ID is required.")
return
}
folders, err := routes.bootstrapService().GetProjectTreeFolders(r.Context(), projectID)
if err != nil {
routes.writeProjectFolderError(w, r, err)
return
}
WriteJSON(w, http.StatusOK, map[string]any{
"data": map[string]any{
"projectId": projectID,
"folders": folders,
},
"meta": map[string]any{
"resource": "project-tree-folders",
},
})
}
func (routes apiRoutes) handleCreateProjectTreeFolder(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Project ID is required.")
return
}
payload, ok := decodeProjectFolderRequest(w, r)
if !ok {
return
}
payload.Name = strings.TrimSpace(payload.Name)
payload.ParentFolderID = strings.TrimSpace(payload.ParentFolderID)
if payload.Name == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Folder name is required.")
return
}
result, err := routes.bootstrapService().CreateProjectTreeFolder(r.Context(), bootstrapservice.CreateProjectFolderInput{
ProjectID: projectID,
ParentFolderID: payload.ParentFolderID,
Name: payload.Name,
})
if err != nil {
routes.writeProjectFolderError(w, r, err)
return
}
WriteJSON(w, http.StatusCreated, map[string]any{
"data": result,
"meta": map[string]any{
"resource": "project-tree-folder-create",
"persisted": true,
},
})
}
func (routes apiRoutes) writeProjectFolderError(w http.ResponseWriter, r *http.Request, err error) {
switch {
case errors.Is(err, bootstrapservice.ErrProjectNotFound), errors.Is(err, bootstrapservice.ErrProjectFolderNotFound):
+2
View File
@@ -36,6 +36,8 @@ func (routes apiRoutes) Register(router chi.Router) {
apiRouter.Route("/projects/{projectId}", func(projectRouter chi.Router) {
projectRouter.Get("/folders", routes.handleProjectFolders)
projectRouter.Post("/folders", routes.handleCreateProjectFolder)
projectRouter.Get("/tree/folders", routes.handleProjectTreeFolders)
projectRouter.Post("/tree/folders", routes.handleCreateProjectTreeFolder)
})
if routes.cfg.Config.IsDevelopment() {