From c1f2053a28b2bf8ba8c154b00f6cf15a6a5b0d99 Mon Sep 17 00:00:00 2001 From: Ian Ballou Date: Thu, 19 Dec 2024 23:11:26 +0000 Subject: [PATCH] Refs #38107 - Make booted container images rows expandable --- .../BootedContainerImagesPage.js | 195 +++++++++++++++--- 1 file changed, 161 insertions(+), 34 deletions(-) diff --git a/webpack/scenes/BootedContainerImages/BootedContainerImagesPage.js b/webpack/scenes/BootedContainerImages/BootedContainerImagesPage.js index 7129ec48b02..e3836e9e751 100644 --- a/webpack/scenes/BootedContainerImages/BootedContainerImagesPage.js +++ b/webpack/scenes/BootedContainerImages/BootedContainerImagesPage.js @@ -1,13 +1,22 @@ import React from 'react'; +import { TableComposable, Thead, Th, Tbody, Tr, Td, ExpandableRowContent } from '@patternfly/react-table'; import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage'; -import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table'; import { useSetParamsAndApiAndSearch, useTableIndexAPIResponse, } from 'foremanReact/components/PF4/TableIndexPage/Table/TableIndexHooks'; import { useUrlParams, + useSet, } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks'; +import { + getColumnHelpers, +} from 'foremanReact/components/PF4/TableIndexPage/Table/helpers'; +import { + useTableSort, +} from 'foremanReact/components/PF4/Helpers/useTableSort'; +import Pagination from 'foremanReact/components/Pagination'; +import EmptyPage from 'foremanReact/routes/common/EmptyPage'; import { translate as __ } from 'foremanReact/common/I18n'; import BOOTED_CONTAINER_IMAGES_KEY, { BOOTED_CONTAINER_IMAGES_API_PATH } from './BootedContainerImagesConstants'; @@ -29,12 +38,6 @@ const BootedContainerImagesPage = () => { }, }; - const STATUS = { - PENDING: 'PENDING', - RESOLVED: 'RESOLVED', - ERROR: 'ERROR', - }; - const { searchParam: urlSearchQuery = '', page: urlPage, @@ -44,15 +47,34 @@ const BootedContainerImagesPage = () => { if (urlPage) defaultParams.page = Number(urlPage); if (urlPerPage) defaultParams.per_page = Number(urlPerPage); const apiOptions = { key: BOOTED_CONTAINER_IMAGES_KEY }; + const response = useTableIndexAPIResponse({ apiUrl: BOOTED_CONTAINER_IMAGES_API_PATH, apiOptions, defaultParams, }); + const columnsToSortParams = {}; + Object.keys(columns).forEach(key => { + if (columns[key].isSorted) { + columnsToSortParams[columns[key].title] = key; + } + }); + const { pfSortParams } = useTableSort({ + allColumns: Object.keys(columns).map(k => columns[k].title), + columnsToSortParams, + onSort, + }); + const expandedImages = useSet([]); + const imageIsExpanded = image_name => expandedImages.has(image_name); + const STATUS = { + PENDING: 'PENDING', + RESOLVED: 'RESOLVED', + ERROR: 'ERROR', + }; const { response: { - results, + results = [], per_page: perPage, page, subtotal, @@ -68,40 +90,145 @@ const BootedContainerImagesPage = () => { setAPIOptions: response.setAPIOptions, }); + const [columnNamesKeys, keysToColumnNames] = getColumnHelpers(columns); + const onSort = (_event, index, direction) => { + setParamsAndAPI({ + ...params, + order: `${Object.keys(columns)[index]} ${direction}`, + }); + }; + const onPagination = newPagination => { + setParamsAndAPI({ ...params, ...newPagination }); + }; + const bottomPagination = ( + + ); + return ( - - setAPIOptions({ - ...apiOptions, - params: { urlSearchQuery }, - }) - } - columns={columns} - errorMessage={ - status === STATUS.ERROR && errorMessage ? errorMessage : null - } - isPending={status === STATUS.PENDING} - /> + <> + + + + <> + + ))} + + + + + {status === STATUS.PENDING && results.length === 0 && ( + + + + )} + {!status === STATUS.PENDING && + results.length === 0 && + !errorMessage && ( + + + + )} + {errorMessage && ( + + + + )} + + {results?.map((result, rowIndex) => { + const { image_name, digests } = result; + const isExpanded = imageIsExpanded(image_name); + return ( + + + <> + + ))} + + + {digests ? + + + + + + + + {digests.map((digest, index) => ( + + + + + ))} + + + + + : null} + + ); + })} + + {results.length > 0 && !errorMessage && bottomPagination} + ); };
+ {columnNamesKeys.map(k => ( + + {keysToColumnNames[k]} +
+ +
+ +
+ +
0 && { + rowIndex, + isExpanded, + onToggle: (_event, _rInx, isOpen,) => expandedImages.onToggle(isOpen, image_name), + expandId: 'booted-containers-expander' + }} + /> + {columnNamesKeys.map(k => ( + + {columns[k].wrapper ? columns[k].wrapper(result) : result[k]} +
+ + +
{__('Image digest')}{__('Hosts')}
{digest.bootc_booted_digest} + {digest.host_count} +