F: Add TypeGraph for RSForm
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Frontend CI / build (22.x) (push) Has been cancelled

This commit is contained in:
Ivan 2024-11-20 00:32:26 +03:00
parent a1782904a9
commit 2b29f0b7bf
17 changed files with 78 additions and 24 deletions

View File

@ -100,6 +100,7 @@ export { LuSubscript as IconAlias } from 'react-icons/lu';
export { TbMathFunction as IconFormula } from 'react-icons/tb';
export { BiFontFamily as IconText } from 'react-icons/bi';
export { BiFont as IconTextOff } from 'react-icons/bi';
export { TbCar4Wd as IconTypeGraph } from 'react-icons/tb';
export { RiTreeLine as IconTree } from 'react-icons/ri';
export { FaRegKeyboard as IconControls } from 'react-icons/fa6';
export { RiLockLine as IconImmutable } from 'react-icons/ri';

View File

@ -6,24 +6,22 @@ import { ReactFlowProvider } from 'reactflow';
import Modal, { ModalProps } from '@/components/ui/Modal';
import { HelpTopic } from '@/models/miscellaneous';
import { IArgumentInfo } from '@/models/rslang';
import { ITypeInfo } from '@/models/rslang';
import { TMGraph } from '@/models/TMGraph';
import { errors } from '@/utils/labels';
import MGraphFlow from './MGraphFlow';
interface DlgShowTypificationProps extends Pick<ModalProps, 'hideWindow'> {
alias: string;
resultTypification: string;
args: IArgumentInfo[];
interface DlgShowTypeGraphProps extends Pick<ModalProps, 'hideWindow'> {
items: ITypeInfo[];
}
function DlgShowTypification({ hideWindow, alias, resultTypification, args }: DlgShowTypificationProps) {
function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) {
const graph = useMemo(() => {
const result = new TMGraph();
result.addConstituenta(alias, resultTypification, args);
items.forEach(item => result.addConstituenta(item.alias, item.result, item.args));
return result;
}, [alias, resultTypification, args]);
}, [items]);
if (graph.nodes.length === 0) {
toast.error(errors.typeStructureFailed);
@ -33,7 +31,7 @@ function DlgShowTypification({ hideWindow, alias, resultTypification, args }: Dl
return (
<Modal
header='Структура типизации'
header='Граф ступеней'
readonly
hideWindow={hideWindow}
className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]'
@ -46,4 +44,4 @@ function DlgShowTypification({ hideWindow, alias, resultTypification, args }: Dl
);
}
export default DlgShowTypification;
export default DlgShowTypeGraph;

View File

@ -1,3 +1,6 @@
'use client';
import { useMemo } from 'react';
import { Handle, Position } from 'reactflow';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
@ -8,16 +11,23 @@ import { globals } from '@/utils/constants';
function MGraphNode(node: MGraphNodeInternal) {
const { colors } = useConceptOptions();
const tooltipText = useMemo(
() =>
(node.data.annotations.length === 0 ? '' : `Конституенты: ${node.data.annotations.join(' ')}<br/>`) +
node.data.text,
[node.data]
);
return (
<>
<Handle type='source' position={Position.Top} style={{ opacity: 0 }} />
<div
className='w-full h-full cursor-default flex items-center justify-center rounded-full'
data-tooltip-id={globals.tooltip}
data-tooltip-content={node.data.text}
data-tooltip-html={tooltipText}
style={{ backgroundColor: colorBgTMGraphNode(node.data, colors) }}
>
{node.data.rank === 0 ? node.data.text : ''}
{node.data.rank === 0 ? node.data.text : node.data.annotations.length > 0 ? node.data.annotations.length : ''}
</div>
<Handle type='target' position={Position.Bottom} style={{ opacity: 0 }} />
</>

View File

@ -0,0 +1 @@
export { default } from './DlgShowTypeGraph';

View File

@ -1 +0,0 @@
export { default } from './DlgShowTypification';

View File

@ -72,6 +72,13 @@ export interface IArgumentInfo {
typification: string;
}
/** Represents global identifier type info. */
export interface ITypeInfo {
alias: string;
result: string;
args: IArgumentInfo[];
}
/**
* Represents function argument value.
*/

View File

@ -15,7 +15,8 @@ import {
IconOSS,
IconReset,
IconRotate3D,
IconText
IconText,
IconTypeGraph
} from '@/components/Icons';
import Divider from '@/components/ui/Divider';
import LinkTopic from '@/components/ui/LinkTopic';
@ -81,6 +82,10 @@ function HelpRSGraphTerm() {
<li>
<IconFitImage className='inline-icon' /> Вписать в экран
</li>
<li>
<IconTypeGraph className='inline-icon' /> Открыть{' '}
<LinkTopic text='граф ступеней' topic={HelpTopic.UI_TYPE_GRAPH} />
</li>
<li>
<IconImage className='inline-icon' /> Сохранить в формат PNG
</li>

View File

@ -13,7 +13,8 @@ function HelpTypeGraph() {
Портале кратные ребра представлены перечислением индексов компонент произведения.
</p>
<li>ребра без надписей означают взятие булеана</li>
<li>цифры означают номера компонент декартова произведения</li>
<li>цифры на ребрах означают номера компонент декартова произведения</li>
<li>цифры на узлах означают количество конституент в данной ступени</li>
<li>основаниями дерева являются ступени базисных, константных множеств</li>
<li>ступень терм-функции - произведение ступеней результата и аргументов</li>
<li>ступень предикат-функции - произведение ступеней аргументов</li>

View File

@ -14,7 +14,7 @@ import SubmitButton from '@/components/ui/SubmitButton';
import TextArea from '@/components/ui/TextArea';
import AnimateFade from '@/components/wrap/AnimateFade';
import { useRSForm } from '@/context/RSFormContext';
import DlgShowTypification from '@/dialogs/DlgShowTypification';
import DlgShowTypeGraph from '@/dialogs/DlgShowTypeGraph';
import { ConstituentaID, CstType, IConstituenta, ICstUpdateData } from '@/models/rsform';
import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI';
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
@ -60,6 +60,17 @@ function FormConstituenta({
const [typification, setTypification] = useState('N/A');
const [showTypification, setShowTypification] = useState(false);
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
const typeInfo = useMemo(
() =>
state
? {
alias: state.alias,
result: localParse ? localParse.typification : state.parse.typification,
args: localParse ? localParse.args : state.parse.args
}
: undefined,
[state, localParse]
);
const [forceComment, setForceComment] = useState(false);
@ -147,12 +158,7 @@ function FormConstituenta({
<AnimateFade className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'>
<AnimatePresence>
{showTypification && state ? (
<DlgShowTypification
alias={state.alias}
resultTypification={localParse ? localParse.typification : state.parse.typification}
args={localParse ? localParse.args : state.parse.args}
hideWindow={() => setShowTypification(false)}
/>
<DlgShowTypeGraph items={typeInfo ? [typeInfo] : []} hideWindow={() => setShowTypification(false)} />
) : null}
</AnimatePresence>
{state ? (

View File

@ -10,7 +10,8 @@ import {
IconNewItem,
IconRotate3D,
IconText,
IconTextOff
IconTextOff,
IconTypeGraph
} from '@/components/Icons';
import BadgeHelp from '@/components/info/BadgeHelp';
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
@ -116,6 +117,11 @@ function ToolbarTermGraph({
onClick={onDelete}
/>
) : null}
<MiniButton
icon={<IconTypeGraph size='1.25rem' className='icon-primary' />}
title='Граф ступеней'
onClick={() => controller.showTypeGraph()}
/>
<MiniButton
icon={<IconImage size='1.25rem' className='icon-primary' />}
title='Сохранить изображение'

View File

@ -22,6 +22,7 @@ import DlgEditVersions from '@/dialogs/DlgEditVersions';
import DlgEditWordForms from '@/dialogs/DlgEditWordForms';
import DlgInlineSynthesis from '@/dialogs/DlgInlineSynthesis';
import DlgRenameCst from '@/dialogs/DlgRenameCst';
import DlgShowTypeGraph from '@/dialogs/DlgShowTypeGraph';
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
import {
@ -106,6 +107,8 @@ export interface IRSEditContext extends ILibraryItemEditor {
produceStructure: () => void;
inlineSynthesis: () => void;
substitute: () => void;
showTypeGraph: () => void;
}
const RSEditContext = createContext<IRSEditContext | null>(null);
@ -169,6 +172,7 @@ export const RSEditState = ({
const [showCreateVersion, setShowCreateVersion] = useState(false);
const [showEditVersions, setShowEditVersions] = useState(false);
const [showInlineSynthesis, setShowInlineSynthesis] = useState(false);
const [showTypeGraph, setShowTypeGraph] = useState(false);
const [createInitialData, setCreateInitialData] = useState<ICstCreateData>();
const [showCreateCst, setShowCreateCst] = useState(false);
@ -179,6 +183,18 @@ export const RSEditState = ({
const [insertCstID, setInsertCstID] = useState<ConstituentaID | undefined>(undefined);
const [showTemplates, setShowTemplates] = useState(false);
const typeInfo = useMemo(
() =>
model.schema
? model.schema.items.map(item => ({
alias: item.alias,
result: item.parse.typification,
args: item.parse.args
}))
: [],
[model.schema]
);
useLayoutEffect(
() =>
setAccessLevel(prev => {
@ -662,7 +678,9 @@ export const RSEditState = ({
reorder,
inlineSynthesis,
produceStructure,
substitute
substitute,
showTypeGraph: () => setShowTypeGraph(true)
}}
>
{model.schema ? (
@ -762,6 +780,8 @@ export const RSEditState = ({
onInlineSynthesis={handleInlineSynthesis}
/>
) : null}
{showTypeGraph ? <DlgShowTypeGraph items={typeInfo} hideWindow={() => setShowTypeGraph(false)} /> : null}
</AnimatePresence>
) : null}