diff --git a/frontend/unified/src/App.tsx b/frontend/unified/src/App.tsx index b8fe598..1f7f38b 100644 --- a/frontend/unified/src/App.tsx +++ b/frontend/unified/src/App.tsx @@ -21,6 +21,7 @@ import { SessionQueryQuery, SessionQueryQueryVariables, } from "./__generated__/App.generated"; +import { WorkflowsQueryQuery } from "./components/JobsViewer/__generated__/JobsTable.generated"; const VERTICAL_SPACING = 2; const HORIZONTAL_SPACING = 2; @@ -93,6 +94,9 @@ export const App: React.FC = () => { const [customSession, setCustomSession] = useState( null ); + const [TableInfo, setTableInfo] = useState( + undefined + ); const { loading, error, data } = useQuery(SESSION_QUERY, { variables: {} }); if (loading) return

Loading...

; @@ -292,6 +296,7 @@ export const App: React.FC = () => { availableTemplates={filterTemplates( Technique[currentTechnique as keyof typeof Technique] )} + visit={selectedVisit} /> @@ -304,7 +309,7 @@ export const App: React.FC = () => { /> Log - + { Jobs - + diff --git a/frontend/unified/src/components/InspectLogMeta.tsx b/frontend/unified/src/components/InspectLogMeta.tsx index 5a046a6..ca620e8 100644 --- a/frontend/unified/src/components/InspectLogMeta.tsx +++ b/frontend/unified/src/components/InspectLogMeta.tsx @@ -1,5 +1,16 @@ -import React, { FC } from "react"; -import { Button, Stack } from "@mui/material"; +import React, { FC, useState } from "react"; +import { + Button, + Stack, + Menu, + MenuItem, + List, + ListItemButton, + ListItemText, + Paper, + Typography, + Divider, +} from "@mui/material"; import { useQuery } from "@apollo/client/react"; import { gql, type TypedDocumentNode } from "@apollo/client"; @@ -8,6 +19,8 @@ import { LogQueryQuery, LogQueryQueryVariables, } from "./__generated__/InspectLogMeta.generated"; +import { Visit } from "@diamondlightsource/sci-react-ui"; +import { WorkflowsQueryQuery } from "./JobsViewer/__generated__/JobsTable.generated"; export const InspectLog_Query: TypedDocumentNode< LogQueryQuery, @@ -31,31 +44,79 @@ export const InspectLog_Query: TypedDocumentNode< } } } + ... on WorkflowErroredStatus { + message + tasks { + name + artifacts { + name + url + mimeType + } + } + } + ... on WorkflowFailedStatus { + message + tasks { + name + artifacts { + name + url + mimeType + } + } + } } } } `; -export const DisplayLogMeta: FC = (props: { visit: any }) => { +type DisplayLogMetaProps = { + visit: Visit; + TableInfo: WorkflowsQueryQuery; +}; + +export const DisplayLogMeta: FC = (props: { + visit: Visit; + TableInfo: WorkflowsQueryQuery; +}) => { + let artifactUrlAndLogFileTuples: [string, string][] = []; + let workflownames: string[] = []; + let y: any = []; + + //ToDO maybe need to Consider what to display if there is no workflow as then workflowsnames is empty + if (props.TableInfo !== undefined) { + props.TableInfo.workflows?.nodes.forEach((workflow) => { + if (workflow.status?.__typename == "WorkflowSucceededStatus") { + workflownames.push(workflow.name); + } + }); + } + + const [selectedWorkflow, setSelectedWorkflow] = useState(0); + const { loading, error, data } = useQuery(InspectLog_Query, { - variables: { visitobj: props.visit, name: "example-template-599zg" }, + variables: { visitobj: props.visit, name: workflownames[0] }, }); - let x: any = []; - if (data !== undefined && data !== null) { - if (data.workflow !== undefined && data.workflow !== null) { - data.workflow.status?.tasks.forEach((element: any) => { - element.artifacts.forEach((subElement: any) => { - if (subElement !== undefined) { - if (subElement.url !== undefined) { - if (subElement.mimeType == "text/plain") { - x.push([subElement.url, element.name + ".log"]); - } + if (data !== undefined) { + if (data.workflow !== null) { + if (data.workflow.status?.__typename == "WorkflowSucceededStatus") { + data.workflow.status.tasks.forEach((task) => { + task.artifacts.forEach((artifact) => { + if (artifact.mimeType == "text/plain") { + artifactUrlAndLogFileTuples.push([ + artifact.url, + task.name + ".log", + ]); } - } + }); }); - }); + } else + y[0] = ["http://localhost:5173/unified", "Error-No-logs-found.log"]; } + } else { + y = ["http://localhost:5173/unified", "Error-No-logs-found.log"]; } const openInNewTab = (url: string) => { @@ -65,19 +126,19 @@ export const DisplayLogMeta: FC = (props: { visit: any }) => { } }; - function makeButtonArray(Arr: any) { + function makeButtonArray(artifactUrlsAndLogFilenames: [string, string][]) { return ( {" "} - {Arr.map((subArr: any) => { + {artifactUrlsAndLogFilenames.map(([artifactUrl, logFilename]) => { return ( ); })}{" "} @@ -85,7 +146,70 @@ export const DisplayLogMeta: FC = (props: { visit: any }) => { ); } - return
{makeButtonArray(x)}
; + //Menu handling + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleClose = () => { + setAnchorEl(null); + }; + const handleClickListItem = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleMenuListItem = ( + event: React.MouseEvent, + index: number + ) => { + setSelectedWorkflow(index); + setAnchorEl(null); + }; + + return ( +
+ + + + + + + + + {workflownames.map((option: string, index: number) => ( + handleMenuListItem(event, index)} + > + {option} + + + ))} + + +

+ + + Choose a log from {workflownames[selectedWorkflow]}: + +

+ {makeButtonArray(artifactUrlAndLogFileTuples)} +

+ ); }; export default DisplayLogMeta; diff --git a/frontend/unified/src/components/JobsViewer/JobsTable.tsx b/frontend/unified/src/components/JobsViewer/JobsTable.tsx index 6f447f8..c35e09b 100644 --- a/frontend/unified/src/components/JobsViewer/JobsTable.tsx +++ b/frontend/unified/src/components/JobsViewer/JobsTable.tsx @@ -3,7 +3,7 @@ import { WorkflowsQueryQuery, WorkflowsQueryQueryVariables, } from "./__generated__/JobsTable.generated"; -import { Suspense, useCallback, useState } from "react"; +import { Suspense, useCallback, useState, useEffect } from "react"; import { Visit } from "./JobsViewer"; import TableContent, { TABLECONTENT_FRAGMENT } from "./TableContent"; @@ -22,7 +22,13 @@ export const JOBSTABLE_QUERY: TypedDocumentNode< ${TABLECONTENT_FRAGMENT} `; -const JobsTable = ({ visit }: { visit: Visit }) => { +const JobsTable = ({ + visit, + setInfo, +}: { + visit: Visit; + setInfo: (_: WorkflowsQueryQuery | undefined) => void; +}) => { const [selectedLimit, setSelectedLimit] = useState(5); const [currentPage, setCurrentPage] = useState(0); const [cursor, setCursor] = useState(null); @@ -45,6 +51,10 @@ const JobsTable = ({ visit }: { visit: Visit }) => { fetchPolicy: "cache-and-network", }); + useEffect(() => { + setInfo(data); + }); + return ( diff --git a/frontend/unified/src/components/JobsViewer/JobsViewer.tsx b/frontend/unified/src/components/JobsViewer/JobsViewer.tsx index b4d5437..80efca1 100644 --- a/frontend/unified/src/components/JobsViewer/JobsViewer.tsx +++ b/frontend/unified/src/components/JobsViewer/JobsViewer.tsx @@ -1,5 +1,6 @@ import { Suspense } from "react"; import JobsTable from "./JobsTable"; +import { WorkflowsQueryQuery } from "./__generated__/JobsTable.generated"; export type Visit = { proposalCode: string; @@ -7,10 +8,16 @@ export type Visit = { number: number; }; -const JobsViewer = ({ visit }: { visit: Visit }) => { +const JobsViewer = ({ + visit, + setInfo, +}: { + visit: Visit; + setInfo: (_: WorkflowsQueryQuery | undefined) => void; +}) => { return ( - + ); };