diff --git a/rsconcept/frontend/src/components/Help/CstClassInfo.tsx b/rsconcept/frontend/src/components/Help/CstClassInfo.tsx new file mode 100644 index 00000000..fdcefd0f --- /dev/null +++ b/rsconcept/frontend/src/components/Help/CstClassInfo.tsx @@ -0,0 +1,29 @@ +import { prefixes } from '../../utils/constants'; +import { mapCstClassInfo } from '../../utils/staticUI'; + +interface CstClassInfoProps { + title?: string +} + +function CstClassInfo({ title }: CstClassInfoProps) { + return ( +
+ { title &&

{title}

} + { [... mapCstClassInfo.values()].map( + (info, index) => { + return ( +

+ + {info.text} + + - + + {info.tooltip} + +

); + })} +
+ ); +} + +export default CstClassInfo; diff --git a/rsconcept/frontend/src/components/Help/CstStatusInfo.tsx b/rsconcept/frontend/src/components/Help/CstStatusInfo.tsx index e1a0c78d..3ae1f379 100644 --- a/rsconcept/frontend/src/components/Help/CstStatusInfo.tsx +++ b/rsconcept/frontend/src/components/Help/CstStatusInfo.tsx @@ -7,13 +7,13 @@ interface CstStatusInfoProps { function CstStatusInfo({ title }: CstStatusInfoProps) { return ( - <> +
{ title &&

{title}

} { [... mapStatusInfo.values()].map( (info, index) => { return ( -

- +

+ {info.text} - @@ -22,7 +22,7 @@ function CstStatusInfo({ title }: CstStatusInfoProps) {

); })} - +
); } diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx new file mode 100644 index 00000000..ddb20b23 --- /dev/null +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx @@ -0,0 +1,144 @@ +import { useLayoutEffect, useState } from 'react'; + +import Checkbox from '../../components/Common/Checkbox'; +import Modal from '../../components/Common/Modal'; +import { CstType } from '../../utils/models'; +import { getCstTypeLabel } from '../../utils/staticUI'; +import { GraphEditorParams } from './EditorTermGraph'; + +interface DlgGraphOptionsProps { + hideWindow: () => void + initial: GraphEditorParams + onConfirm: (params: GraphEditorParams) => void +} + +function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps) { + const [ noHermits, setNoHermits ] = useState(true); + const [ noTransitive, setNoTransitive ] = useState(false); + const [ noTemplates, setNoTemplates ] = useState(true); + + const [ allowBase, setAllowBase ] = useState(true); + const [ allowStruct, setAllowStruct ] = useState(true); + const [ allowTerm, setAllowTerm ] = useState(true); + const [ allowAxiom, setAllowAxiom ] = useState(true); + const [ allowFunction, setAllowFunction ] = useState(true); + const [ allowPredicate, setAllowPredicate ] = useState(true); + const [ allowConstant, setAllowConstant ] = useState(true); + const [ allowTheorem, setAllowTheorem ] = useState(true); + + function getParams() { + return { + noHermits: noHermits, + noTransitive: noTransitive, + noTemplates: noTemplates, + + allowBase: allowBase, + allowStruct: allowStruct, + allowTerm: allowTerm, + allowAxiom: allowAxiom, + allowFunction: allowFunction, + allowPredicate: allowPredicate, + allowConstant: allowConstant, + allowTheorem: allowTheorem + } + } + + const handleSubmit = () => { + hideWindow(); + onConfirm(getParams()); + }; + + useLayoutEffect(() => { + setNoHermits(initial.noHermits); + setNoTransitive(initial.noTransitive); + setNoTemplates(initial.noTemplates); + + setAllowBase(initial.allowBase); + setAllowStruct(initial.allowStruct); + setAllowTerm(initial.allowTerm); + setAllowAxiom(initial.allowAxiom); + setAllowFunction(initial.allowFunction); + setAllowPredicate(initial.allowPredicate); + setAllowConstant(initial.allowConstant); + setAllowTheorem(initial.allowTheorem); + }, [initial]); + + return ( + +
+
+

Преобразования

+ setNoHermits(event.target.checked) } + /> + setNoTemplates(event.target.checked) } + /> + setNoTransitive(event.target.checked) } + /> +
+
+

Типы конституент

+ setAllowBase(event.target.checked) } + /> + setAllowStruct(event.target.checked) } + /> + setAllowTerm(event.target.checked) } + /> + setAllowAxiom(event.target.checked) } + /> + setAllowFunction(event.target.checked) } + /> + setAllowPredicate(event.target.checked) } + /> + setAllowConstant(event.target.checked) } + /> + setAllowTheorem(event.target.checked) } + /> +
+
+
+ ); +} + +export default DlgGraphOptions; diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx index 5c6afa2e..9fff700d 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx @@ -157,93 +157,92 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps) setSelected(selectedRows.map(cst => cst.id)); }, [setSelected]); - const columns = useMemo(() => - [ - { - name: 'ID', - id: 'id', - selector: (cst: IConstituenta) => cst.id, - omit: true - }, - { - name: 'Имя', - id: 'alias', - selector: (cst: IConstituenta) => cst.alias, - cell: (cst: IConstituenta) => { - const info = mapStatusInfo.get(cst.status)!; - return (<> -
- {cst.alias} -
- -

Статус: {info.tooltip}

-
- ); - }, - width: '65px', - maxWidth: '65px', - reorder: true, - }, - { - name: 'Тип', - id: 'type', - cell: (cst: IConstituenta) =>
{getCstTypificationLabel(cst)}
, - width: '175px', - maxWidth: '175px', - wrap: true, - reorder: true, - hide: 1600 - }, - { - name: 'Термин', - id: 'term', - selector: (cst: IConstituenta) => cst.term?.resolved ?? cst.term?.raw ?? '', - width: '350px', - minWidth: '150px', - maxWidth: '350px', - wrap: true, - reorder: true - }, - { - name: 'Формальное определение', - id: 'expression', - selector: (cst: IConstituenta) => cst.definition?.formal ?? '', - minWidth: '300px', - maxWidth: '500px', - grow: 2, - wrap: true, - reorder: true - }, - { - name: 'Текстовое определение', - id: 'definition', - cell: (cst: IConstituenta) => ( -
- {cst.definition?.text.resolved ?? cst.definition?.text.raw ?? ''} + const columns = useMemo( + () => [ + { + name: 'ID', + id: 'id', + selector: (cst: IConstituenta) => cst.id, + omit: true + }, + { + name: 'Имя', + id: 'alias', + selector: (cst: IConstituenta) => cst.alias, + cell: (cst: IConstituenta) => { + const info = mapStatusInfo.get(cst.status)!; + return (<> +
+ {cst.alias}
- ), - minWidth: '200px', - grow: 2, - wrap: true, - reorder: true + +

Статус: {info.tooltip}

+
+ ); }, - { - name: 'Конвенция / Комментарий', - id: 'convention', - cell: (cst: IConstituenta) =>
{cst.convention ?? ''}
, - minWidth: '100px', - wrap: true, - reorder: true, - hide: 1800 - } - ], [] - ); + width: '65px', + maxWidth: '65px', + reorder: true, + }, + { + name: 'Тип', + id: 'type', + cell: (cst: IConstituenta) =>
{getCstTypificationLabel(cst)}
, + width: '175px', + maxWidth: '175px', + wrap: true, + reorder: true, + hide: 1600 + }, + { + name: 'Термин', + id: 'term', + selector: (cst: IConstituenta) => cst.term?.resolved ?? cst.term?.raw ?? '', + width: '350px', + minWidth: '150px', + maxWidth: '350px', + wrap: true, + reorder: true + }, + { + name: 'Формальное определение', + id: 'expression', + selector: (cst: IConstituenta) => cst.definition?.formal ?? '', + minWidth: '300px', + maxWidth: '500px', + grow: 2, + wrap: true, + reorder: true + }, + { + name: 'Текстовое определение', + id: 'definition', + cell: (cst: IConstituenta) => ( +
+ {cst.definition?.text.resolved ?? cst.definition?.text.raw ?? ''} +
+ ), + minWidth: '200px', + grow: 2, + wrap: true, + reorder: true + }, + { + name: 'Конвенция / Комментарий', + id: 'convention', + cell: (cst: IConstituenta) =>
{cst.convention ?? ''}
, + minWidth: '100px', + wrap: true, + reorder: true, + hide: 1800 + } + ], []); return (
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx index 52e0bb91..d4bb4b33 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx @@ -8,19 +8,22 @@ import Checkbox from '../../components/Common/Checkbox'; import ConceptSelect from '../../components/Common/ConceptSelect'; import ConceptTooltip from '../../components/Common/ConceptTooltip'; import Divider from '../../components/Common/Divider'; +import MiniButton from '../../components/Common/MiniButton'; import ConstituentaInfo from '../../components/Help/ConstituentaInfo'; +import CstClassInfo from '../../components/Help/CstClassInfo'; import CstStatusInfo from '../../components/Help/CstStatusInfo'; -import { ArrowsRotateIcon, HelpIcon } from '../../components/Icons'; +import { ArrowsRotateIcon, FilterCogIcon, HelpIcon } from '../../components/Icons'; import { useRSForm } from '../../context/RSFormContext'; import { useConceptTheme } from '../../context/ThemeContext'; import useLocalStorage from '../../hooks/useLocalStorage'; import { prefixes, resources } from '../../utils/constants'; import { Graph } from '../../utils/Graph'; -import { IConstituenta } from '../../utils/models'; -import { getCstStatusColor, getCstTypeColor, +import { CstType, IConstituenta } from '../../utils/models'; +import { getCstClassColor, getCstStatusColor, GraphColoringSelector, GraphLayoutSelector, - mapColoringLabels, mapLayoutLabels, mapStatusInfo + mapColoringLabels, mapLayoutLabels } from '../../utils/staticUI'; +import DlgGraphOptions from './DlgGraphOptions'; import ConstituentaTooltip from './elements/ConstituentaTooltip'; export type ColoringScheme = 'none' | 'status' | 'type'; @@ -28,12 +31,27 @@ const TREE_SIZE_MILESTONE = 50; function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, darkMode: boolean): string { if (coloringScheme === 'type') { - return getCstTypeColor(cst.cstType, darkMode); + return getCstClassColor(cst.cstClass, darkMode); } if (coloringScheme === 'status') { return getCstStatusColor(cst.status, darkMode); } - return ''; + return (darkMode ? '#7a8c9e' :'#7ca0ab'); +} + +export interface GraphEditorParams { + noHermits: boolean + noTransitive: boolean + noTemplates: boolean + + allowBase: boolean + allowStruct: boolean + allowTerm: boolean + allowAxiom: boolean + allowFunction: boolean + allowPredicate: boolean + allowConstant: boolean + allowTheorem: boolean } interface EditorTermGraphProps { @@ -49,13 +67,24 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { const [ layout, setLayout ] = useLocalStorage('graph_layout', 'treeTd2d'); const [ coloringScheme, setColoringScheme ] = useLocalStorage('graph_coloring', 'none'); const [ orbit, setOrbit ] = useState(false); + const [ noHermits, setNoHermits ] = useLocalStorage('graph_no_hermits', true); const [ noTransitive, setNoTransitive ] = useLocalStorage('graph_no_transitive', false); + const [ noTemplates, setNoTemplates ] = useLocalStorage('graph_no_templates', false); + const [ allowBase, setAllowBase ] = useLocalStorage('graph_allow_base', true); + const [ allowStruct, setAllowStruct ] = useLocalStorage('graph_allow_struct', true); + const [ allowTerm, setAllowTerm ] = useLocalStorage('graph_allow_term', true); + const [ allowAxiom, setAllowAxiom ] = useLocalStorage('graph_allow_axiom', true); + const [ allowFunction, setAllowFunction ] = useLocalStorage('function', true); + const [ allowPredicate, setAllowPredicate ] = useLocalStorage('graph_allow_predicate', true); + const [ allowConstant, setAllowConstant ] = useLocalStorage('graph_allow_constant', true); + const [ allowTheorem, setAllowTheorem ] = useLocalStorage('graph_allow_theorem', true); const [ filtered, setFiltered ] = useState(new Graph()); const [ dismissed, setDismissed ] = useState([]); const [ selectedDismissed, setSelectedDismissed ] = useState([]); const graphRef = useRef(null); + const [showOptions, setShowOptions] = useState(false); const [hoverID, setHoverID] = useState(undefined); const hoverCst = useMemo( @@ -64,6 +93,19 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { }, [schema?.items, hoverID]); const is3D = useMemo(() => layout.includes('3d'), [layout]); + const allowedTypes: CstType[] = useMemo( + () => { + const result: CstType[] = []; + if (allowBase) result.push(CstType.BASE); + if (allowStruct) result.push(CstType.STRUCTURED); + if (allowTerm) result.push(CstType.TERM); + if (allowAxiom) result.push(CstType.AXIOM); + if (allowFunction) result.push(CstType.FUNCTION); + if (allowPredicate) result.push(CstType.PREDICATE); + if (allowConstant) result.push(CstType.CONSTANT); + if (allowTheorem) result.push(CstType.THEOREM); + return result; + }, [allowBase, allowStruct, allowTerm, allowAxiom, allowFunction, allowPredicate, allowConstant, allowTheorem]); useEffect( () => { @@ -78,6 +120,20 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { if (noTransitive) { graph.transitiveReduction(); } + if (noTemplates) { + schema.items.forEach(cst => { + if (cst.isTemplate) { + graph.foldNode(cst.id); + } + }); + } + if (allowedTypes.length < Object.values(CstType).length) { + schema.items.forEach(cst => { + if (!allowedTypes.includes(cst.cstType)) { + graph.foldNode(cst.id); + } + }); + } const newDismissed: number[] = []; schema.items.forEach(cst => { if (!graph.nodes.has(cst.id)) { @@ -88,7 +144,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { setDismissed(newDismissed); setSelectedDismissed([]); setHoverID(undefined); - }, [schema, noHermits, noTransitive]); + }, [schema, noHermits, noTransitive, noTemplates, allowedTypes]); function toggleDismissed(cstID: number) { setSelectedDismissed(prev => { @@ -153,7 +209,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { focusOnSelect: false }); - const handleCenter = useCallback( + const handleRecreate = useCallback( () => { graphRef.current?.resetControls(); graphRef.current?.centerGraph(); @@ -180,6 +236,41 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { if (onNodeClick) onNodeClick(node); }, [onNodeClick, selections, onOpenEdit]); + function getOptions() { + return { + noHermits: noHermits, + noTemplates: noTemplates, + noTransitive: noTransitive, + + allowBase: allowBase, + allowStruct: allowStruct, + allowTerm: allowTerm, + allowAxiom: allowAxiom, + allowFunction: allowFunction, + allowPredicate: allowPredicate, + allowConstant: allowConstant, + allowTheorem: allowTheorem + } + } + + const handleChangeOptions = useCallback( + (params: GraphEditorParams) => { + setNoHermits(params.noHermits); + setNoTransitive(params.noTransitive); + setNoTemplates(params.noTemplates); + + setAllowBase(params.allowBase); + setAllowStruct(params.allowStruct); + setAllowTerm(params.allowTerm); + setAllowAxiom(params.allowAxiom); + setAllowFunction(params.allowFunction); + setAllowPredicate(params.allowPredicate); + setAllowConstant(params.allowConstant); + setAllowTheorem(params.allowTheorem); + }, [setNoHermits, setNoTransitive, setNoTemplates, + setAllowBase, setAllowStruct, setAllowTerm, setAllowAxiom, setAllowFunction, + setAllowPredicate, setAllowConstant, setAllowTheorem]); + const canvasWidth = useMemo( () => { return 'calc(100vw - 14.6rem)'; @@ -199,6 +290,12 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { return (
+ {showOptions && + setShowOptions(false)} + initial={getOptions()} + onConfirm={handleChangeOptions} + />}
{hoverCst &&
@@ -209,11 +306,11 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
}