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

379 lines
12 KiB
TypeScript
Raw Normal View History

'use client';
2023-07-25 20:27:29 +03:00
import { urls } from '@/app/urls';
import {
IconAdmin,
2024-05-02 19:13:54 +03:00
IconAlert,
IconArchive,
IconClone,
IconDestroy,
IconDownload,
2024-05-02 19:13:54 +03:00
IconEdit2,
2024-05-27 20:42:34 +03:00
IconEditor,
2024-05-02 19:13:54 +03:00
IconGenerateNames,
IconGenerateStructure,
IconInlineSynthesis,
IconLibrary,
IconMenu,
IconNewItem,
2024-08-24 12:29:38 +03:00
IconNewVersion,
IconOSS,
IconOwner,
2024-12-18 12:35:48 +03:00
IconQR,
IconReader,
IconReplace,
IconShare,
2024-05-02 17:04:18 +03:00
IconSortList,
2024-05-02 19:13:54 +03:00
IconTemplates,
IconUpload
} from '@/components/Icons';
import Button from '@/components/ui/Button';
import Divider from '@/components/ui/Divider';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import { useAuth } from '@/context/AuthContext';
2024-08-16 20:57:37 +03:00
import { useGlobalOss } from '@/context/GlobalOssContext';
2023-12-26 14:23:51 +03:00
import { useConceptNavigation } from '@/context/NavigationContext';
import { useRSForm } from '@/context/RSFormContext';
import useDropdown from '@/hooks/useDropdown';
2024-06-18 15:07:41 +03:00
import { AccessPolicy } from '@/models/library';
2025-01-15 23:03:35 +03:00
import { UserRole } from '@/models/user';
import { useRoleStore } from '@/stores/role';
2024-06-18 15:07:41 +03:00
import { describeAccessMode, labelAccessMode, tooltips } from '@/utils/labels';
2023-07-20 17:11:03 +03:00
import { OssTabID } from '../OssPage/OssTabs';
import { useRSEdit } from './RSEditContext';
2023-12-28 14:04:44 +03:00
interface MenuRSTabsProps {
2023-12-28 14:04:44 +03:00
onDestroy: () => void;
2023-07-28 18:23:37 +03:00
}
function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
const controller = useRSEdit();
const router = useConceptNavigation();
2023-07-25 20:27:29 +03:00
const { user } = useAuth();
const model = useRSForm();
2024-08-16 20:57:37 +03:00
const oss = useGlobalOss();
2023-12-16 19:20:26 +03:00
2025-01-15 23:03:35 +03:00
const role = useRoleStore(state => state.role);
const setRole = useRoleStore(state => state.setRole);
2023-12-16 19:20:26 +03:00
2023-07-20 17:11:03 +03:00
const schemaMenu = useDropdown();
const editMenu = useDropdown();
2023-12-16 19:20:26 +03:00
const accessMenu = useDropdown();
2023-07-21 00:09:05 +03:00
2023-08-25 22:51:20 +03:00
function handleDelete() {
schemaMenu.hide();
onDestroy();
2023-08-25 22:51:20 +03:00
}
2023-12-28 14:04:44 +03:00
function handleDownload() {
schemaMenu.hide();
controller.download();
2023-08-25 22:51:20 +03:00
}
2023-08-25 22:51:20 +03:00
function handleUpload() {
schemaMenu.hide();
controller.promptUpload();
2023-08-25 22:51:20 +03:00
}
2023-08-25 22:51:20 +03:00
function handleClone() {
schemaMenu.hide();
controller.promptClone();
2023-08-25 22:51:20 +03:00
}
2023-08-24 11:10:04 +03:00
function handleShare() {
schemaMenu.hide();
controller.share();
2023-08-24 11:10:04 +03:00
}
2024-12-18 12:35:48 +03:00
function handleShowQR() {
schemaMenu.hide();
controller.showQR();
}
2024-09-16 14:02:44 +03:00
function handleCreateVersion() {
schemaMenu.hide();
controller.createVersion();
}
2023-12-16 19:20:26 +03:00
function handleReindex() {
editMenu.hide();
controller.reindex();
2023-12-16 19:20:26 +03:00
}
2024-04-24 10:27:17 +03:00
function handleRestoreOrder() {
editMenu.hide();
controller.reorder();
}
function handleSubstituteCst() {
editMenu.hide();
controller.substitute();
}
2023-12-16 19:20:26 +03:00
function handleTemplates() {
editMenu.hide();
controller.promptTemplate();
2023-12-16 19:20:26 +03:00
}
2024-03-15 12:34:41 +03:00
function handleProduceStructure() {
editMenu.hide();
controller.produceStructure();
}
function handleInlineSynthesis() {
editMenu.hide();
controller.inlineSynthesis();
}
2025-01-15 23:03:35 +03:00
function handleChangeMode(newMode: UserRole) {
2023-12-16 19:20:26 +03:00
accessMenu.hide();
2025-01-15 23:03:35 +03:00
setRole(newMode);
2023-12-16 19:20:26 +03:00
}
2023-08-24 11:10:04 +03:00
function handleCreateNew() {
router.push(urls.create_schema);
2023-08-24 11:10:04 +03:00
}
2023-07-25 20:27:29 +03:00
function handleLogin() {
router.push(urls.login);
}
2023-12-28 14:04:44 +03:00
return (
<div className='flex'>
<div ref={schemaMenu.ref}>
<Button
dense
noBorder
noOutline
2023-12-28 14:04:44 +03:00
tabIndex={-1}
title='Меню'
hideTitle={schemaMenu.isOpen}
2024-05-02 19:13:54 +03:00
icon={<IconMenu size='1.25rem' className='clr-text-controls' />}
2023-12-28 14:04:44 +03:00
className='h-full pl-2'
onClick={schemaMenu.toggle}
2023-07-20 17:11:03 +03:00
/>
2023-12-28 14:04:44 +03:00
<Dropdown isOpen={schemaMenu.isOpen}>
<DropdownButton
text='Поделиться'
2024-06-18 15:07:41 +03:00
titleHtml={tooltips.shareItem(controller.schema?.access_policy)}
icon={<IconShare size='1rem' className='icon-primary' />}
2023-12-28 14:04:44 +03:00
onClick={handleShare}
2024-06-18 15:07:41 +03:00
disabled={controller.schema?.access_policy !== AccessPolicy.PUBLIC}
2023-12-28 14:04:44 +03:00
/>
2024-12-18 12:35:48 +03:00
<DropdownButton
text='QR-код'
title='Показать QR-код схемы'
icon={<IconQR size='1rem' className='icon-primary' />}
onClick={handleShowQR}
/>
{user ? (
<DropdownButton
text='Клонировать'
2024-12-18 12:35:48 +03:00
icon={<IconClone size='1rem' className='icon-green' />}
2024-03-28 18:44:34 +03:00
disabled={model.isArchive}
onClick={handleClone}
/>
) : null}
2024-08-24 12:29:38 +03:00
<DropdownButton
text='Сохранить версию'
disabled={!controller.isContentEditable}
2024-09-16 14:02:44 +03:00
onClick={handleCreateVersion}
2024-08-24 12:29:38 +03:00
icon={<IconNewVersion size='1rem' className='icon-green' />}
/>
2023-12-28 14:04:44 +03:00
<DropdownButton
text='Выгрузить в Экстеор'
icon={<IconDownload size='1rem' className='icon-primary' />}
2023-12-28 14:04:44 +03:00
onClick={handleDownload}
/>
2024-03-28 18:44:34 +03:00
{controller.isContentEditable ? (
<DropdownButton
text='Загрузить из Экстеор'
icon={<IconUpload size='1rem' className='icon-red' />}
disabled={controller.isProcessing || controller.schema?.oss.length !== 0}
onClick={handleUpload}
/>
) : null}
{controller.isMutable ? (
<DropdownButton
text='Удалить схему'
icon={<IconDestroy size='1rem' className='icon-red' />}
2025-01-15 23:03:35 +03:00
disabled={controller.isProcessing || role < UserRole.OWNER}
onClick={handleDelete}
/>
) : null}
2024-09-12 11:17:01 +03:00
<Divider margins='mx-3 my-1' />
2024-09-12 11:17:01 +03:00
{user ? (
<DropdownButton
text='Создать новую схему'
icon={<IconNewItem size='1rem' className='icon-primary' />}
onClick={handleCreateNew}
/>
) : null}
2024-08-16 20:57:37 +03:00
{oss.schema ? (
<DropdownButton
text='Перейти к ОСС'
icon={<IconOSS size='1rem' className='icon-primary' />}
2024-08-16 20:57:37 +03:00
onClick={() => router.push(urls.oss(oss.schema!.id, OssTabID.GRAPH))}
/>
) : null}
<DropdownButton
text='Библиотека'
2024-05-02 19:13:54 +03:00
icon={<IconLibrary size='1rem' className='icon-primary' />}
onClick={() => router.push(urls.library)}
/>
2023-12-28 14:04:44 +03:00
</Dropdown>
</div>
{!model.isArchive && user ? (
<div ref={editMenu.ref}>
<Button
dense
noBorder
noOutline
tabIndex={-1}
2024-08-23 22:53:53 +03:00
title='Редактирование'
hideTitle={editMenu.isOpen}
className='h-full px-2'
2024-05-02 19:13:54 +03:00
icon={<IconEdit2 size='1.25rem' className={controller.isContentEditable ? 'icon-green' : 'icon-red'} />}
onClick={editMenu.toggle}
/>
<Dropdown isOpen={editMenu.isOpen}>
<DropdownButton
text='Шаблоны'
title='Создать конституенту из шаблона'
2024-05-02 19:13:54 +03:00
icon={<IconTemplates size='1rem' className='icon-green' />}
2024-03-28 18:44:34 +03:00
disabled={!controller.isContentEditable || controller.isProcessing}
onClick={handleTemplates}
/>
<DropdownButton
2024-03-25 13:13:54 +03:00
text='Встраивание'
2024-06-07 13:42:50 +03:00
titleHtml='Импортировать совокупность <br/>конституент из другой схемы'
2024-05-02 19:13:54 +03:00
icon={<IconInlineSynthesis size='1rem' className='icon-green' />}
2024-03-28 18:44:34 +03:00
disabled={!controller.isContentEditable || controller.isProcessing}
onClick={handleInlineSynthesis}
/>
2024-09-12 11:17:01 +03:00
<Divider margins='mx-3 my-1' />
2024-09-12 11:17:01 +03:00
<DropdownButton
2024-04-24 10:27:17 +03:00
text='Упорядочить список'
2024-06-07 13:42:50 +03:00
titleHtml='Упорядочить список, исходя из <br/>логики типов и связей конституент'
2024-05-02 17:04:18 +03:00
icon={<IconSortList size='1rem' className='icon-primary' />}
2024-04-24 10:27:17 +03:00
disabled={!controller.isContentEditable || controller.isProcessing}
onClick={handleRestoreOrder}
/>
<DropdownButton
2024-03-25 13:13:54 +03:00
text='Порядковые имена'
2024-06-07 13:42:50 +03:00
titleHtml='Присвоить порядковые имена <br/>и обновить выражения'
2024-05-02 19:13:54 +03:00
icon={<IconGenerateNames size='1rem' className='icon-primary' />}
2024-03-28 18:44:34 +03:00
disabled={!controller.isContentEditable || controller.isProcessing}
onClick={handleReindex}
/>
2024-03-15 12:34:41 +03:00
<DropdownButton
text='Порождение структуры'
2024-06-07 13:42:50 +03:00
titleHtml='Раскрыть структуру типизации <br/>выделенной конституенты'
2024-05-02 19:13:54 +03:00
icon={<IconGenerateStructure size='1rem' className='icon-primary' />}
2024-08-30 20:18:21 +03:00
disabled={!controller.isContentEditable || !controller.canProduceStructure || controller.isProcessing}
2024-03-15 12:34:41 +03:00
onClick={handleProduceStructure}
/>
<DropdownButton
text='Отождествление'
2024-06-07 13:42:50 +03:00
titleHtml='Заменить вхождения <br/>одной конституенты на другую'
icon={<IconReplace size='1rem' className='icon-red' />}
onClick={handleSubstituteCst}
2024-03-28 18:44:34 +03:00
disabled={!controller.isContentEditable || controller.isProcessing}
/>
</Dropdown>
</div>
) : null}
{model.isArchive && user ? (
2023-12-28 14:04:44 +03:00
<Button
dense
noBorder
noOutline
2023-12-28 14:04:44 +03:00
tabIndex={-1}
titleHtml='<b>Архив</b>: Редактирование запрещено<br />Перейти к актуальной версии'
hideTitle={accessMenu.isOpen}
2024-04-06 22:36:37 +03:00
className='h-full px-2'
2024-05-02 19:13:54 +03:00
icon={<IconArchive size='1.25rem' className='icon-primary' />}
onClick={event => controller.viewVersion(undefined, event.ctrlKey || event.metaKey)}
2023-12-16 19:20:26 +03:00
/>
) : null}
2023-12-28 14:04:44 +03:00
{user ? (
<div ref={accessMenu.ref}>
<Button
dense
noBorder
noOutline
tabIndex={-1}
2025-01-15 23:03:35 +03:00
title={`Режим ${labelAccessMode(role)}`}
hideTitle={accessMenu.isOpen}
className='h-full pr-2'
icon={
2025-01-15 23:03:35 +03:00
role === UserRole.ADMIN ? (
<IconAdmin size='1.25rem' className='icon-primary' />
2025-01-15 23:03:35 +03:00
) : role === UserRole.OWNER ? (
<IconOwner size='1.25rem' className='icon-primary' />
2025-01-15 23:03:35 +03:00
) : role === UserRole.EDITOR ? (
2024-05-27 20:42:34 +03:00
<IconEditor size='1.25rem' className='icon-primary' />
) : (
<IconReader size='1.25rem' className='icon-primary' />
)
}
onClick={accessMenu.toggle}
/>
<Dropdown isOpen={accessMenu.isOpen}>
<DropdownButton
2025-01-15 23:03:35 +03:00
text={labelAccessMode(UserRole.READER)}
title={describeAccessMode(UserRole.READER)}
icon={<IconReader size='1rem' className='icon-primary' />}
2025-01-15 23:03:35 +03:00
onClick={() => handleChangeMode(UserRole.READER)}
2024-05-27 20:42:34 +03:00
/>
<DropdownButton
2025-01-15 23:03:35 +03:00
text={labelAccessMode(UserRole.EDITOR)}
title={describeAccessMode(UserRole.EDITOR)}
2024-05-27 20:42:34 +03:00
icon={<IconEditor size='1rem' className='icon-primary' />}
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
2025-01-15 23:03:35 +03:00
onClick={() => handleChangeMode(UserRole.EDITOR)}
/>
<DropdownButton
2025-01-15 23:03:35 +03:00
text={labelAccessMode(UserRole.OWNER)}
title={describeAccessMode(UserRole.OWNER)}
icon={<IconOwner size='1rem' className='icon-primary' />}
2024-03-28 18:44:34 +03:00
disabled={!model.isOwned}
2025-01-15 23:03:35 +03:00
onClick={() => handleChangeMode(UserRole.OWNER)}
/>
<DropdownButton
2025-01-15 23:03:35 +03:00
text={labelAccessMode(UserRole.ADMIN)}
title={describeAccessMode(UserRole.ADMIN)}
icon={<IconAdmin size='1rem' className='icon-primary' />}
2024-03-28 18:44:34 +03:00
disabled={!user?.is_staff}
2025-01-15 23:03:35 +03:00
onClick={() => handleChangeMode(UserRole.ADMIN)}
/>
</Dropdown>
</div>
) : null}
{!user ? (
2023-12-28 14:04:44 +03:00
<Button
dense
noBorder
noOutline
2023-12-28 14:04:44 +03:00
tabIndex={-1}
titleHtml='<b>Анонимный режим</b><br />Войти в Портал'
hideTitle={accessMenu.isOpen}
2023-12-28 14:04:44 +03:00
className='h-full pr-2'
2024-05-02 19:13:54 +03:00
icon={<IconAlert size='1.25rem' className='icon-red' />}
onClick={handleLogin}
2023-12-16 19:20:26 +03:00
/>
) : null}
2023-07-20 17:11:03 +03:00
</div>
2023-12-28 14:04:44 +03:00
);
2023-07-20 17:11:03 +03:00
}
export default MenuRSTabs;