2025-02-05 21:55:26 +03:00
|
|
|
|
import { useState } from 'react';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
import { useIntl } from 'react-intl';
|
2025-02-12 21:36:03 +03:00
|
|
|
|
import clsx from 'clsx';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2025-02-10 01:32:16 +03:00
|
|
|
|
import { FlexColumn } from '@/components/Container';
|
|
|
|
|
import { MiniButton } from '@/components/Control';
|
2025-02-20 20:22:05 +03:00
|
|
|
|
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/DataTable';
|
2025-02-10 01:32:16 +03:00
|
|
|
|
import { Dropdown, useDropdown } from '@/components/Dropdown';
|
2025-01-28 23:23:03 +03:00
|
|
|
|
import { IconClose, IconFolderTree } from '@/components/Icons';
|
2025-02-12 13:41:58 +03:00
|
|
|
|
import { SearchBar } from '@/components/Input';
|
2025-02-22 14:03:13 +03:00
|
|
|
|
import { type Styling } from '@/components/props';
|
2025-02-11 21:07:06 +03:00
|
|
|
|
import { APP_COLORS } from '@/styling/colors';
|
2024-09-12 13:27:06 +03:00
|
|
|
|
import { prefixes } from '@/utils/constants';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2025-02-22 14:03:13 +03:00
|
|
|
|
import { type ILibraryItem, type LibraryItemType } from '../backend/types';
|
2025-02-12 15:12:59 +03:00
|
|
|
|
import { matchLibraryItem } from '../models/libraryAPI';
|
2025-02-12 21:36:03 +03:00
|
|
|
|
|
2025-02-19 23:29:45 +03:00
|
|
|
|
import { SelectLocation } from './SelectLocation';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2025-02-20 20:22:05 +03:00
|
|
|
|
interface PickSchemaProps extends Styling {
|
2024-06-07 20:17:03 +03:00
|
|
|
|
id?: string;
|
2025-02-12 15:12:59 +03:00
|
|
|
|
value: number | null;
|
|
|
|
|
onChange: (newValue: number) => void;
|
2025-02-04 20:35:18 +03:00
|
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
|
initialFilter?: string;
|
|
|
|
|
rows?: number;
|
|
|
|
|
|
2024-08-17 22:30:49 +03:00
|
|
|
|
items: ILibraryItem[];
|
|
|
|
|
itemType: LibraryItemType;
|
2024-07-26 00:33:22 +03:00
|
|
|
|
baseFilter?: (target: ILibraryItem) => boolean;
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const columnHelper = createColumnHelper<ILibraryItem>();
|
|
|
|
|
|
2025-02-12 12:20:52 +03:00
|
|
|
|
export function PickSchema({
|
2024-08-17 22:30:49 +03:00
|
|
|
|
id,
|
|
|
|
|
initialFilter = '',
|
|
|
|
|
rows = 4,
|
|
|
|
|
items,
|
|
|
|
|
itemType,
|
|
|
|
|
value,
|
2025-02-04 20:35:18 +03:00
|
|
|
|
onChange,
|
2024-10-29 12:44:51 +03:00
|
|
|
|
baseFilter,
|
|
|
|
|
className,
|
|
|
|
|
...restProps
|
2024-08-17 22:30:49 +03:00
|
|
|
|
}: PickSchemaProps) {
|
2024-06-07 20:17:03 +03:00
|
|
|
|
const intl = useIntl();
|
2025-02-05 21:55:26 +03:00
|
|
|
|
const locationMenu = useDropdown();
|
|
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
|
const [filterText, setFilterText] = useState(initialFilter);
|
2024-09-12 13:27:06 +03:00
|
|
|
|
const [filterLocation, setFilterLocation] = useState('');
|
|
|
|
|
|
2025-02-05 21:55:26 +03:00
|
|
|
|
const baseFiltered = items
|
|
|
|
|
.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item)))
|
|
|
|
|
.filter(item => matchLibraryItem(item, filterText));
|
|
|
|
|
const filtered =
|
|
|
|
|
filterLocation.length > 0
|
|
|
|
|
? baseFiltered.filter(item => item.location === filterLocation || item.location.startsWith(`${filterLocation}/`))
|
|
|
|
|
: baseFiltered;
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
|
const columns = [
|
|
|
|
|
columnHelper.accessor('alias', {
|
|
|
|
|
id: 'alias',
|
|
|
|
|
header: 'Шифр',
|
|
|
|
|
size: 150,
|
|
|
|
|
minSize: 80,
|
|
|
|
|
maxSize: 150
|
|
|
|
|
}),
|
|
|
|
|
columnHelper.accessor('title', {
|
|
|
|
|
id: 'title',
|
|
|
|
|
header: 'Название',
|
|
|
|
|
size: 1200,
|
|
|
|
|
minSize: 200,
|
|
|
|
|
maxSize: 1200,
|
|
|
|
|
cell: props => <div className='text-ellipsis'>{props.getValue()}</div>
|
|
|
|
|
}),
|
|
|
|
|
columnHelper.accessor('time_update', {
|
|
|
|
|
id: 'time_update',
|
|
|
|
|
header: 'Дата',
|
|
|
|
|
cell: props => (
|
|
|
|
|
<div className='whitespace-nowrap'>
|
|
|
|
|
{new Date(props.getValue()).toLocaleString(intl.locale, {
|
|
|
|
|
year: '2-digit',
|
|
|
|
|
month: '2-digit',
|
|
|
|
|
day: '2-digit'
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
];
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
|
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
|
|
|
|
|
{
|
|
|
|
|
when: (item: ILibraryItem) => item.id === value,
|
2024-12-16 23:51:31 +03:00
|
|
|
|
style: { backgroundColor: APP_COLORS.bgSelected }
|
2024-12-13 21:30:49 +03:00
|
|
|
|
}
|
|
|
|
|
];
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
2025-02-22 14:03:13 +03:00
|
|
|
|
function handleLocationClick(event: React.MouseEvent<Element>, newValue: string) {
|
2024-12-13 21:30:49 +03:00
|
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
locationMenu.hide();
|
|
|
|
|
setFilterLocation(newValue);
|
|
|
|
|
}
|
2024-09-12 13:27:06 +03:00
|
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
|
return (
|
2024-10-29 12:44:51 +03:00
|
|
|
|
<div className={clsx('border divide-y', className)} {...restProps}>
|
|
|
|
|
<div className='flex justify-between clr-input items-center pr-1 rounded-t-md'>
|
2024-09-12 13:27:06 +03:00
|
|
|
|
<SearchBar
|
|
|
|
|
id={id ? `${id}__search` : undefined}
|
2025-02-20 20:22:05 +03:00
|
|
|
|
className='clr-input grow rounded-t-md'
|
2024-09-12 13:27:06 +03:00
|
|
|
|
noBorder
|
2024-11-21 15:09:31 +03:00
|
|
|
|
query={filterText}
|
|
|
|
|
onChangeQuery={newValue => setFilterText(newValue)}
|
2024-09-12 13:27:06 +03:00
|
|
|
|
/>
|
2025-03-07 02:45:37 +03:00
|
|
|
|
<div className='relative' ref={locationMenu.ref}>
|
2024-09-12 13:27:06 +03:00
|
|
|
|
<MiniButton
|
|
|
|
|
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
|
|
|
|
|
title='Фильтр по расположению'
|
|
|
|
|
className='mt-1'
|
|
|
|
|
onClick={() => locationMenu.toggle()}
|
|
|
|
|
/>
|
2025-03-07 02:45:37 +03:00
|
|
|
|
<Dropdown isOpen={locationMenu.isOpen} stretchLeft className='w-[20rem] h-[12.5rem] z-modal-tooltip'>
|
2024-09-12 13:27:06 +03:00
|
|
|
|
<SelectLocation
|
|
|
|
|
value={filterLocation}
|
|
|
|
|
prefix={prefixes.folders_list}
|
|
|
|
|
dense
|
|
|
|
|
onClick={(event, target) => handleLocationClick(event, target.getPath())}
|
|
|
|
|
/>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
</div>
|
|
|
|
|
{filterLocation.length > 0 ? (
|
|
|
|
|
<MiniButton
|
|
|
|
|
icon={<IconClose size='1.25rem' className='icon-red' />}
|
|
|
|
|
title='Сбросить фильтр'
|
|
|
|
|
onClick={() => setFilterLocation('')}
|
|
|
|
|
/>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
<DataTable
|
|
|
|
|
id={id}
|
|
|
|
|
rows={rows}
|
|
|
|
|
dense
|
|
|
|
|
noHeader
|
|
|
|
|
noFooter
|
|
|
|
|
className='text-sm select-none cc-scroll-y'
|
2024-08-17 22:30:49 +03:00
|
|
|
|
data={filtered}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
columns={columns}
|
|
|
|
|
conditionalRowStyles={conditionalRowStyles}
|
|
|
|
|
noDataComponent={
|
2024-06-21 19:16:41 +03:00
|
|
|
|
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
<p>Список схем пуст</p>
|
|
|
|
|
<p>Измените параметры фильтра</p>
|
|
|
|
|
</FlexColumn>
|
|
|
|
|
}
|
2025-02-04 20:35:18 +03:00
|
|
|
|
onRowClicked={rowData => onChange(rowData.id)}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|