Skip to content

Commit

Permalink
chore(tables): refactor event type table
Browse files Browse the repository at this point in the history
  • Loading branch information
Thuan Vo committed Nov 19, 2022
1 parent da8a874 commit 69077d2
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 84 deletions.
124 changes: 70 additions & 54 deletions src/app/Events/EventTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -70,45 +71,35 @@ 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<EventTypesProps> = (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 [displayedTypes, setDisplayedTypes] = React.useState([] as RowData[]);
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) => {
Expand Down Expand Up @@ -163,7 +154,6 @@ export const EventTypes: React.FunctionComponent<EventTypesProps> = (props) => {
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;
Expand All @@ -183,33 +173,36 @@ export const EventTypes: React.FunctionComponent<EventTypesProps> = (props) => {

React.useEffect(() => {
const offset = (currentPage - 1) * perPage;
const page = filterTypesByText().slice(offset, offset + perPage);
const visibleTemplates = 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 });
const rows: RowData[] = [];
visibleTemplates.forEach((t: EventType, idx: number) => {
let child = '';
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] });
}
rows.push({
cellContents: [t.name, t.typeId, t.description, getCategoryString(t)],
isExpanded: idx === openRow,
children: <>{child}</>,
});
});

setDisplayedTypes(rows);
}, [currentPage, perPage, filterTypesByText, openRow]);
}, [currentPage, perPage, filterTypesByText, openRow, setDisplayedTypes]);

const onCurrentPage = React.useCallback(
(evt, currentPage) => {
(_, currentPage: number) => {
setOpenRow(-1);
setCurrentPage(currentPage);
},
[setOpenRow, setCurrentPage]
);

const onPerPage = React.useCallback(
(evt, perPage) => {
(_, perPage: number) => {
const offset = (currentPage - 1) * prevPerPage.current;
prevPerPage.current = perPage;
setOpenRow(-1);
Expand All @@ -219,16 +212,12 @@ export const EventTypes: React.FunctionComponent<EventTypesProps> = (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 onToggle = React.useCallback(
(rowData: RowData, index: number) => {
if (index === openRow) {
setOpenRow(-1);
} else {
setOpenRow(index);
}
},
[setOpenRow, openRow]
Expand All @@ -238,7 +227,34 @@ export const EventTypes: React.FunctionComponent<EventTypesProps> = (props) => {
context.target.setAuthRetry();
}, [context.target, context.target.setAuthRetry]);

// TODO replace table with data list so collapsed event options can be custom formatted
const typeRows = React.useMemo(() => {
return displayedTypes.map((rowData: RowData, index) => (
<>
<Tr key={`event-type-${index}`}>
<Td
key={`event-type-expandable-${index}`}
expand={{
rowIndex: index,
isExpanded: rowData.isExpanded,
expandId: `expandable-event-type-row-${index}`,
onToggle: () => onToggle(rowData, index),
}}
/>
{rowData.cellContents.map((content, idx) => (
<Td key={`event-type-${tableColumns[idx].toLowerCase()}-${idx}`} dataLabel={tableColumns[idx]}>
{content}
</Td>
))}
</Tr>
<Tr key={`event-type-${index}-expandable-child`} isExpanded={index === openRow}>
<Td dataLabel="event-details" colSpan={tableColumns.length}>
<ExpandableRowContent>{rowData.children}</ExpandableRowContent>
</Td>
</Tr>
</>
));
}, [displayedTypes, onToggle, tableColumns]);

if (errorMessage != '') {
return (
<ErrorView
Expand Down Expand Up @@ -267,28 +283,28 @@ export const EventTypes: React.FunctionComponent<EventTypesProps> = (props) => {
</ToolbarItem>
<ToolbarItem variant={ToolbarItemVariant.pagination}>
<Pagination
itemCount={filterText ? filterTypesByText().length : types.length}
itemCount={filterTypesByText().length}
page={currentPage}
perPage={perPage}
onSetPage={onCurrentPage}
widgetId="event-types-pagination"
onPerPageSelect={onPerPage}
isCompact
/>
</ToolbarItem>
</ToolbarContent>
</Toolbar>
{displayedTypes.length ? (
<Table
aria-label="Event Types table"
cells={tableColumns}
rows={displayedTypes}
onCollapse={onCollapse}
variant={TableVariant.compact}
>
<TableHeader />
<TableBody />
</Table>
{typeRows.length ? (
// TODO replace table with data list so collapsed event options can be custom formatted
<TableComposable aria-label="Event Types Table" variant={TableVariant.compact}>
<Thead>
<Tr>
{tableColumns.map((column) => (
<Th key={`event-type-header-${column}`}>{column}</Th>
))}
</Tr>
</Thead>
<Tbody>{typeRows}</Tbody>
</TableComposable>
) : (
<EmptyState>
<EmptyStateIcon icon={SearchIcon} />
Expand Down
Loading

0 comments on commit 69077d2

Please sign in to comment.