import { type AxiosResponse } from 'axios'; import { useCallback, useMemo, useState } from 'react'; import { toast } from 'react-toastify'; import Button from '../../components/Common/Button'; import DataTableThemed from '../../components/Common/DataTableThemed'; import Divider from '../../components/Common/Divider'; import { ArrowDownIcon, ArrowsRotateIcon, ArrowUpIcon, DumpBinIcon, SmallPlusIcon } from '../../components/Icons'; import { useRSForm } from '../../context/RSFormContext'; import { useConceptTheme } from '../../context/ThemeContext'; import { CstType, type IConstituenta, type INewCstData, inferStatus, ParsingStatus, ValueClass } from '../../utils/models' import { createAliasFor, getCstTypeLabel, getCstTypePrefix, getStatusInfo, getTypeLabel } from '../../utils/staticUI'; import CreateCstModal from './CreateCstModal'; interface ConstituentsTableProps { onOpenEdit: (cst: IConstituenta) => void } function ConstituentsTable({ onOpenEdit }: ConstituentsTableProps) { const { schema, isEditable, cstCreate, cstDelete, cstMoveTo } = useRSForm(); const { noNavigation } = useConceptTheme(); const [selected, setSelected] = useState([]); const nothingSelected = useMemo(() => selected.length === 0, [selected]); const [showCstModal, setShowCstModal] = useState(false); const handleRowClicked = useCallback( (cst: IConstituenta, event: React.MouseEvent) => { if (event.altKey) { onOpenEdit(cst); } }, [onOpenEdit]); const handleSelectionChange = useCallback( ({ selectedRows }: { allSelected: boolean selectedCount: number selectedRows: IConstituenta[] }) => { setSelected(selectedRows.map((cst) => cst.id)); }, [setSelected]); // Delete selected constituents const handleDelete = useCallback(() => { if (!schema?.items || !window.confirm('Вы уверены, что хотите удалить выбранные конституенты?')) { return; } const data = { items: selected.map(id => { return { id }; }) } const deletedNames = selected.map(id => schema.items?.find((cst) => cst.id === id)?.alias); cstDelete(data, () => toast.success(`Конституенты удалены: ${deletedNames.toString()}`)); }, [selected, schema?.items, cstDelete]); // Move selected cst up const handleMoveUp = useCallback( () => { if (!schema?.items || selected.length === 0) { return; } const currentIndex = schema.items.reduce((prev, cst, index) => { if (!selected.includes(cst.id)) { return prev; } else if (prev === -1) { return index; } return Math.min(prev, index); }, -1); const insertIndex = Math.max(0, currentIndex - 1) + 1 const data = { items: selected.map(id => { return { id }; }), move_to: insertIndex } cstMoveTo(data); }, [selected, schema?.items, cstMoveTo]); // Move selected cst down const handleMoveDown = useCallback( () => { if (!schema?.items || selected.length === 0) { return; } let count = 0; const currentIndex = schema.items.reduce((prev, cst, index) => { if (!selected.includes(cst.id)) { return prev; } else { count += 1; if (prev === -1) { return index; } return Math.max(prev, index); } }, -1); const insertIndex = Math.min(schema.items.length - 1, currentIndex - count + 2) + 1 const data = { items: selected.map(id => { return { id }; }), move_to: insertIndex } cstMoveTo(data); }, [selected, schema?.items, cstMoveTo]); // Generate new names for all constituents const handleReindex = useCallback(() => { toast.info('Переиндексация'); }, []); // Add new constituent const handleAddNew = useCallback((csttype?: CstType) => { if (!schema) { return; } if (!csttype) { setShowCstModal(true); } else { const data: INewCstData = { csttype, alias: createAliasFor(csttype, schema) } if (selected.length > 0) { data.insert_after = selected[selected.length - 1] } cstCreate(data, (response: AxiosResponse) => toast.success(`Добавлена конституента ${response.data.new_cst.alias as string}`)); } }, [schema, selected, cstCreate]); // Implement hotkeys for working with constituents table const handleTableKey = useCallback((event: React.KeyboardEvent) => { if (!event.altKey) { return; } if (!isEditable || selected.length === 0) { return; } switch (event.key) { case 'ArrowUp': handleMoveUp(); return; case 'ArrowDown': handleMoveDown(); } }, [isEditable, selected, handleMoveUp, handleMoveDown]); const columns = useMemo(() => [ { name: 'ID', id: 'id', selector: (cst: IConstituenta) => cst.id, omit: true }, { name: 'Статус', id: 'status', cell: (cst: IConstituenta) =>
{getStatusInfo(inferStatus(cst.parse?.status, cst.parse?.valueClass)).text}
, width: '80px', maxWidth: '80px', reorder: true, hide: 1280, conditionalCellStyles: [ { when: (cst: IConstituenta) => cst.parse?.status !== ParsingStatus.VERIFIED, classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]'] }, { when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.INVALID, classNames: ['bg-[#beeefa]', 'dark:bg-[#286675]'] }, { when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.PROPERTY, classNames: ['bg-[#a5e9fa]', 'dark:bg-[#36899e]'] } ] }, { name: 'Имя', id: 'alias', selector: (cst: IConstituenta) => cst.alias, width: '65px', maxWidth: '65px', reorder: true, conditionalCellStyles: [ { when: (cst: IConstituenta) => cst.parse?.status !== ParsingStatus.VERIFIED, classNames: ['bg-[#ff8080]', 'dark:bg-[#800000]'] }, { when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.INVALID, classNames: ['bg-[#ffbb80]', 'dark:bg-[#964600]'] }, { when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.PROPERTY, classNames: ['bg-[#a5e9fa]', 'dark:bg-[#36899e]'] } ] }, { name: 'Тип', id: 'type', cell: (cst: IConstituenta) =>
{getTypeLabel(cst)}
, width: '140px', minWidth: '100px', maxWidth: '140px', wrap: true, reorder: true, hide: 1600 }, { name: 'Термин', id: 'term', selector: (cst: IConstituenta) => cst.term?.resolved ?? cst.term?.raw ?? '', width: '350px', minWidth: '150px', maxWidth: '350px', wrap: true, reorder: true }, { name: 'Формальное определение', id: 'expression', selector: (cst: IConstituenta) => cst.definition?.formal ?? '', minWidth: '300px', maxWidth: '500px', grow: 2, wrap: true, reorder: true }, { name: 'Текстовое определение', id: 'definition', cell: (cst: IConstituenta) => (
{cst.definition?.text.resolved ?? cst.definition?.text.raw ?? ''}
), minWidth: '200px', grow: 2, wrap: true, reorder: true }, { name: 'Конвенция / Комментарий', id: 'convention', cell: (cst: IConstituenta) =>
{cst.convention ?? ''}
, minWidth: '100px', wrap: true, reorder: true, hide: 1800 } ], [] ); return (<> { setShowCstModal(false); }} onCreate={handleAddNew} />
Выбраны {selected.length} из {schema?.stats?.count_all ?? 0}
{isEditable &&
}

Список пуст

Создайте новую конституенту

} striped highlightOnHover pointerOnHover selectableRows selectableRowsHighlight onSelectedRowsChange={handleSelectionChange} onRowDoubleClicked={onOpenEdit} onRowClicked={handleRowClicked} dense />
); } export default ConstituentsTable;