UNPKG

mod-arch-shared

Version:

Shared UI components and utilities for modular architecture micro-frontend projects

112 lines 7.03 kB
import * as React from 'react'; import { Button, Checkbox, EmptyState, EmptyStateBody, EmptyStateVariant, Flex, FlexItem, Label, Stack, StackItem, Tooltip, } from '@patternfly/react-core'; import { SearchIcon } from '@patternfly/react-icons'; import { DragDropSort, } from '@patternfly/react-drag-drop'; import ContentModal from '../../../components/modals/ContentModal'; import { ManageColumnSearchInput } from './ManageColumnSearchInput'; import { reorderColumns } from './utils'; import './ManageColumnsModal.scss'; export const ManageColumnsModal = ({ manageColumnsResult, title = 'Customize columns', description, maxSelections, maxSelectionsTooltip = 'Maximum columns selected.', searchPlaceholder = 'Filter by column name', dataTestId = 'manage-columns-modal', }) => { const { managedColumns: initialColumns, setVisibleColumnIds, defaultVisibleColumnIds, isModalOpen, closeModal, } = manageColumnsResult; const [columns, setColumns] = React.useState(initialColumns); const [searchValue, setSearchValue] = React.useState(''); // Normalize whitespace (including NBSP) to regular spaces for search comparison const normalizeWhitespace = (str) => str.replace(/\s+/g, ' '); // Derive filtered columns from search const columnsMatchingSearch = React.useMemo(() => searchValue ? columns.filter((col) => normalizeWhitespace(col.label.toLowerCase()).includes(normalizeWhitespace(searchValue.toLowerCase()))) : columns, [columns, searchValue]); // Reset state when modal opens with new columns React.useEffect(() => { if (isModalOpen) { setColumns(initialColumns); setSearchValue(''); } }, [isModalOpen, initialColumns]); const selectedCount = columns.filter((col) => col.isVisible).length; const isMaxReached = maxSelections !== undefined && selectedCount >= maxSelections; const handleUpdate = React.useCallback(() => { const visibleColumnIds = columns.filter((col) => col.isVisible).map((col) => col.id); setVisibleColumnIds(visibleColumnIds); closeModal(); }, [columns, setVisibleColumnIds, closeModal]); const handleSearch = React.useCallback((value) => { setSearchValue(value); }, []); const handleToggleColumn = React.useCallback((columnId, isChecked) => { setColumns((prev) => prev.map((col) => (col.id === columnId ? { ...col, isVisible: isChecked } : col))); }, []); const handleDrop = React.useCallback((_, newItems) => { const reorderedIds = newItems.map((item) => String(item.id)); const matchingIds = new Set(columnsMatchingSearch.map((c) => c.id)); setColumns((prev) => reorderColumns(prev, matchingIds, reorderedIds)); }, [columnsMatchingSearch]); const handleRestoreDefaults = React.useCallback(() => { if (!defaultVisibleColumnIds) { return; } // Update visibility based on default column IDs // Also reorder to put default columns first in their original order setColumns((prev) => { const defaultSet = new Set(defaultVisibleColumnIds); const defaultColumns = defaultVisibleColumnIds .map((id) => prev.find((col) => col.id === id)) .filter((col) => col !== undefined) .map((col) => ({ ...col, isVisible: true })); const nonDefaultColumns = prev .filter((col) => !defaultSet.has(col.id)) .map((col) => ({ ...col, isVisible: false })); return [...defaultColumns, ...nonDefaultColumns]; }); }, [defaultVisibleColumnIds]); if (!isModalOpen) { return null; } const buttonActions = [ { label: 'Update', onClick: handleUpdate, variant: 'primary', dataTestId: `${dataTestId}-update-button`, }, { label: 'Cancel', onClick: closeModal, variant: 'link', dataTestId: `${dataTestId}-cancel-button`, }, ]; const descriptionContent = (React.createElement(Stack, { hasGutter: true, className: "pf-v6-u-pb-md" }, description && React.createElement(StackItem, { className: "pf-v6-u-mt-sm" }, description), React.createElement(StackItem, null, React.createElement(ManageColumnSearchInput, { value: searchValue, placeholder: searchPlaceholder, onSearch: handleSearch, dataTestId: `${dataTestId}-search` })), React.createElement(StackItem, null, React.createElement(Flex, { justifyContent: { default: 'justifyContentSpaceBetween' }, alignItems: { default: 'alignItemsCenter' } }, React.createElement(FlexItem, null, React.createElement(Label, null, selectedCount, " / total ", columns.length, " selected")), defaultVisibleColumnIds && (React.createElement(FlexItem, null, React.createElement(Button, { variant: "link", isInline: true, onClick: handleRestoreDefaults, "data-testid": `${dataTestId}-restore-defaults` }, "Restore default columns"))))))); const draggableItems = columnsMatchingSearch.map((col) => { const currentCol = columns.find((c) => c.id === col.id) ?? col; const isDisabled = isMaxReached && !currentCol.isVisible; const checkbox = (React.createElement(Checkbox, { id: col.id, "aria-label": col.label, isChecked: currentCol.isVisible, isDisabled: isDisabled, onChange: (_, checked) => handleToggleColumn(col.id, checked) })); return { id: col.id, content: (React.createElement("div", { className: "pf-v6-u-display-inline-block" }, React.createElement(Flex, { alignItems: { default: 'alignItemsCenter' }, flexWrap: { default: 'nowrap' }, spaceItems: { default: 'spaceItemsSm' } }, React.createElement(FlexItem, null, isDisabled ? React.createElement(Tooltip, { content: maxSelectionsTooltip }, checkbox) : checkbox), React.createElement(FlexItem, null, col.label)))), props: { checked: currentCol.isVisible, className: 'mod-arch-manage-columns__draggable', }, }; }); return (React.createElement(ContentModal, { onClose: closeModal, title: title, description: descriptionContent, contents: columnsMatchingSearch.length === 0 && searchValue ? (React.createElement(EmptyState, { headingLevel: "h4", icon: SearchIcon, titleText: "No results found", variant: EmptyStateVariant.sm }, React.createElement(EmptyStateBody, null, "No columns match your search. Try adjusting your search terms."))) : (React.createElement(DragDropSort, { items: draggableItems, variant: "default", onDrop: handleDrop })), buttonActions: buttonActions, dataTestId: dataTestId, variant: "small", bodyLabel: "Column names" })); }; //# sourceMappingURL=ManageColumnsModal.js.map