From 11e355321db20b70c76c35b6e8fc36dbb9d97fc6 Mon Sep 17 00:00:00 2001 From: vincent van beek Date: Wed, 15 Apr 2026 16:19:02 +0200 Subject: add a job report to the scenario overview with details and time data (#406) * add a job report to the scenario overview with details and time data * create Report data class --- .../webui/components/portfolios/ScenarioTable.js | 37 ++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'opendc-web/opendc-web-server/src/main/webui/components/portfolios/ScenarioTable.js') diff --git a/opendc-web/opendc-web-server/src/main/webui/components/portfolios/ScenarioTable.js b/opendc-web/opendc-web-server/src/main/webui/components/portfolios/ScenarioTable.js index b068d045..db88456b 100644 --- a/opendc-web/opendc-web-server/src/main/webui/components/portfolios/ScenarioTable.js +++ b/opendc-web/opendc-web-server/src/main/webui/components/portfolios/ScenarioTable.js @@ -23,24 +23,36 @@ import { Bullseye } from '@patternfly/react-core' import Link from 'next/link' import { TableComposable, Thead, Tr, Th, Tbody, Td, ActionsColumn } from '@patternfly/react-table' -import React from 'react' +import React, { useState } from 'react' import { Portfolio, Status } from '../../shapes' import TableEmptyState from '../util/TableEmptyState' import ScenarioState from './ScenarioState' import { useDeleteScenario } from '../../data/project' +import JobReportModal from './JobReportModal' function ScenarioTable({ portfolio, status }) { const { mutate: deleteScenario } = useDeleteScenario() const projectId = portfolio?.project?.id const scenarios = portfolio?.scenarios ?? [] + const [reportJobId, setReportJobId] = useState(null) - const actions = ({ number }) => [ - { - title: 'Delete Scenario', - onClick: () => deleteScenario({ projectId: projectId, number }), - isDisabled: number === 0, - }, - ] + const actions = (scenario) => { + const latestJob = scenario.jobs[scenario.jobs.length - 1] + const canViewReport = latestJob && (latestJob.state === 'FINISHED' || latestJob.state === 'FAILED') + + return [ + { + title: 'View Report', + onClick: () => setReportJobId(latestJob.id), + isDisabled: !canViewReport, + }, + { + title: 'Delete Scenario', + onClick: () => deleteScenario({ projectId: projectId, number: scenario.number }), + isDisabled: scenario.number === 0, + }, + ] + } return ( @@ -49,6 +61,7 @@ function ScenarioTable({ portfolio, status }) { Name Topology Trace + Created State @@ -68,6 +81,11 @@ function ScenarioTable({ portfolio, status }) { {`${scenario.workload.trace.name} (${ scenario.workload.samplingFraction * 100 }%)`} + + {scenario.jobs && scenario.jobs.length > 0 + ? new Date(scenario.jobs[0].createdAt).toLocaleString() + : '-'} + @@ -78,7 +96,7 @@ function ScenarioTable({ portfolio, status }) { ))} {scenarios.length === 0 && ( - + )} + {reportJobId && setReportJobId(null)} />} ) } -- cgit v1.2.3