Skip to content

Commit

Permalink
implemented general Table component
Browse files Browse the repository at this point in the history
implemented general Table component

implemented table component

eslint fixes

removed as string usage

delete unused projectTable comp

emptyTableView updated

emptytableview update

fixed tbody in row components

reverted BYON table changes

fixed sorting and pagination

fix expandable rows

lint fix

fix env
  • Loading branch information
Gkrumbach07 committed Mar 3, 2023
1 parent 0b996c1 commit d7e9bf7
Show file tree
Hide file tree
Showing 14 changed files with 393 additions and 482 deletions.
116 changes: 116 additions & 0 deletions frontend/src/components/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Pagination, Toolbar, ToolbarContent, ToolbarItem } from '@patternfly/react-core';
import {
TableComposable,
Thead,
Tr,
Th,
TableComposableProps,
Caption,
Td,
} from '@patternfly/react-table';
import React, { useEffect } from 'react';
import useTableColumnSort, { SortableData } from '~/utilities/useTableColumnSort';

type TableProps<DataType> = {
data: DataType[];
columns: SortableData<DataType>[];
rowRenderer: (data: DataType) => React.ReactNode;
enablePagination?: boolean;
minPageSize?: number;
toolbarContent?: React.ReactElement<typeof ToolbarItem>;
emptyTableView?: React.ReactElement<typeof Tr>;
caption?: string;
} & Omit<TableComposableProps, 'ref' | 'data'>;

const Table = <T,>({
data: allData,
columns,
rowRenderer,
enablePagination,
minPageSize = 10,
toolbarContent,
emptyTableView,
caption,
...props
}: TableProps<T>): React.ReactElement => {
const [page, setPage] = React.useState(1);
const [pageSize, setPageSize] = React.useState(minPageSize);

const data = enablePagination ? allData.slice(pageSize * (page - 1), pageSize * page) : allData;

// update page to 1 if data changes (common when filter is applied)
useEffect(() => setPage(1), [data]);

const sort = useTableColumnSort<T>(columns, 0);

const showPagination = enablePagination && data.length > minPageSize;
const pagination = (pageDirection: 'up' | 'down') => (
<Pagination
dropDirection={pageDirection}
perPageComponent="button"
itemCount={data.length}
perPage={pageSize}
page={page}
onSetPage={(e, newPage) => setPage(newPage)}
onPerPageSelect={(e, newSize, newPage) => {
setPageSize(newSize);
setPage(newPage);
}}
widgetId="table-pagination"
/>
);

return (
<>
{(toolbarContent || showPagination) && (
<Toolbar>
<ToolbarContent>
{toolbarContent}
{showPagination && (
<ToolbarItem variant="pagination" alignment={{ default: 'alignRight' }}>
{pagination('down')}
</ToolbarItem>
)}
</ToolbarContent>
</Toolbar>
)}
<TableComposable {...props}>
{caption && <Caption>{caption}</Caption>}
<Thead>
<Tr>
{columns.map((col, i) => (
<Th
key={col.field + i}
sort={col.sortable ? sort.getColumnSort(i) : undefined}
width={col.width}
>
{col.label}
</Th>
))}
</Tr>
</Thead>
<>
{emptyTableView && data.length === 0 && (
<Tr>
<Td colSpan={columns.length} style={{ textAlign: 'center' }}>
{emptyTableView}
</Td>
</Tr>
)}
{sort.transformData(data).map((row) => rowRenderer(row))}
</>
</TableComposable>
{showPagination && (
<Toolbar>
<ToolbarContent>
<ToolbarItem variant="pagination" alignment={{ default: 'alignRight' }}>
{pagination('up')}
</ToolbarItem>
</ToolbarContent>
</Toolbar>
)}
</>
);
};

export default Table;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import ServeModelButton from './ServeModelButton';
import { getGlobalInferenceServiceColumns } from './data';
import InferenceServiceTable from './InferenceServiceTable';

const MIN_PAGE_SIZE = 10;

type InferenceServiceListViewProps = {
inferenceServices: InferenceServiceKind[];
Expand All @@ -26,8 +25,6 @@ const InferenceServiceListView: React.FC<InferenceServiceListViewProps> = ({
} = React.useContext(ModelServingContext);
const [searchType, setSearchType] = React.useState<SearchType>(SearchType.NAME);
const [search, setSearch] = React.useState('');
const [page, setPage] = React.useState(1);
const [pageSize, setPageSize] = React.useState(MIN_PAGE_SIZE);
const sortInferenceService = useTableColumnSort<InferenceServiceKind>(
getGlobalInferenceServiceColumns(projects),
0,
Expand All @@ -53,23 +50,6 @@ const InferenceServiceListView: React.FC<InferenceServiceListViewProps> = ({
setSearch('');
};

const showPagination = unfilteredInferenceServices.length > MIN_PAGE_SIZE;
const pagination = (pageDirection: 'up' | 'down') =>
showPagination && (
<Pagination
dropDirection={pageDirection}
perPageComponent="button"
itemCount={filteredInferenceServices.length}
perPage={pageSize}
page={page}
onSetPage={(e, newPage) => setPage(newPage)}
onPerPageSelect={(e, newSize, newPage) => {
setPageSize(newSize);
setPage(newPage);
}}
widgetId="table-pagination"
/>
);

const searchTypes = React.useMemo(
() => Object.keys(SearchType).filter((key) => SearchType[key] === SearchType.NAME),
Expand All @@ -78,46 +58,33 @@ const InferenceServiceListView: React.FC<InferenceServiceListViewProps> = ({

return (
<>
<Toolbar>
<ToolbarContent>
<ToolbarItem>
<SearchField
types={searchTypes}
searchType={searchType}
searchValue={search}
onSearchTypeChange={(searchType) => {
setSearchType(searchType);
}}
onSearchValueChange={(searchValue) => {
setPage(1);
setSearch(searchValue);
}}
/>
</ToolbarItem>
<ToolbarItem>
<ServeModelButton />
</ToolbarItem>
<ToolbarItem variant="pagination" alignment={{ default: 'alignRight' }}>
{pagination('down')}
</ToolbarItem>
</ToolbarContent>
</Toolbar>
<InferenceServiceTable
clearFilters={resetFilters}
servingRuntimes={servingRuntimes}
inferenceServices={filteredInferenceServices.slice(pageSize * (page - 1), pageSize * page)}
getColumnSort={sortInferenceService.getColumnSort}
inferenceServices={filteredInferenceServices}
refresh={refresh}
/>
{showPagination && (
<Toolbar>
<ToolbarContent>
<ToolbarItem variant="pagination" alignment={{ default: 'alignRight' }}>
{pagination('up')}
enablePagination={true}
toolbarContent={(
<>
<ToolbarItem>
<SearchField
types={searchTypes}
searchType={searchType}
searchValue={search}
onSearchTypeChange={(searchType) => {
setSearchType(searchType);
}}
onSearchValueChange={(searchValue) => {
setSearch(searchValue);
}}
/>
</ToolbarItem>
</ToolbarContent>
</Toolbar>
)}
<ToolbarItem>
<ServeModelButton />
</ToolbarItem>
</>
)}
/>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import * as React from 'react';
import { TableComposable, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { Button } from '@patternfly/react-core';
import { GetColumnSort } from '~/utilities/useTableColumnSort';
import { InferenceServiceKind, ServingRuntimeKind } from '~/k8sTypes';
import { Button, ToolbarItem } from '@patternfly/react-core';
import ManageInferenceServiceModal from '~/pages/modelServing/screens/projects/InferenceServiceModal/ManageInferenceServiceModal';
import { ModelServingContext } from '~/pages/modelServing/ModelServingContext';
import { getGlobalInferenceServiceColumns, getProjectInferenceServiceColumns } from './data';
import Table from '~/components/Table';

import { InferenceServiceKind, ServingRuntimeKind } from '~/k8sTypes';
import InferenceServiceTableRow from './InferenceServiceTableRow';
import { getGlobalInferenceServiceColumns, getProjectInferenceServiceColumns } from './data';
import DeleteInferenceServiceModal from './DeleteInferenceServiceModal';

type InferenceServiceTableProps = {
clearFilters?: () => void;
inferenceServices: InferenceServiceKind[];
servingRuntimes: ServingRuntimeKind[];
getColumnSort: GetColumnSort;
refresh: () => void;
enablePagination?: boolean;
toolbarContent?: React.ReactElement<typeof ToolbarItem>;
};

const InferenceServiceTable: React.FC<InferenceServiceTableProps> = ({
clearFilters,
inferenceServices,
servingRuntimes,
getColumnSort,
refresh,
enablePagination,
toolbarContent
}) => {
const {
projects: { data: projects },
Expand All @@ -36,29 +38,23 @@ const InferenceServiceTable: React.FC<InferenceServiceTableProps> = ({
: getProjectInferenceServiceColumns();
return (
<>
<TableComposable variant={isGlobal ? undefined : 'compact'}>
<Thead>
<Tr>
{mappedColumns.map((col, i) => (
<Th key={col.field} sort={getColumnSort(i)} width={col.width}>
{col.label}
</Th>
))}
</Tr>
</Thead>
{isGlobal && inferenceServices.length === 0 && (
<Tbody>
<Tr>
<Td colSpan={mappedColumns.length} style={{ textAlign: 'center' }}>
No projects match your filters.{' '}
<Button variant="link" isInline onClick={clearFilters}>
Clear filters
</Button>
</Td>
</Tr>
</Tbody>
)}
{inferenceServices.map((is) => (
<Table
data={inferenceServices}
columns={mappedColumns}
variant={isGlobal ? undefined : 'compact'}
toolbarContent={toolbarContent}
enablePagination={enablePagination}
emptyTableView={
isGlobal ? undefined : (
<>
No projects match your filters.{' '}
<Button variant="link" isInline onClick={clearFilters}>
Clear filters
</Button>
</>
)
}
rowRenderer={(is) => (
<InferenceServiceTableRow
key={is.metadata.uid}
obj={is}
Expand All @@ -69,8 +65,8 @@ const InferenceServiceTable: React.FC<InferenceServiceTableProps> = ({
onDeleteInferenceService={setDeleteInferenceService}
onEditInferenceService={setEditInferenceService}
/>
))}
</TableComposable>
)}
/>
<DeleteInferenceServiceModal
inferenceService={deleteInferenceService}
onClose={(deleted) => {
Expand Down
Loading

0 comments on commit d7e9bf7

Please sign in to comment.