mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 21:10:38 +03:00
Improve consituenta editor UI
Started implementing TemplateExpressions
This commit is contained in:
parent
72039727ff
commit
848617496e
31
rsconcept/frontend/src/components/Common/SwitchButton.tsx
Normal file
31
rsconcept/frontend/src/components/Common/SwitchButton.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
interface SwitchButtonProps<ValueType> {
|
||||||
|
id?: string
|
||||||
|
value: ValueType
|
||||||
|
label?: string
|
||||||
|
icon?: React.ReactNode
|
||||||
|
tooltip?: string
|
||||||
|
dimensions?: string
|
||||||
|
|
||||||
|
isSelected?: boolean
|
||||||
|
onSelect: (value: ValueType) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function SwitchButton<ValueType>({
|
||||||
|
value, icon, label, tooltip,
|
||||||
|
dimensions='w-fit h-fit',
|
||||||
|
isSelected, onSelect, ...props
|
||||||
|
}: SwitchButtonProps<ValueType>) {
|
||||||
|
return (
|
||||||
|
<button type='button' tabIndex={-1}
|
||||||
|
title={tooltip}
|
||||||
|
onClick={() => onSelect(value)}
|
||||||
|
className={`px-2 py-1 border font-semibold small-caps rounded-none cursor-pointer clr-btn-clear clr-hover ${dimensions} ${isSelected ? 'clr-selected': ''}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{icon && icon}
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SwitchButton;
|
10
rsconcept/frontend/src/components/Help/HelpRSTemplates.tsx
Normal file
10
rsconcept/frontend/src/components/Help/HelpRSTemplates.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
function HelpRSTemplates() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Банк выражений</h1>
|
||||||
|
<p>Реализовано создание конституент из параметризованных выражений.</p>
|
||||||
|
<p>Функционал фильтрации и выбор шаблонов выражений находится в активной разработке.</p>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HelpRSTemplates;
|
|
@ -81,7 +81,7 @@ export function NotSubscribedIcon(props: IconProps) {
|
||||||
export function ASTNetworkIcon(props: IconProps) {
|
export function ASTNetworkIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 24 24' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
<path d='M21 6c0-1.654-1.346-3-3-3a2.993 2.993 0 00-2.815 2h-6.37A2.993 2.993 0 006 3C4.346 3 3 4.346 3 6c0 1.302.839 2.401 2 2.815v6.369A2.997 2.997 0 003 18c0 1.654 1.346 3 3 3a2.993 2.993 0 002.815-2h6.369a2.994 2.994 0 002.815 2c1.654 0 3-1.346 3-3a2.997 2.997 0 00-2-2.816V8.816A2.996 2.996 0 0021 6zm-3-1a1.001 1.001 0 11-1 1c0-.551.448-1 1-1zm-2.815 12h-6.37A2.99 2.99 0 007 15.184V8.816A2.99 2.99 0 008.815 7h6.369A2.99 2.99 0 0017 8.815v6.369A2.99 2.99 0 0015.185 17zM6 5a1.001 1.001 0 11-1 1c0-.551.448-1 1-1zm0 14a1.001 1.001 0 010-2 1.001 1.001 0 010 2zm12 0a1.001 1.001 0 010-2 1.001 1.001 0 010 2z'/>
|
<path d='M12 1a2.5 2.5 0 00-2.5 2.5A2.5 2.5 0 0011 5.79V7H7a2 2 0 00-2 2v.71A2.5 2.5 0 003.5 12 2.5 2.5 0 005 14.29V15H4a2 2 0 00-2 2v1.21A2.5 2.5 0 00.5 20.5 2.5 2.5 0 003 23a2.5 2.5 0 002.5-2.5A2.5 2.5 0 004 18.21V17h4v1.21a2.5 2.5 0 00-1.5 2.29A2.5 2.5 0 009 23a2.5 2.5 0 002.5-2.5 2.5 2.5 0 00-1.5-2.29V17a2 2 0 00-2-2H7v-.71A2.5 2.5 0 008.5 12 2.5 2.5 0 007 9.71V9h10v.71A2.5 2.5 0 0015.5 12a2.5 2.5 0 001.5 2.29V15h-1a2 2 0 00-2 2v1.21a2.5 2.5 0 00-1.5 2.29A2.5 2.5 0 0015 23a2.5 2.5 0 002.5-2.5 2.5 2.5 0 00-1.5-2.29V17h4v1.21a2.5 2.5 0 00-1.5 2.29A2.5 2.5 0 0021 23a2.5 2.5 0 002.5-2.5 2.5 2.5 0 00-1.5-2.29V17a2 2 0 00-2-2h-1v-.71A2.5 2.5 0 0020.5 12 2.5 2.5 0 0019 9.71V9a2 2 0 00-2-2h-4V5.79a2.5 2.5 0 001.5-2.29A2.5 2.5 0 0012 1m0 1.5a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1M6 11a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m12 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1M3 19.5a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m6 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m6 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m6 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1z'/>
|
||||||
</IconSVG>
|
</IconSVG>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -225,6 +225,15 @@ export function SmallPlusIcon(props: IconProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ArrowDropdownIcon(props: IconProps) {
|
||||||
|
return (
|
||||||
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
|
<path d='M12 1.993C6.486 1.994 2 6.48 2 11.994c0 5.513 4.486 9.999 10 10 5.514 0 10-4.486 10-10s-4.485-10-10-10.001zm0 18.001c-4.411-.001-8-3.59-8-8 0-4.411 3.589-8 8-8.001 4.411.001 8 3.59 8 8.001s-3.589 8-8 8z' />
|
||||||
|
<path d='M13 8h-2v4H7.991l4.005 4.005L16 12h-3z' />
|
||||||
|
</IconSVG>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function UploadIcon(props: IconProps) {
|
export function UploadIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 24 24' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
|
@ -253,16 +262,16 @@ export function OwnerIcon(props: IconProps) {
|
||||||
|
|
||||||
export function ArrowUpIcon(props: IconProps) {
|
export function ArrowUpIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 16 16' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
<path d='M8 12a.5.5 0 00.5-.5V5.707l2.146 2.147a.5.5 0 00.708-.708l-3-3a.5.5 0 00-.708 0l-3 3a.5.5 0 10.708.708L7.5 5.707V11.5a.5.5 0 00.5.5z' />
|
<path d='M12.781 2.375c-.381-.475-1.181-.475-1.562 0l-8 10A1.001 1.001 0 004 14h4v7a1 1 0 001 1h6a1 1 0 001-1v-7h4a1.001 1.001 0 00.781-1.625l-8-10zM15 12h-1v8h-4v-8H6.081L12 4.601 17.919 12H15z' />
|
||||||
</IconSVG>
|
</IconSVG>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ArrowDownIcon(props: IconProps) {
|
export function ArrowDownIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 16 16' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
<path d='M8 4a.5.5 0 01.5.5v5.793l2.146-2.147a.5.5 0 01.708.708l-3 3a.5.5 0 01-.708 0l-3-3a.5.5 0 11.708-.708L7.5 10.293V4.5A.5.5 0 018 4z' />
|
<path d='M20.901 10.566A1.001 1.001 0 0020 10h-4V3a1 1 0 00-1-1H9a1 1 0 00-1 1v7H4a1.001 1.001 0 00-.781 1.625l8 10a1 1 0 001.562 0l8-10c.24-.301.286-.712.12-1.059zM12 19.399L6.081 12H10V4h4v8h3.919L12 19.399z' />
|
||||||
</IconSVG>
|
</IconSVG>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -293,6 +302,14 @@ export function CloneIcon(props: IconProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DiamondIcon(props: IconProps) {
|
||||||
|
return (
|
||||||
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
|
<path d='M17.813 3.838A2 2 0 0016.187 3H7.813c-.644 0-1.252.313-1.667.899l-4 6.581a.999.999 0 00.111 1.188l9 10a.995.995 0 001.486.001l9-10a.997.997 0 00.111-1.188l-4.041-6.643zM12 19.505L5.245 12h13.509L12 19.505zM4.777 10l3.036-5 8.332-.062L19.222 10H4.777z' />
|
||||||
|
</IconSVG>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function DumpBinIcon(props: IconProps) {
|
export function DumpBinIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 24 24' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
|
@ -335,10 +352,11 @@ export function GithubIcon(props: IconProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MeshIcon(props: IconProps) {
|
export function UpdateIcon(props: IconProps) {
|
||||||
return (
|
return (
|
||||||
<IconSVG viewbox='0 0 1024 1024' {...props}>
|
<IconSVG viewbox='0 0 24 24' {...props}>
|
||||||
<path d='M872 394c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8H708V152c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v166H400V152c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v166H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h168v236H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h168v166c0 4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V706h228v166c0 4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V706h164c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8H708V394h164zM628 630H400V394h228v236z' />
|
<path d='M2 12h2a7.986 7.986 0 012.337-5.663 7.91 7.91 0 012.542-1.71 8.12 8.12 0 016.13-.041A2.488 2.488 0 0017.5 7C18.886 7 20 5.886 20 4.5S18.886 2 17.5 2c-.689 0-1.312.276-1.763.725-2.431-.973-5.223-.958-7.635.059a9.928 9.928 0 00-3.18 2.139 9.92 9.92 0 00-2.14 3.179A10.005 10.005 0 002 12zm17.373 3.122c-.401.952-.977 1.808-1.71 2.541s-1.589 1.309-2.542 1.71a8.12 8.12 0 01-6.13.041A2.488 2.488 0 006.5 17C5.114 17 4 18.114 4 19.5S5.114 22 6.5 22c.689 0 1.312-.276 1.763-.725A9.965 9.965 0 0012 22a9.983 9.983 0 009.217-6.102A9.992 9.992 0 0022 12h-2a7.993 7.993 0 01-.627 3.122z' />
|
||||||
|
<path d='M12 7.462c-2.502 0-4.538 2.036-4.538 4.538S9.498 16.538 12 16.538s4.538-2.036 4.538-4.538S14.502 7.462 12 7.462zm0 7.076c-1.399 0-2.538-1.139-2.538-2.538S10.601 9.462 12 9.462s2.538 1.139 2.538 2.538-1.139 2.538-2.538 2.538z' />
|
||||||
</IconSVG>
|
</IconSVG>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@ import { createColumnHelper } from '@tanstack/react-table';
|
||||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { getCompatibleGrams, Grammeme, parseEntityReference,parseGrammemes,parseSyntacticReference,ReferenceType } from '../../models/language';
|
import {
|
||||||
|
getCompatibleGrams, Grammeme,
|
||||||
|
parseEntityReference, parseGrammemes,
|
||||||
|
parseSyntacticReference, ReferenceType
|
||||||
|
} from '../../models/language';
|
||||||
import { CstMatchMode } from '../../models/miscelanious';
|
import { CstMatchMode } from '../../models/miscelanious';
|
||||||
import { IConstituenta, matchConstituenta } from '../../models/rsform';
|
import { IConstituenta, matchConstituenta } from '../../models/rsform';
|
||||||
import ConstituentaTooltip from '../../pages/RSFormPage/elements/ConstituentaTooltip';
|
import ConstituentaTooltip from '../../pages/RSFormPage/elements/ConstituentaTooltip';
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import { ReferenceType } from '../../models/language';
|
import { ReferenceType } from '../../models/language';
|
||||||
import { labelReferenceType } from '../../utils/labels';
|
import { labelReferenceType } from '../../utils/labels';
|
||||||
|
import SwitchButton from '../Common/SwitchButton';
|
||||||
|
|
||||||
interface ReferenceTypeButtonProps {
|
interface ReferenceTypeButtonProps {
|
||||||
id?: string
|
|
||||||
type: ReferenceType
|
type: ReferenceType
|
||||||
isSelected?: boolean
|
isSelected?: boolean
|
||||||
onSelect: (type: ReferenceType) => void
|
onSelect: (type: ReferenceType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReferenceTypeButton({ type, isSelected, onSelect, ...props }: ReferenceTypeButtonProps) {
|
function ReferenceTypeButton({ type, isSelected, onSelect }: ReferenceTypeButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button type='button' tabIndex={-1}
|
<SwitchButton
|
||||||
onClick={() => onSelect(type)}
|
value={type}
|
||||||
className={`min-w-[12rem] px-2 py-1 border font-semibold small-caps rounded-none cursor-pointer clr-btn-clear clr-hover ${isSelected ? 'clr-selected': ''}`}
|
isSelected={isSelected}
|
||||||
{...props}
|
onSelect={onSelect}
|
||||||
>
|
dimensions='min-w-[12rem] h-fit'
|
||||||
{labelReferenceType(type)}
|
label={labelReferenceType(type)}
|
||||||
</button>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
--cl-red-bg-100: hsl(000, 100%, 095%);
|
--cl-red-bg-100: hsl(000, 100%, 095%);
|
||||||
--cl-red-fg-100: hsl(000, 072%, 051%);
|
--cl-red-fg-100: hsl(000, 072%, 051%);
|
||||||
--cl-green-fg-100: hsl(120, 080%, 058%);
|
--cl-green-fg-100: hsl(120, 080%, 37%);
|
||||||
|
|
||||||
/* Dark Theme */
|
/* Dark Theme */
|
||||||
--cd-bg-120: hsl(000, 000%, 005%);
|
--cd-bg-120: hsl(000, 000%, 005%);
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
--cd-red-bg-100: hsl(000, 100%, 015%);
|
--cd-red-bg-100: hsl(000, 100%, 015%);
|
||||||
--cd-red-fg-100: hsl(000, 080%, 055%);
|
--cd-red-fg-100: hsl(000, 080%, 055%);
|
||||||
--cd-green-fg-100: hsl(120, 080%, 040%);
|
--cd-green-fg-100: hsl(120, 080%, 042%);
|
||||||
|
|
||||||
/* Import overrides */
|
/* Import overrides */
|
||||||
--toastify-color-dark: var(--cd-bg-60);
|
--toastify-color-dark: var(--cd-bg-60);
|
||||||
|
|
|
@ -20,6 +20,7 @@ export enum HelpTopic {
|
||||||
CSTLIST = 'cstlist',
|
CSTLIST = 'cstlist',
|
||||||
CONSTITUENTA = 'constituenta',
|
CONSTITUENTA = 'constituenta',
|
||||||
GRAPH_TERM = 'graph-term',
|
GRAPH_TERM = 'graph-term',
|
||||||
|
RSTEMPLATES = 'rstemplates',
|
||||||
RSLANG = 'rslang',
|
RSLANG = 'rslang',
|
||||||
TERM_CONTROL = 'terminology-control',
|
TERM_CONTROL = 'terminology-control',
|
||||||
EXTEOR = 'exteor',
|
EXTEOR = 'exteor',
|
||||||
|
|
|
@ -73,7 +73,11 @@ export interface IConstituentaList {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICstCreateData
|
export interface ICstCreateData
|
||||||
extends Pick<IConstituentaMeta, 'alias' | 'cst_type' | 'definition_raw' | 'term_raw' | 'convention' | 'definition_formal' > {
|
extends Pick<
|
||||||
|
IConstituentaMeta,
|
||||||
|
'alias' | 'cst_type' | 'definition_raw' | 'term_raw' |
|
||||||
|
'convention' | 'definition_formal' | 'term_forms'
|
||||||
|
> {
|
||||||
insert_after: number | null
|
insert_after: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import HelpMain from '../../components/Help/HelpMain';
|
||||||
import HelpRSFormItems from '../../components/Help/HelpRSFormItems';
|
import HelpRSFormItems from '../../components/Help/HelpRSFormItems';
|
||||||
import HelpRSFormMeta from '../../components/Help/HelpRSFormMeta';
|
import HelpRSFormMeta from '../../components/Help/HelpRSFormMeta';
|
||||||
import HelpRSLang from '../../components/Help/HelpRSLang';
|
import HelpRSLang from '../../components/Help/HelpRSLang';
|
||||||
|
import HelpRSTemplates from '../../components/Help/HelpRSTemplates';
|
||||||
import HelpTermGraph from '../../components/Help/HelpTermGraph';
|
import HelpTermGraph from '../../components/Help/HelpTermGraph';
|
||||||
import HelpTerminologyControl from '../../components/Help/HelpTerminologyControl';
|
import HelpTerminologyControl from '../../components/Help/HelpTerminologyControl';
|
||||||
import { HelpTopic } from '../../models/miscelanious';
|
import { HelpTopic } from '../../models/miscelanious';
|
||||||
|
@ -23,6 +24,7 @@ function ViewTopic({ topic }: ViewTopicProps) {
|
||||||
{topic === HelpTopic.CSTLIST && <HelpRSFormItems />}
|
{topic === HelpTopic.CSTLIST && <HelpRSFormItems />}
|
||||||
{topic === HelpTopic.CONSTITUENTA && <HelpConstituenta />}
|
{topic === HelpTopic.CONSTITUENTA && <HelpConstituenta />}
|
||||||
{topic === HelpTopic.GRAPH_TERM && <HelpTermGraph />}
|
{topic === HelpTopic.GRAPH_TERM && <HelpTermGraph />}
|
||||||
|
{topic === HelpTopic.RSTEMPLATES && <HelpRSTemplates />}
|
||||||
{topic === HelpTopic.RSLANG && <HelpRSLang />}
|
{topic === HelpTopic.RSLANG && <HelpRSLang />}
|
||||||
{topic === HelpTopic.TERM_CONTROL && <HelpTerminologyControl />}
|
{topic === HelpTopic.TERM_CONTROL && <HelpTerminologyControl />}
|
||||||
{topic === HelpTopic.EXTEOR && <HelpExteor />}
|
{topic === HelpTopic.EXTEOR && <HelpExteor />}
|
||||||
|
|
|
@ -35,7 +35,8 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
||||||
convention: convention,
|
convention: convention,
|
||||||
definition_formal: expression,
|
definition_formal: expression,
|
||||||
definition_raw: textDefinition,
|
definition_raw: textDefinition,
|
||||||
term_raw: term
|
term_raw: term,
|
||||||
|
term_forms: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
178
rsconcept/frontend/src/pages/RSFormPage/DlgTemplates.tsx
Normal file
178
rsconcept/frontend/src/pages/RSFormPage/DlgTemplates.tsx
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
||||||
|
import Modal, { ModalProps } from '../../components/Common/Modal';
|
||||||
|
import SelectSingle from '../../components/Common/SelectSingle';
|
||||||
|
import SwitchButton from '../../components/Common/SwitchButton';
|
||||||
|
import TextArea from '../../components/Common/TextArea';
|
||||||
|
import TextInput from '../../components/Common/TextInput';
|
||||||
|
import HelpRSTemplates from '../../components/Help/HelpRSTemplates';
|
||||||
|
import { HelpIcon } from '../../components/Icons';
|
||||||
|
import RSInput from '../../components/RSInput';
|
||||||
|
import { CstType,ICstCreateData, IRSForm } from '../../models/rsform';
|
||||||
|
import { labelCstType } from '../../utils/labels';
|
||||||
|
import { createAliasFor, getCstTypePrefix } from '../../utils/misc';
|
||||||
|
import { SelectorCstType } from '../../utils/selectors';
|
||||||
|
|
||||||
|
interface DlgTemplatesProps
|
||||||
|
extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
schema: IRSForm
|
||||||
|
onCreate: (data: ICstCreateData) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function DlgTemplates({ hideWindow, schema, onCreate }: DlgTemplatesProps) {
|
||||||
|
const [validated, setValidated] = useState(false);
|
||||||
|
const [selectedType, setSelectedType] = useState<CstType>(CstType.TERM);
|
||||||
|
const [alias, setAlias] = useState('');
|
||||||
|
|
||||||
|
const [term, setTerm] = useState('');
|
||||||
|
const [textDefinition, setTextDefinition] = useState('');
|
||||||
|
const [expression, setExpression] = useState('');
|
||||||
|
const [convention, setConvention] = useState('');
|
||||||
|
|
||||||
|
const [ showAttributes, setShowAttributes ] = useState(false);
|
||||||
|
|
||||||
|
function getData(): ICstCreateData {
|
||||||
|
return {
|
||||||
|
cst_type: selectedType,
|
||||||
|
insert_after: null,
|
||||||
|
alias: alias,
|
||||||
|
convention: convention,
|
||||||
|
definition_formal: expression,
|
||||||
|
definition_raw: textDefinition,
|
||||||
|
term_raw: term,
|
||||||
|
term_forms: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = () => onCreate(getData());
|
||||||
|
|
||||||
|
useLayoutEffect(
|
||||||
|
() => {
|
||||||
|
setAlias(createAliasFor(selectedType, schema));
|
||||||
|
}, [selectedType, schema]);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
if(alias.length < 2 || alias[0] !== getCstTypePrefix(selectedType)) {
|
||||||
|
setValidated(false);
|
||||||
|
} else {
|
||||||
|
setValidated(!schema.items.find(cst => cst.alias === alias))
|
||||||
|
}
|
||||||
|
}, [alias, selectedType, schema]);
|
||||||
|
|
||||||
|
{/* <SwitchButton
|
||||||
|
value={type}
|
||||||
|
isSelected={isSelected}
|
||||||
|
onSelect={onSelect}
|
||||||
|
dimensions='min-w-[12rem] h-fit'
|
||||||
|
label={labelReferenceType(type)}
|
||||||
|
/> */}
|
||||||
|
// <div className='flex items-center self-center flex-start'>
|
||||||
|
// <ReferenceTypeButton
|
||||||
|
// type={ReferenceType.ENTITY}
|
||||||
|
// onSelect={setType}
|
||||||
|
// isSelected={type === ReferenceType.ENTITY}
|
||||||
|
// />
|
||||||
|
// <ReferenceTypeButton
|
||||||
|
// type={ReferenceType.SYNTACTIC}
|
||||||
|
// onSelect={setType}
|
||||||
|
// isSelected={type === ReferenceType.SYNTACTIC}
|
||||||
|
// />
|
||||||
|
|
||||||
|
// </div>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title='Создание конституенты из шаблона'
|
||||||
|
hideWindow={hideWindow}
|
||||||
|
canSubmit={validated}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
submitText='Создать'
|
||||||
|
>
|
||||||
|
<div className='h-fit max-w-[40rem] min-w-[40rem] min-h-[35rem] px-2 mb-2 flex flex-col justify-stretch gap-3'>
|
||||||
|
<div className='flex items-center self-center flex-start'>
|
||||||
|
<SwitchButton
|
||||||
|
label='Шаблон'
|
||||||
|
tooltip='Выбор шаблона выражения'
|
||||||
|
dimensions='min-w-[10rem] h-fit'
|
||||||
|
value={false}
|
||||||
|
isSelected={!showAttributes}
|
||||||
|
onSelect={(value) => setShowAttributes(value)}
|
||||||
|
/>
|
||||||
|
<SwitchButton
|
||||||
|
label='Конституента'
|
||||||
|
tooltip='Редактирование атрибутов конституенты'
|
||||||
|
dimensions='min-w-[10rem] h-fit'
|
||||||
|
value={true}
|
||||||
|
isSelected={showAttributes}
|
||||||
|
onSelect={(value) => setShowAttributes(value)}
|
||||||
|
/>
|
||||||
|
<div id='templates-help' className='px-1 py-1'>
|
||||||
|
<HelpIcon color='text-primary' size={5} />
|
||||||
|
</div>
|
||||||
|
<ConceptTooltip
|
||||||
|
anchorSelect='#templates-help'
|
||||||
|
className='max-w-[30rem] z-modal-tooltip'
|
||||||
|
offset={4}
|
||||||
|
>
|
||||||
|
<HelpRSTemplates />
|
||||||
|
</ConceptTooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ !showAttributes &&
|
||||||
|
<div>
|
||||||
|
Выбор шаблона и параметров
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
{ showAttributes &&
|
||||||
|
<div>
|
||||||
|
<div className='flex justify-center w-full gap-6'>
|
||||||
|
<SelectSingle
|
||||||
|
className='my-2 min-w-[15rem] self-center'
|
||||||
|
options={SelectorCstType}
|
||||||
|
placeholder='Выберите тип'
|
||||||
|
value={selectedType ? { value: selectedType, label: labelCstType(selectedType) } : null}
|
||||||
|
onChange={data => setSelectedType(data?.value ?? CstType.BASE)}
|
||||||
|
/>
|
||||||
|
<TextInput id='alias' label='Имя'
|
||||||
|
dense
|
||||||
|
dimensions='w-[7rem]'
|
||||||
|
value={alias}
|
||||||
|
onChange={event => setAlias(event.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<TextArea id='term' label='Термин'
|
||||||
|
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
||||||
|
rows={2}
|
||||||
|
value={term}
|
||||||
|
spellCheck
|
||||||
|
onChange={event => setTerm(event.target.value)}
|
||||||
|
/>
|
||||||
|
<RSInput id='expression' label='Формальное выражение'
|
||||||
|
placeholder='Родоструктурное выражение, задающее формальное определение'
|
||||||
|
editable
|
||||||
|
height='4.8rem'
|
||||||
|
value={expression}
|
||||||
|
onChange={value => setExpression(value)}
|
||||||
|
/>
|
||||||
|
<TextArea id='definition' label='Текстовое определение'
|
||||||
|
placeholder='Лингвистическая интерпретация формального выражения'
|
||||||
|
rows={2}
|
||||||
|
value={textDefinition}
|
||||||
|
spellCheck
|
||||||
|
onChange={event => setTextDefinition(event.target.value)}
|
||||||
|
/>
|
||||||
|
<TextArea id='convention' label='Конвенция / Комментарий'
|
||||||
|
placeholder='Договоренность об интерпретации неопределяемого понятия
Комментарий к производному понятию'
|
||||||
|
rows={2}
|
||||||
|
value={convention}
|
||||||
|
spellCheck
|
||||||
|
onChange={event => setConvention(event.target.value)}
|
||||||
|
/>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
</Modal>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DlgTemplates;
|
|
@ -116,6 +116,7 @@ function EditorConstituenta({
|
||||||
definition_formal: '',
|
definition_formal: '',
|
||||||
definition_raw: '',
|
definition_raw: '',
|
||||||
convention: '',
|
convention: '',
|
||||||
|
term_forms: []
|
||||||
};
|
};
|
||||||
onCreateCst(data);
|
onCreateCst(data);
|
||||||
}
|
}
|
||||||
|
@ -132,6 +133,7 @@ function EditorConstituenta({
|
||||||
definition_formal: activeCst.definition_formal,
|
definition_formal: activeCst.definition_formal,
|
||||||
definition_raw: activeCst.definition_raw,
|
definition_raw: activeCst.definition_raw,
|
||||||
convention: activeCst.convention,
|
convention: activeCst.convention,
|
||||||
|
term_forms: activeCst.term_forms
|
||||||
};
|
};
|
||||||
onCreateCst(data, true);
|
onCreateCst(data, true);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +211,7 @@ function EditorConstituenta({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col gap-2 mt-1'>
|
<div className='flex flex-col gap-3 mt-1'>
|
||||||
<RefsInput id='term' label='Термин'
|
<RefsInput id='term' label='Термин'
|
||||||
placeholder='Обозначение, используемое в текстовых определениях данной схемы'
|
placeholder='Обозначение, используемое в текстовых определениях данной схемы'
|
||||||
height='2.1rem'
|
height='2.1rem'
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import Button from '../../components/Common/Button';
|
|
||||||
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
||||||
import DataTable, { createColumnHelper, type RowSelectionState,VisibilityState } from '../../components/DataTable';
|
import DataTable, { createColumnHelper, type RowSelectionState,VisibilityState } from '../../components/DataTable';
|
||||||
import HelpRSFormItems from '../../components/Help/HelpRSFormItems';
|
|
||||||
import { ArrowDownIcon, ArrowUpIcon, DumpBinIcon, HelpIcon, MeshIcon, SmallPlusIcon } from '../../components/Icons';
|
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import useWindowSize from '../../hooks/useWindowSize';
|
import useWindowSize from '../../hooks/useWindowSize';
|
||||||
|
@ -13,29 +10,27 @@ import { CstType, IConstituenta, ICstCreateData, ICstMovetoData } from '../../mo
|
||||||
import { colorfgCstStatus } from '../../utils/color';
|
import { colorfgCstStatus } from '../../utils/color';
|
||||||
import { prefixes } from '../../utils/constants';
|
import { prefixes } from '../../utils/constants';
|
||||||
import { describeExpressionStatus, labelCstTypification } from '../../utils/labels';
|
import { describeExpressionStatus, labelCstTypification } from '../../utils/labels';
|
||||||
import { getCstTypePrefix, getCstTypeShortcut } from '../../utils/misc';
|
import RSItemsMenu from './elements/RSItemsMenu';
|
||||||
|
|
||||||
// Window width cutoff for columns
|
// Window width cutoff for columns
|
||||||
const COLUMN_DEFINITION_HIDE_THRESHOLD = 1000;
|
const COLUMN_DEFINITION_HIDE_THRESHOLD = 1000;
|
||||||
const COLUMN_TYPE_HIDE_THRESHOLD = 1200;
|
const COLUMN_TYPE_HIDE_THRESHOLD = 1200;
|
||||||
const COLUMN_CONVENTION_HIDE_THRESHOLD = 1800;
|
const COLUMN_CONVENTION_HIDE_THRESHOLD = 1800;
|
||||||
|
|
||||||
const EDITOR_BUTTON_DIMENSIONS = 'h-[1.5rem] w-[1.8em]';
|
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<IConstituenta>();
|
const columnHelper = createColumnHelper<IConstituenta>();
|
||||||
|
|
||||||
interface EditorItemsProps {
|
interface EditorItemsProps {
|
||||||
onOpenEdit: (cstID: number) => void
|
onOpenEdit: (cstID: number) => void
|
||||||
|
onTemplates: (selected: number[]) => void
|
||||||
onCreateCst: (initial: ICstCreateData, skipDialog?: boolean) => void
|
onCreateCst: (initial: ICstCreateData, skipDialog?: boolean) => void
|
||||||
onDeleteCst: (selected: number[], callback: (items: number[]) => void) => void
|
onDeleteCst: (selected: number[], callback: (items: number[]) => void) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps) {
|
function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst, onTemplates }: EditorItemsProps) {
|
||||||
const { colors, mainHeight } = useConceptTheme();
|
const { colors, mainHeight } = useConceptTheme();
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const { schema, isEditable, cstMoveTo, resetAliases } = useRSForm();
|
const { schema, isEditable, cstMoveTo, resetAliases } = useRSForm();
|
||||||
const [selected, setSelected] = useState<number[]>([]);
|
const [selected, setSelected] = useState<number[]>([]);
|
||||||
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
|
|
||||||
|
|
||||||
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
||||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
|
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
|
||||||
|
@ -130,10 +125,33 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
|
||||||
definition_formal: '',
|
definition_formal: '',
|
||||||
definition_raw: '',
|
definition_raw: '',
|
||||||
convention: '',
|
convention: '',
|
||||||
|
term_forms: []
|
||||||
};
|
};
|
||||||
onCreateCst(data, type !== undefined);
|
onCreateCst(data, type !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone selected
|
||||||
|
function handleClone() {
|
||||||
|
if (selected.length !== 1 || !schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const activeCst = schema.items.find(cst => cst.id === selected[0]);
|
||||||
|
if (!activeCst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data: ICstCreateData = {
|
||||||
|
insert_after: activeCst.id,
|
||||||
|
cst_type: activeCst.cst_type,
|
||||||
|
alias: '',
|
||||||
|
term_raw: activeCst.term_raw,
|
||||||
|
definition_formal: activeCst.definition_formal,
|
||||||
|
definition_raw: activeCst.definition_raw,
|
||||||
|
convention: activeCst.convention,
|
||||||
|
term_forms: activeCst.term_forms
|
||||||
|
};
|
||||||
|
onCreateCst(data, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Implement hotkeys for working with constituents table
|
// Implement hotkeys for working with constituents table
|
||||||
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
if (!isEditable) {
|
if (!isEditable) {
|
||||||
|
@ -297,73 +315,21 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
|
||||||
onKeyDown={handleTableKey}
|
onKeyDown={handleTableKey}
|
||||||
>
|
>
|
||||||
<div className='sticky top-0 flex justify-start w-full gap-1 px-2 py-1 border-b items-center h-[2.2rem] select-none clr-app'>
|
<div className='sticky top-0 flex justify-start w-full gap-1 px-2 py-1 border-b items-center h-[2.2rem] select-none clr-app'>
|
||||||
<div className='mr-3 min-w-[9rem] whitespace-nowrap'>
|
<div className='mr-3 min-w-[9rem] whitespace-nowrap small-caps'>
|
||||||
Выбор {selected.length} из {schema?.stats?.count_all ?? 0}
|
Выбор {selected.length} из {schema?.stats?.count_all ?? 0}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center justify-center w-full gap-1 pr-[9rem]'>
|
<RSItemsMenu
|
||||||
<Button
|
selected={selected}
|
||||||
tooltip='Переместить вверх'
|
onMoveUp={handleMoveUp}
|
||||||
icon={<ArrowUpIcon size={6}/>}
|
onMoveDown={handleMoveDown}
|
||||||
disabled={!isEditable || nothingSelected}
|
onClone={handleClone}
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
onCreate={handleCreateCst}
|
||||||
dense
|
onDelete={handleDelete}
|
||||||
onClick={handleMoveUp}
|
onTemplates={() => onTemplates(selected)}
|
||||||
/>
|
onReindex={handleReindex}
|
||||||
<Button
|
/>
|
||||||
tooltip='Переместить вниз'
|
|
||||||
icon={<ArrowDownIcon size={6}/>}
|
|
||||||
disabled={!isEditable || nothingSelected}
|
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
|
||||||
dense
|
|
||||||
onClick={handleMoveDown}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
tooltip='Удалить выбранные'
|
|
||||||
icon={<DumpBinIcon color={isEditable && !nothingSelected ? 'text-warning' : ''} size={5}/>}
|
|
||||||
disabled={!isEditable || nothingSelected}
|
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
|
||||||
dense
|
|
||||||
onClick={handleDelete}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
tooltip='Сбросить имена'
|
|
||||||
icon={<MeshIcon color={isEditable ? 'text-primary': ''} size={5}/>}
|
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
|
||||||
dense
|
|
||||||
disabled={!isEditable}
|
|
||||||
onClick={handleReindex}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
tooltip='Новая конституента'
|
|
||||||
icon={<SmallPlusIcon color={isEditable ? 'text-success': ''} size={5}/>}
|
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
|
||||||
dense
|
|
||||||
disabled={!isEditable}
|
|
||||||
onClick={() => handleCreateCst()}
|
|
||||||
/>
|
|
||||||
{(Object.values(CstType)).map(
|
|
||||||
(typeStr) => {
|
|
||||||
const type = typeStr as CstType;
|
|
||||||
return (
|
|
||||||
<Button key={type}
|
|
||||||
text={getCstTypePrefix(type)}
|
|
||||||
tooltip={getCstTypeShortcut(type)}
|
|
||||||
dense
|
|
||||||
dimensions={EDITOR_BUTTON_DIMENSIONS}
|
|
||||||
disabled={!isEditable}
|
|
||||||
tabIndex={-1}
|
|
||||||
onClick={() => handleCreateCst(type)}
|
|
||||||
/>);
|
|
||||||
})}
|
|
||||||
<div id='items-table-help'>
|
|
||||||
<HelpIcon color='text-primary' size={5} />
|
|
||||||
</div>
|
|
||||||
<ConceptTooltip anchorSelect='#items-table-help' offset={30}>
|
|
||||||
<HelpRSFormItems />
|
|
||||||
</ConceptTooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full h-full text-sm'>
|
<div className='w-full h-full text-sm'>
|
||||||
<DataTable
|
<DataTable
|
||||||
data={schema?.items ?? []}
|
data={schema?.items ?? []}
|
||||||
|
|
|
@ -118,7 +118,7 @@ function EditorRSExpression({
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-start w-full'>
|
<div className='flex flex-col items-start w-full'>
|
||||||
<div className='relative w-full'>
|
<div className='relative w-full'>
|
||||||
<div className='absolute top-[-0.2rem] left-[10.3rem]'>
|
<div className='absolute top-[-0.2rem] left-[10.5rem]'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Дерево разбора выражения'
|
tooltip='Дерево разбора выражения'
|
||||||
noHover
|
noHover
|
||||||
|
@ -138,13 +138,14 @@ function EditorRSExpression({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
/>
|
/>
|
||||||
<div className='w-full mt-1 max-h-[5rem] min-h-[5rem] flex gap-2'>
|
<div className='w-full max-h-[5rem] min-h-[5rem] flex'>
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col'>
|
||||||
<Button
|
<Button
|
||||||
tooltip='Проверить формальное выражение'
|
tooltip='Проверить формальное выражение'
|
||||||
text='Проверить'
|
text='Проверить'
|
||||||
dimensions='w-fit h-[3rem]'
|
dimensions='w-fit h-[3rem] z-pop'
|
||||||
colorClass='clr-btn-default'
|
colorClass='clr-btn-default'
|
||||||
|
borderClass='rounded-none border'
|
||||||
onClick={() => handleCheckExpression()}
|
onClick={() => handleCheckExpression()}
|
||||||
/>
|
/>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
|
@ -153,7 +154,7 @@ function EditorRSExpression({
|
||||||
parseData={parseData}
|
parseData={parseData}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full overflow-y-auto text-sm border'>
|
<div className='w-full overflow-y-auto text-sm border rounded-none'>
|
||||||
{ loading && <ConceptLoader size={6} />}
|
{ loading && <ConceptLoader size={6} />}
|
||||||
{ !loading && parseData &&
|
{ !loading && parseData &&
|
||||||
<ParsingResult
|
<ParsingResult
|
||||||
|
|
|
@ -278,6 +278,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
||||||
definition_formal: allSelected.map(id => schema.items.find(cst => cst.id === id)!.alias).join(' '),
|
definition_formal: allSelected.map(id => schema.items.find(cst => cst.id === id)!.alias).join(' '),
|
||||||
definition_raw: '',
|
definition_raw: '',
|
||||||
convention: '',
|
convention: '',
|
||||||
|
term_forms: []
|
||||||
};
|
};
|
||||||
onCreateCst(data);
|
onCreateCst(data);
|
||||||
}
|
}
|
||||||
|
@ -416,7 +417,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
<div className='flex items-center justify-between py-1'>
|
<div className='flex items-center justify-between py-1'>
|
||||||
<div className='mr-3 text-base'>
|
<div className='mr-3 text-base small-caps'>
|
||||||
Выбор {allSelected.length} из {schema?.stats?.count_all ?? 0}
|
Выбор {allSelected.length} из {schema?.stats?.count_all ?? 0}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import DlgDeleteCst from './DlgDeleteCst';
|
||||||
import DlgEditWordForms from './DlgEditWordForms';
|
import DlgEditWordForms from './DlgEditWordForms';
|
||||||
import DlgRenameCst from './DlgRenameCst';
|
import DlgRenameCst from './DlgRenameCst';
|
||||||
import DlgShowAST from './DlgShowAST';
|
import DlgShowAST from './DlgShowAST';
|
||||||
|
import DlgTemplates from './DlgTemplates';
|
||||||
import DlgUploadRSForm from './DlgUploadRSForm';
|
import DlgUploadRSForm from './DlgUploadRSForm';
|
||||||
import EditorConstituenta from './EditorConstituenta';
|
import EditorConstituenta from './EditorConstituenta';
|
||||||
import EditorItems from './EditorItems';
|
import EditorItems from './EditorItems';
|
||||||
|
@ -89,6 +90,8 @@ function RSTabs() {
|
||||||
|
|
||||||
const [showEditTerm, setShowEditTerm] = useState(false);
|
const [showEditTerm, setShowEditTerm] = useState(false);
|
||||||
|
|
||||||
|
const [showTemplates, setShowTemplates] = useState(false);
|
||||||
|
|
||||||
const panelHeight = useMemo(
|
const panelHeight = useMemo(
|
||||||
() => {
|
() => {
|
||||||
return !noNavigation ?
|
return !noNavigation ?
|
||||||
|
@ -261,6 +264,11 @@ function RSTabs() {
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onShowTemplates = useCallback(
|
||||||
|
() => {
|
||||||
|
setShowTemplates(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const onDownloadSchema = useCallback(
|
const onDownloadSchema = useCallback(
|
||||||
() => {
|
() => {
|
||||||
if (isModified) {
|
if (isModified) {
|
||||||
|
@ -367,6 +375,12 @@ function RSTabs() {
|
||||||
onSave={handleSaveWordforms}
|
onSave={handleSaveWordforms}
|
||||||
target={activeCst!}
|
target={activeCst!}
|
||||||
/>}
|
/>}
|
||||||
|
{showTemplates &&
|
||||||
|
<DlgTemplates
|
||||||
|
schema={schema}
|
||||||
|
hideWindow={() => setShowTemplates(false)}
|
||||||
|
onCreate={handleCreateCst}
|
||||||
|
/>}
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={onSelectTab}
|
onSelect={onSelectTab}
|
||||||
|
@ -381,6 +395,7 @@ function RSTabs() {
|
||||||
onClaim={onClaimSchema}
|
onClaim={onClaimSchema}
|
||||||
onShare={onShareSchema}
|
onShare={onShareSchema}
|
||||||
onToggleSubscribe={handleToggleSubscribe}
|
onToggleSubscribe={handleToggleSubscribe}
|
||||||
|
onTemplates={onShowTemplates}
|
||||||
showCloneDialog={promptClone}
|
showCloneDialog={promptClone}
|
||||||
showUploadDialog={() => setShowUpload(true)}
|
showUploadDialog={() => setShowUpload(true)}
|
||||||
/>
|
/>
|
||||||
|
@ -422,6 +437,7 @@ function RSTabs() {
|
||||||
onOpenEdit={onOpenCst}
|
onOpenEdit={onOpenCst}
|
||||||
onCreateCst={promptCreateCst}
|
onCreateCst={promptCreateCst}
|
||||||
onDeleteCst={promptDeleteCst}
|
onDeleteCst={promptDeleteCst}
|
||||||
|
onTemplates={() => onShowTemplates()} // TODO: implement insertion point
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,8 @@ interface RSEditorControlsProps {
|
||||||
|
|
||||||
function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center justify-between w-full mt-1 text-sm'>
|
<div className='flex items-center justify-between w-full text-sm'>
|
||||||
<div className='w-fit'>
|
<div className='border-r w-fit'>
|
||||||
<div className='flex justify-start'>
|
<div className='flex justify-start'>
|
||||||
{MAIN_FIRST_ROW.map(
|
{MAIN_FIRST_ROW.map(
|
||||||
(token) =>
|
(token) =>
|
||||||
|
@ -110,7 +110,7 @@ function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-fit'>
|
<div className='border-l w-fit'>
|
||||||
<div className='flex justify-start'>
|
<div className='flex justify-start'>
|
||||||
{SECONDARY_FIRST_ROW.map(
|
{SECONDARY_FIRST_ROW.map(
|
||||||
({text, tooltip}) =>
|
({text, tooltip}) =>
|
||||||
|
|
114
rsconcept/frontend/src/pages/RSFormPage/elements/RSItemsMenu.tsx
Normal file
114
rsconcept/frontend/src/pages/RSFormPage/elements/RSItemsMenu.tsx
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
import ConceptTooltip from '../../../components/Common/ConceptTooltip';
|
||||||
|
import Dropdown from '../../../components/Common/Dropdown';
|
||||||
|
import DropdownButton from '../../../components/Common/DropdownButton';
|
||||||
|
import MiniButton from '../../../components/Common/MiniButton';
|
||||||
|
import HelpRSFormItems from '../../../components/Help/HelpRSFormItems';
|
||||||
|
import { ArrowDownIcon, ArrowDropdownIcon, ArrowUpIcon, CloneIcon, DiamondIcon, DumpBinIcon, HelpIcon, SmallPlusIcon,UpdateIcon } from '../../../components/Icons';
|
||||||
|
import { useRSForm } from '../../../context/RSFormContext';
|
||||||
|
import useDropdown from '../../../hooks/useDropdown';
|
||||||
|
import { CstType } from '../../../models/rsform';
|
||||||
|
import { labelCstType } from '../../../utils/labels';
|
||||||
|
import { getCstTypePrefix, getCstTypeShortcut } from '../../../utils/misc';
|
||||||
|
|
||||||
|
interface RSItemsMenuProps {
|
||||||
|
selected: number[]
|
||||||
|
|
||||||
|
onMoveUp: () => void
|
||||||
|
onMoveDown: () => void
|
||||||
|
onDelete: () => void
|
||||||
|
onClone: () => void
|
||||||
|
onCreate: (type?: CstType) => void
|
||||||
|
onTemplates: () => void
|
||||||
|
onReindex: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function RSItemsMenu({
|
||||||
|
selected,
|
||||||
|
onMoveUp, onMoveDown, onDelete, onClone, onCreate, onTemplates, onReindex
|
||||||
|
}: RSItemsMenuProps) {
|
||||||
|
const { isEditable } = useRSForm();
|
||||||
|
const insertMenu = useDropdown();
|
||||||
|
|
||||||
|
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-center w-full pr-[9rem]'>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Переместить вверх'
|
||||||
|
icon={<ArrowUpIcon size={5}/>}
|
||||||
|
disabled={!isEditable || nothingSelected}
|
||||||
|
onClick={onMoveUp}
|
||||||
|
/>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Переместить вниз'
|
||||||
|
icon={<ArrowDownIcon size={5}/>}
|
||||||
|
disabled={!isEditable || nothingSelected}
|
||||||
|
onClick={onMoveDown}
|
||||||
|
/>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Удалить выбранные'
|
||||||
|
icon={<DumpBinIcon color={isEditable && !nothingSelected ? 'text-warning' : ''} size={5}/>}
|
||||||
|
disabled={!isEditable || nothingSelected}
|
||||||
|
onClick={onDelete}
|
||||||
|
/>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Клонировать конституенту'
|
||||||
|
icon={<CloneIcon color={isEditable && selected.length === 1 ? 'text-success': ''} size={5}/>}
|
||||||
|
disabled={!isEditable || selected.length !== 1}
|
||||||
|
onClick={onClone}
|
||||||
|
/>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Добавить новую конституенту...'
|
||||||
|
icon={<SmallPlusIcon color={isEditable ? 'text-success': ''} size={5}/>}
|
||||||
|
disabled={!isEditable}
|
||||||
|
onClick={() => onCreate()}
|
||||||
|
/>
|
||||||
|
<div ref={insertMenu.ref} className='flex justify-center'>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Добавить пустую конституенту'
|
||||||
|
icon={<ArrowDropdownIcon color={isEditable ? 'text-success': ''} size={5}/>}
|
||||||
|
disabled={!isEditable}
|
||||||
|
onClick={insertMenu.toggle}
|
||||||
|
/>
|
||||||
|
{ insertMenu.isActive &&
|
||||||
|
<Dropdown>
|
||||||
|
{(Object.values(CstType)).map(
|
||||||
|
(typeStr) => {
|
||||||
|
const type = typeStr as CstType;
|
||||||
|
return (
|
||||||
|
<DropdownButton
|
||||||
|
onClick={() => onCreate(type)}
|
||||||
|
tooltip={getCstTypeShortcut(type)}
|
||||||
|
>
|
||||||
|
{`${getCstTypePrefix(type)}1 — ${labelCstType(type)}`}
|
||||||
|
</DropdownButton>);
|
||||||
|
})}
|
||||||
|
</Dropdown>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Создать конституенту из шаблона'
|
||||||
|
icon={<DiamondIcon color={isEditable ? 'text-primary': ''} size={5}/>}
|
||||||
|
disabled={!isEditable}
|
||||||
|
onClick={onTemplates}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Сброс имен: присвоить порядковые имена'
|
||||||
|
icon={<UpdateIcon color={isEditable ? 'text-primary': ''} size={5}/>}
|
||||||
|
disabled={!isEditable}
|
||||||
|
onClick={onReindex}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className='ml-1' id='items-table-help'>
|
||||||
|
<HelpIcon color='text-primary' size={5} />
|
||||||
|
</div>
|
||||||
|
<ConceptTooltip anchorSelect='#items-table-help' offset={30}>
|
||||||
|
<HelpRSFormItems />
|
||||||
|
</ConceptTooltip>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RSItemsMenu;
|
|
@ -15,7 +15,7 @@ function RSLocalButton({ text, tooltip, disabled, onInsert }: RSLocalButtonProps
|
||||||
onClick={() => onInsert(TokenID.ID_LOCAL, text)}
|
onClick={() => onInsert(TokenID.ID_LOCAL, text)}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className='w-[2.25rem] h-6 cursor-pointer disabled:cursor-default border rounded-none clr-hover clr-btn-clear'
|
className='w-[2rem] h-6 cursor-pointer disabled:cursor-default border rounded-none clr-hover clr-btn-clear'
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Dropdown from '../../../components/Common/Dropdown';
|
||||||
import DropdownButton from '../../../components/Common/DropdownButton';
|
import DropdownButton from '../../../components/Common/DropdownButton';
|
||||||
import DropdownCheckbox from '../../../components/Common/DropdownCheckbox';
|
import DropdownCheckbox from '../../../components/Common/DropdownCheckbox';
|
||||||
import {
|
import {
|
||||||
CloneIcon, DownloadIcon, DumpBinIcon, EditIcon, MenuIcon, NotSubscribedIcon,
|
CloneIcon, DiamondIcon, DownloadIcon, DumpBinIcon, EditIcon, MenuIcon, NotSubscribedIcon,
|
||||||
OwnerIcon, ShareIcon, SmallPlusIcon, SubscribedIcon, UploadIcon
|
OwnerIcon, ShareIcon, SmallPlusIcon, SubscribedIcon, UploadIcon
|
||||||
} from '../../../components/Icons';
|
} from '../../../components/Icons';
|
||||||
import { useAuth } from '../../../context/AuthContext';
|
import { useAuth } from '../../../context/AuthContext';
|
||||||
|
@ -20,11 +20,12 @@ interface RSTabsMenuProps {
|
||||||
onShare: () => void
|
onShare: () => void
|
||||||
onDownload: () => void
|
onDownload: () => void
|
||||||
onToggleSubscribe: () => void
|
onToggleSubscribe: () => void
|
||||||
|
onTemplates: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSTabsMenu({
|
function RSTabsMenu({
|
||||||
showUploadDialog, showCloneDialog,
|
showUploadDialog, showCloneDialog,
|
||||||
onDestroy, onShare, onDownload, onClaim, onToggleSubscribe
|
onDestroy, onShare, onDownload, onClaim, onToggleSubscribe, onTemplates
|
||||||
}: RSTabsMenuProps) {
|
}: RSTabsMenuProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
@ -45,6 +46,11 @@ function RSTabsMenu({
|
||||||
onDestroy();
|
onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTemplates() {
|
||||||
|
schemaMenu.hide();
|
||||||
|
onTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
function handleDownload () {
|
function handleDownload () {
|
||||||
schemaMenu.hide();
|
schemaMenu.hide();
|
||||||
onDownload();
|
onDownload();
|
||||||
|
@ -70,118 +76,123 @@ function RSTabsMenu({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-stretch h-full w-fit'>
|
<div className='flex items-stretch h-full w-fit'>
|
||||||
<div ref={schemaMenu.ref}>
|
<div ref={schemaMenu.ref}>
|
||||||
<Button
|
<Button
|
||||||
tooltip='Действия'
|
tooltip='Действия'
|
||||||
icon={<MenuIcon color='text-controls' size={5}/>}
|
icon={<MenuIcon color='text-controls' size={5}/>}
|
||||||
borderClass=''
|
borderClass=''
|
||||||
dimensions='h-full w-fit pl-2'
|
dimensions='h-full w-fit pl-2'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
dense
|
dense
|
||||||
onClick={schemaMenu.toggle}
|
onClick={schemaMenu.toggle}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
/>
|
/>
|
||||||
{ schemaMenu.isActive &&
|
{ schemaMenu.isActive &&
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownButton onClick={handleShare}>
|
<DropdownButton onClick={handleShare}>
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<ShareIcon color='text-primary' size={4}/>
|
<ShareIcon color='text-primary' size={4}/>
|
||||||
<p>Поделиться</p>
|
<p>Поделиться</p>
|
||||||
</div>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton onClick={handleClone} disabled={!user} >
|
<DropdownButton onClick={handleClone} disabled={!user} >
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<CloneIcon color='text-primary' size={4}/>
|
<CloneIcon color='text-primary' size={4}/>
|
||||||
<p>Клонировать</p>
|
<p>Клонировать</p>
|
||||||
</div>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton onClick={handleDownload}>
|
<DropdownButton onClick={handleTemplates} disabled={!isEditable} >
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<DownloadIcon color='text-primary' size={4}/>
|
<DiamondIcon color={isEditable ? 'text-success' : ''} size={4}/>
|
||||||
<p>Выгрузить в Экстеор</p>
|
<p>Банк выражений</p>
|
||||||
</div>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton disabled={!isEditable} onClick={handleUpload}>
|
<DropdownButton onClick={handleDownload}>
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<UploadIcon color={isEditable ? 'text-warning' : ''} size={4}/>
|
<DownloadIcon color='text-primary' size={4}/>
|
||||||
<p>Загрузить из Экстеора</p>
|
<p>Выгрузить в Экстеор</p>
|
||||||
</div>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton disabled={!isEditable} onClick={handleDelete}>
|
<DropdownButton disabled={!isEditable} onClick={handleUpload}>
|
||||||
<span className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<DumpBinIcon color={isEditable ? 'text-warning' : ''} size={4} />
|
<UploadIcon color={isEditable ? 'text-warning' : ''} size={4}/>
|
||||||
<p>Удалить схему</p>
|
<p>Загрузить из Экстеора</p>
|
||||||
</span>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton onClick={handleCreateNew}>
|
<DropdownButton disabled={!isEditable} onClick={handleDelete}>
|
||||||
<span className='inline-flex items-center justify-start gap-2'>
|
<span className='inline-flex items-center justify-start gap-2'>
|
||||||
<SmallPlusIcon color='text-url' size={4} />
|
<DumpBinIcon color={isEditable ? 'text-warning' : ''} size={4} />
|
||||||
<p>Создать новую схему</p>
|
<p>Удалить схему</p>
|
||||||
</span>
|
</span>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
</Dropdown>}
|
<DropdownButton onClick={handleCreateNew}>
|
||||||
</div>
|
<span className='inline-flex items-center justify-start gap-2'>
|
||||||
<div ref={editMenu.ref}>
|
<SmallPlusIcon color='text-url' size={4} />
|
||||||
<Button
|
<p>Создать новую схему</p>
|
||||||
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
|
</span>
|
||||||
borderClass=''
|
</DropdownButton>
|
||||||
dimensions='h-full w-fit'
|
</Dropdown>}
|
||||||
style={{outlineColor: 'transparent'}}
|
|
||||||
icon={<EditIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
|
|
||||||
dense
|
|
||||||
onClick={editMenu.toggle}
|
|
||||||
tabIndex={-1}
|
|
||||||
/>
|
|
||||||
{ editMenu.isActive &&
|
|
||||||
<Dropdown>
|
|
||||||
<DropdownButton
|
|
||||||
disabled={!user || !isClaimable}
|
|
||||||
onClick={!isOwned ? handleClaimOwner : undefined}
|
|
||||||
tooltip={!user || !isClaimable ? 'Стать владельцем можно только для общей изменяемой схемы' : ''}
|
|
||||||
>
|
|
||||||
<div className='flex items-center gap-2 pl-1'>
|
|
||||||
<span><OwnerIcon size={5} color={isOwned ? 'text-success' : 'text-controls'} /></span>
|
|
||||||
<p>
|
|
||||||
{ isOwned && <b>Владелец схемы</b> }
|
|
||||||
{ !isOwned && <b>Стать владельцем</b> }
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</DropdownButton>
|
|
||||||
{(isOwned || user?.is_staff) &&
|
|
||||||
<DropdownCheckbox
|
|
||||||
value={isReadonly}
|
|
||||||
setValue={toggleReadonly}
|
|
||||||
label='Я — читатель!'
|
|
||||||
tooltip='Режим чтения'
|
|
||||||
/>}
|
|
||||||
{user?.is_staff &&
|
|
||||||
<DropdownCheckbox
|
|
||||||
value={isForceAdmin}
|
|
||||||
setValue={toggleForceAdmin}
|
|
||||||
label='Я — администратор!'
|
|
||||||
tooltip='Режим редактирования для администраторов'
|
|
||||||
/>}
|
|
||||||
</Dropdown>}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
tooltip={'отслеживание: ' + (isTracking ? '[включено]' : '[выключено]')}
|
|
||||||
disabled={processing}
|
|
||||||
icon={isTracking
|
|
||||||
? <SubscribedIcon color='text-primary' size={5}/>
|
|
||||||
: <NotSubscribedIcon color='text-controls' size={5}/>
|
|
||||||
}
|
|
||||||
dimensions='h-full w-fit pr-2'
|
|
||||||
borderClass=''
|
|
||||||
style={{outlineColor: 'transparent'}}
|
|
||||||
dense
|
|
||||||
onClick={onToggleSubscribe}
|
|
||||||
tabIndex={-1}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
<div ref={editMenu.ref}>
|
||||||
|
<Button
|
||||||
|
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
|
||||||
|
borderClass=''
|
||||||
|
dimensions='h-full w-fit'
|
||||||
|
style={{outlineColor: 'transparent'}}
|
||||||
|
icon={<EditIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
|
||||||
|
dense
|
||||||
|
onClick={editMenu.toggle}
|
||||||
|
tabIndex={-1}
|
||||||
|
/>
|
||||||
|
{ editMenu.isActive &&
|
||||||
|
<Dropdown>
|
||||||
|
<DropdownButton
|
||||||
|
disabled={!user || !isClaimable}
|
||||||
|
onClick={!isOwned ? handleClaimOwner : undefined}
|
||||||
|
tooltip={!user || !isClaimable ? 'Стать владельцем можно только для общей изменяемой схемы' : ''}
|
||||||
|
>
|
||||||
|
<div className='flex items-center gap-2 pl-1'>
|
||||||
|
<span><OwnerIcon size={5} color={isOwned ? 'text-success' : 'text-controls'} /></span>
|
||||||
|
<p>
|
||||||
|
{ isOwned && <b>Владелец схемы</b> }
|
||||||
|
{ !isOwned && <b>Стать владельцем</b> }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</DropdownButton>
|
||||||
|
{(isOwned || user?.is_staff) &&
|
||||||
|
<DropdownCheckbox
|
||||||
|
value={isReadonly}
|
||||||
|
setValue={toggleReadonly}
|
||||||
|
label='Я — читатель!'
|
||||||
|
tooltip='Режим чтения'
|
||||||
|
/>}
|
||||||
|
{user?.is_staff &&
|
||||||
|
<DropdownCheckbox
|
||||||
|
value={isForceAdmin}
|
||||||
|
setValue={toggleForceAdmin}
|
||||||
|
label='Я — администратор!'
|
||||||
|
tooltip='Режим редактирования для администраторов'
|
||||||
|
/>}
|
||||||
|
</Dropdown>}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
tooltip={'отслеживание: ' + (isTracking ? '[включено]' : '[выключено]')}
|
||||||
|
disabled={processing}
|
||||||
|
icon={isTracking
|
||||||
|
? <SubscribedIcon color='text-primary' size={5}/>
|
||||||
|
: <NotSubscribedIcon color='text-controls' size={5}/>
|
||||||
|
}
|
||||||
|
dimensions='h-full w-fit pr-2'
|
||||||
|
borderClass=''
|
||||||
|
style={{outlineColor: 'transparent'}}
|
||||||
|
dense
|
||||||
|
onClick={onToggleSubscribe}
|
||||||
|
tabIndex={-1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RSTabsMenu
|
export default RSTabsMenu;
|
|
@ -17,7 +17,7 @@ function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) {
|
||||||
onClick={() => onInsert(token)}
|
onClick={() => onInsert(token)}
|
||||||
title={describeToken(token)}
|
title={describeToken(token)}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={`px-1 cursor-pointer disabled:cursor-default border rounded-none h-6 ${width} clr-outline clr-hover clr-btn-clear`}
|
className={`px-1 cursor-pointer disabled:cursor-default border rounded-none h-6 ${width} outline-none clr-hover clr-btn-clear`}
|
||||||
>
|
>
|
||||||
{label && <span className='whitespace-nowrap'>{label}</span>}
|
{label && <span className='whitespace-nowrap'>{label}</span>}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -28,7 +28,7 @@ function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div title={describeExpressionStatus(status)}
|
<div title={describeExpressionStatus(status)}
|
||||||
className='inline-flex items-center justify-center w-full h-full text-sm font-semibold align-middle border select-none small-caps'
|
className='inline-flex items-center justify-center w-full h-full text-sm font-semibold align-middle border rounded-none select-none small-caps'
|
||||||
style={{backgroundColor: colorbgCstStatus(status, colors)}}
|
style={{backgroundColor: colorbgCstStatus(status, colors)}}
|
||||||
>
|
>
|
||||||
{labelExpressionStatus(status)}
|
{labelExpressionStatus(status)}
|
||||||
|
|
|
@ -244,6 +244,7 @@ export function labelHelpTopic(topic: HelpTopic): string {
|
||||||
case HelpTopic.CSTLIST: return '- список конституент';
|
case HelpTopic.CSTLIST: return '- список конституент';
|
||||||
case HelpTopic.CONSTITUENTA: return '- конституента';
|
case HelpTopic.CONSTITUENTA: return '- конституента';
|
||||||
case HelpTopic.GRAPH_TERM: return '- граф термов';
|
case HelpTopic.GRAPH_TERM: return '- граф термов';
|
||||||
|
case HelpTopic.RSTEMPLATES: return '- Банк выражений';
|
||||||
case HelpTopic.RSLANG: return 'Экспликация';
|
case HelpTopic.RSLANG: return 'Экспликация';
|
||||||
case HelpTopic.TERM_CONTROL: return 'Терминологизация';
|
case HelpTopic.TERM_CONTROL: return 'Терминологизация';
|
||||||
case HelpTopic.EXTEOR: return 'Экстеор';
|
case HelpTopic.EXTEOR: return 'Экстеор';
|
||||||
|
@ -259,6 +260,7 @@ export function describeHelpTopic(topic: HelpTopic): string {
|
||||||
case HelpTopic.CSTLIST: return 'Описание работы со списком конституентт';
|
case HelpTopic.CSTLIST: return 'Описание работы со списком конституентт';
|
||||||
case HelpTopic.CONSTITUENTA: return 'Описание редактирования конституенты';
|
case HelpTopic.CONSTITUENTA: return 'Описание редактирования конституенты';
|
||||||
case HelpTopic.GRAPH_TERM: return 'Описание работы с графом термов схемы';
|
case HelpTopic.GRAPH_TERM: return 'Описание работы с графом термов схемы';
|
||||||
|
case HelpTopic.RSTEMPLATES: return 'Описание работы с Банком выражений>';
|
||||||
case HelpTopic.RSLANG: return 'Справка по языку родов структур и экспликации';
|
case HelpTopic.RSLANG: return 'Справка по языку родов структур и экспликации';
|
||||||
case HelpTopic.TERM_CONTROL: return 'Справка по контролю терминов и текстовым отсылкам';
|
case HelpTopic.TERM_CONTROL: return 'Справка по контролю терминов и текстовым отсылкам';
|
||||||
case HelpTopic.EXTEOR: return 'Справка по программе для экспликации "Экстеор" для Windows';
|
case HelpTopic.EXTEOR: return 'Справка по программе для экспликации "Экстеор" для Windows';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user