From 89ef5bc815246ba0afca12df08cc59234335d0f4 Mon Sep 17 00:00:00 2001 From: Thuan Vo Date: Fri, 18 Nov 2022 19:25:55 -0500 Subject: [PATCH] chore(tables): refactor event type table --- src/app/Events/EventTypes.tsx | 167 ++++++++++-------- .../__snapshots__/EventTypes.test.tsx.snap | 152 +++++++++++++--- 2 files changed, 216 insertions(+), 103 deletions(-) diff --git a/src/app/Events/EventTypes.tsx b/src/app/Events/EventTypes.tsx index 9f36e9969a..2f925957b8 100644 --- a/src/app/Events/EventTypes.tsx +++ b/src/app/Events/EventTypes.tsx @@ -49,8 +49,9 @@ import { EmptyState, EmptyStateIcon, Title, + Text, } from '@patternfly/react-core'; -import { expandable, Table, TableBody, TableHeader, TableVariant } from '@patternfly/react-table'; +import { ExpandableRowContent, TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; import { concatMap, filter, first } from 'rxjs/operators'; import { LoadingView } from '@app/LoadingView/LoadingView'; import { authFailMessage, ErrorView, isAuthFail } from '@app/ErrorView/ErrorView'; @@ -70,45 +71,34 @@ export interface OptionDescriptor { defaultValue: string; } -type Row = { - cells: string[]; - parent?: number; - isOpen?: boolean; - fullWidth?: boolean; -}; +interface RowData { + isExpanded: boolean; + cellContents: React.ReactNode[]; + children?: React.ReactNode; +} const getCategoryString = (eventType: EventType): string => { return eventType.category.join(', ').trim(); }; +const includesSubstr = (a: string, b: string) => !!a && !!b && a.toLowerCase().includes(b.trim().toLowerCase()); + export interface EventTypesProps {} export const EventTypes: React.FunctionComponent = (props) => { const context = React.useContext(ServiceContext); const addSubscription = useSubscriptions(); + const prevPerPage = React.useRef(10); const [types, setTypes] = React.useState([] as EventType[]); - const [displayedTypes, setDisplayedTypes] = React.useState([] as Row[]); const [currentPage, setCurrentPage] = React.useState(1); const [perPage, setPerPage] = React.useState(10); - const prevPerPage = React.useRef(10); const [openRow, setOpenRow] = React.useState(-1); const [filterText, setFilterText] = React.useState(''); const [isLoading, setIsLoading] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(''); - const tableColumns = React.useMemo( - () => [ - { - title: 'Name', - cellFormatters: [expandable], - }, - 'Type ID', - 'Description', - 'Categories', - ], - [expandable] - ); + const tableColumns = ['', 'Name', 'Type ID', 'Description', 'Categories']; const handleTypes = React.useCallback( (types) => { @@ -159,49 +149,41 @@ export const EventTypes: React.FunctionComponent = (props) => { addSubscription(context.target.authFailure().subscribe(() => setErrorMessage(authFailMessage))); }, [context.target]); - const filterTypesByText = React.useCallback(() => { + const filterTypesByText = React.useMemo(() => { if (!filterText) { return types; } - const includesSubstr = (a, b) => !!a && !!b && a.toLowerCase().includes(b.trim().toLowerCase()); - return types.filter((t) => { - if (includesSubstr(t.name, filterText)) { - return true; - } - if (includesSubstr(t.typeId, filterText)) { - return true; - } - if (includesSubstr(t.description, filterText)) { - return true; - } - if (includesSubstr(getCategoryString(t), filterText)) { - return true; - } - return false; - }); + return types.filter( + (t) => + includesSubstr(t.name, filterText) || + includesSubstr(t.typeId, filterText) || + includesSubstr(t.description, filterText) || + includesSubstr(getCategoryString(t), filterText) + ); }, [types, filterText]); - React.useEffect(() => { + const displayedTypeRowData = React.useMemo(() => { const offset = (currentPage - 1) * perPage; - const page = filterTypesByText().slice(offset, offset + perPage); + const visibleTypes = filterTypesByText.slice(offset, offset + perPage); - const rows: Row[] = []; - page.forEach((t: EventType, idx: number) => { - rows.push({ cells: [t.name, t.typeId, t.description, getCategoryString(t)], isOpen: idx === openRow }); - if (idx === openRow) { - let child = ''; - for (const opt in t.options) { - child += `${opt}=[${t.options[opt].defaultValue}]\t`; - } - rows.push({ parent: idx, fullWidth: true, cells: [child] }); + const rows: RowData[] = []; + visibleTypes.forEach((t: EventType, idx: number) => { + let child = ''; + for (const opt in t.options) { + child += `${opt}=[${t.options[opt].defaultValue}]\t`; } + rows.push({ + cellContents: [t.name, t.typeId, t.description, getCategoryString(t)], + isExpanded: idx === openRow, + children: <>{child}, + }); }); - setDisplayedTypes(rows); + return rows; }, [currentPage, perPage, filterTypesByText, openRow]); const onCurrentPage = React.useCallback( - (evt, currentPage) => { + (_, currentPage: number) => { setOpenRow(-1); setCurrentPage(currentPage); }, @@ -209,7 +191,7 @@ export const EventTypes: React.FunctionComponent = (props) => { ); const onPerPage = React.useCallback( - (evt, perPage) => { + (_, perPage: number) => { const offset = (currentPage - 1) * prevPerPage.current; prevPerPage.current = perPage; setOpenRow(-1); @@ -219,16 +201,20 @@ export const EventTypes: React.FunctionComponent = (props) => { [currentPage, prevPerPage, setOpenRow, setPerPage, setCurrentPage] ); - const onCollapse = React.useCallback( - (event, rowKey, isOpen) => { - if (isOpen) { - if (openRow === -1) { - setOpenRow(rowKey); - } else { - setOpenRow(rowKey > openRow ? rowKey - 1 : rowKey); - } - } else { + const onFilterChange = React.useCallback( + (filterText: string) => { + setFilterText(filterText); + setOpenRow(-1); + }, + [setFilterText, setOpenRow] + ); + + const onToggle = React.useCallback( + (rowData: RowData, index: number) => { + if (index === openRow) { setOpenRow(-1); + } else { + setOpenRow(index); } }, [setOpenRow, openRow] @@ -238,7 +224,36 @@ export const EventTypes: React.FunctionComponent = (props) => { context.target.setAuthRetry(); }, [context.target, context.target.setAuthRetry]); - // TODO replace table with data list so collapsed event options can be custom formatted + const typeRowPairs = React.useMemo(() => { + return displayedTypeRowData.map((rowData: RowData, index) => ( + <> + + + onToggle(rowData, index), + }} + /> + {rowData.cellContents.map((content, idx) => ( + + {content} + + ))} + + + + {rowData.children} + + + + + )); + }, [displayedTypeRowData, onToggle, tableColumns]); + if (errorMessage != '') { return ( = (props) => { type="search" placeholder="Filter..." aria-label="Event filter" - onChange={setFilterText} + onChange={onFilterChange} isDisabled={errorMessage != ''} /> - {displayedTypes.length ? ( - - - -
+ {typeRowPairs.length ? ( + // TODO replace table with data list so collapsed event options can be custom formatted + + + + {tableColumns.map((column) => ( + {column} + ))} + + + {typeRowPairs} + ) : ( diff --git a/src/test/Events/__snapshots__/EventTypes.test.tsx.snap b/src/test/Events/__snapshots__/EventTypes.test.tsx.snap index 2477fcbee3..e606de8786 100644 --- a/src/test/Events/__snapshots__/EventTypes.test.tsx.snap +++ b/src/test/Events/__snapshots__/EventTypes.test.tsx.snap @@ -40,7 +40,7 @@ Array [ className="pf-c-toolbar__item pf-m-pagination" >
+
+ +
@@ -139,7 +176,7 @@ Array [ aria-label="Go to previous page" className="pf-c-button pf-m-plain pf-m-disabled" data-action="previous" - data-ouia-component-id="OUIA-Generated-Button-plain-1" + data-ouia-component-id="OUIA-Generated-Button-plain-2" data-ouia-component-type="PF4/Button" data-ouia-safe={true} disabled={true} @@ -168,6 +205,28 @@ Array [
+
+ + +
@@ -176,7 +235,7 @@ Array [ aria-label="Go to next page" className="pf-c-button pf-m-plain pf-m-disabled" data-action="next" - data-ouia-component-id="OUIA-Generated-Button-plain-2" + data-ouia-component-id="OUIA-Generated-Button-plain-3" data-ouia-component-type="PF4/Button" data-ouia-safe={true} disabled={true} @@ -205,13 +264,50 @@ Array [
+
+ +
, + + +
@@ -256,8 +350,6 @@ Array [ @@ -265,8 +357,6 @@ Array [ @@ -274,8 +364,6 @@ Array [ @@ -283,8 +371,6 @@ Array [ @@ -302,26 +388,22 @@ Array [ data-ouia-component-type="PF4/TableRow" data-ouia-safe={true} hidden={false} - onClick={[Function]} - onKeyDown={[Function]} > @@ -360,7 +441,6 @@ Array [ @@ -368,7 +448,6 @@ Array [ @@ -376,13 +455,32 @@ Array [ Category 1, Category 2
, ]