Initial commit: StackPilot Phase 1 (Core)

Self-hosted Docker Compose manager.
- Backend: FastAPI + docker-py + SQLite (JWT auth, file-first stacks,
  lifecycle, live status, WebSocket logs, docker-run converter, audit log)
- Frontend: React + Vite + Tailwind (login/setup, dashboard, stacks,
  stack detail, Monaco editor, dark/light theme)
- Deployment: docker-compose.yml, Dockerfiles, nginx reverse proxy

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
menzelj
2026-06-07 16:04:58 +00:00
co-authored by Claude Opus 4.8
commit f732cb080b
59 changed files with 3677 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
import { useState } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { stacksApi } from "@/api/stacks";
import { apiErrorMessage } from "@/api/client";
export function useStackActions() {
const qc = useQueryClient();
const [busyId, setBusyId] = useState<string | null>(null);
const run = async (
id: string,
label: string,
fn: (id: string) => Promise<unknown>
) => {
setBusyId(id);
const t = toast.loading(`${label} ${id}`);
try {
await fn(id);
toast.success(`${label} ${id}`, { id: t });
qc.invalidateQueries({ queryKey: ["stacks"] });
qc.invalidateQueries({ queryKey: ["stack", id] });
} catch (err) {
toast.error(apiErrorMessage(err), { id: t });
} finally {
setBusyId(null);
}
};
return {
busyId,
start: (id: string) => run(id, "Starting", stacksApi.start),
stop: (id: string) => run(id, "Stopping", stacksApi.stop),
restart: (id: string) => run(id, "Restarting", stacksApi.restart),
pull: (id: string) => run(id, "Pulling", stacksApi.pull),
updateImages: (id: string) => run(id, "Updating", stacksApi.update_images),
down: (id: string) => run(id, "Tearing down", stacksApi.down),
};
}