summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/projects
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-09-20 14:28:40 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-09-20 16:07:06 +0200
commit86bc9e74630374853d11bc1c8f7ba5ffafbaa868 (patch)
tree855256f27ded3cf0ec662119dbf26c3b138a8f5b /opendc-web/opendc-web-ui/src/components/projects
parent1bc6b557efed112ced28e3f3539f06029addaa71 (diff)
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.
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/projects')
-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
2 files changed, 103 insertions, 91 deletions
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>
)
}