-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from mturley/fix-selection
Replace lib-ui useSelectionState with a batteries implementation, fix related quirks, handle shift+click multiselect and bulk selection
- Loading branch information
Showing
35 changed files
with
737 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 189 additions & 8 deletions
197
packages/module/patternfly-docs/content/examples/ExampleFeatureSelection.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,190 @@ | ||
import React from 'react'; | ||
import { ExtendedButton } from '@patternfly-labs/react-table-batteries'; | ||
|
||
export const ExampleFeatureSelection: React.FunctionComponent = () => ( | ||
<> | ||
Table stuff goes here! | ||
<ExtendedButton>My custom extension button</ExtendedButton> | ||
</> | ||
); | ||
import { | ||
Toolbar, | ||
ToolbarContent, | ||
ToolbarItem, | ||
EmptyState, | ||
EmptyStateIcon, | ||
Title, | ||
Pagination | ||
} from '@patternfly/react-core'; | ||
import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon'; | ||
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table'; | ||
import { | ||
useClientTableBatteries, | ||
TableHeaderContentWithBatteries, | ||
ConditionalTableBody, | ||
TableRowContentWithBatteries, | ||
FilterToolbar, | ||
FilterType, | ||
ToolbarBulkSelector | ||
} from '@patternfly-labs/react-table-batteries'; | ||
|
||
// This example table's rows represent Thing objects in our fake API. | ||
interface Thing { | ||
id: number; | ||
name: string; | ||
description: string; | ||
} | ||
|
||
// This is a barebones mock API server to demonstrate fetching data. | ||
// We use a timeout of 1000ms here to simulate the loading state when data is fetched. | ||
interface MockAPIResponse { | ||
data: Thing[]; | ||
} | ||
const fetchMockData = () => | ||
new Promise<MockAPIResponse>((resolve) => { | ||
setTimeout(() => { | ||
const mockData: Thing[] = [ | ||
{ id: 1, name: 'Thing 01', description: 'Something from the API' }, | ||
{ id: 2, name: 'Thing 02', description: 'Something else from the API' }, | ||
{ id: 3, name: 'Thing 03', description: 'Another API object. This one is not selectable!' }, | ||
{ id: 4, name: 'Thing 04', description: 'We have more than 10 things here' }, | ||
{ id: 5, name: 'Thing 05', description: 'So you can try the "select page" behavior' }, | ||
{ id: 6, name: 'Thing 06', description: 'These all need descriptions' }, | ||
{ id: 7, name: 'Thing 07', description: 'But there is nothing else to say' }, | ||
{ id: 8, name: 'Thing 08', description: "I hope you're enjoying these examples" }, | ||
{ id: 9, name: 'Thing 09', description: 'Some pretty cool stuff if I do say so myself' }, | ||
{ id: 10, name: 'Thing 10', description: 'See you later' }, | ||
{ id: 11, name: 'Thing 11', description: 'Oh hey you made it to page 2' }, | ||
{ id: 12, name: 'Thing 12', description: 'Nice work' } | ||
]; | ||
resolve({ data: mockData }); | ||
}, 1000); | ||
}); | ||
|
||
export const ExampleFeatureSelection: React.FunctionComponent = () => { | ||
// In a real table we'd use a real API fetch here, perhaps using a library like react-query. | ||
const [mockApiResponse, setMockApiResponse] = React.useState<MockAPIResponse>({ data: [] }); | ||
const [isLoadingMockData, setIsLoadingMockData] = React.useState(false); | ||
React.useEffect(() => { | ||
setIsLoadingMockData(true); | ||
fetchMockData().then((response) => { | ||
setMockApiResponse(response); | ||
setIsLoadingMockData(false); | ||
}); | ||
}, []); | ||
|
||
const tableBatteries = useClientTableBatteries({ | ||
persistTo: 'urlParams', | ||
persistenceKeyPrefix: 't1', // The first Things table on this page. | ||
idProperty: 'id', // The name of a unique string or number property on the data items. | ||
items: mockApiResponse.data, // The generic type `TItem` is inferred from the items passed here. | ||
columnNames: { | ||
// The keys of this object define the inferred generic type `TColumnKey`. See "Unique Identifiers". | ||
name: 'Name', | ||
description: 'Description' | ||
}, | ||
isFilterEnabled: true, | ||
isSortEnabled: true, | ||
isPaginationEnabled: true, | ||
isSelectionEnabled: true, | ||
// Because isFilterEnabled is true, TypeScript will require these filterCategories: | ||
filterCategories: [ | ||
{ | ||
key: 'name', | ||
title: 'Name', | ||
type: FilterType.search, | ||
placeholderText: 'Filter by name...', | ||
getItemValue: (thing) => thing.name || '' | ||
}, | ||
{ | ||
key: 'description', | ||
title: 'Description', | ||
type: FilterType.search, | ||
placeholderText: 'Filter by description...' | ||
} | ||
], | ||
// Because isSortEnabled is true, TypeScript will require these sort-related properties: | ||
sortableColumns: ['name', 'description'], | ||
getSortValues: (thing) => ({ | ||
name: thing.name || '', | ||
description: thing.description || '' | ||
}), | ||
initialSort: { columnKey: 'name', direction: 'asc' }, | ||
isItemSelectable: (item) => item.id !== 3, // Testing the non-selectable item behavior | ||
isLoading: isLoadingMockData, | ||
variant: 'compact' | ||
}); | ||
|
||
// Here we destructure some of the properties from `tableBatteries` for rendering. | ||
// Later we also spread the entire `tableBatteries` object onto components whose props include subsets of it. | ||
const { | ||
currentPageItems, // These items have already been paginated. | ||
// `numRenderedColumns` is based on the number of columnNames and additional columns needed for | ||
// rendering controls related to features like selection, expansion, etc. | ||
// It is used as the colSpan when rendering a full-table-wide cell. | ||
numRenderedColumns, | ||
// The objects and functions in `propHelpers` correspond to the props needed for specific PatternFly or Tackle | ||
// components and are provided to reduce prop-drilling and make the rendering code as short as possible. | ||
propHelpers: { | ||
toolbarProps, | ||
toolbarBulkSelectorProps, | ||
filterToolbarProps, | ||
paginationToolbarItemProps, | ||
paginationProps, | ||
tableProps, | ||
getThProps, | ||
getTrProps, | ||
getTdProps | ||
}, | ||
selectionDerivedState: { selectedItems } | ||
} = tableBatteries; | ||
|
||
// eslint-disable-next-line no-console | ||
console.log('Do something with selected items:', selectedItems); | ||
|
||
return ( | ||
<> | ||
<Toolbar {...toolbarProps}> | ||
<ToolbarContent> | ||
<ToolbarBulkSelector {...toolbarBulkSelectorProps} /> | ||
<FilterToolbar {...filterToolbarProps} id="client-paginated-example-filters" /> | ||
{/* You can render whatever other custom toolbar items you may need here! */} | ||
<ToolbarItem {...paginationToolbarItemProps}> | ||
<Pagination variant="top" isCompact {...paginationProps} widgetId="client-paginated-example-pagination" /> | ||
</ToolbarItem> | ||
</ToolbarContent> | ||
</Toolbar> | ||
<Table {...tableProps} aria-label="Example things table"> | ||
<Thead> | ||
<Tr> | ||
<TableHeaderContentWithBatteries {...tableBatteries}> | ||
<Th {...getThProps({ columnKey: 'name' })} /> | ||
<Th {...getThProps({ columnKey: 'description' })} /> | ||
</TableHeaderContentWithBatteries> | ||
</Tr> | ||
</Thead> | ||
<ConditionalTableBody | ||
isLoading={isLoadingMockData} | ||
isNoData={currentPageItems.length === 0} | ||
noDataEmptyState={ | ||
<EmptyState variant="sm"> | ||
<EmptyStateIcon icon={CubesIcon} /> | ||
<Title headingLevel="h2" size="lg"> | ||
No things available | ||
</Title> | ||
</EmptyState> | ||
} | ||
numRenderedColumns={numRenderedColumns} | ||
> | ||
<Tbody> | ||
{currentPageItems?.map((thing, rowIndex) => ( | ||
<Tr key={thing.id} {...getTrProps({ item: thing })}> | ||
<TableRowContentWithBatteries {...tableBatteries} item={thing} rowIndex={rowIndex}> | ||
<Td width={30} {...getTdProps({ columnKey: 'name' })}> | ||
{thing.name} | ||
</Td> | ||
<Td width={70} {...getTdProps({ columnKey: 'description' })}> | ||
{thing.description} | ||
</Td> | ||
</TableRowContentWithBatteries> | ||
</Tr> | ||
))} | ||
</Tbody> | ||
</ConditionalTableBody> | ||
</Table> | ||
<Pagination variant="bottom" isCompact {...paginationProps} widgetId="client-paginated-example-pagination" /> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
export * from './useActiveItemState'; | ||
export * from './getActiveItemDerivedState'; | ||
export * from './useActiveItemDerivedState'; | ||
export * from './useActiveItemPropHelpers'; | ||
export * from './useActiveItemEffects'; |
Oops, something went wrong.