summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui')
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js109
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js105
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js89
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js98
4 files changed, 209 insertions, 192 deletions
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 ? (
- <Link href={`/projects/${projectId}/topologies/${topology.number}`}>
- <a>{topology.name}</a>
- </Link>
- ) : (
- 'Unknown Topology'
- ),
- },
- `${scenario.workload.trace.name} (${scenario.workload.samplingFraction * 100}%)`,
- { title: <ScenarioState state={scenario.job.state} /> },
- ]
- })
- : [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 4 },
- title: (
- <TableEmptyState
- status={status}
- loadingTitle="Loading Scenarios"
- emptyTitle="No scenarios"
- emptyText="You have not created any scenario for this portfolio yet. Click the New Scenario button to create one."
- />
- ),
- },
- ],
- },
- ]
-
- 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 (
- <Table
- aria-label="Scenario List"
- variant="compact"
- cells={columns}
- rows={rows}
- actionResolver={scenarios.length > 0 ? actionResolver : undefined}
- >
- <TableHeader />
- <TableBody />
- </Table>
+ <TableComposable aria-label="Scenario List" variant="compact">
+ <Thead>
+ <Tr>
+ <Th>Name</Th>
+ <Th>Topology</Th>
+ <Th>Trace</Th>
+ <Th>State</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {scenarios.map((scenario) => (
+ <Tr key={scenario.id}>
+ <Td dataLabel="Name">{scenario.name}</Td>
+ <Td dataLabel="Topology">
+ {scenario.topology ? (
+ <Link href={`/projects/${projectId}/topologies/${scenario.topology.number}`}>
+ <a>{scenario.topology.name}</a>
+ </Link>
+ ) : (
+ 'Unknown Topology'
+ )}
+ ,
+ </Td>
+ <Td dataLabel="Workload">{`${scenario.workload.trace.name} (${
+ scenario.workload.samplingFraction * 100
+ }%)`}</Td>
+ <Td dataLabel="State">
+ <ScenarioState state={scenario.job.state} />
+ </Td>
+ <Td isActionCell>
+ <ActionsColumn items={actions(scenario)} />
+ </Td>
+ </Tr>
+ ))}
+ {scenarios.length === 0 && (
+ <Tr>
+ <Td colSpan={4}>
+ <Bullseye>
+ <TableEmptyState
+ status={status}
+ loadingTitle="Loading Scenarios"
+ emptyTitle="No scenarios"
+ emptyText="You have not created any scenario for this portfolio yet. Click the New Scenario button to create one."
+ />
+ </Bullseye>
+ </Td>
+ </Tr>
+ )}
+ </Tbody>
+ </TableComposable>
)
}
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: (
- <Link href={`/projects/${projectId}/portfolios/${portfolio.number}`}>{portfolio.name}</Link>
- ),
- },
- 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: (
- <TableEmptyState
- status={status}
- loadingTitle="Loading portfolios"
- emptyTitle="No portfolios"
- emptyText="You have not created any portfolio for this project yet. Click the New Portfolio button to create one."
- />
- ),
- },
- ],
- },
- ]
-
- 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 (
- <Table aria-label="Portfolio List" variant="compact" cells={columns} rows={rows} actions={actions}>
- <TableHeader />
- <TableBody />
- </Table>
+ <TableComposable aria-label="Portfolio List" variant="compact">
+ <Thead>
+ <Tr>
+ <Th>Name</Th>
+ <Th>Scenarios</Th>
+ <Th>Metrics</Th>
+ <Th>Repeats</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {portfolios.map((portfolio) => (
+ <Tr key={portfolio.id}>
+ <Td dataLabel="Name">
+ <Link href={`/projects/${projectId}/portfolios/${portfolio.number}`}>{portfolio.name}</Link>
+ </Td>
+ <Td dataLabel="Scenarios">
+ {portfolio.scenarios.length === 1
+ ? '1 scenario'
+ : `${portfolio.scenarios.length} scenarios`}
+ </Td>
+ <Td dataLabel="Metrics">
+ {portfolio.targets.metrics.length === 1
+ ? '1 metric'
+ : `${portfolio.targets.metrics.length} metrics`}
+ </Td>
+ <Td dataLabel="Repeats">
+ {portfolio.targets.repeats === 1 ? '1 repeat' : `${portfolio.targets.repeats} repeats`}
+ </Td>
+ <Td isActionCell>
+ <ActionsColumn items={actions(portfolio)} />
+ </Td>
+ </Tr>
+ ))}
+ {portfolios.length === 0 && (
+ <Tr>
+ <Td colSpan={4}>
+ <Bullseye>
+ <TableEmptyState
+ status={status}
+ loadingTitle="Loading portfolios"
+ emptyTitle="No portfolios"
+ emptyText="You have not created any portfolio for this project yet. Click the New Portfolio button to create one."
+ />
+ </Bullseye>
+ </Td>
+ </Tr>
+ )}
+ </Tbody>
+ </TableComposable>
)
}
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: <Link href={`/projects/${projectId}/topologies/${topology.number}`}>{topology.name}</Link>,
- },
- topology.rooms.length === 1 ? '1 room' : `${topology.rooms.length} rooms`,
- parseAndFormatDateTime(topology.updatedAt),
- ])
- : [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 3 },
- title: (
- <TableEmptyState
- status={status}
- loadingTitle="Loading topologies"
- emptyTitle="No topologies"
- emptyText="You have not created any topology for this project yet. Click the New Topology button to create one."
- />
- ),
- },
- ],
- },
- ]
-
- 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 (
- <Table
- aria-label="Topology List"
- variant="compact"
- cells={columns}
- rows={rows}
- actionResolver={topologies.length > 0 ? actionResolver : () => []}
- >
- <TableHeader />
- <TableBody />
- </Table>
+ <TableComposable aria-label="Topology List" variant="compact">
+ <Thead>
+ <Tr>
+ <Th>Name</Th>
+ <Th>Rooms</Th>
+ <Th>Last Edited</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {topologies.map((topology) => (
+ <Tr key={topology.id}>
+ <Td dataLabel="Name">
+ <Link href={`/projects/${projectId}/topologies/${topology.number}`}>{topology.name}</Link>
+ </Td>
+ <Td dataLabel="Rooms">
+ {topology.rooms.length === 1 ? '1 room' : `${topology.rooms.length} rooms`}
+ </Td>
+ <Td dataLabel="Last Edited">{parseAndFormatDateTime(topology.updatedAt)}</Td>
+ <Td isActionCell>
+ <ActionsColumn items={actions(topology)} />
+ </Td>
+ </Tr>
+ ))}
+ {topologies.length === 0 && (
+ <Tr>
+ <Td colSpan={3}>
+ <Bullseye>
+ <TableEmptyState
+ status={status}
+ loadingTitle="Loading topologies"
+ emptyTitle="No topologies"
+ emptyText="You have not created any topology for this project yet. Click the New Topology button to create one."
+ />
+ </Bullseye>
+ </Td>
+ </Tr>
+ )}
+ </Tbody>
+ </TableComposable>
)
}
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: (
- <Button variant="link" isInline onClick={() => onSelect(room)}>
- {room.name}
- </Button>
- ),
- },
- tileCount === 1 ? '1 tile' : `${tileCount} tiles`,
- rackCount === 1 ? '1 rack' : `${rackCount} racks`,
- ]
- })
- : [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 3 },
- title: <TableEmptyState status={status} loadingTitle="Loading Rooms" />,
- },
- ],
- },
- ]
-
- 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 (
- <Table aria-label="Room list" variant="compact" cells={columns} rows={rows} actions={actions}>
- <TableHeader />
- <TableBody />
- </Table>
+ <TableComposable aria-label="Room list" variant="compact">
+ <Thead>
+ <Tr>
+ <Th>Name</Th>
+ <Th>Tiles</Th>
+ <Th>Racks</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {topology?.rooms.map((room) => {
+ const tileCount = room.tiles.length
+ const rackCount = room.tiles.filter((tile) => tile.rack).length
+ return (
+ <Tr key={room.id}>
+ <Td dataLabel="Name">
+ <Button variant="link" isInline onClick={() => onSelect(room)}>
+ {room.name}
+ </Button>
+ </Td>
+ <Td dataLabel="Tiles">{tileCount === 1 ? '1 tile' : `${tileCount} tiles`}</Td>
+ <Td dataLabel="Racks">{rackCount === 1 ? '1 rack' : `${rackCount} racks`}</Td>
+ <Td isActionCell>
+ <ActionsColumn items={actions(room)} />
+ </Td>
+ </Tr>
+ )
+ })}
+ {topology?.rooms.length === 0 && (
+ <Tr>
+ <Td colSpan={4}>
+ <Bullseye>
+ <TableEmptyState
+ status={status}
+ loadingTitle="Loading Rooms"
+ emptyTitle="No rooms"
+ emptyText="There are currently no rooms in this topology. Open the Floor Plan to create a room"
+ />
+ </Bullseye>
+ </Td>
+ </Tr>
+ )}
+ </Tbody>
+ </TableComposable>
)
}