From 8ad5b7876cd94b48d192617569a682376abda2c1 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Fri, 5 Aug 2022 13:03:48 +0000 Subject: [PATCH] Basic MultiJobs --- .replit-default => .replit | 3 + Dockerfile | 3 +- package.json | 2 +- src/Dashboard.jsx | 9 +- src/ctx/JobContext.jsx | 104 +++++++++++------- src/ctx/StoreContext.jsx | 51 +++++++-- src/views/Navbar.jsx | 1 - src/views/Views.jsx | 8 +- src/views/catalog/CatalogBox.jsx | 8 +- src/views/failing/Failing.jsx | 2 +- src/views/failing/FailingBox.jsx | 9 +- src/views/jobs/JobLogView.jsx | 25 ++++- src/views/jobs/JobView.jsx | 97 +++++++++++----- src/views/jobs/Jobs.jsx | 16 +-- src/views/jobs/builder/GroupConfirm.jsx | 25 +++++ src/views/jobs/builder/GroupSelector.jsx | 30 +++++ src/views/jobs/builder/IndividualConfirm.jsx | 25 +++++ src/views/jobs/builder/IndividualSelector.jsx | 31 ++++++ src/views/jobs/builder/JobBuilder.jsx | 63 +++++++---- src/views/jobs/builder/PipelineConfirm.jsx | 26 +++++ src/views/jobs/builder/PipelineSelector.jsx | 91 +++++++++++++++ .../jobs/builder/PipelineTrackSelector.jsx | 25 +++++ src/views/settings/Settings.jsx | 18 +-- tests/assets/suite/runner.js | 2 + vite.config.js | 7 ++ 25 files changed, 539 insertions(+), 142 deletions(-) rename .replit-default => .replit (94%) create mode 100644 src/views/jobs/builder/GroupConfirm.jsx create mode 100644 src/views/jobs/builder/GroupSelector.jsx create mode 100644 src/views/jobs/builder/IndividualConfirm.jsx create mode 100644 src/views/jobs/builder/IndividualSelector.jsx create mode 100644 src/views/jobs/builder/PipelineConfirm.jsx create mode 100644 src/views/jobs/builder/PipelineSelector.jsx create mode 100644 src/views/jobs/builder/PipelineTrackSelector.jsx diff --git a/.replit-default b/.replit similarity index 94% rename from .replit-default rename to .replit index c91084d..5963f54 100644 --- a/.replit-default +++ b/.replit @@ -1,3 +1,6 @@ +# The command that is executed when the run button is clicked. +run = ["echo", "run"] + entrypoint = "index.js" [nix] diff --git a/Dockerfile b/Dockerfile index be725bc..6fa6eb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:16 -WORKDIR /dunemask/net/cairo +WORKDIR /dunemask/net/qualiteer # Copy dependencies COPY package.json . COPY package-lock.json . @@ -8,6 +8,7 @@ RUN npm i COPY public public COPY src src COPY lib lib +COPY index.html . RUN npm run build:react # Copy bin over COPY bin bin diff --git a/package.json b/package.json index 957cb38..51750e6 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build:react": "vite build", "start": "node dist/app.js", "start:dev": "nodemon dist/app.js", - "start:dev:replit": "npm run start:dev & npm run start:react:replit", + "start:dev:replit": "npm run start:react:replit & (sleep 5 && npm run start:dev)", "start:react": "vite preview", "start:react:replit": "vite --host", "test": "node tests/index.js", diff --git a/src/Dashboard.jsx b/src/Dashboard.jsx index bbe9ee3..a9b5865 100644 --- a/src/Dashboard.jsx +++ b/src/Dashboard.jsx @@ -8,13 +8,14 @@ import Views from "./views/Views.jsx"; export default function Dashboard() { return (
+ + - - + - - + +
); } diff --git a/src/ctx/JobContext.jsx b/src/ctx/JobContext.jsx index 0631b08..503d163 100644 --- a/src/ctx/JobContext.jsx +++ b/src/ctx/JobContext.jsx @@ -1,4 +1,5 @@ import React, { useReducer, createContext, useMemo } from "react"; +import Initiator from "../../lib/sockets/clients/Initiator.js"; const JobContext = createContext(); export const jobStatus = { @@ -15,32 +16,20 @@ const ACTIONS = { UPDATE: "u", DELETE: "d", }; -/**/ -const jobMock = Object.values(jobStatus).map((v, i) => ({ - name: `Job${i + 1}`, - test: `someTestName${i + 1}`, - status: v, - exitcode: 0, -})); + +const url = "https://qualiteer.elijahparker3.repl.co/"; const initialState = { - jobs: jobMock, + jobs: [], + pipelines: [], }; + /* +pipelines: [{tracks:[ { - name: "Job1", - test: "someTestName", - status: JOB_STATUS.SUCCESS, - exitcode: 0 -} -OR -{ - compound: true, - name: "Compound Job", - pipeline: [{}] } - +]}] */ const reducer = (state, action) => { @@ -55,7 +44,7 @@ const reducer = (state, action) => { case ACTIONS.UPDATE: jobIndex = jobs.find((j) => j.id === (action.job.id ?? action.jobId)); - jobs[jobIndex] = action.job; + jobs[jobIndex] = { ...jobs[jobIndex], ...action.job }; return { ...state, jobs }; case ACTIONS.DELETE: @@ -82,31 +71,68 @@ export const JobProvider = ({ children }) => { console.log("Would retry all failing tests!"); } - function activeJobStates() { - const jobs = { state }; - console.log("Would return all active job states"); - } - - function mockRun() { - dispatch({ - job: { - name: "Job1", - test: "someTestName", - log: [], - status: jobStatus.OK, - exitcode: 0, - }, - action: ACTIONS.CREATE, - }); - } - function jobBuilder(tests) { if (!Array.isArray(tests)) throw Error("Error from within JobContext.jsx"); console.log("Would run tests", tests); + return jobFactory({ testNames: ["single"] }); + } + + function pipelineFactory(builderCache) { + + } + + function jobFactory(builderCache) { + // Find test + const i = new Initiator(url); + const jobId = `j${Date.now()}`; + const job = { + name: jobId, + status: jobStatus.PENDING, + jobId, + isPipeline: false, + builderCache, + }; + + const request = { + testName: builderCache.testNames[0], + image: "node", + type: "single", + name: jobId, + }; + + jobCreate(job); + + const onLog = (d) => { + const job = state.jobs.find((j) => j.jobId === jobId); + job.log.push(d); + job.status = jobStatus.ACTIVE; + jobUpdate({ ...job }, jobId); + }; + + const onClose = (c) => { + const job = state.jobs.find((j) => j.jobId === jobId); + job.exitcode = c; + job.status = c === 0 ? jobStatus.OK : jobStatus.ERROR; + jobUpdate({ ...job }, jobId); + }; + + const started = i.newJob(request, onLog, onClose); + started.then(() => jobUpdate({ status: jobStatus.ACTIVE }, jobId)); + + /*const job = { + type: "compound", + testName: "primary", + pipelineTriggers: "secondary", + name: "testing", + image: "node", + };*/ + return jobId; } function retrySingle(test) { console.log("Would retry test", test); + return jobFactory({ testNames: ["single"] }); + } const context = { @@ -118,7 +144,7 @@ export const JobProvider = ({ children }) => { retryAll, retrySingle, jobBuilder, - activeJobStates, + jobFactory, }; const contextValue = useMemo(() => context, [state, dispatch]); diff --git a/src/ctx/StoreContext.jsx b/src/ctx/StoreContext.jsx index c1e921c..4ae2729 100644 --- a/src/ctx/StoreContext.jsx +++ b/src/ctx/StoreContext.jsx @@ -1,5 +1,4 @@ import React, { useReducer, createContext, useMemo } from "react"; -import { jobStatus } from "./JobContext.jsx"; const StoreContext = createContext(); @@ -7,6 +6,11 @@ const ACTIONS = { UPDATE: "u", }; + +const pipelineMappingsMock = [["primary", "secondary1","tertiary1"], + ["primary", "secondary1", "tertiary2"], + ["primary", "secondary2", "tertiary3"]]; + const silencedMock = new Array(10).fill(0).map((v, i) => ({ name: `Test${i + 1}`, class: `SomeTestClass${i % 2 ? i - 1 : i / 2}`, @@ -39,36 +43,58 @@ const failingMock = new Array(12).fill(0).map((v, i) => ({ jobStatus: (() => { switch (i) { case 1: - return jobStatus.OK; + return "o"; case 3: - return jobStatus.ERROR; + return "e"; case 4: - return jobStatus.PENDING; + return "p"; case 5: - return jobStatus.ACTIVE; + return "a"; case 6: - return jobStatus.CANCELED; + return "c"; case 8: - return jobStatus.QUEUED; + return "q"; default: return null; } })(), })); +const localStorage = {setItem: ()=>{}, getItem: ()=>{}}; + +const localSettings = localStorage.getItem("settings"); +const defaultSettings = { + focusJob: true, + simplifiedControls: true, + logAppDetails: true, + defaultRegion: "us", + defaultPage: "failing", +}; + +const settings = localSettings ? JSON.parse(localSettings) : defaultSettings; +const settingsKeys = Object.keys(defaultSettings); + const initialState = { pages: ["failing", "alerting", "jobs", "catalog", "settings", "about"], intervals: [], catalog: catalogMock, failing: failingMock, silenced: silencedMock, + pipelineMappings: pipelineMappingsMock, regions: [], catalogSearch: "", - focusJob: false, - simplifiedControls: true, - logAppDetails: true, - defaultRegion: "us", // Local Store - defaultPage: "failing", // Local Store + ...settings, +}; + +const settingsUpdater = (oldState, storeUpdate) => { + const settingsToUpdate = {}; + for (var k of settingsKeys) { + settingsToUpdate[k] = oldState[k]; + if (storeUpdate[k] === undefined) continue; + settingsToUpdate[k] = storeUpdate[k]; + } + + localStorage.setItem("settings", JSON.stringify(settingsToUpdate)); }; const reducer = (state, action) => { @@ -76,6 +102,7 @@ const reducer = (state, action) => { // Actions switch (action.type) { case ACTIONS.UPDATE: + settingsUpdater(state, store); return { ...state, ...store }; default: return state; diff --git a/src/views/Navbar.jsx b/src/views/Navbar.jsx index cd7abd9..5d1f568 100644 --- a/src/views/Navbar.jsx +++ b/src/views/Navbar.jsx @@ -29,7 +29,6 @@ const drawerWidth = 250; export default function Navbar(props) { const { state: jobState } = useContext(JobContext); const { state: store } = useContext(StoreContext); - const { inModal } = props; const pages = store.pages; const icons = [ diff --git a/src/views/Views.jsx b/src/views/Views.jsx index 0e2ac7d..68c5e3a 100644 --- a/src/views/Views.jsx +++ b/src/views/Views.jsx @@ -1,7 +1,8 @@ +import { useContext } from "react"; import { Routes, Route, Navigate } from "react-router-dom"; import Box from "@mui/material/Box"; import Toolbar from "@mui/material/Toolbar"; - +import StoreContext from "../ctx/StoreContext.jsx"; // Import Navbar import Navbar from "./Navbar.jsx"; // Import Pages @@ -14,6 +15,7 @@ import About from "./about/About.jsx"; import NotFound from "./NotFound.jsx"; export default function Views() { + const { state: store } = useContext(StoreContext); return (
@@ -24,7 +26,9 @@ export default function Views() { } + element={ + + } /> { e.preventDefault(); e.stopPropagation(); - jobBuilder([catalogTest]); + const jobId = jobBuilder([catalogTest]); + if(store.focusJob) navigate(`/qualiteer/jobs#${jobId}`); }; function Actions() { diff --git a/src/views/failing/Failing.jsx b/src/views/failing/Failing.jsx index e8192fc..9af22fd 100644 --- a/src/views/failing/Failing.jsx +++ b/src/views/failing/Failing.jsx @@ -18,7 +18,7 @@ import DialogTitle from "@mui/material/DialogTitle"; import ReplayIcon from "@mui/icons-material/Replay"; export default function Failing() { - const { state: jobState, retryAll, activeJobStates } = useContext(JobContext); + const { state: jobState, retryAll } = useContext(JobContext); const { state: store, diff --git a/src/views/failing/FailingBox.jsx b/src/views/failing/FailingBox.jsx index 62df505..071c768 100644 --- a/src/views/failing/FailingBox.jsx +++ b/src/views/failing/FailingBox.jsx @@ -1,4 +1,5 @@ import React, { useState, useContext } from "react"; +import {useNavigate} from "react-router-dom"; import StoreContext from "../../ctx/StoreContext.jsx"; import JobContext, { jobStatus } from "../../ctx/JobContext.jsx"; @@ -35,7 +36,6 @@ const stopPropagation = (e) => e.stopPropagation() && e.preventDefault(); export default function FailingBox(props) { const { failingTest, silenceClick } = props; - const { class: testClass, name: testName, @@ -50,6 +50,8 @@ export default function FailingBox(props) { jobStatus: testJobStatus, } = failingTest; + const navigate = useNavigate(); + const { state: jobState, retrySingle } = useContext(JobContext); const { state: store, updateStore, removeFailure } = useContext(StoreContext); @@ -74,7 +76,10 @@ export default function FailingBox(props) { return "error"; } - const retryTest = () => retrySingle(failingTest); + const retryTest = () => { + const jobId = retrySingle(failingTest); + if(store.focusJob) navigate(`/qualiteer/jobs#${jobId}`); + } const jobOnClick = () => { switch (testJobStatus) { diff --git a/src/views/jobs/JobLogView.jsx b/src/views/jobs/JobLogView.jsx index 65b4d5c..a61fbc7 100644 --- a/src/views/jobs/JobLogView.jsx +++ b/src/views/jobs/JobLogView.jsx @@ -1,5 +1,5 @@ -import { useContext, useState, useEffect } from "react"; -import JobContext from "../../ctx/JobContext.jsx"; +import React from "react"; +import { jobStatus } from "../../ctx/JobContext.jsx"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; @@ -7,7 +7,7 @@ import Skeleton from "@mui/material/Skeleton"; import Stack from "@mui/material/Stack"; export default function JobLogView(props) { - const { log } = props; + const { log, status } = props; const LoadingDot = () => ( ))} - - - + {status === jobStatus.PENDING && ( + + Waiting for Executor... + + )} + {(status === jobStatus.ACTIVE || status === jobStatus.PENDING) && ( + + + + + + )} ); diff --git a/src/views/jobs/JobView.jsx b/src/views/jobs/JobView.jsx index 6da09a6..14fa4e0 100644 --- a/src/views/jobs/JobView.jsx +++ b/src/views/jobs/JobView.jsx @@ -1,34 +1,67 @@ import React, { useContext, useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import JobContext from "../../ctx/JobContext.jsx"; +import JobContext, { jobStatus } from "../../ctx/JobContext.jsx"; import Box from "@mui/material/Box"; import AppBar from "@mui/material/AppBar"; import Toolbar from "@mui/material/Toolbar"; -import Button from "@mui/material/Button"; +import IconButton from "@mui/material/IconButton"; import Typography from "@mui/material/Typography"; +import Menu from "@mui/material/Menu"; +import MenuItem from "@mui/material/MenuItem"; import JobLogView from "./JobLogView.jsx"; +import ListItemText from "@mui/material/ListItemText"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import MoreVertIcon from "@mui/icons-material/MoreVert"; +import DownloadIcon from "@mui/icons-material/Download"; +import ReplayIcon from "@mui/icons-material/Replay"; +import ArrowBackIcon from "@mui/icons-material/ArrowBack"; export default function JobView(props) { const navigate = useNavigate(); - const { state: jobState } = useContext(JobContext); - const { job: initJob } = props; - const [job, setJob] = useState({ log: [initJob.name] }); + const { job } = props; + const { jobFactory } = useContext(JobContext); - function retryJob() {} + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleClick = (event) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; - function downloadLog() {} + function download(filename, text) { + var element = document.createElement("a"); + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + encodeURIComponent(text) + ); + element.setAttribute("download", filename); + element.style.display = "none"; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + } + + function retryJob() { + jobFactory(job.builderCache); + } + + function downloadLog() { + if (job.status === jobStatus.PENDING) return; + download(`${job.jobId}.txt`, job.log.join("\n")); + } + + const menuSelect = (cb) => () => { + handleClose(); + cb(); + }; function navigateToJobs() { navigate("/qualiteer/jobs"); } - function onLog(d) { - const j = { ...job }; - j.log.push(d); - setJob(j); - } - return ( - + + + - {initJob.name} + {job.name} - - + + + - - - + + + + + + + Retry + + + + + + Download Log + + ); } diff --git a/src/views/jobs/Jobs.jsx b/src/views/jobs/Jobs.jsx index e23b159..c6833c3 100644 --- a/src/views/jobs/Jobs.jsx +++ b/src/views/jobs/Jobs.jsx @@ -1,19 +1,21 @@ import { useState, useContext, useEffect } from "react"; -import { useLocation } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import JobContext from "../../ctx/JobContext.jsx"; import JobBox from "./JobBox.jsx"; -import JobTestSelector from "./JobTestSelector.jsx"; import JobView from "./JobView.jsx"; import JobBuilder from "./builder/JobBuilder.jsx"; export default function Jobs() { - const { - state: jobState, - dispatch: jobDispatch, - jobBuilder, - } = useContext(JobContext); + const { state: jobState } = useContext(JobContext); const location = useLocation(); + const navigate = useNavigate(); + + useEffect(() => { + const jobName = location.hash.slice(1); + if (!jobName || jobState.jobs.find((job) => job.name === jobName)) return; + navigate("/qualiteer/jobs"); + }); return (
diff --git a/src/views/jobs/builder/GroupConfirm.jsx b/src/views/jobs/builder/GroupConfirm.jsx new file mode 100644 index 0000000..7a3514b --- /dev/null +++ b/src/views/jobs/builder/GroupConfirm.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function GroupConfirm(props) { + const { cache, setCache, back, start } = props; + + return ( + + +

Confirm group?

+ {JSON.stringify(cache)} +
+ + + + +
+ ); +} + +export default GroupConfirm; diff --git a/src/views/jobs/builder/GroupSelector.jsx b/src/views/jobs/builder/GroupSelector.jsx new file mode 100644 index 0000000..98d5fbe --- /dev/null +++ b/src/views/jobs/builder/GroupSelector.jsx @@ -0,0 +1,30 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function GroupSelector(props) { + const { cache, setCache, cancel, next } = props; + function makeReq() { + setCache({ + testNames: ["single"], + }); + } + + return ( + + + {JSON.stringify(cache)} + + + + + + + + ); +} + +export default GroupSelector; diff --git a/src/views/jobs/builder/IndividualConfirm.jsx b/src/views/jobs/builder/IndividualConfirm.jsx new file mode 100644 index 0000000..3f91839 --- /dev/null +++ b/src/views/jobs/builder/IndividualConfirm.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function IndividualConfirm(props) { + const { cache, setCache, back, start } = props; + + return ( + + +

Individual Confirm?

+ {JSON.stringify(cache)} +
+ + + + +
+ ); +} + +export default IndividualConfirm; diff --git a/src/views/jobs/builder/IndividualSelector.jsx b/src/views/jobs/builder/IndividualSelector.jsx new file mode 100644 index 0000000..2bdaacd --- /dev/null +++ b/src/views/jobs/builder/IndividualSelector.jsx @@ -0,0 +1,31 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function IndividualSelector(props) { + const { cache, setCache, cancel, next } = props; + function makeReq() { + setCache({ + testNames: ["failing"], + }); + + } + + return ( + + + {JSON.stringify(cache)} + + + + + + + + ); +} + +export default IndividualSelector; diff --git a/src/views/jobs/builder/JobBuilder.jsx b/src/views/jobs/builder/JobBuilder.jsx index 36191e4..bc90607 100644 --- a/src/views/jobs/builder/JobBuilder.jsx +++ b/src/views/jobs/builder/JobBuilder.jsx @@ -1,11 +1,9 @@ import React, { useContext, useState, useEffect } from "react"; - +import {useNavigate} from "react-router-dom"; import StoreContext from "../../../ctx/StoreContext.jsx"; +import JobContext from "../../../ctx/JobContext.jsx"; -import Button from "@mui/material/Button"; import Dialog from "@mui/material/Dialog"; -import DialogActions from "@mui/material/DialogActions"; -import DialogContent from "@mui/material/DialogContent"; import Toolbar from "@mui/material/Toolbar"; import DialogTitle from "@mui/material/DialogTitle"; @@ -18,9 +16,22 @@ import PageviewIcon from "@mui/icons-material/Pageview"; import ViewColumnIcon from "@mui/icons-material/ViewColumn"; import ViewCarouselIcon from "@mui/icons-material/ViewCarousel"; -export default function JobBuilder(props) { - const { state: store, updateStore } = useContext(StoreContext); +import IndividualSelector from "./IndividualSelector.jsx"; +import IndividualConfirm from "./IndividualConfirm.jsx"; +import GroupSelector from "./GroupSelector.jsx"; +import GroupConfirm from "./GroupConfirm.jsx"; + +import PipelineSelector from "./PipelineSelector.jsx"; +import PipelineTrackSelector from "./PipelineTrackSelector.jsx"; +import PipelineConfirm from "./PipelineConfirm.jsx"; + + + +export default function JobBuilder() { + const navigate = useNavigate(); + const { state: store } = useContext(StoreContext); + const { jobFactory } = useContext(JobContext); const [quickOpen, setQuickOpen] = useState(false); const [jobDialogOpen, setJobDialogOpen] = useState(false); @@ -28,39 +39,51 @@ export default function JobBuilder(props) { e.preventDefault(); e.stopPropagation(); if (!store.simplifiedControls) return setQuickOpen(!quickOpen); + setBuilderPage("individualSelect"); setJobDialogOpen(true); }; const quickOpenClose = () => setQuickOpen(false); - const handleClickOpen = () => setJobDialogOpen(true); - + const handleClickOpen = (page)=> () =>{ + setBuilderPage(page); + setJobDialogOpen(true); + } + const [builderPage, setBuilderPage] = useState(); const [cache, setCache] = useState({}); const handleClose = (confirmed) => () => { setJobDialogOpen(false); if (!confirmed) return; - jobBuilder(cache); + const jobId = jobFactory(cache); + if(store.focusJob) + navigate(`/qualiteer/jobs#${jobId}`); }; // Pull info from url if possible? const actions = [ - { name: "Suite", icon: }, - { name: "Compound", icon: }, - { name: "Manual", icon: }, + { name: "Suite", icon: , page: "groupSelect" }, + { name: "Compound", icon: , page: "pipelineSelect" }, + { name: "Manual", icon: , page: "individualSelect" }, ]; + const changePage = (page) => () => setBuilderPage(page); + + const pages = { + individualSelect: , + individualConfirm: , + groupSelect: , + groupConfirm: , + pipelineSelect: , + pipelineTrackSelect: , + pipelineConfirm: + } + return ( New Job - - - - - + {pages[builderPage]} @@ -76,7 +99,7 @@ export default function JobBuilder(props) { key={action.name} icon={action.icon} tooltipTitle={action.name} - onClick={handleClickOpen} + onClick={handleClickOpen(action.page)} /> ))} diff --git a/src/views/jobs/builder/PipelineConfirm.jsx b/src/views/jobs/builder/PipelineConfirm.jsx new file mode 100644 index 0000000..aeb0a53 --- /dev/null +++ b/src/views/jobs/builder/PipelineConfirm.jsx @@ -0,0 +1,26 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function PipelineConfirm(props) { + const { cache, back, start } = props; + + return ( + + +

Pipeline Confirm

+ {JSON.stringify(cache)} + +
+ + + + +
+ ); +} + +export default PipelineConfirm; diff --git a/src/views/jobs/builder/PipelineSelector.jsx b/src/views/jobs/builder/PipelineSelector.jsx new file mode 100644 index 0000000..5fc2ec6 --- /dev/null +++ b/src/views/jobs/builder/PipelineSelector.jsx @@ -0,0 +1,91 @@ +import React, {useContext} from "react"; +import StoreContext from "../../../ctx/StoreContext.jsx"; + +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +import Accordion from "@mui/material/Accordion"; +import AccordionDetails from "@mui/material/AccordionDetails"; +import AccordionSummary from "@mui/material/AccordionSummary"; +import Typography from "@mui/material/Typography"; +import Stack from "@mui/material/Stack"; + +function PipelineSelector(props){ + const {cache, setCache, cancel, next} = props; + const {state: store} = useContext(StoreContext); + const { pipelineMappings } = store; + const primaryMappings = {}; + for(var pm of pipelineMappings){ + if(!(pm[0] in primaryMappings)) primaryMappings[pm[0]] = []; + primaryMappings[pm[0]].push(pm); + } + + const selectPrimary = (primarySelectedMappings) => ()=>{ + setCache({primarySelectedMappings}); + }; + + return( + + {Object.keys(primaryMappings).map((k, i)=>( + + + {k} + + + {primaryMappings[k].length} + + + ))} + + + + + + ) + + +} +export default PipelineSelector; + +/* + Server -> pipeMappings + [["primary", "secondary1", "tertiary1"], ["primary", "secondary2", "tertiary3"]] + */ + /* + const primaryMappings = pipeMappings.filter((m)=>m[0] === "primary"); // Select Page + + const displayTracks = []; + // Track Select Page + for(var pm of primaryMappings){ + for(var i=0;i{ + + }) + */ + /* Cache: + { + testTree: [["primary"],["secondary1", "secondary2"], ["tertiary1", "tertiary3"]] + } + */ + /* + tracks: [["primary", "secondary1", "tertiary1"], ["primary", "secondary2", "tertiary3"]] + */ + /**/ \ No newline at end of file diff --git a/src/views/jobs/builder/PipelineTrackSelector.jsx b/src/views/jobs/builder/PipelineTrackSelector.jsx new file mode 100644 index 0000000..083ae2a --- /dev/null +++ b/src/views/jobs/builder/PipelineTrackSelector.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import Button from "@mui/material/Button"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; + +function PipelineTrackSelector(props) { + const { cache, setCache, back, next } = props; + + return ( + + +

Select Track

+ {JSON.stringify(cache)} +
+ + + + +
+ ); +} + +export default PipelineTrackSelector; diff --git a/src/views/settings/Settings.jsx b/src/views/settings/Settings.jsx index 9713af6..1c16182 100644 --- a/src/views/settings/Settings.jsx +++ b/src/views/settings/Settings.jsx @@ -107,29 +107,17 @@ export default function Settings(props) { - + - + - + { }; axios.post(reportingUrl, { testResult }).catch((e) => { console.log(e.response.status); + }).then(()=>{ + if(status.status === 1) process.exit(1); }); }, endLiveCount * 1000); diff --git a/vite.config.js b/vite.config.js index 904b0fb..2a03780 100644 --- a/vite.config.js +++ b/vite.config.js @@ -9,6 +9,13 @@ export default () => { hmr: { port: 443, }, + proxy: { + '/api': 'http://localhost:52000', + '/socket.io': { + target: 'ws://localhost:52000', + ws: true + } + } }, build: { outDir: "./build",