Merge dev into main #19
@@ -10,15 +10,96 @@ router = APIRouter()
|
|||||||
client = docker.DockerClient(base_url=DOCKER_HOST, timeout=5)
|
client = docker.DockerClient(base_url=DOCKER_HOST, timeout=5)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_cc_connect_container():
|
||||||
|
matches = client.containers.list(all=True, filters={"name": "cc-connect"})
|
||||||
|
return matches[0] if matches else None
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/start")
|
||||||
|
def start_cc_connect():
|
||||||
|
try:
|
||||||
|
container = _get_cc_connect_container()
|
||||||
|
except Exception as exc:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": None,
|
||||||
|
"error": f"docker check failed: {exc}",
|
||||||
|
}
|
||||||
|
|
||||||
|
if not container:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": "not_found",
|
||||||
|
"error": "cc-connect container not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
container.start()
|
||||||
|
container.reload()
|
||||||
|
container_status = container.status
|
||||||
|
return {
|
||||||
|
"ok": container_status == "running",
|
||||||
|
"status": "up" if container_status == "running" else "down",
|
||||||
|
"container_status": container_status,
|
||||||
|
"error": None if container_status == "running" else "cc-connect failed to start",
|
||||||
|
}
|
||||||
|
except Exception as exc:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": container.status,
|
||||||
|
"error": f"docker start failed: {exc}",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/stop")
|
||||||
|
def stop_cc_connect():
|
||||||
|
try:
|
||||||
|
container = _get_cc_connect_container()
|
||||||
|
except Exception as exc:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": None,
|
||||||
|
"error": f"docker check failed: {exc}",
|
||||||
|
}
|
||||||
|
|
||||||
|
if not container:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": "not_found",
|
||||||
|
"error": "cc-connect container not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
container.stop()
|
||||||
|
container.reload()
|
||||||
|
container_status = container.status
|
||||||
|
return {
|
||||||
|
"ok": container_status != "running",
|
||||||
|
"status": "down",
|
||||||
|
"container_status": container_status,
|
||||||
|
"error": None if container_status != "running" else "cc-connect failed to stop",
|
||||||
|
}
|
||||||
|
except Exception as exc:
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"status": "down",
|
||||||
|
"container_status": container.status,
|
||||||
|
"error": f"docker stop failed: {exc}",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/health")
|
@router.get("/health")
|
||||||
async def cc_connect_health():
|
async def cc_connect_health():
|
||||||
url = (CC_CONNECT_URL or "").strip()
|
url = (CC_CONNECT_URL or "").strip()
|
||||||
|
|
||||||
container = None
|
container = None
|
||||||
try:
|
try:
|
||||||
matches = client.containers.list(all=True, filters={"name": "cc-connect"})
|
container = _get_cc_connect_container()
|
||||||
if matches:
|
|
||||||
container = matches[0]
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return {
|
return {
|
||||||
"ok": False,
|
"ok": False,
|
||||||
|
|||||||
@@ -147,6 +147,14 @@ export function getCcConnectHealth() {
|
|||||||
return get("/cc-connect/health");
|
return get("/cc-connect/health");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function startCcConnect() {
|
||||||
|
return post("/cc-connect/start");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopCcConnect() {
|
||||||
|
return post("/cc-connect/stop");
|
||||||
|
}
|
||||||
|
|
||||||
export function getInfoEngineItems(params = {}) {
|
export function getInfoEngineItems(params = {}) {
|
||||||
const query = new URLSearchParams();
|
const query = new URLSearchParams();
|
||||||
if (params.limit !== undefined) query.set("limit", String(params.limit));
|
if (params.limit !== undefined) query.set("limit", String(params.limit));
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { getCcConnectHealth } from "../lib/api.js";
|
import { getCcConnectHealth, startCcConnect, stopCcConnect } from "../lib/api.js";
|
||||||
|
|
||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let health = $state(null);
|
let health = $state(null);
|
||||||
let requestError = $state("");
|
let requestError = $state("");
|
||||||
|
let actionLoading = $state("");
|
||||||
|
|
||||||
async function loadHealth() {
|
async function loadHealth() {
|
||||||
loading = true;
|
loading = true;
|
||||||
@@ -19,6 +20,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runAction(action) {
|
||||||
|
actionLoading = action;
|
||||||
|
requestError = "";
|
||||||
|
try {
|
||||||
|
const result = action === "start" ? await startCcConnect() : await stopCcConnect();
|
||||||
|
if (!result?.ok) {
|
||||||
|
requestError = result?.error || `Failed to ${action} cc-connect`;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
requestError = e?.body?.detail || e?.message || `Failed to ${action} cc-connect`;
|
||||||
|
} finally {
|
||||||
|
actionLoading = "";
|
||||||
|
await loadHealth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function statusBadgeClass(status) {
|
function statusBadgeClass(status) {
|
||||||
if (status === "up") {
|
if (status === "up") {
|
||||||
return "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300";
|
return "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300";
|
||||||
@@ -43,14 +60,33 @@
|
|||||||
<span class="px-2 py-0.5 rounded-full bg-rose-100 text-rose-700 dark:bg-rose-900/40 dark:text-rose-300">down</span>
|
<span class="px-2 py-0.5 rounded-full bg-rose-100 text-rose-700 dark:bg-rose-900/40 dark:text-rose-300">down</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button onclick={loadHealth} disabled={loading} class="px-3 py-1.5 text-xs font-medium text-primary-600 bg-primary-50 hover:bg-primary-100 rounded-lg transition-colors disabled:opacity-50 dark:bg-primary-900/30 dark:text-primary-300">
|
<div class="flex items-center gap-2">
|
||||||
{loading ? "Loading..." : "Refresh"}
|
{#if health?.container_status === "running"}
|
||||||
</button>
|
<button
|
||||||
|
onclick={() => runAction("stop")}
|
||||||
|
disabled={loading || actionLoading === "stop"}
|
||||||
|
class="px-3 py-1.5 text-xs font-medium text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-colors disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{actionLoading === "stop" ? "Stopping..." : "Stop"}
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
onclick={() => runAction("start")}
|
||||||
|
disabled={loading || actionLoading === "start"}
|
||||||
|
class="px-3 py-1.5 text-xs font-medium text-emerald-600 bg-emerald-50 hover:bg-emerald-100 rounded-lg transition-colors disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{actionLoading === "start" ? "Starting..." : "Start"}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
<button onclick={loadHealth} disabled={loading || Boolean(actionLoading)} class="px-3 py-1.5 text-xs font-medium text-primary-600 bg-primary-50 hover:bg-primary-100 rounded-lg transition-colors disabled:opacity-50 dark:bg-primary-900/30 dark:text-primary-300">
|
||||||
|
{loading ? "Loading..." : "Refresh"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if requestError}
|
{#if requestError}
|
||||||
<div class="bg-rose-50 dark:bg-rose-900/20 border border-rose-200 dark:border-rose-700 rounded-xl p-4 shadow-sm">
|
<div class="bg-rose-50 dark:bg-rose-900/20 border border-rose-200 dark:border-rose-700 rounded-xl p-4 shadow-sm">
|
||||||
<p class="text-sm font-medium text-rose-700 dark:text-rose-300">Failed to fetch cc-connect health</p>
|
<p class="text-sm font-medium text-rose-700 dark:text-rose-300">cc-connect action failed</p>
|
||||||
<p class="text-xs text-rose-600 dark:text-rose-400 mt-1">{requestError}</p>
|
<p class="text-xs text-rose-600 dark:text-rose-400 mt-1">{requestError}</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user