import { Fragment, useState } from 'react'; import { Badge, Button, Card, CardHeader, CardBody, CardTitle, Content, Divider, Drawer, DrawerActions, DrawerPanelBody, DrawerCloseButton, DrawerContent, DrawerContentBody, DrawerHead, DrawerPanelContent, Dropdown, DropdownItem, DropdownList, Flex, FlexItem, Gallery, MenuToggle, MenuToggleCheckbox, PageSection, Pagination, Progress, Select, SelectList, SelectOption, Title, Toolbar, ToolbarFilter, ToolbarItem, ToolbarContent, MenuToggleElement } from '@patternfly/react-core'; import TrashIcon from '@patternfly/react-icons/dist/esm/icons/trash-icon'; import pfIcon from './assets/pf-logo-small.svg'; import activeMQIcon from './assets/activemq-core_200x150.png'; import avroIcon from './assets/camel-avro_200x150.png'; import dropBoxIcon from './assets/camel-dropbox_200x150.png'; import infinispanIcon from './assets/camel-infinispan_200x150.png'; import saxonIcon from './assets/camel-saxon_200x150.png'; import sparkIcon from './assets/camel-spark_200x150.png'; import swaggerIcon from './assets/camel-swagger-java_200x150.png'; import azureIcon from './assets/FuseConnector_Icons_AzureServices.png'; import restIcon from './assets/FuseConnector_Icons_REST.png'; import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; import { DashboardWrapper } from '@patternfly/react-core/src/demos/DashboardWrapper'; import { data } from '@patternfly/react-core/src/demos/CardView/examples/CardViewData.jsx'; export const PrimaryDetailCardView: React.FunctionComponent = () => { const [totalItemCount, setTotalItemCount] = useState(10); const [cardData, setCardData] = useState(data); const [isChecked, setIsChecked] = useState(false); const [isDrawerExpanded, setIsDrawerExpanded] = useState(false); const [selectedItems, setSelectedItems] = useState([]); const [areAllSelected, setAreAllSelected] = useState(false); const [splitButtonDropdownIsOpen, setSplitButtonDropdownIsOpen] = useState(false); const [isLowerToolbarDropdownOpen, setIsLowerToolbarDropdownOpen] = useState(false); const [isLowerToolbarKebabDropdownOpen, setIsLowerToolbarKebabDropdownOpen] = useState(false); const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(10); const [filters, setFilters] = useState>({ products: [] }); const [state, setState] = useState({}); const [activeCard, setActiveCard] = useState(-1); interface ProductType { id: number; name: string; icon: string; description: string; } const onToolbarDropdownToggle = () => { setIsLowerToolbarDropdownOpen(!isLowerToolbarDropdownOpen); }; const onToolbarKebabDropdownToggle = () => { setIsLowerToolbarKebabDropdownOpen(!isLowerToolbarKebabDropdownOpen); }; const onToolbarKebabDropdownSelect = () => { setIsLowerToolbarKebabDropdownOpen(!isLowerToolbarKebabDropdownOpen); }; const onCardKebabDropdownToggle = ( event: React.MouseEvent | React.MouseEvent, key: string ) => { setState({ [key]: !state[key as keyof Object] }); }; const checkAllSelected = (selected: number, total: number) => { if (selected && selected < total) { return null; } return selected === total; }; const onNameSelect = (event: any, selection = '') => { const checked = event.target.checked; const prevSelections = filters.products; setFilters({ ...filters, products: checked ? [...prevSelections, selection] : prevSelections.filter((value) => value !== selection) }); }; const onDelete = (type = '', _id = '') => { if (type) { setFilters(filters); } else { setFilters({ products: [] }); } }; const deleteItem = (item: ProductType) => { const filter = (getter) => (val) => getter(val) !== item.id; setCardData(cardData.filter(filter(({ id }) => id))); setSelectedItems(selectedItems.filter(filter((id) => id))); setTotalItemCount(totalItemCount - 1); setIsDrawerExpanded(false); setActiveCard(-1); }; const onSetPage = (_event: any, pageNumber: number) => { setPage(pageNumber); }; const onPerPageSelect = (_event: any, perPage: number) => { setPerPage(perPage); setPage(1); }; const onSplitButtonToggle = () => { setSplitButtonDropdownIsOpen(!splitButtonDropdownIsOpen); }; const onSplitButtonSelect = () => { setSplitButtonDropdownIsOpen(false); setIsDrawerExpanded(false); setActiveCard(-1); }; const onCloseDrawerClick = () => { setActiveCard(-1); setIsDrawerExpanded(false); }; const onChange = (event: React.FormEvent) => { const name = event.currentTarget.name; const productId = Number(name.charAt(name.length - 1)); if (selectedItems.includes(productId * 1)) { setSelectedItems(selectedItems.filter((id) => productId * 1 !== id)); const checkAll = checkAllSelected(selectedItems.length - 1, totalItemCount); setAreAllSelected(!!checkAll); } else { setSelectedItems([...selectedItems, productId * 1]); const checkAll = checkAllSelected(selectedItems.length + 1, totalItemCount); setAreAllSelected(!!checkAll); } }; const onCardClick = (productId) => { if (productId === activeCard) { setIsDrawerExpanded(!isDrawerExpanded); setActiveCard(-1); } else { setActiveCard(productId); setIsDrawerExpanded(true); } }; const selectPage = (e: { target: { checked: any } }) => { const { checked } = e.target; let collection: number[] = []; collection = getAllItems(); setSelectedItems(collection); setIsChecked(checked); setAreAllSelected(totalItemCount === perPage ? true : false); updateSelected(); }; const selectAll = () => { let collection: number[] = []; for (let i = 0; i <= 9; i++) { collection = [...collection, i]; } setSelectedItems(collection); setIsChecked(true); setAreAllSelected(true); updateSelected(); }; const selectNone = () => { setSelectedItems([]); setIsChecked(false); setAreAllSelected(false); setIsDrawerExpanded(false); setActiveCard(-1); updateSelected(); }; const updateSelected = () => { const rows = cardData.map((post) => { post.selected = selectedItems.includes(post.id); return post; }); setCardData(rows); }; const getAllItems = () => { const collection: number[] = []; for (const items of cardData) { collection.push(items.id); } return collection; }; const splitCheckboxSelectAll = (e: any) => { let collection: number[] = []; if (e.target.checked) { for (let i = 0; i <= 9; i++) { collection = [...collection, i]; } } setSelectedItems(collection); setIsChecked(isChecked); setAreAllSelected(e.target.checked); setIsDrawerExpanded(false); setActiveCard(-1); updateSelected(); }; const renderPagination = () => { const defaultPerPageOptions = [ { title: '1', value: 1 }, { title: '5', value: 5 }, { title: '10', value: 10 } ]; return ( ); }; const buildSelectDropdown = () => { const numSelected = selectedItems.length; const anySelected = numSelected > 0; const splitButtonDropdownItems = ( <> Select none (0 items) Select page ({perPage} items) Select all ({totalItemCount} items) ); return ( setSplitButtonDropdownIsOpen(isOpen)} toggle={(toggleRef) => ( {numSelected !== 0 && `${numSelected} selected`} ]} > )} > {splitButtonDropdownItems} ); }; const buildFilterDropdown = () => { const filterDropdownItems = ( PatternFly ActiveMQ Apache Spark Avro Azure Services Crypto DropBox JBoss Data Grid REST SWAGGER ); return ( onDelete(type as string, id as string)} > ); }; const toolbarKebabDropdownItems = ( <> Action ev.preventDefault()} > Link Disabled Action Disabled Link Separated Action ev.preventDefault()}> Separated Link ); const toolbarItems = ( {buildSelectDropdown()} {buildFilterDropdown()} setIsLowerToolbarKebabDropdownOpen(isOpen)} toggle={(toggleRef) => ( } /> )} > {toolbarKebabDropdownItems} {renderPagination()} ); const filtered = filters.products.length > 0 ? data.filter((card: { name: string }) => filters.products.length === 0 || filters.products.includes(card.name)) : cardData.slice((page - 1) * perPage, perPage === 1 ? page * perPage : page * perPage - 1); const icons = { pfIcon, activeMQIcon, sparkIcon, avroIcon, azureIcon, saxonIcon, dropBoxIcon, infinispanIcon, restIcon, swaggerIcon }; const drawerContent = ( {filtered.map((product, key) => ( setState({ [key]: isOpen })} popperProps={{ position: 'right' }} toggle={(toggleRef: React.Ref) => ( { onCardKebabDropdownToggle(e, key.toString()); }} isExpanded={!!state[key]} icon={} /> )} > { deleteItem(product); }} > Delete ) }} selectableActions={{ isChecked: selectedItems.includes(product.id), selectableActionId: `selectable-actions-item-${product.id}`, selectableActionAriaLabelledby: `${'card-view-' + key}`, name: `check-${product.id}`, onChange }} > {`${product.name} Provided by Red Hat {product.description} ))} ); const panelContent = ( node-{activeCard}

The content of the drawer really is up to you. It could have form fields, definition lists, text lists, labels, charts, progress bars, etc. Spacing recommendation is 24px margins. You can put tabs in here, and can also make the drawer scrollable.

); return (

Projects

This is a demo that showcases Patternfly cards.

{toolbarItems} {drawerContent}
); };