diff --git a/client/src/Pages/Logs/TabQueue.tsx b/client/src/Pages/Logs/TabQueue.tsx index a39250be0..bb3aac368 100644 --- a/client/src/Pages/Logs/TabQueue.tsx +++ b/client/src/Pages/Logs/TabQueue.tsx @@ -2,7 +2,7 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import { TableJobs, TableFailedJobs } from "./components/TableJobs"; - +import { TableWorkers } from "./components/TableWorkers"; import { useTheme } from "@mui/material"; import { useTranslation, Trans } from "react-i18next"; import { useGet, usePost } from "@/Hooks/UseApi"; @@ -25,6 +25,10 @@ export const TabQueue = () => { const { post, loading: isFlushing } = usePost(); const jobs = queueData?.jobs ?? []; + const workers = (queueData?.metrics?.workers ?? []).map((worker, idx) => ({ + ...worker, + id: idx, + })); const metrics = queueData?.metrics ?? null; const hasNeverRun = !isLoading && metrics !== null && (metrics.totalRuns ?? 0) === 0; const noQueueData = !isLoading && metrics === null && jobs.length === 0; @@ -46,6 +50,34 @@ export const TabQueue = () => { return ( + + + + {t("pages.logs.workers")} + + + + ), + }} + /> + + + + { ); }, }, + { + id: "lockedBy", + content: t("pages.logs.table.headers.lockedBy"), + render: (row) => { + const lockedBy = row.lockedBy; + if (!lockedBy) { + return -; + } + + const workerId = lockedBy.split(":")[2]; + const shortWorkerId = workerId.slice(workerId.length - 8); + return ( + + {`...${shortWorkerId}`} + + ); + }, + }, ]; return ( diff --git a/client/src/Pages/Logs/components/TableWorkers.tsx b/client/src/Pages/Logs/components/TableWorkers.tsx new file mode 100644 index 000000000..5d1f44860 --- /dev/null +++ b/client/src/Pages/Logs/components/TableWorkers.tsx @@ -0,0 +1,94 @@ +import { Table } from "@/Components/design-elements"; +import { Typography, useTheme } from "@mui/material"; +import { formatTimestamp } from "@/Utils/TimeUtils"; + +import { useTranslation } from "react-i18next"; +import type { QueueWorker } from "@/Types/Queue"; +import type { Header } from "@/Components/design-elements"; + +type QueueWorkerWithId = QueueWorker & { id: number }; + +interface TableWorkersProps { + queueWorkers: QueueWorkerWithId[]; +} + +export const TableWorkers = ({ queueWorkers }: TableWorkersProps) => { + const { t } = useTranslation(); + const theme = useTheme(); + + const cellSx = { + whiteSpace: "nowrap" as const, + overflow: "hidden", + textOverflow: "ellipsis", + maxWidth: 220, + }; + + const headers: Header[] = [ + { + id: "host", + content: t("pages.logs.table.headers.host"), + render: (row) => { + const host = row.workerId.split(":")[0]; + return ( + + {host} + + ); + }, + }, + { + id: "processId", + content: t("pages.logs.table.headers.processId"), + render: (row) => { + const processId = row.workerId.split(":")[1]; + return ( + + {processId} + + ); + }, + }, + { + id: "id", + content: t("pages.logs.table.headers.workerId"), + render: (row) => { + const workerId = row.workerId.split(":")[2]; + const shortWorkerId = workerId.slice(workerId.length - 8); + return ( + + {`...${shortWorkerId}`} + + ); + }, + }, + { + id: "mode", + content: t("pages.logs.table.headers.workerMode"), + render: (row) => {row.mode}, + }, + { + id: "lastSeen", + content: t("pages.logs.table.headers.lastSeenAt"), + render: (row) => ( + {formatTimestamp(row.lastSeenAt)} + ), + }, + ]; + + return ( + + ); +}; diff --git a/client/src/Pages/Logs/index.tsx b/client/src/Pages/Logs/index.tsx index b21e331c5..9d71e3253 100644 --- a/client/src/Pages/Logs/index.tsx +++ b/client/src/Pages/Logs/index.tsx @@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next"; const LogsPage = () => { const { t } = useTranslation(); - const [activeTab, setActiveTab] = useState(0); + const [activeTab, setActiveTab] = useState(1); return ( Highlighted rows are jobs currently being processed by a worker.", "failedJobs": "Failed jobs", @@ -1000,6 +1002,11 @@ }, "table": { "headers": { + "host": "Host", + "processId": "Process ID", + "workerId": "Worker ID", + "workerMode": "Worker mode", + "lastSeenAt": "Last seen at", "state": "State", "timestamp": "Timestamp", "level": "Level", @@ -1010,6 +1017,7 @@ "failCount": "Count", "lastRunAt": "Last run at", "lockedAt": "Locked at", + "lockedBy": "Locked by", "lastFinishedAt": "Last finished at", "lastRunTook": "Last run took", "lastFailedAt": "Last failed",