ConceptPortal-public/rsconcept/frontend/src/pages/RSFormPage/ConstituentsTable.tsx

237 lines
7.8 KiB
TypeScript
Raw Normal View History

2023-07-20 17:11:03 +03:00
import { CstType, IConstituenta, ParsingStatus, ValueClass, inferStatus } from '../../utils/models'
2023-07-15 17:46:19 +03:00
import { useCallback, useMemo, useState } from 'react';
import DataTableThemed, { SelectionInfo } from '../../components/Common/DataTableThemed';
import { useRSForm } from '../../context/RSFormContext';
2023-07-20 17:11:03 +03:00
import Button from '../../components/Common/Button';
import { ArrowDownIcon, ArrowUpIcon, ArrowsRotateIcon, DumpBinIcon, SmallPlusIcon } from '../../components/Icons';
import { toast } from 'react-toastify';
import Divider from '../../components/Common/Divider';
import { getCstTypeLabel, getCstTypePrefix, getStatusInfo, getTypeLabel } from '../../utils/staticUI';
2023-07-15 17:46:19 +03:00
interface ConstituentsTableProps {
onOpenEdit: (cst: IConstituenta) => void
}
function ConstituentsTable({onOpenEdit}: ConstituentsTableProps) {
const { schema, isEditable, } = useRSForm();
2023-07-15 17:46:19 +03:00
const [selectedRows, setSelectedRows] = useState<IConstituenta[]>([]);
2023-07-20 17:11:03 +03:00
const nothingSelected = useMemo(() => selectedRows.length === 0, [selectedRows]);
2023-07-15 17:46:19 +03:00
const handleRowSelected = useCallback(
({selectedRows} : SelectionInfo<IConstituenta>) => {
setSelectedRows(selectedRows);
}, []);
2023-07-20 17:11:03 +03:00
const handleRowClicked = useCallback(
(cst: IConstituenta, event: React.MouseEvent<Element, MouseEvent>) => {
if (event.ctrlKey) {
onOpenEdit(cst);
2023-07-20 17:11:03 +03:00
}
}, [onOpenEdit]);
2023-07-20 17:11:03 +03:00
const handleDelete = useCallback(() => {
toast.info('Удаление конституент');
}, []);
const handleMoveUp = useCallback(() => {
toast.info('Перемещение вверх');
}, []);
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
const handleMoveDown = useCallback(() => {
toast.info('Перемещение вниз');
}, []);
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
const handleReindex = useCallback(() => {
toast.info('Переиндексация');
}, []);
const handleAddNew = useCallback((cstType?: CstType) => {
toast.info(`Новая конституента ${cstType || 'NEW'}`);
}, []);
2023-07-15 17:46:19 +03:00
const columns = useMemo(() =>
[
{
name: 'ID',
id: 'id',
selector: (cst: IConstituenta) => cst.entityUID,
omit: true,
},
{
name: 'Статус',
id: 'status',
2023-07-20 17:11:03 +03:00
cell: (cst: IConstituenta) =>
<div style={{fontSize: 12}}>
{getStatusInfo(inferStatus(cst.parse?.status, cst.parse?.valueClass)).text}
</div>,
2023-07-15 17:46:19 +03:00
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,
2023-07-20 17:11:03 +03:00
classNames: ['bg-[#ff8080]', 'dark:bg-[#800000]']
2023-07-15 17:46:19 +03:00
},
{
when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.INVALID,
2023-07-20 17:11:03 +03:00
classNames: ['bg-[#ffbb80]', 'dark:bg-[#964600]']
2023-07-15 17:46:19 +03:00
},
{
when: (cst: IConstituenta) => cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.PROPERTY,
classNames: ['bg-[#a5e9fa]', 'dark:bg-[#36899e]']
},
],
},
{
name: 'Тип',
id: 'type',
2023-07-20 17:11:03 +03:00
cell: (cst: IConstituenta) => <div style={{fontSize: 12}}>{getTypeLabel(cst)}</div>,
2023-07-15 17:46:19 +03:00
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 || '',
2023-07-20 17:11:03 +03:00
minWidth: '300px',
2023-07-15 17:46:19 +03:00
maxWidth: '500px',
2023-07-20 17:11:03 +03:00
grow: 2,
2023-07-15 17:46:19 +03:00
wrap: true,
reorder: true,
},
{
name: 'Текстовое определение',
id: 'definition',
cell: (cst: IConstituenta) => (
<div style={{fontSize: 12}}>
{cst.definition?.text.resolved || cst.definition?.text.raw || ''}
</div>
),
minWidth: '200px',
2023-07-20 17:11:03 +03:00
grow: 2,
2023-07-15 17:46:19 +03:00
wrap: true,
reorder: true,
},
{
name: 'Конвенция / Комментарий',
id: 'convention',
cell: (cst: IConstituenta) => <div style={{fontSize: 12}}>{cst.convention || ''}</div>,
2023-07-20 17:11:03 +03:00
minWidth: '100px',
2023-07-15 17:46:19 +03:00
wrap: true,
reorder: true,
hide: 1800,
},
], []
);
return (
2023-07-20 17:11:03 +03:00
<div className='w-full'>
<div className='flex justify-start w-full gap-1 px-2 py-1 border-y items-center h-[2.2rem]'>
<div className='mr-3 whitespace-nowrap'>Выбраны <span className='ml-2'><b>{selectedRows.length}</b> из {schema?.stats?.count_all || 0}</span></div>
{isEditable && <div className='flex justify-start w-full gap-1'>
<Button
tooltip='Переместить вверх'
icon={<ArrowUpIcon size={6}/>}
disabled={nothingSelected}
dense
onClick={handleMoveUp}
/>
<Button
tooltip='Переместить вниз'
icon={<ArrowDownIcon size={6}/>}
disabled={nothingSelected}
dense
onClick={handleMoveDown}
/>
<Button
tooltip='Удалить выбранные'
icon={<DumpBinIcon color={!nothingSelected ? 'text-red': ''} size={6}/>}
disabled={nothingSelected}
dense
onClick={handleDelete}
/>
<Divider vertical margins='1' />
<Button
tooltip='Переиндексировать имена'
icon={<ArrowsRotateIcon color='text-primary' size={6}/>}
dense
onClick={handleReindex}
/>
<Button
tooltip='Новая конституента'
icon={<SmallPlusIcon color='text-green' size={6}/>}
dense
onClick={() => handleAddNew()}
/>
{(Object.values(CstType)).map(
(typeStr) => {
const type = typeStr as CstType;
return <Button
text={`${getCstTypePrefix(type)}`}
tooltip={getCstTypeLabel(type)}
dense
onClick={() =>handleAddNew(type)}
/>;
})}
</div>}
2023-07-20 17:11:03 +03:00
</div>
<DataTableThemed
data={schema!.items!}
columns={columns}
keyField='id'
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
striped
highlightOnHover
pointerOnHover
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
selectableRows
// selectableRowSelected={(cst) => selectedRows.indexOf(cst) < -1}
selectableRowsHighlight
onSelectedRowsChange={handleRowSelected}
onRowDoubleClicked={onOpenEdit}
onRowClicked={handleRowClicked}
dense
/>
</div>
2023-07-15 17:46:19 +03:00
);
}
export default ConstituentsTable;