Refactor and more linking
This commit is contained in:
parent
f17c7e01f5
commit
2db11ac3dd
24 changed files with 197 additions and 177 deletions
|
@ -1,7 +1,7 @@
|
||||||
// Import Contexts
|
// Import Contexts
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { JobProvider } from "./ctx/JobContext.jsx";
|
import { JobProvider } from "@qltr/jobs";
|
||||||
import { StoreProvider } from "./ctx/StoreContext.jsx";
|
import { StoreProvider } from "@qltr/store";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
// Import Views
|
// Import Views
|
||||||
import Views from "./views/Views.jsx";
|
import Views from "./views/Views.jsx";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useReducer, createContext, useMemo } from "react";
|
import React, { useReducer, createContext, useMemo } from "react";
|
||||||
import Initiator from "../../lib/sockets/clients/Initiator.js";
|
import Initiator from "@qltr/initiator";
|
||||||
const JobContext = createContext();
|
const JobContext = createContext();
|
||||||
|
|
||||||
export const jobStatus = {
|
export const jobStatus = {
|
||||||
|
|
56
src/util/JobTools.jsx
Normal file
56
src/util/JobTools.jsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
|
|
||||||
|
import CheckIcon from "@mui/icons-material/Check";
|
||||||
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
|
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
|
||||||
|
import PendingIcon from "@mui/icons-material/Pending";
|
||||||
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||||
|
import DoNotDisturbIcon from "@mui/icons-material/DoNotDisturb";
|
||||||
|
import ReplayIcon from "@mui/icons-material/Replay";
|
||||||
|
|
||||||
|
function statusIcon(status) {
|
||||||
|
switch (status) {
|
||||||
|
case jobStatus.OK:
|
||||||
|
return <CheckIcon color="success" />;
|
||||||
|
case jobStatus.ERROR:
|
||||||
|
return <ClearIcon color="error" />;
|
||||||
|
case jobStatus.PENDING:
|
||||||
|
return <PendingIcon color="info" />;
|
||||||
|
case jobStatus.ACTIVE:
|
||||||
|
return <VisibilityIcon color="primary" />;
|
||||||
|
case jobStatus.CANCELED:
|
||||||
|
return <DoNotDisturbIcon color="warning" />;
|
||||||
|
case jobStatus.QUEUED:
|
||||||
|
return <ViewColumnIcon color="secondary" />;
|
||||||
|
default:
|
||||||
|
return <ReplayIcon />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const pipelineJobs = (pipeline, jobs) =>
|
||||||
|
jobs.filter((j) => j.isPipeline && j.pipelineId === pipeline.id);
|
||||||
|
|
||||||
|
export const useJobIconState = (job) => statusIcon(job.status);
|
||||||
|
|
||||||
|
export const usePipelineIconState = (pipeline) => {
|
||||||
|
const { state: jobState } = useContext(JobContext);
|
||||||
|
const jobStatuses = pipelineJobs(pipeline, jobState.jobs).map(
|
||||||
|
(j) => j.status
|
||||||
|
);
|
||||||
|
if (jobStatuses.includes(jobStatus.ERROR)) return statusIcon(jobStatus.ERROR);
|
||||||
|
|
||||||
|
if (jobStatuses.includes(jobStatus.ACTIVE))
|
||||||
|
return statusIcon(jobStatus.ACTIVE);
|
||||||
|
if (jobStatuses.includes(jobStatus.PENDING))
|
||||||
|
return statusIcon(jobStatus.PENDING);
|
||||||
|
if (pipeline.isCanceled) return statusIcon(jobStatus.CANCELED);
|
||||||
|
return statusIcon(jobStatus.QUEUED);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const selectedPipelineBranches = (pipeline) =>
|
||||||
|
pipeline.branches.map((b) =>
|
||||||
|
b.filter((t) => pipeline.selectedBranches.includes(t))
|
||||||
|
);
|
||||||
|
|
||||||
|
export const findPipelineJobByTestName = (pipeline, jobs, testName) =>
|
||||||
|
pipelineJobs(pipeline, jobs).find((j) => j.branchId === testName);
|
|
@ -1,7 +1,7 @@
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { useCurrentlyFailing } from "../Queries.jsx";
|
import { useCurrentlyFailing } from "@qltr/queries";
|
||||||
import JobContext from "../ctx/JobContext.jsx";
|
import JobContext from "@qltr/jobs";
|
||||||
import StoreContext from "../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
|
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import AppBar from "@mui/material/AppBar";
|
import AppBar from "@mui/material/AppBar";
|
||||||
|
@ -28,7 +28,7 @@ import SentimentSatisfiedAltIcon from "@mui/icons-material/SentimentSatisfiedAlt
|
||||||
|
|
||||||
const drawerWidth = 250;
|
const drawerWidth = 250;
|
||||||
|
|
||||||
export default function Navbar(props) {
|
export default function Navbar() {
|
||||||
const { state: jobState } = useContext(JobContext);
|
const { state: jobState } = useContext(JobContext);
|
||||||
const { state: store } = useContext(StoreContext);
|
const { state: store } = useContext(StoreContext);
|
||||||
const { isLoading, data: failing } = useCurrentlyFailing();
|
const { isLoading, data: failing } = useCurrentlyFailing();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useContext } from "react";
|
||||||
import { Routes, Route, Navigate } from "react-router-dom";
|
import { Routes, Route, Navigate } from "react-router-dom";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
import StoreContext from "../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
// Import Navbar
|
// Import Navbar
|
||||||
import Navbar from "./Navbar.jsx";
|
import Navbar from "./Navbar.jsx";
|
||||||
// Import Pages
|
// Import Pages
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import { useSilencedAlerts } from "../../Queries.jsx";
|
import { useSilencedAlerts } from "@qltr/queries";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import SilencedBox from "./SilencedBox.jsx";
|
import SilencedBox from "./SilencedBox.jsx";
|
||||||
import SilenceDialog from "./SilenceDialog.jsx";
|
import SilenceDialog from "./SilenceDialog.jsx";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useContext, useEffect } from "react";
|
import { useState, useContext, useEffect } from "react";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
|
|
||||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
import { useTheme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
|
@ -8,7 +8,6 @@ import Typography from "@mui/material/Typography";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import EditIcon from "@mui/icons-material/Edit";
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
|
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
|
|
||||||
export default function SilencingBox(props) {
|
export default function SilencingBox(props) {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { useEffect, useContext } from "react";
|
import { useEffect, useContext } from "react";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext from "../../ctx/JobContext.jsx";
|
import JobContext from "@qltr/jobs";
|
||||||
import CatalogBox from "./CatalogBox.jsx";
|
import CatalogBox from "./CatalogBox.jsx";
|
||||||
import CatalogSearch from "./CatalogSearch.jsx";
|
import CatalogSearch from "./CatalogSearch.jsx";
|
||||||
import { useCatalogTests } from "../../Queries.jsx";
|
import { useCatalogTests } from "@qltr/queries";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
|
|
||||||
export default function Catalog() {
|
export default function Catalog() {
|
||||||
const { state: store, updateStore } = useContext(StoreContext);
|
const { state: store, updateStore } = useContext(StoreContext);
|
||||||
|
const { state: jobState } = useContext(JobContext);
|
||||||
const { isLoading, data: tests } = useCatalogTests();
|
const { isLoading, data: tests } = useCatalogTests();
|
||||||
const handleSearchChange = (e) =>
|
const handleSearchChange = (e) =>
|
||||||
updateStore({ catalogSearch: e.target.value });
|
updateStore({ catalogSearch: e.target.value });
|
||||||
|
@ -20,6 +21,31 @@ export default function Catalog() {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const catalogWithJobs = () => {
|
||||||
|
for (var test of tests) {
|
||||||
|
if (test.isPipeline) {
|
||||||
|
const pipeline = jobState.pipelines.find((p) =>
|
||||||
|
p.selectedBranches.includes(test.name)
|
||||||
|
);
|
||||||
|
if (!pipeline) continue;
|
||||||
|
const pipelineJob = jobState.jobs.find(
|
||||||
|
(j) =>
|
||||||
|
j.isPipeline &&
|
||||||
|
j.pipelineId === pipeline.id &&
|
||||||
|
j.branchId === test.name
|
||||||
|
);
|
||||||
|
if (!pipelineJob) test.pipeline = pipeline;
|
||||||
|
test.job = pipelineJob;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const job = jobState.jobs.find(
|
||||||
|
(j) => !j.isPipeline && j.builderCache.testNames.includes(test.name)
|
||||||
|
);
|
||||||
|
if (job) test.job = job;
|
||||||
|
}
|
||||||
|
return tests;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="catalog">
|
<div className="catalog">
|
||||||
<CatalogSearch
|
<CatalogSearch
|
||||||
|
@ -30,7 +56,9 @@ export default function Catalog() {
|
||||||
<h6>{store.catalogSearch}</h6>
|
<h6>{store.catalogSearch}</h6>
|
||||||
{isLoading
|
{isLoading
|
||||||
? null
|
? null
|
||||||
: tests.map((v, i) => <CatalogBox key={i} catalogTest={v} />)}
|
: catalogWithJobs().map((v, i) => (
|
||||||
|
<CatalogBox key={i} catalogTest={v} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { usePipelineMappings } from "../../Queries.jsx";
|
import { usePipelineMappings } from "@qltr/queries";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext from "../../ctx/JobContext.jsx";
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
|
import { useJobIconState, usePipelineIconState } from "@qltr/util/JobTools";
|
||||||
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
|
@ -11,15 +12,11 @@ import Typography from "@mui/material/Typography";
|
||||||
|
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||||
|
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
|
||||||
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import {
|
import { asTree, asBranches, as1d } from "@qltr/util/pipelines.js";
|
||||||
selectBranch,
|
|
||||||
asTree,
|
|
||||||
asBranches,
|
|
||||||
as1d,
|
|
||||||
} from "../../../lib/jobs/pipelines.js";
|
|
||||||
|
|
||||||
export default function CatalogBox(props) {
|
export default function CatalogBox(props) {
|
||||||
const { catalogTest } = props;
|
const { catalogTest } = props;
|
||||||
|
@ -30,24 +27,28 @@ export default function CatalogBox(props) {
|
||||||
repo: testRepo,
|
repo: testRepo,
|
||||||
isPipeline,
|
isPipeline,
|
||||||
type: testType,
|
type: testType,
|
||||||
|
job,
|
||||||
|
pipeline,
|
||||||
} = catalogTest;
|
} = catalogTest;
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { data: pipelineMappings, isLoading } = usePipelineMappings();
|
const { data: pipelineMappings, isLoading } = usePipelineMappings();
|
||||||
const { state: store, updateStore } = useContext(StoreContext);
|
const { state: store } = useContext(StoreContext);
|
||||||
|
|
||||||
const { state: jobState, jobFactory } = useContext(JobContext);
|
const { jobFactory } = useContext(JobContext);
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const toggleOpen = () => setOpen(!open);
|
const toggleOpen = () => setOpen(!open);
|
||||||
|
|
||||||
const runTest = (e) => {
|
const navigateToJob = () => {
|
||||||
e.preventDefault();
|
if (pipeline) return navigate(`/qualiteer/jobs#p${pipeline.id}`);
|
||||||
e.stopPropagation();
|
navigate(`/qualiteer/jobs#${job.jobId}`);
|
||||||
console.log(catalogTest);
|
};
|
||||||
|
|
||||||
|
const runTest = () => {
|
||||||
if (isPipeline) return runPipelineTest();
|
if (isPipeline) return runPipelineTest();
|
||||||
const jobId = jobFactory({ testNames: [testName] });
|
const jobId = jobFactory({ testNames: [testName], isTriage: true });
|
||||||
if (store.focusJob) navigate(`/qualiteer/jobs#${jobId}`);
|
if (store.focusJob) navigate(`/qualiteer/jobs#${jobId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +64,20 @@ export default function CatalogBox(props) {
|
||||||
if (store.focusJob) navigate(`/qualiteer/jobs#p${pipeline.id}`);
|
if (store.focusJob) navigate(`/qualiteer/jobs#p${pipeline.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const jobOnClick = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (pipeline) return navigateToJob();
|
||||||
|
if (!job) return runTest();
|
||||||
|
navigateToJob();
|
||||||
|
};
|
||||||
|
|
||||||
|
function jobIcon() {
|
||||||
|
if (pipeline) return usePipelineIconState(pipeline);
|
||||||
|
if (!job) return <PlayArrowIcon />;
|
||||||
|
return useJobIconState(job);
|
||||||
|
}
|
||||||
|
|
||||||
function Actions() {
|
function Actions() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -70,9 +85,9 @@ export default function CatalogBox(props) {
|
||||||
color="success"
|
color="success"
|
||||||
aria-label="play"
|
aria-label="play"
|
||||||
component="span"
|
component="span"
|
||||||
onClick={runTest}
|
onClick={jobOnClick}
|
||||||
>
|
>
|
||||||
<PlayArrowIcon />
|
{jobIcon()}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
@ -98,6 +113,11 @@ export default function CatalogBox(props) {
|
||||||
{`${testClass}#`}
|
{`${testClass}#`}
|
||||||
<Box fontWeight="bold" display="inline">
|
<Box fontWeight="bold" display="inline">
|
||||||
{testName}
|
{testName}
|
||||||
|
{isPipeline && (
|
||||||
|
<IconButton component="span">
|
||||||
|
<ViewColumnIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<br />
|
<br />
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -119,7 +139,7 @@ export default function CatalogBox(props) {
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Typography component={"span"} style={{ wordBreak: "break-word" }}>
|
<Typography component={"span"} style={{ wordBreak: "break-word" }}>
|
||||||
{JSON.stringify(catalogTest)}
|
{"Test info"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useState, useContext } from "react";
|
import { useState, useContext } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useCurrentlyFailing, useSilencedAlerts } from "../../Queries.jsx";
|
import { useCurrentlyFailing, useSilencedAlerts } from "@qltr/queries";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext from "../../ctx/JobContext.jsx";
|
import JobContext from "@qltr/jobs";
|
||||||
import SilenceDialog from "../alerting/SilenceDialog.jsx";
|
import SilenceDialog from "../alerting/SilenceDialog.jsx";
|
||||||
import FailingBox from "./FailingBox.jsx";
|
import FailingBox from "./FailingBox.jsx";
|
||||||
|
|
||||||
|
@ -14,20 +14,14 @@ import DialogActions from "@mui/material/DialogActions";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
import DialogContentText from "@mui/material/DialogContentText";
|
import DialogContentText from "@mui/material/DialogContentText";
|
||||||
import DialogTitle from "@mui/material/DialogTitle";
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
|
|
||||||
import ReplayIcon from "@mui/icons-material/Replay";
|
import ReplayIcon from "@mui/icons-material/Replay";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
|
||||||
export default function Failing() {
|
export default function Failing() {
|
||||||
const { state: jobState, retryAll } = useContext(JobContext);
|
const { state: jobState, retryAll } = useContext(JobContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const {
|
const { state: store, silenceRequest } = useContext(StoreContext);
|
||||||
state: store,
|
|
||||||
updateStore,
|
|
||||||
silenceRequest,
|
|
||||||
} = useContext(StoreContext);
|
|
||||||
const { isLoading, data: failing } = useCurrentlyFailing();
|
const { isLoading, data: failing } = useCurrentlyFailing();
|
||||||
const { isSilencedLoading, data: silencedAlerts } = useSilencedAlerts();
|
const { isSilencedLoading, data: silencedAlerts } = useSilencedAlerts();
|
||||||
const [silenceEntry, setSilenceEntry] = useState({ open: false });
|
const [silenceEntry, setSilenceEntry] = useState({ open: false });
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { usePipelineMappings } from "../../Queries.jsx";
|
import { usePipelineMappings } from "@qltr/queries";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
|
import { useJobIconState, usePipelineIconState } from "@qltr/util/JobTools";
|
||||||
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
|
@ -33,12 +34,7 @@ import Badge from "@mui/material/Badge";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
import {
|
import { asTree, asBranches, as1d } from "@qltr/util/pipelines.js";
|
||||||
selectBranch,
|
|
||||||
asTree,
|
|
||||||
asBranches,
|
|
||||||
as1d,
|
|
||||||
} from "../../../lib/jobs/pipelines.js";
|
|
||||||
|
|
||||||
const stopPropagation = (e) => e.stopPropagation() && e.preventDefault();
|
const stopPropagation = (e) => e.stopPropagation() && e.preventDefault();
|
||||||
|
|
||||||
|
@ -112,45 +108,13 @@ export default function FailingBox(props) {
|
||||||
const jobOnClick = () => {
|
const jobOnClick = () => {
|
||||||
if (pipeline) return navigateToJob;
|
if (pipeline) return navigateToJob;
|
||||||
if (!job) return retryTest;
|
if (!job) return retryTest;
|
||||||
switch (job.status) {
|
navigateToJob();
|
||||||
case jobStatus.OK:
|
|
||||||
return navigateToJob;
|
|
||||||
case jobStatus.ERROR:
|
|
||||||
return retryTest;
|
|
||||||
case jobStatus.PENDING:
|
|
||||||
return navigateToJob;
|
|
||||||
case jobStatus.ACTIVE:
|
|
||||||
return navigateToJob;
|
|
||||||
case jobStatus.CANCELED:
|
|
||||||
return navigateToJob;
|
|
||||||
case jobStatus.QUEUED:
|
|
||||||
return navigateToJob;
|
|
||||||
default:
|
|
||||||
return retryTest;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function jobIcon() {
|
function jobIcon() {
|
||||||
if (pipeline && pipeline.isCanceled)
|
if (pipeline) return usePipelineIconState(pipeline);
|
||||||
return <DoNotDisturbIcon color="warning" />;
|
|
||||||
if (pipeline) return <ViewColumnIcon color="secondary" />;
|
|
||||||
if (!job) return <ReplayIcon />;
|
if (!job) return <ReplayIcon />;
|
||||||
switch (job.status) {
|
return useJobIconState(job);
|
||||||
case jobStatus.OK:
|
|
||||||
return <CheckIcon color="success" />;
|
|
||||||
case jobStatus.ERROR:
|
|
||||||
return <ClearIcon color="error" />;
|
|
||||||
case jobStatus.PENDING:
|
|
||||||
return <PendingIcon color="info" />;
|
|
||||||
case jobStatus.ACTIVE:
|
|
||||||
return <VisibilityIcon color="primary" />;
|
|
||||||
case jobStatus.CANCELED:
|
|
||||||
return <DoNotDisturbIcon color="warning" />;
|
|
||||||
case jobStatus.QUEUED:
|
|
||||||
return <ViewColumnIcon color="secondary" />;
|
|
||||||
default:
|
|
||||||
return <ReplayIcon />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Actions() {
|
function Actions() {
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React from "react";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
|
||||||
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
|
|
||||||
|
|
||||||
|
import { useJobIconState } from "@qltr/util/JobTools";
|
||||||
import Accordion from "@mui/material/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
|
||||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import CheckIcon from "@mui/icons-material/Check";
|
|
||||||
import ClearIcon from "@mui/icons-material/Clear";
|
|
||||||
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
|
|
||||||
import PendingIcon from "@mui/icons-material/Pending";
|
|
||||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
|
||||||
import DoNotDisturbIcon from "@mui/icons-material/DoNotDisturb";
|
|
||||||
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
|
|
||||||
export default function JobBox(props) {
|
export default function JobBox(props) {
|
||||||
|
@ -23,25 +14,6 @@ export default function JobBox(props) {
|
||||||
|
|
||||||
const { name, status } = job;
|
const { name, status } = job;
|
||||||
|
|
||||||
function jobIcon() {
|
|
||||||
switch (status) {
|
|
||||||
case jobStatus.OK:
|
|
||||||
return <CheckIcon color="success" />;
|
|
||||||
case jobStatus.ERROR:
|
|
||||||
return <ClearIcon color="error" />;
|
|
||||||
case jobStatus.PENDING:
|
|
||||||
return <PendingIcon color="info" />;
|
|
||||||
case jobStatus.ACTIVE:
|
|
||||||
return <VisibilityIcon color="primary" />;
|
|
||||||
case jobStatus.CANCELED:
|
|
||||||
return <DoNotDisturbIcon color="warning" />;
|
|
||||||
case jobStatus.QUEUED:
|
|
||||||
return <ViewColumnIcon color="secondary" />;
|
|
||||||
default:
|
|
||||||
return <ReplayIcon />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion expanded={false} disableGutters={true} square>
|
<Accordion expanded={false} disableGutters={true} square>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
|
@ -58,7 +30,7 @@ export default function JobBox(props) {
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stack sx={{ ml: "auto" }}>
|
<Stack sx={{ ml: "auto" }}>
|
||||||
<IconButton aria-label="retry" component="span">
|
<IconButton aria-label="retry" component="span">
|
||||||
{jobIcon()}
|
{useJobIconState(job)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { jobStatus } from "../../ctx/JobContext.jsx";
|
import { jobStatus } from "@qltr/jobs";
|
||||||
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
|
import { usePipelineIconState } from "@qltr/util/JobTools";
|
||||||
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
|
@ -20,10 +21,7 @@ import Stack from "@mui/material/Stack";
|
||||||
|
|
||||||
export default function JobPipelineBox(props) {
|
export default function JobPipelineBox(props) {
|
||||||
const { pipeline } = props;
|
const { pipeline } = props;
|
||||||
|
const pipelineIcon = usePipelineIconState(pipeline);
|
||||||
function jobIcon() {
|
|
||||||
return <ViewColumnIcon />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion expanded={false} disableGutters={true} square>
|
<Accordion expanded={false} disableGutters={true} square>
|
||||||
|
@ -41,7 +39,7 @@ export default function JobPipelineBox(props) {
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stack sx={{ ml: "auto" }}>
|
<Stack sx={{ ml: "auto" }}>
|
||||||
<IconButton aria-label="" component="span">
|
<IconButton aria-label="" component="span">
|
||||||
{jobIcon()}
|
{pipelineIcon}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
|
import {
|
||||||
|
selectedPipelineBranches,
|
||||||
|
pipelineJobs,
|
||||||
|
findPipelineJobByTestName,
|
||||||
|
useJobIconState,
|
||||||
|
} from "@qltr/util/JobTools";
|
||||||
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import AppBar from "@mui/material/AppBar";
|
import AppBar from "@mui/material/AppBar";
|
||||||
|
@ -44,20 +50,8 @@ function JobPipelineDisplay(props) {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const pipelineJobs = jobState.jobs.filter(
|
|
||||||
(j) => j.isPipeline && j.pipelineId === pipeline.id
|
|
||||||
);
|
|
||||||
const selectedBranches = () => {
|
|
||||||
return pipeline.branches.map((b) => {
|
|
||||||
return b.filter((t) => pipeline.selectedBranches.includes(t));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const findJob = (testName) =>
|
|
||||||
pipelineJobs.find((j) => j.branchId === testName);
|
|
||||||
|
|
||||||
const selectJob = (testName) => () => {
|
const selectJob = (testName) => () => {
|
||||||
const job = findJob(testName);
|
const job = findPipelineJobByTestName(pipeline, jobState.jobs, testName);
|
||||||
if (!job) return;
|
if (!job) return;
|
||||||
navigate(`/qualiteer/jobs#${job.jobId}`);
|
navigate(`/qualiteer/jobs#${job.jobId}`);
|
||||||
};
|
};
|
||||||
|
@ -80,31 +74,16 @@ function JobPipelineDisplay(props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
function pipelineActive() {
|
function pipelineActive() {
|
||||||
return pipelineJobs.find(
|
return pipelineJobs(pipeline, jobState.jobs).find(
|
||||||
(j) => j.status === jobStatus.ACTIVE || j.status === jobStatus.PENDING
|
(j) => j.status === jobStatus.ACTIVE || j.status === jobStatus.PENDING
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function jobIcon(name) {
|
function jobIcon(name) {
|
||||||
const job = findJob(name);
|
|
||||||
const status = job ? job.status : null;
|
|
||||||
if (pipeline.isCanceled) return <DoNotDisturbIcon color="warning" />;
|
if (pipeline.isCanceled) return <DoNotDisturbIcon color="warning" />;
|
||||||
switch (status) {
|
const job = findPipelineJobByTestName(pipeline, jobState.jobs, name);
|
||||||
case jobStatus.OK:
|
if (!job) return <ViewColumnIcon color="secondary" />;
|
||||||
return <CheckIcon color="success" />;
|
return useJobIconState(job);
|
||||||
case jobStatus.ERROR:
|
|
||||||
return <ClearIcon color="error" />;
|
|
||||||
case jobStatus.PENDING:
|
|
||||||
return <PendingIcon color="info" />;
|
|
||||||
case jobStatus.ACTIVE:
|
|
||||||
return <VisibilityIcon color="primary" />;
|
|
||||||
case jobStatus.CANCELED:
|
|
||||||
return <DoNotDisturbIcon color="warning" />;
|
|
||||||
case jobStatus.QUEUED:
|
|
||||||
return <ViewColumnIcon color="secondary" />;
|
|
||||||
default:
|
|
||||||
return <ViewColumnIcon color="secondary" />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -133,7 +112,7 @@ function JobPipelineDisplay(props) {
|
||||||
</Box>
|
</Box>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
<Toolbar disableGutters />
|
<Toolbar disableGutters />
|
||||||
{selectedBranches().map((track, i) => (
|
{selectedPipelineBranches(pipeline).map((track, i) => (
|
||||||
<React.Fragment key={i}>
|
<React.Fragment key={i}>
|
||||||
<Typography variant="h6">{i + 1}</Typography>
|
<Typography variant="h6">{i + 1}</Typography>
|
||||||
<Box>
|
<Box>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext, useState, useEffect } from "react";
|
import React, { useContext, useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
|
import JobContext, { jobStatus } from "@qltr/jobs";
|
||||||
import StoreContext from "../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import AppBar from "@mui/material/AppBar";
|
import AppBar from "@mui/material/AppBar";
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useContext, useEffect } from "react";
|
import React, { useState, useContext, useEffect } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import JobContext from "../../ctx/JobContext.jsx";
|
import JobContext from "@qltr/jobs";
|
||||||
import JobBox from "./JobBox.jsx";
|
import JobBox from "./JobBox.jsx";
|
||||||
import JobPipelineBox from "./JobPipelineBox.jsx";
|
import JobPipelineBox from "./JobPipelineBox.jsx";
|
||||||
import JobView from "./JobView.jsx";
|
import JobView from "./JobView.jsx";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext, useState, useEffect } from "react";
|
import React, { useContext, useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import StoreContext from "../../../ctx/StoreContext.jsx";
|
import StoreContext from "@qltr/store";
|
||||||
import JobContext from "../../../ctx/JobContext.jsx";
|
import JobContext from "@qltr/jobs";
|
||||||
|
|
||||||
import Dialog from "@mui/material/Dialog";
|
import Dialog from "@mui/material/Dialog";
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useContext } from "react";
|
import React from "react";
|
||||||
import { usePipelineMappings } from "../../../Queries.jsx";
|
import { usePipelineMappings } from "@qltr/queries";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
asTree,
|
asTree,
|
||||||
asBranches,
|
asBranches,
|
||||||
as1d,
|
as1d,
|
||||||
} from "../../../../lib/jobs/pipelines.js";
|
} from "@qltr/util/pipelines.js";
|
||||||
|
|
||||||
function PipelineTrackSelector(props) {
|
function PipelineTrackSelector(props) {
|
||||||
const { cache, setCache, back, next } = props;
|
const { cache, setCache, back, next } = props;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return defineConfig({
|
return defineConfig({
|
||||||
|
@ -10,16 +11,25 @@ export default () => {
|
||||||
port: 443,
|
port: 443,
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://localhost:52000',
|
"/api": "http://localhost:52000",
|
||||||
'/socket.io': {
|
"/socket.io": {
|
||||||
target: 'ws://localhost:52000',
|
target: "ws://localhost:52000",
|
||||||
ws: true
|
ws: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: "./build",
|
outDir: "./build",
|
||||||
},
|
},
|
||||||
base: "/qualiteer/",
|
base: "/qualiteer/",
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@qltr/util": path.resolve("./src/util/"),
|
||||||
|
"@qltr/queries": path.resolve("./src/util/queries"),
|
||||||
|
"@qltr/jobs": path.resolve("./src/ctx/JobContext.jsx"),
|
||||||
|
"@qltr/store": path.resolve("./src/ctx/StoreContext.jsx"),
|
||||||
|
"@qltr/initiator": path.resolve("./lib/sockets/clients/Initiator.js"),
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue