feat: orphan stack detection/deletion, filebrowser infra, setup scripts
- Add orphan detection: stacks not in catalog marked as "Elavult"
- Add DELETE /api/stacks/{name} endpoint with HDD data handling
- Add GET /api/stacks/{name}/hdd-data endpoint
- Add delete confirmation modal with HDD data checkbox (Hungarian UI)
- Add filebrowser to protected stacks list
- Add scripts/hdd-setup.sh and scripts/docker-setup.sh for node setup
- Hide "Frissítés" and "Részletek" buttons for orphaned stacks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,14 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
case hasSuffix(path, "/logs") && req.Method == http.MethodGet:
|
||||
r.getStackLogs(w, req, extractName(path, "/logs"))
|
||||
|
||||
// GET /api/stacks/{name}/hdd-data
|
||||
case hasSuffix(path, "/hdd-data") && req.Method == http.MethodGet:
|
||||
r.getStackHDDData(w, req, extractName(path, "/hdd-data"))
|
||||
|
||||
// DELETE /api/stacks/{name}
|
||||
case strings.HasPrefix(path, "/stacks/") && req.Method == http.MethodDelete && !hasSubpath(path, "/stacks/"):
|
||||
r.deleteStack(w, req, trimSegment(path, "/stacks/"))
|
||||
|
||||
// POST /api/sync — trigger immediate catalog sync
|
||||
case path == "/sync" && req.Method == http.MethodPost:
|
||||
r.triggerSync(w, req)
|
||||
@@ -250,6 +258,45 @@ func (r *Router) getStackLogs(w http.ResponseWriter, req *http.Request, name str
|
||||
writeJSON(w, http.StatusOK, apiResponse{OK: true, Data: map[string]string{"logs": output}})
|
||||
}
|
||||
|
||||
func (r *Router) getStackHDDData(w http.ResponseWriter, _ *http.Request, name string) {
|
||||
resp, err := r.stackMgr.GetStackHDDData(name)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusNotFound, apiResponse{OK: false, Error: err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, apiResponse{OK: true, Data: resp})
|
||||
}
|
||||
|
||||
func (r *Router) deleteStack(w http.ResponseWriter, req *http.Request, name string) {
|
||||
r.logger.Printf("[API] Delete requested for stack: %s", name)
|
||||
|
||||
var body struct {
|
||||
RemoveHDDData bool `json:"remove_hdd_data"`
|
||||
}
|
||||
if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
|
||||
body.RemoveHDDData = false
|
||||
}
|
||||
|
||||
resp, err := r.stackMgr.DeleteStack(name, body.RemoveHDDData)
|
||||
if err != nil {
|
||||
r.logger.Printf("[API] Delete failed for %s: %v", name, err)
|
||||
status := http.StatusInternalServerError
|
||||
if strings.Contains(err.Error(), "protected") {
|
||||
status = http.StatusForbidden
|
||||
}
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
status = http.StatusNotFound
|
||||
}
|
||||
if strings.Contains(err.Error(), "not orphaned") || strings.Contains(err.Error(), "still running") {
|
||||
status = http.StatusConflict
|
||||
}
|
||||
writeJSON(w, status, apiResponse{OK: false, Error: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, apiResponse{OK: true, Data: resp, Message: "Stack " + name + " deleted"})
|
||||
}
|
||||
|
||||
func (r *Router) triggerSync(w http.ResponseWriter, _ *http.Request) {
|
||||
r.logger.Println("[API] Manual catalog sync requested")
|
||||
result := r.syncer.TriggerSync()
|
||||
|
||||
Reference in New Issue
Block a user