F: Improve OSS UI

This commit is contained in:
Ivan 2024-08-17 12:16:50 +03:00
parent a97d1bebb9
commit 259259ec7e
13 changed files with 102 additions and 33 deletions

View File

@ -72,6 +72,11 @@ function TooltipOperation({ node, anchor }: TooltipOperationProps) {
<b>КС не принадлежит ОСС</b>
</p>
) : null}
{node.data.operation.is_consolidation ? (
<p>
<b>Ромбовидный синтез</b>
</p>
) : null}
{node.data.operation.title ? (
<p>
<b>Название: </b>

View File

@ -62,6 +62,7 @@ export class OssLoader {
this.graph.topologicalOrder().forEach(operationID => {
const operation = this.operationByID.get(operationID)!;
const schema = this.items.find(item => item.id === operation.result);
operation.is_consolidation = this.inferConsolidation(operationID);
operation.is_owned = !schema || (schema.owner === this.oss.owner && schema.location === this.oss.location);
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
operation.arguments = this.oss.arguments
@ -70,6 +71,19 @@ export class OssLoader {
});
}
private inferConsolidation(operationID: OperationID): boolean {
const inputs = this.graph.expandInputs([operationID]);
if (inputs.length === 0) {
return false;
}
const ancestors = [...inputs];
inputs.forEach(input => {
ancestors.push(...this.graph.expandAllInputs([input]));
});
const unique = new Set(ancestors);
return unique.size < ancestors.length;
}
private calculateStats(): IOperationSchemaStats {
const items = this.oss.items;
return {

View File

@ -37,6 +37,7 @@ export interface IOperation {
result: LibraryItemID | null;
is_owned: boolean;
is_consolidation: boolean; // aka 'diamond synthesis'
substitutions: ICstSubstituteEx[];
arguments: OperationID[];
}

View File

@ -148,7 +148,7 @@ function TableLibraryItems({ items, resetQuery, folderMode, toggleFolderMode }:
{
when: (item: ILibraryItem) => item.item_type === LibraryItemType.OSS,
style: {
backgroundColor: colors.bgGreen50
color: colors.fgGreen
}
}
],

View File

@ -1,24 +1,37 @@
import { IconOSS, IconPredecessor } from '@/components/Icons';
import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous';
function HelpConceptOSS() {
return (
<div>
<div className='text-justify'>
<h1>Операционная схема синтеза</h1>
<p>
Работа со сложными предметными областями требует многократного{' '}
<LinkTopic text='синтеза' topic={HelpTopic.CC_SYNTHESIS} /> для построения целевых понятий. Последовательность
синтезов концептуальных схем задается с помощью <b>Операционной схемы синтеза (ОСС)</b> в форме Графа синтеза.
синтезов задается с помощью{' '}
<span className='text-nowrap'>
<IconOSS className='inline-icon' /> <b>Операционной схемы синтеза (ОСС)</b>
</span>{' '}
и отображается в форме <LinkTopic text='Графа синтеза' topic={HelpTopic.UI_OSS_GRAPH} />.
</p>
<p>
Отдельные операции в рамках ОСС задаются <b>таблицами отождествлений</b> понятий из синтезируемых схем. Таким
образом <LinkTopic text='конституенты' topic={HelpTopic.CC_CONSTITUENTA} /> в каждой КС разделяются на
наследованные, отождествленные и дописанные.
образом <LinkTopic text='конституенты' topic={HelpTopic.CC_CONSTITUENTA} /> в каждой КС разделяются на исходные
(дописанные), наследованные, отождествленные (удаляемые).
</p>
<p>
Портал поддерживает <b>сквозные изменения</b> в рамках ОСС. Изменения, внесенные в исходные концептуальные схемы
автоматически проносятся через граф синтеза (путем обновления наследованных конституент). Формальные определения
наследованных конституент можно редактировать только путем изменения исходных конституент.
наследованных конституент можно редактировать только путем изменения{' '}
<span className='text-nowrap'>
<IconPredecessor className='inline-icon' /> исходных конституент.
</span>
</p>
<p>
<b>Ромбовидным синтезом</b> называется операция, где используются КС, имеющие общих предков. При таком синтезе
могут возникать дубликаты и неоднозначности в результате. Необходимо внимательно формировать таблицу
отождествлений, добавляя дублирующиеся понятия из синтезируемых схем.
</p>
</div>
);

View File

@ -40,8 +40,8 @@ function HelpConceptSynthesis() {
<LinkTopic text='разделе Операции' topic={HelpTopic.RSL_OPERATIONS} />
</p>
<p>
Для управления совокупностью синтезов используются <b>операционные схемы синтеза</b>. В данный момент этот
функционал еще не реализован в Портале.
Для управления совокупностью синтезов используются{' '}
<LinkTopic text='операционные схемы синтеза' topic={HelpTopic.CC_OSS} />.
</p>
</div>
);

View File

@ -5,18 +5,28 @@ import {
IconFolderEmpty,
IconFolderOpened,
IconFolderTree,
IconOSS,
IconRSForm,
IconSearch,
IconShow,
IconSortAsc,
IconSortDesc
} from '@/components/Icons';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
function HelpLibrary() {
const { colors } = useConceptOptions();
return (
<div>
<h1>Библиотека схем</h1>
<p>В библиотеке собраны концептуальные схемы, эксплицированные в родоструктурном аппарате</p>
<p>
В библиотеке собраны <IconRSForm size='1rem' className='inline-icon' /> системы определений (КС) <br />и
<IconOSS size='1rem' className='inline-icon' /> операционные схемы синтеза (ОСС).
</p>
<li>
<span style={{ color: colors.fgGreen }}>зеленым текстом</span> выделены ОСС
</li>
<li>клик по строке - переход к редактированию схемы</li>
<li>Ctrl + клик по строке откроет схему в новой вкладке</li>
<li>Фильтры атрибутов три позиции: да/нет/не применять</li>

View File

@ -1,4 +1,5 @@
import {
IconAlert,
IconAnimation,
IconAnimationOff,
IconConnect,
@ -23,7 +24,7 @@ import { HelpTopic } from '@/models/miscellaneous';
function HelpOssGraph() {
return (
<div className='flex flex-col'>
<h1>Граф синтеза</h1>
<h1 className='sm:pr-[6rem]'>Граф синтеза</h1>
<div className='flex flex-col sm:flex-row'>
<div className='w-full sm:w-[14rem]'>
<h1>Настройка графа</h1>
@ -50,7 +51,10 @@ function HelpOssGraph() {
<li>Клик на операцию выделение</li>
<li>Esc сбросить выделение</li>
<li>
<IconEdit2 className='inline-icon' /> Двойной клик редактирование
Двойной клик переход к связанной <LinkTopic text='КС' topic={HelpTopic.CC_SYSTEM} />
</li>
<li>
<IconEdit2 className='inline-icon' /> Редактирование операции
</li>
<li>
<IconNewItem className='inline-icon icon-green' /> Новая операция
@ -73,7 +77,7 @@ function HelpOssGraph() {
<IconSave className='inline-icon' /> Сохранить положения
</li>
<li>
<IconImage className='inline-icon' /> Сохранить в формат SVG
<IconImage className='inline-icon' /> Сохранить в SVG
</li>
</div>
@ -82,9 +86,12 @@ function HelpOssGraph() {
<div className='dense w-[21rem]'>
<h1>Контекстное меню</h1>
<li>
<IconRSForm className='inline-icon icon-green' /> Переход к связанной{' '}
<IconRSForm className='inline-icon icon-green' /> Статус связанной{' '}
<LinkTopic text='КС' topic={HelpTopic.CC_SYSTEM} />
</li>
<li>
<IconAlert className='inline-icon' /> <LinkTopic text='Ромбовидный синтез' topic={HelpTopic.CC_OSS} />
</li>
<li>
<IconNewRSForm className='inline-icon icon-green' /> Создать пустую КС для загрузки
</li>

View File

@ -21,11 +21,12 @@ function InputNode(node: OssNodeInternal) {
<>
<Handle type='source' position={Position.Bottom} />
<Overlay position='top-[-0.2rem] right-[-0.2rem]'>
<Overlay position='top-0 right-0' className='flex'>
<MiniButton
icon={<IconRSForm className={hasFile ? 'clr-text-green' : 'clr-text-red'} size='0.75rem' />}
noHover
title='Связанная КС'
noPadding
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
hideTitle={!controller.showTooltip}
onClick={() => {
handleOpenSchema();

View File

@ -105,7 +105,7 @@ function NodeContextMenu({
<Dropdown isOpen={isOpen} stretchLeft={cursorX >= window.innerWidth - PARAMETER.ossContextMenuWidth}>
<DropdownButton
text='Редактировать'
titleHtml={prepareTooltip('Редактировать операцию', 'Двойной клик')}
title='Редактировать операцию'
icon={<IconEdit2 size='1rem' className='icon-primary' />}
disabled={controller.isProcessing}
onClick={handleEditOperation}
@ -113,7 +113,7 @@ function NodeContextMenu({
{operation.result ? (
<DropdownButton
text='Открыть схему'
text={prepareTooltip('Открыть схему', 'Двойной клик')}
title='Открыть привязанную КС'
icon={<IconRSForm size='1rem' className='icon-green' />}
disabled={controller.isProcessing}

View File

@ -1,6 +1,6 @@
import { Handle, Position } from 'reactflow';
import { IconRSForm } from '@/components/Icons';
import { IconAlert, IconRSForm } from '@/components/Icons';
import TooltipOperation from '@/components/info/TooltipOperation';
import MiniButton from '@/components/ui/MiniButton.tsx';
import Overlay from '@/components/ui/Overlay';
@ -22,15 +22,31 @@ function OperationNode(node: OssNodeInternal) {
<>
<Handle type='source' position={Position.Bottom} />
<Overlay position='top-[-0.2rem] right-[-0.2rem]'>
<Overlay position='top-0 right-0' className='flex flex-col gap-1'>
<MiniButton
icon={<IconRSForm className={hasFile ? 'clr-text-green' : 'clr-text-red'} size='0.75rem' />}
icon={
<IconRSForm
className={hasFile ? 'clr-text-green' : 'clr-text-red'}
size={node.data.operation.is_consolidation ? '0.6rem' : '0.75rem'}
/>
}
noHover
title='Связанная КС'
noPadding
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
hideTitle={!controller.showTooltip}
onClick={handleOpenSchema}
disabled={!hasFile}
/>
{node.data.operation.is_consolidation ? (
<MiniButton
icon={<IconAlert className='clr-text-primary' size='0.6rem' />}
disabled
noPadding
noHover
title='Внимание! Ромбовидный синтез'
hideTitle={!controller.showTooltip}
/>
) : null}
</Overlay>
{!node.data.operation.is_owned ? (

View File

@ -299,9 +299,13 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
(event: CProps.EventMouse, node: OssNode) => {
event.preventDefault();
event.stopPropagation();
handleEditOperation(Number(node.id));
if (node.data.operation.result) {
controller.openOperationSchema(Number(node.id));
} else {
handleEditOperation(Number(node.id));
}
},
[handleEditOperation]
[handleEditOperation, controller.openOperationSchema]
);
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {

View File

@ -89,16 +89,14 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
/>
{accessLevel >= UserLevel.OWNER ? (
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
<div className='flex items-start'>
<MiniButton
title='Изменить редакторов'
noHover
onClick={() => controller.promptEditors()}
icon={<IconEdit size='1rem' className='mt-1 icon-primary' />}
disabled={isModified || controller.isProcessing}
/>
</div>
<Overlay position='top-[-0.5rem] left-[5.5rem]' className='cc-icons'>
<MiniButton
title='Изменить редакторов'
noHover
onClick={() => controller.promptEditors()}
icon={<IconEdit size='1rem' className='mt-1 icon-primary' />}
disabled={isModified || controller.isProcessing}
/>
</Overlay>
) : null}
<LabeledValue