ConceptPortal-public/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx

149 lines
4.9 KiB
TypeScript
Raw Normal View History

2023-07-25 20:27:29 +03:00
import { useCallback, useEffect, useMemo, useState } from 'react';
2023-07-28 00:03:37 +03:00
import Checkbox from '../../../components/Common/Checkbox';
import DataTableThemed from '../../../components/Common/DataTableThemed';
import { useRSForm } from '../../../context/RSFormContext';
import useLocalStorage from '../../../hooks/useLocalStorage';
import { CstType, type IConstituenta, matchConstituenta } from '../../../utils/models';
import { extractGlobals, getMockConstituenta } from '../../../utils/staticUI';
2023-07-20 17:11:03 +03:00
2023-07-28 00:03:37 +03:00
interface ViewSideConstituentsProps {
2023-07-20 17:11:03 +03:00
expression: string
}
2023-07-28 00:03:37 +03:00
function ViewSideConstituents({ expression }: ViewSideConstituentsProps) {
const { schema, setActiveID } = useRSForm();
2023-07-25 20:27:29 +03:00
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
2023-07-20 17:11:03 +03:00
const [filterText, setFilterText] = useLocalStorage('side-filter-text', '')
const [onlyExpression, setOnlyExpression] = useLocalStorage('side-filter-flag', false);
useEffect(() => {
if (!schema?.items) {
setFilteredData([]);
return;
}
if (onlyExpression) {
const aliases = extractGlobals(expression);
2023-07-25 20:27:29 +03:00
const filtered = schema?.items.filter((cst) => aliases.has(cst.alias));
const names = filtered.map(cst => cst.alias)
2023-07-25 20:27:29 +03:00
const diff = Array.from(aliases).filter(name => !names.includes(name));
if (diff.length > 0) {
diff.forEach(
(alias, index) => filtered.push(getMockConstituenta(-index, alias, CstType.BASE, 'Конституента отсутствует')));
}
setFilteredData(filtered);
2023-07-20 17:11:03 +03:00
} else if (!filterText) {
setFilteredData(schema?.items);
} else {
setFilteredData(schema?.items.filter((cst) => matchConstituenta(filterText, cst)));
}
}, [filterText, setFilteredData, onlyExpression, expression, schema]);
const handleRowClicked = useCallback(
2023-07-25 20:27:29 +03:00
(cst: IConstituenta, event: React.MouseEvent<Element, MouseEvent>) => {
if (event.altKey && cst.id > 0) {
setActiveID(cst.id);
2023-07-20 17:11:03 +03:00
}
2023-07-25 20:27:29 +03:00
}, [setActiveID]);
2023-07-20 17:11:03 +03:00
const handleDoubleClick = useCallback(
(cst: IConstituenta) => {
2023-07-25 20:27:29 +03:00
if (cst.id > 0) setActiveID(cst.id);
}, [setActiveID]);
2023-07-20 17:11:03 +03:00
2023-07-25 20:27:29 +03:00
const columns = useMemo(() =>
2023-07-20 17:11:03 +03:00
[
{
id: 'id',
selector: (cst: IConstituenta) => cst.id,
2023-07-25 20:27:29 +03:00
omit: true
2023-07-20 17:11:03 +03:00
},
{
name: 'ID',
id: 'alias',
selector: (cst: IConstituenta) => cst.alias,
width: '62px',
maxWidth: '62px',
conditionalCellStyles: [
{
when: (cst: IConstituenta) => cst.id <= 0,
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
2023-07-25 20:27:29 +03:00
}
]
2023-07-20 17:11:03 +03:00
},
{
name: 'Описание',
id: 'description',
2023-07-25 20:27:29 +03:00
selector: (cst: IConstituenta) =>
cst.term?.resolved ?? cst.definition?.text.resolved ?? cst.definition?.formal ?? cst.convention ?? '',
2023-07-20 17:11:03 +03:00
minWidth: '350px',
wrap: true,
conditionalCellStyles: [
{
when: (cst: IConstituenta) => cst.id <= 0,
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
2023-07-25 20:27:29 +03:00
}
]
2023-07-20 17:11:03 +03:00
},
{
name: 'Выражение',
id: 'expression',
2023-07-25 20:27:29 +03:00
selector: (cst: IConstituenta) => cst.definition?.formal ?? '',
2023-07-20 17:11:03 +03:00
minWidth: '200px',
hide: 1600,
grow: 2,
wrap: true,
conditionalCellStyles: [
{
when: (cst: IConstituenta) => cst.id <= 0,
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
2023-07-25 20:27:29 +03:00
}
]
2023-07-20 17:11:03 +03:00
}
], []
);
return (
<div className='max-h-[80vh] overflow-y-scroll border flex-grow w-full'>
<div className='sticky top-0 left-0 right-0 z-10 flex items-center justify-between w-full gap-1 px-2 py-1 bg-white border-b-2 border-gray-400 rounded dark:bg-gray-700 dark:border-gray-300'>
2023-07-20 17:11:03 +03:00
<div className='w-full'>
<input type='text'
className='w-full px-2 outline-none dark:bg-gray-700 hover:text-clip'
placeholder='текст для фильтрации списка'
value={filterText}
2023-07-25 20:27:29 +03:00
onChange={event => { setFilterText(event.target.value); }}
2023-07-20 17:11:03 +03:00
disabled={onlyExpression}
/>
</div>
<div className='w-fit min-w-[8rem]'>
<Checkbox
label='из выражения'
value={onlyExpression}
2023-07-25 20:27:29 +03:00
onChange={event => { setOnlyExpression(event.target.checked); }}
2023-07-20 17:11:03 +03:00
/>
</div>
</div>
<DataTableThemed
data={filteredData}
columns={columns}
keyField='id'
noContextMenu
noDataComponent={<span className='flex flex-col justify-center p-2 text-center'>
2023-07-22 12:24:14 +03:00
<p>Список конституент пуст</p>
<p>Измените параметры фильтра</p>
</span>}
2023-07-20 17:11:03 +03:00
striped
highlightOnHover
pointerOnHover
onRowDoubleClicked={handleDoubleClick}
onRowClicked={handleRowClicked}
dense
/>
</div>
);
}
2023-07-28 00:03:37 +03:00
export default ViewSideConstituents;