UNPKG

@adaptabletools/adaptable

Version:

Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

338 lines (337 loc) 15.5 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import * as React from 'react'; import useSelection from './useSelection'; import { CheckBox } from '../../../components/CheckBox'; import Radio from '../../../components/Radio'; import Dropdown from '../../../components/Dropdown'; import Input from '../../../components/Input'; import { useRef, useState } from 'react'; import StringExtensions from '../../../Utilities/Extensions/StringExtensions'; import { DataSource, InfiniteTableGrid, } from '../../../components/InfiniteTable'; import { Box, Flex } from '../../../components/Flex'; import { throttle } from '../../../Utilities/Helpers/TimingHelper'; import { twMerge } from '../../../twMerge'; const dataTypes = [ { value: 'text', label: 'Text (string)', }, { value: 'number', label: 'Number' }, { value: 'date', label: 'Date', }, { value: 'boolean', label: 'Boolean', }, ]; const inputStyle = { width: '100%', minWidth: 80, textAlign: 'start', }; const useForceRender = () => { const [, setNow] = useState(Date.now()); return () => { setNow(Date.now()); }; }; const ThrottledInput = React.memo((props) => { const [stateValue, setStateValue] = useState(props.value); const throttleOnChange = React.useRef(throttle(props.onChange, 600, { leading: false })); const handleChange = React.useCallback((event) => { const newValue = event.target.value; setStateValue(newValue); throttleOnChange.current(newValue); }, []); React.useEffect(() => { setStateValue(props.value); }, [props.value]); return _jsx(Input, { style: props.style, value: stateValue, onChange: handleChange }); }); const tableDOMProps = { style: { height: '100%', minWidth: '10rem', minHeight: 600, }, }; const ColumnsList = ({ columns: cols, handle, onValidityChange, onChange, onSelectionChange, selectedColumns, theme, }) => { const rerender = useForceRender(); const columnsRef = useRef(cols); const silentSetColumns = (columns) => { columnsRef.current = columns; onChange?.(columns); }; const setColumns = (columns) => { silentSetColumns(columns); rerender(); }; const getColumns = () => columnsRef.current; const columns = columnsRef.current; const onColumnChange = (col, value, property) => { col = { ...col, [property]: value }; const cols = getColumns().map((c) => { if (c.field === col.field) { return col; } return c; }); setColumns(cols); }; const onColumnBatchChange = (value, property) => { const cols = getColumns().map((c) => ({ ...c, [property]: value })); setColumns(cols); }; const setColumnCaption = (caption, field) => { const cols = getColumns().map((c) => { if (c.field === field) { const newCol = { ...c, caption }; return newCol; } return c; }); setColumns(cols); }; const onColumnTypeChange = (col, type) => { const cols = getColumns().map((c) => { if (c.field === col.field) { return { ...c, type }; } return c; }); setColumns(cols); }; const [primaryKeyField, setPrimaryKeyField] = React.useState(columns[0].field); const { selected: includedColumnsMap, isSelected: isIncludedColumn, isAllSelected: isAllIncludedColumns, isNoneSelected: isNoneIncludedColumns, selectColumn: includeColumn, deselectColumn: excludeColumn, selectAll: includeAllColumns, deselectAll: excludeAllColumns, } = useSelection(columns, selectedColumns ?? true, null, { onChange: onSelectionChange }); handle.current = { getColumns: () => getColumns().filter((col) => isIncludedColumn(col.field)), getPrimaryKey: () => primaryKeyField, }; const { isSelected: isSortableColumn, isAllSelected: isAllSortableColumns, isNoneSelected: isNoneSortableColumns, selectColumn: setSortableColumn, deselectColumn: setUnsortableColumn, selectAll: setAllSortable, deselectAll: setAllUnsortable, } = useSelection(columns, true, 'sortable', { onBatchChange: (flag) => { onColumnBatchChange(flag, 'sortable'); }, onChange: (col, flag) => { onColumnChange(col, flag, 'sortable'); }, }); const { isSelected: isGroupableColumn, isAllSelected: isAllGroupableColumns, isNoneSelected: isNoneGroupableColumns, selectColumn: setGroupableColumn, deselectColumn: setUngroupableColumn, selectAll: setAllGroupable, deselectAll: setAllUngroupable, } = useSelection(columns, true, 'enableRowGroup', { onBatchChange: (flag) => { onColumnBatchChange(flag, 'enableRowGroup'); }, onChange: (col, flag) => { onColumnChange(col, flag, 'enableRowGroup'); }, }); const { isSelected: isResizableColumn, isAllSelected: isAllResizableColumns, isNoneSelected: isNoneResizableColumns, selectColumn: setResizableColumn, deselectColumn: setUnresizableColumn, selectAll: setAllResizable, deselectAll: setAllUnresizable, } = useSelection(columns, true, 'resizable', { onBatchChange: (flag) => { onColumnBatchChange(flag, 'resizable'); }, onChange: (col, flag) => { onColumnChange(col, flag, 'resizable'); }, }); const { isSelected: isEditableColumn, isAllSelected: isAllEditableColumns, isNoneSelected: isNoneEditableColumns, selectColumn: setEditableColumn, deselectColumn: setUneditableColumn, selectAll: setAllEditable, deselectAll: setAllUneditable, } = useSelection(columns, true, 'editable', { onBatchChange: (flag) => { onColumnBatchChange(flag, 'editable'); }, onChange: (col, flag) => { onColumnChange(col, flag, 'editable'); }, }); const { isSelected: isFilterableColumn, isAllSelected: isAllFilterableColumns, isNoneSelected: isNoneFilterableColumns, selectColumn: setFilterableColumn, deselectColumn: setUnFilterableColumn, selectAll: setAllFilterable, deselectAll: setAllUnfilterable, } = useSelection(columns, true, 'filter', { onBatchChange: (flag) => { onColumnBatchChange(flag, 'filter'); }, onChange: (col, flag) => { onColumnChange(col, flag, 'filter'); }, }); const allIncluded = isAllIncludedColumns(); const allExcluded = isNoneIncludedColumns(); React.useEffect(() => { onValidityChange(isIncludedColumn(primaryKeyField)); }, [includedColumnsMap, primaryKeyField]); const data = columns; const CellWrapper = (props) => { return (_jsx(Flex, { ...props, style: { ...props.style, position: 'absolute', textAlign: 'center', top: 0, left: 0, height: '100%', width: '100%', whiteSpace: 'normal', }, justifyContent: "center", alignItems: "center", children: props.children })); }; const HeaderCellWrapper = (props) => (_jsx(CellWrapper, { ...props, className: twMerge('twa:text-3 twa:font-bold', props.className) })); const HeaderWithCheckbox = (props) => { const { label, onChange, checked, ...flexProps } = props; return (_jsxs(HeaderCellWrapper, { ...flexProps, flexDirection: "column", children: [_jsx(Box, { children: label }), _jsx(Box, { className: "twa:text-center twa:ml-1", children: _jsx(CheckBox, { checked: checked, onChange: onChange }) })] })); }; const columnsMap = { pk: { header: () => _jsx(HeaderCellWrapper, { children: "Primary Key" }), maxWidth: 80, defaultSortable: false, renderMenuIcon: false, render: (params) => { const { data } = params; const column = data; const isPrimaryKey = column?.field === primaryKeyField; return (_jsx(Radio, { checked: isPrimaryKey, onChange: (checked) => { if (checked && isIncludedColumn(column.field)) { setPrimaryKeyField(column.field); } } })); }, }, included: { maxWidth: 80, resizable: true, renderMenuIcon: false, header: () => (_jsx(HeaderWithCheckbox, { label: "Included", checked: allIncluded ? true : allExcluded ? false : null, onChange: (allIncluded) => { if (allIncluded) { includeAllColumns(); } else { excludeAllColumns(); } } })), render: (params) => { const column = params.data; return (_jsx(CellWrapper, { children: _jsx(CheckBox, { checked: isIncludedColumn(column.field), onChange: (included) => { if (included) { includeColumn(column.field); } else { excludeColumn(column.field); } } }) })); }, }, field: { header: _jsx(HeaderCellWrapper, { children: "Field" }), field: 'field', minWidth: 150, renderMenuIcon: false, render: (params) => { const column = params.data; const humanized = StringExtensions.Humanize(column.field); return (_jsx(Box, { className: "twa:p-2", children: _jsx(ThrottledInput, { style: inputStyle, value: column.caption != undefined ? column.caption : humanized, placeholder: humanized, onChange: (value) => { setColumnCaption(value, column.field); } }, column.field) })); }, }, type: { header: _jsx(HeaderCellWrapper, { children: "Type" }), maxWidth: 140, renderMenuIcon: false, render: (params) => { const column = params.data; return (_jsx(CellWrapper, { className: "twa:px-1", children: _jsx(Dropdown, { style: inputStyle, showClearButton: false, options: dataTypes, value: column?.type ?? '', onChange: onColumnTypeChange.bind(null, column) }) })); }, }, sortable: { renderMenuIcon: false, header: (_jsx(HeaderWithCheckbox, { label: "Sortable", checked: isAllSortableColumns() ? true : isNoneSortableColumns() ? false : null, onChange: (allSortable) => { if (allSortable) { setAllSortable(); } else { setAllUnsortable(); } } })), render: (params) => { const column = params.data; return (_jsx(CheckBox, { checked: isSortableColumn(column.field), onChange: (sortable) => { sortable ? setSortableColumn(column.field) : setUnsortableColumn(column.field); } })); }, }, editable: { renderMenuIcon: false, header: (_jsx(HeaderWithCheckbox, { label: "Editable", checked: isAllEditableColumns() ? true : isNoneEditableColumns() ? false : null, onChange: (allEditable) => { if (allEditable) { setAllEditable(); } else { setAllUneditable(); } } })), render: (params) => { const col = params.data; return (_jsx(CellWrapper, { children: _jsx(CheckBox, { checked: isEditableColumn(col.field), onChange: (editable) => { editable ? setEditableColumn(col.field) : setUneditableColumn(col.field); } }) })); }, }, resizable: { renderMenuIcon: false, header: (_jsx(HeaderWithCheckbox, { label: "Resizable", checked: isAllResizableColumns() ? true : isNoneResizableColumns() ? false : null, onChange: (allResizable) => { if (allResizable) { setAllResizable(); } else { setAllUnresizable(); } } })), render: (params) => { const col = params.data; return (_jsx(CellWrapper, { children: _jsx(CheckBox, { checked: isResizableColumn(col.field), onChange: (resizable) => { resizable ? setResizableColumn(col.field) : setUnresizableColumn(col.field); } }) })); }, }, groupable: { renderMenuIcon: false, header: (_jsx(HeaderWithCheckbox, { label: "Groupable", checked: isAllGroupableColumns() ? true : isNoneGroupableColumns() ? false : null, onChange: (allGroupable) => { if (allGroupable) { setAllGroupable(); } else { setAllUngroupable(); } } })), render: (params) => { const col = params.data; return (_jsx(CellWrapper, { children: _jsx(CheckBox, { checked: isGroupableColumn(col.field), onChange: (groupable) => { groupable ? setGroupableColumn(col.field) : setUngroupableColumn(col.field); } }) })); }, }, filterable: { renderMenuIcon: false, header: (_jsx(HeaderWithCheckbox, { label: "Filterable", checked: isAllFilterableColumns() ? true : isNoneFilterableColumns() ? false : null, onChange: (allFilterable) => { if (allFilterable) { setAllFilterable(); } else { setAllUnfilterable(); } } })), render: (params) => { const col = params.data; return (_jsx(CellWrapper, { children: _jsx(CheckBox, { checked: isFilterableColumn(col.field), onChange: (filterable) => { filterable ? setFilterableColumn(col.field) : setUnFilterableColumn(col.field); } }) })); }, }, }; return (_jsx(Box, { className: twMerge('twa:p-2 twa:h-full', theme), children: _jsx(DataSource, { data: data, primaryKey: "colId", children: _jsx(InfiniteTableGrid, { columnTypes: { default: { defaultFlex: 1, align: 'center', defaultSortable: false, }, }, rowHeight: 40, columnHeaderHeight: 60, headerOptions: { alwaysReserveSpaceForSortIcon: false, }, domProps: tableDOMProps, columns: columnsMap }) }) })); }; function areEqual() { return true; } export default React.memo(ColumnsList, areEqual);