From 86bc9e74630374853d11bc1c8f7ba5ffafbaa868 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Tue, 20 Sep 2022 14:28:40 +0200 Subject: refactor(web/ui): Migrate to composable table This change updates the web interface to use the composable table API offered by PatternFly 4. This has replaced the legacy table API which will be removed in the next major version of PatternFly. --- .../src/components/portfolios/ScenarioTable.js | 109 +++++++++++---------- .../src/components/projects/PortfolioTable.js | 105 +++++++++++--------- .../src/components/projects/TopologyTable.js | 89 ++++++++--------- .../src/components/topologies/RoomTable.js | 98 +++++++++--------- 4 files changed, 209 insertions(+), 192 deletions(-) (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js index 68647957..8dc52f7a 100644 --- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js +++ b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js @@ -20,8 +20,9 @@ * SOFTWARE. */ +import { Bullseye } from '@patternfly/react-core' import Link from 'next/link' -import { Table, TableBody, TableHeader } from '@patternfly/react-table' +import { TableComposable, Thead, Tr, Th, Tbody, Td, ActionsColumn } from '@patternfly/react-table' import React from 'react' import { Portfolio, Status } from '../../shapes' import TableEmptyState from '../util/TableEmptyState' @@ -33,65 +34,65 @@ function ScenarioTable({ portfolio, status }) { const projectId = portfolio?.project?.id const scenarios = portfolio?.scenarios ?? [] - const columns = ['Name', 'Topology', 'Trace', 'State'] - const rows = - scenarios.length > 0 - ? scenarios.map((scenario) => { - const topology = scenario.topology - - return [ - scenario.name, - { - title: topology ? ( - - {topology.name} - - ) : ( - 'Unknown Topology' - ), - }, - `${scenario.workload.trace.name} (${scenario.workload.samplingFraction * 100}%)`, - { title: }, - ] - }) - : [ - { - heightAuto: true, - cells: [ - { - props: { colSpan: 4 }, - title: ( - - ), - }, - ], - }, - ] - - const actionResolver = (_, { rowIndex }) => [ + const actions = ({ number }) => [ { title: 'Delete Scenario', - onClick: (_, rowId) => deleteScenario({ projectId: projectId, number: scenarios[rowId].number }), - isDisabled: rowIndex === 0, + onClick: () => deleteScenario({ projectId: projectId, number }), + isDisabled: number === 0, }, ] return ( - 0 ? actionResolver : undefined} - > - - -
+ + + + Name + Topology + Trace + State + + + + {scenarios.map((scenario) => ( + + {scenario.name} + + {scenario.topology ? ( + + {scenario.topology.name} + + ) : ( + 'Unknown Topology' + )} + , + + {`${scenario.workload.trace.name} (${ + scenario.workload.samplingFraction * 100 + }%)`} + + + + + + + + ))} + {scenarios.length === 0 && ( + + + + + + + + )} + + ) } diff --git a/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js b/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js index aa679843..0afeaeaf 100644 --- a/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js +++ b/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js @@ -20,64 +20,75 @@ * SOFTWARE. */ +import { Bullseye } from '@patternfly/react-core' import PropTypes from 'prop-types' import Link from 'next/link' -import { Table, TableBody, TableHeader } from '@patternfly/react-table' +import { TableComposable, Thead, Tbody, Tr, Th, Td, ActionsColumn } from '@patternfly/react-table' import React from 'react' import TableEmptyState from '../util/TableEmptyState' import { usePortfolios, useDeletePortfolio } from '../../data/project' -const PortfolioTable = ({ projectId }) => { +function PortfolioTable({ projectId }) { const { status, data: portfolios = [] } = usePortfolios(projectId) const { mutate: deletePortfolio } = useDeletePortfolio() - const columns = ['Name', 'Scenarios', 'Metrics', 'Repeats'] - const rows = - portfolios.length > 0 - ? portfolios.map((portfolio) => [ - { - title: ( - {portfolio.name} - ), - }, - portfolio.scenarios.length === 1 ? '1 scenario' : `${portfolio.scenarios.length} scenarios`, - portfolio.targets.metrics.length === 1 ? '1 metric' : `${portfolio.targets.metrics.length} metrics`, - portfolio.targets.repeats === 1 ? '1 repeat' : `${portfolio.targets.repeats} repeats`, - ]) - : [ - { - heightAuto: true, - cells: [ - { - props: { colSpan: 4 }, - title: ( - - ), - }, - ], - }, - ] - - const actions = - portfolios.length > 0 - ? [ - { - title: 'Delete Portfolio', - onClick: (_, rowId) => deletePortfolio({ projectId, number: portfolios[rowId].number }), - }, - ] - : [] + const actions = (portfolio) => [ + { + title: 'Delete Portfolio', + onClick: () => deletePortfolio({ projectId, number: portfolio.number }), + }, + ] return ( - - - -
+ + + + Name + Scenarios + Metrics + Repeats + + + + {portfolios.map((portfolio) => ( + + + {portfolio.name} + + + {portfolio.scenarios.length === 1 + ? '1 scenario' + : `${portfolio.scenarios.length} scenarios`} + + + {portfolio.targets.metrics.length === 1 + ? '1 metric' + : `${portfolio.targets.metrics.length} metrics`} + + + {portfolio.targets.repeats === 1 ? '1 repeat' : `${portfolio.targets.repeats} repeats`} + + + + + + ))} + {portfolios.length === 0 && ( + + + + + + + + )} + + ) } diff --git a/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js b/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js index ced5304a..62deace0 100644 --- a/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js +++ b/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js @@ -20,66 +20,67 @@ * SOFTWARE. */ +import { Bullseye } from '@patternfly/react-core' import PropTypes from 'prop-types' import Link from 'next/link' -import { Table, TableBody, TableHeader } from '@patternfly/react-table' +import { Tr, Th, Thead, Td, ActionsColumn, Tbody, TableComposable } from '@patternfly/react-table' import React from 'react' import TableEmptyState from '../util/TableEmptyState' import { parseAndFormatDateTime } from '../../util/date-time' import { useTopologies, useDeleteTopology } from '../../data/topology' -const TopologyTable = ({ projectId }) => { +function TopologyTable({ projectId }) { const { status, data: topologies = [] } = useTopologies(projectId) const { mutate: deleteTopology } = useDeleteTopology() - const columns = ['Name', 'Rooms', 'Last Edited'] - const rows = - topologies.length > 0 - ? topologies.map((topology) => [ - { - title: {topology.name}, - }, - topology.rooms.length === 1 ? '1 room' : `${topology.rooms.length} rooms`, - parseAndFormatDateTime(topology.updatedAt), - ]) - : [ - { - heightAuto: true, - cells: [ - { - props: { colSpan: 3 }, - title: ( - - ), - }, - ], - }, - ] - - const actionResolver = (_, { rowIndex }) => [ + const actions = ({ number }) => [ { title: 'Delete Topology', - onClick: (_, rowId) => deleteTopology({ projectId, number: topologies[rowId].number }), - isDisabled: rowIndex === 0, + onClick: () => deleteTopology({ projectId, number }), + isDisabled: number === 0, }, ] return ( - 0 ? actionResolver : () => []} - > - - -
+ + + + Name + Rooms + Last Edited + + + + {topologies.map((topology) => ( + + + {topology.name} + + + {topology.rooms.length === 1 ? '1 room' : `${topology.rooms.length} rooms`} + + {parseAndFormatDateTime(topology.updatedAt)} + + + + + ))} + {topologies.length === 0 && ( + + + + + + + + )} + + ) } diff --git a/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js b/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js index 49e5f095..7f7b4171 100644 --- a/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js +++ b/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js @@ -1,63 +1,67 @@ -import { Button } from '@patternfly/react-core' +import { Button, Bullseye } from '@patternfly/react-core' import PropTypes from 'prop-types' import React from 'react' import { useDispatch } from 'react-redux' import { useTopology } from '../../data/topology' -import { Table, TableBody, TableHeader } from '@patternfly/react-table' +import { Tr, Th, Thead, TableComposable, Td, ActionsColumn, Tbody } from '@patternfly/react-table' import { deleteRoom } from '../../redux/actions/topology/room' import TableEmptyState from '../util/TableEmptyState' function RoomTable({ projectId, topologyId, onSelect }) { const dispatch = useDispatch() const { status, data: topology } = useTopology(projectId, topologyId) - const onDelete = (room) => dispatch(deleteRoom(room.id)) - - const columns = ['Name', 'Tiles', 'Racks'] - const rows = - topology?.rooms.length > 0 - ? topology.rooms.map((room) => { - const tileCount = room.tiles.length - const rackCount = room.tiles.filter((tile) => tile.rack).length - return [ - { - title: ( - - ), - }, - tileCount === 1 ? '1 tile' : `${tileCount} tiles`, - rackCount === 1 ? '1 rack' : `${rackCount} racks`, - ] - }) - : [ - { - heightAuto: true, - cells: [ - { - props: { colSpan: 3 }, - title: , - }, - ], - }, - ] - - const actions = - topology?.rooms.length > 0 - ? [ - { - title: 'Delete room', - onClick: (_, rowId) => onDelete(topology.rooms[rowId]), - }, - ] - : [] + const actions = (room) => [ + { + title: 'Delete room', + onClick: () => onDelete(room), + }, + ] return ( - - - -
+ + + + Name + Tiles + Racks + + + + {topology?.rooms.map((room) => { + const tileCount = room.tiles.length + const rackCount = room.tiles.filter((tile) => tile.rack).length + return ( + + + + + {tileCount === 1 ? '1 tile' : `${tileCount} tiles`} + {rackCount === 1 ? '1 rack' : `${rackCount} racks`} + + + + + ) + })} + {topology?.rooms.length === 0 && ( + + + + + + + + )} + + ) } -- cgit v1.2.3