mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-07 07:23:22 +00:00
Added support for the new agent mechanism and Binary
Added bullMQ + redis to the platform for automation and queue mechanism Added new tabs in host details
This commit is contained in:
@@ -1,20 +1,17 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
Activity,
|
||||
AlertCircle,
|
||||
ArrowDown,
|
||||
ArrowUp,
|
||||
ArrowUpDown,
|
||||
Bot,
|
||||
CheckCircle,
|
||||
Clock,
|
||||
Play,
|
||||
RefreshCw,
|
||||
Settings,
|
||||
XCircle,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import api from "../utils/api";
|
||||
|
||||
const Automation = () => {
|
||||
@@ -33,7 +30,7 @@ const Automation = () => {
|
||||
});
|
||||
|
||||
// Fetch queue statistics
|
||||
const { data: queueStats, isLoading: statsLoading } = useQuery({
|
||||
useQuery({
|
||||
queryKey: ["automation-stats"],
|
||||
queryFn: async () => {
|
||||
const response = await api.get("/automation/stats");
|
||||
@@ -43,7 +40,7 @@ const Automation = () => {
|
||||
});
|
||||
|
||||
// Fetch recent jobs
|
||||
const { data: recentJobs, isLoading: jobsLoading } = useQuery({
|
||||
useQuery({
|
||||
queryKey: ["automation-jobs"],
|
||||
queryFn: async () => {
|
||||
const jobs = await Promise.all([
|
||||
@@ -62,7 +59,7 @@ const Automation = () => {
|
||||
refetchInterval: 30000,
|
||||
});
|
||||
|
||||
const getStatusIcon = (status) => {
|
||||
const _getStatusIcon = (status) => {
|
||||
switch (status) {
|
||||
case "completed":
|
||||
return <CheckCircle className="h-4 w-4 text-green-500" />;
|
||||
@@ -75,7 +72,7 @@ const Automation = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
const _getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case "completed":
|
||||
return "bg-green-100 text-green-800";
|
||||
@@ -88,12 +85,12 @@ const Automation = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateString) => {
|
||||
const _formatDate = (dateString) => {
|
||||
if (!dateString) return "N/A";
|
||||
return new Date(dateString).toLocaleString();
|
||||
};
|
||||
|
||||
const formatDuration = (ms) => {
|
||||
const _formatDuration = (ms) => {
|
||||
if (!ms) return "N/A";
|
||||
return `${ms}ms`;
|
||||
};
|
||||
@@ -127,7 +124,7 @@ const Automation = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getNextRunTime = (schedule, lastRun) => {
|
||||
const getNextRunTime = (schedule, _lastRun) => {
|
||||
if (schedule === "Manual only") return "Manual trigger only";
|
||||
if (schedule === "Daily at midnight") {
|
||||
const now = new Date();
|
||||
@@ -198,6 +195,19 @@ const Automation = () => {
|
||||
return Number.MAX_SAFE_INTEGER; // Unknown schedules go to bottom
|
||||
};
|
||||
|
||||
const openBullBoard = () => {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) {
|
||||
alert("Please log in to access the Queue Monitor");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the proxied URL through the frontend (port 3000)
|
||||
// This avoids CORS issues as everything goes through the same origin
|
||||
const url = `/admin/queues?token=${encodeURIComponent(token)}`;
|
||||
window.open(url, "_blank", "width=1200,height=800");
|
||||
};
|
||||
|
||||
const triggerManualJob = async (jobType, data = {}) => {
|
||||
try {
|
||||
let endpoint;
|
||||
@@ -206,13 +216,11 @@ const Automation = () => {
|
||||
endpoint = "/automation/trigger/github-update";
|
||||
} else if (jobType === "sessions") {
|
||||
endpoint = "/automation/trigger/session-cleanup";
|
||||
} else if (jobType === "echo") {
|
||||
endpoint = "/automation/trigger/echo-hello";
|
||||
} else if (jobType === "orphaned-repos") {
|
||||
endpoint = "/automation/trigger/orphaned-repo-cleanup";
|
||||
}
|
||||
|
||||
const response = await api.post(endpoint, data);
|
||||
const _response = await api.post(endpoint, data);
|
||||
|
||||
// Refresh data
|
||||
window.location.reload();
|
||||
@@ -303,34 +311,40 @@ const Automation = () => {
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => triggerManualJob("github")}
|
||||
onClick={openBullBoard}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
title="Trigger manual GitHub update check"
|
||||
title="Open Bull Board Queue Monitor"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
Check Updates
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => triggerManualJob("sessions")}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
title="Trigger manual session cleanup"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
Clean Sessions
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
triggerManualJob("echo", {
|
||||
message: "Hello from Automation Page!",
|
||||
})
|
||||
}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
title="Trigger echo hello task"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
Echo Hello
|
||||
<svg
|
||||
className="h-4 w-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 36 36"
|
||||
role="img"
|
||||
aria-label="Bull Board"
|
||||
>
|
||||
<circle fill="#DD2E44" cx="18" cy="18" r="18" />
|
||||
<circle fill="#FFF" cx="18" cy="18" r="13.5" />
|
||||
<circle fill="#DD2E44" cx="18" cy="18" r="10" />
|
||||
<circle fill="#FFF" cx="18" cy="18" r="6" />
|
||||
<circle fill="#DD2E44" cx="18" cy="18" r="3" />
|
||||
<path
|
||||
opacity=".2"
|
||||
d="M18.24 18.282l13.144 11.754s-2.647 3.376-7.89 5.109L17.579 18.42l.661-.138z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFAC33"
|
||||
d="M18.294 19a.994.994 0 01-.704-1.699l.563-.563a.995.995 0 011.408 1.407l-.564.563a.987.987 0 01-.703.292z"
|
||||
/>
|
||||
<path
|
||||
fill="#55ACEE"
|
||||
d="M24.016 6.981c-.403 2.079 0 4.691 0 4.691l7.054-7.388c.291-1.454-.528-3.932-1.718-4.238-1.19-.306-4.079.803-5.336 6.935zm5.003 5.003c-2.079.403-4.691 0-4.691 0l7.388-7.054c1.454-.291 3.932.528 4.238 1.718.306 1.19-.803 4.079-6.935 5.336z"
|
||||
/>
|
||||
<path
|
||||
fill="#3A87C2"
|
||||
d="M32.798 4.485L21.176 17.587c-.362.362-1.673.882-2.51.046-.836-.836-.419-2.08-.057-2.443L31.815 3.501s.676-.635 1.159-.152-.176 1.136-.176 1.136z"
|
||||
/>
|
||||
</svg>
|
||||
Queue Monitor
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -509,10 +523,6 @@ const Automation = () => {
|
||||
triggerManualJob("github");
|
||||
} else if (automation.queue.includes("session")) {
|
||||
triggerManualJob("sessions");
|
||||
} else if (automation.queue.includes("echo")) {
|
||||
triggerManualJob("echo", {
|
||||
message: "Manual trigger from table",
|
||||
});
|
||||
} else if (
|
||||
automation.queue.includes("orphaned-repo")
|
||||
) {
|
||||
@@ -525,20 +535,7 @@ const Automation = () => {
|
||||
<Play className="h-3 w-3" />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (automation.queue.includes("echo")) {
|
||||
triggerManualJob("echo", {
|
||||
message: "Manual trigger from table",
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="inline-flex items-center justify-center w-6 h-6 border border-transparent rounded text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition-colors duration-200"
|
||||
title="Trigger"
|
||||
>
|
||||
<Play className="h-3 w-3" />
|
||||
</button>
|
||||
<span className="text-gray-400 text-xs">Manual</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-2 whitespace-nowrap">
|
||||
|
||||
Reference in New Issue
Block a user