diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/dlg-show-term-graph.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/dlg-show-term-graph.tsx new file mode 100644 index 00000000..4a1e4076 --- /dev/null +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/dlg-show-term-graph.tsx @@ -0,0 +1,52 @@ +// Dialog for read-only display of the TermGraph for OSS. Currently ignores activeCst and only shows the schema graph. +import { ReactFlowProvider } from 'reactflow'; + +import { urls, useConceptNavigation } from '@/app'; +// import { useDialogsStore } from '@/stores/dialogs'; +import { type IRSForm } from '@/features/rsform'; +import { TGFlow } from '@/features/rsform/pages/rsform-page/editor-term-graph/tg-flow'; +import { RSTabID } from '@/features/rsform/pages/rsform-page/rsedit-context'; + +import { MiniButton } from '@/components/control'; +import { IconRSForm } from '@/components/icons'; +import { ModalView } from '@/components/modal'; +import { useDialogsStore } from '@/stores/dialogs'; + +export interface DlgShowTermGraphProps { + schema: IRSForm; +} + +export function DlgShowTermGraph() { + const { schema } = useDialogsStore(state => state.props as DlgShowTermGraphProps); + const hideDialog = useDialogsStore(state => state.hideDialog); + const router = useConceptNavigation(); + + function navigateToSchema() { + hideDialog(); + router.push({ + path: urls.schema_props({ + id: schema.id, + tab: RSTabID.GRAPH + }) + }); + } + + return ( + + } + onClick={navigateToSchema} + /> + + {/* TGFlow expects schema from context, so you may need to refactor TGFlow to accept schema as prop if needed */} + + + + ); +} diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/index.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/index.tsx new file mode 100644 index 00000000..bb2f5ae8 --- /dev/null +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-show-term-graph/index.tsx @@ -0,0 +1 @@ +export * from './dlg-show-term-graph'; diff --git a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/oss-flow-state.tsx b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/oss-flow-state.tsx index 0c2b7b7e..eef62b8e 100644 --- a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/oss-flow-state.tsx +++ b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/oss-flow-state.tsx @@ -17,7 +17,6 @@ import { OssFlowContext } from './oss-flow-context'; const Z_BLOCK = 1; const Z_SCHEMA = 10; -// TODO: decouple nodes and edges from controller callbacks export const OssFlowState = ({ children }: React.PropsWithChildren) => { const { schema, setSelected } = useOssEdit(); const { fitView } = useReactFlow(); @@ -77,6 +76,7 @@ export const OssFlowState = ({ children }: React.PropsWithChildren) => { target: target.nodeID, type: edgeStraight ? 'straight' : 'simplebezier', animated: edgeAnimate, + focusable: false, targetHandle: source.x > target.x ? 'right' : 'left' }; }); diff --git a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/side-panel/toolbar-constituents.tsx b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/side-panel/toolbar-constituents.tsx index 7f0589f1..8e392f07 100644 --- a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/side-panel/toolbar-constituents.tsx +++ b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/side-panel/toolbar-constituents.tsx @@ -23,7 +23,6 @@ import { cn } from '@/components/utils'; import { useDialogsStore } from '@/stores/dialogs'; import { PARAMETER, prefixes } from '@/utils/constants'; import { type RO } from '@/utils/meta'; -import { notImplemented } from '@/utils/utils'; interface ToolbarConstituentsProps { schema: IRSForm; @@ -52,6 +51,7 @@ export function ToolbarConstituents({ const showCreateCst = useDialogsStore(state => state.showCreateCst); const showDeleteCst = useDialogsStore(state => state.showDeleteCst); const showTypeGraph = useDialogsStore(state => state.showShowTypeGraph); + const showTermGraph = useDialogsStore(state => state.showShowTermGraph); const { moveConstituents } = useMoveConstituents(); const { createConstituenta } = useCreateConstituenta(); @@ -225,7 +225,7 @@ export function ToolbarConstituents({ } title='Граф термов' - onClick={notImplemented} + onClick={() => showTermGraph({ schema })} /> } diff --git a/rsconcept/frontend/src/features/rsform/dialogs/dlg-edit-cst/dlg-edit-cst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/dlg-edit-cst/dlg-edit-cst.tsx index f65d0318..f663fda2 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/dlg-edit-cst/dlg-edit-cst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/dlg-edit-cst/dlg-edit-cst.tsx @@ -92,7 +92,6 @@ export function DlgEditCst() { title='Редактировать в КС' noPadding icon={} - className='' onClick={navigateToTarget} /> [], edges: Edge[], subLabels: boolean) { +export interface TGNodeState { + cst: IConstituenta; + focused: boolean; +} + +/** Represents graph node. */ +export interface TGNodeData extends Node { + id: string; + data: TGNodeState; +} + +/** Represents graph node internal data. */ +export interface TGNodeInternal { + id: string; + data: TGNodeState; + selected: boolean; + dragging: boolean; + xPos: number; + yPos: number; +} + +export function applyLayout(nodes: Node[], edges: Edge[], subLabels: boolean) { const dagreGraph = new dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({})); dagreGraph.setGraph({ rankdir: 'TB', diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/form-constituenta.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/form-constituenta.tsx index e114402b..df74a807 100644 --- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/form-constituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/form-constituenta.tsx @@ -277,7 +277,7 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, id='cst_convention' {...register('item_data.convention')} fitContent - className='max-h-32' + className='disabled:min-h-9 max-h-32' spellCheck label={isBasic ? 'Конвенция' : 'Комментарий'} placeholder={disabled ? '' : isBasic ? 'Договоренность об интерпретации' : 'Пояснение разработчика'} diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/graph/tg-node.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/graph/tg-node.tsx index 9db73316..7acf9067 100644 --- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/graph/tg-node.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/graph/tg-node.tsx @@ -8,45 +8,19 @@ import { globalIDs } from '@/utils/constants'; import { colorBgGraphNode } from '../../../../colors'; import { labelCstTypification } from '../../../../labels'; +import { type TGNodeInternal } from '../../../../models/graph-layout'; import { type IConstituenta } from '../../../../models/rsform'; import { useTermGraphStore } from '../../../../stores/term-graph'; -import { useRSEdit } from '../../rsedit-context'; const DESCRIPTION_THRESHOLD = 15; const LABEL_THRESHOLD = 3; -/** - * Represents graph AST node internal data. - */ -interface TGNodeInternal { - id: string; - data: IConstituenta; - selected: boolean; - dragging: boolean; - xPos: number; - yPos: number; -} - export function TGNode(node: TGNodeInternal) { - const { focusCst, setFocus, navigateCst } = useRSEdit(); const filter = useTermGraphStore(state => state.filter); const coloring = useTermGraphStore(state => state.coloring); - const isFocused = focusCst?.id === node.data.id; - const label = node.data.alias; - const description = !filter.noText ? node.data.term_resolved : ''; - - function handleContextMenu(event: React.MouseEvent) { - event.stopPropagation(); - event.preventDefault(); - setFocus(isFocused ? null : node.data); - } - - function handleDoubleClick(event: React.MouseEvent) { - event.preventDefault(); - event.stopPropagation(); - navigateCst(node.data.id); - } + const label = node.data.cst.alias; + const description = !filter.noText ? node.data.cst.term_resolved : ''; return ( <> @@ -54,21 +28,19 @@ export function TGNode(node: TGNodeInternal) {
LABEL_THRESHOLD ? 'text-[12px]/[16px]' : 'text-[14px]/[20px]' )} style={{ backgroundColor: node.selected ? APP_COLORS.bgActiveSelection - : isFocused + : node.data.focused ? APP_COLORS.bgPurple - : colorBgGraphNode(node.data, coloring) + : colorBgGraphNode(node.data.cst, coloring) }} data-tooltip-id={globalIDs.tooltip} - data-tooltip-html={describeCstNode(node.data)} + data-tooltip-html={describeCstNode(node.data.cst)} data-tooltip-hidden={node.dragging} - onContextMenu={handleContextMenu} - onDoubleClick={handleDoubleClick} >
{label}
@@ -80,8 +52,6 @@ export function TGNode(node: TGNodeInternal) { 'pointer-events-none', description.length > DESCRIPTION_THRESHOLD ? 'text-[10px]/[12px]' : 'text-[12px]/[16px]' )} - onContextMenu={handleContextMenu} - onDoubleClick={handleDoubleClick} >
{description} diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/schemas-guide.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/schemas-guide.tsx index e75cd64a..6407dc5c 100644 --- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/schemas-guide.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/schemas-guide.tsx @@ -1,15 +1,18 @@ import { useLibrary } from '@/features/library/backend/use-library'; +import { type IRSForm } from '@/features/rsform/models/rsform'; import { Tooltip } from '@/components/container'; import { IconHelp } from '@/components/icons'; import { globalIDs, prefixes } from '@/utils/constants'; import { colorBgSchemas } from '../../../colors'; -import { useRSEdit } from '../rsedit-context'; -export function SchemasGuide() { +interface SchemasGuideProps { + schema: IRSForm; +} + +export function SchemasGuide({ schema }: SchemasGuideProps) { const libraryItems = useLibrary().items; - const schema = useRSEdit().schema; const schemas = (() => { const processed = new Set(); diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/select-coloring.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/select-coloring.tsx index 0ced2ee0..a410134b 100644 --- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/select-coloring.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-term-graph/select-coloring.tsx @@ -1,23 +1,32 @@ import { HelpTopic } from '@/features/help'; import { BadgeHelp } from '@/features/help/components/badge-help'; +import { type IRSForm } from '@/features/rsform/models/rsform'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/input/select'; +import { cn } from '@/components/utils'; import { mapLabelColoring } from '../../../labels'; import { useTermGraphStore } from '../../../stores/term-graph'; import { SchemasGuide } from './schemas-guide'; -export function SelectColoring() { +interface SelectColoringProps { + className?: string; + schema: IRSForm; +} + +export function SelectColoring({ className, schema }: SelectColoringProps) { const coloring = useTermGraphStore(state => state.coloring); const setColoring = useTermGraphStore(state => state.setColoring); return ( -
+
{coloring === 'status' ? : null} {coloring === 'type' ? : null} - {coloring === 'schemas' ? : null} + {coloring === 'schemas' ? : null}