LABEL_THRESHOLD ? FONT_SIZE_MED : FONT_SIZE_MAX
}}
data-tooltip-id={globalIDs.tooltip}
- data-tooltip-html={describeCstNode(node.data.cst)}
+ data-tooltip-html={describeCstNode(node.data)}
+ data-tooltip-hidden={node.dragging}
+ onContextMenu={handleContextMenu}
+ onDoubleClick={handleDoubleClick}
>
DESCRIPTION_THRESHOLD ? FONT_SIZE_MIN : FONT_SIZE_MED
}}
+ onContextMenu={handleContextMenu}
+ onDoubleClick={handleDoubleClick}
>
{description}
diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/useFilteredGraph.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/useFilteredGraph.tsx
new file mode 100644
index 00000000..cfaaf083
--- /dev/null
+++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/useFilteredGraph.tsx
@@ -0,0 +1,74 @@
+import { CstType } from '../../../backend/types';
+import { type IConstituenta, type IRSForm } from '../../../models/rsform';
+import { type GraphFilterParams, useTermGraphStore } from '../../../stores/termGraph';
+import { useRSEdit } from '../RSEditContext';
+
+export function useFilteredGraph() {
+ const { schema, focusCst } = useRSEdit();
+ const filter = useTermGraphStore(state => state.filter);
+
+ const filteredGraph = produceFilteredGraph(schema, filter, focusCst);
+ const hidden = schema.items.filter(cst => !filteredGraph.hasNode(cst.id)).map(cst => cst.id);
+
+ return { filteredGraph, hidden };
+}
+
+// ====== Internals =========
+function produceFilteredGraph(schema: IRSForm, params: GraphFilterParams, focusCst: IConstituenta | null) {
+ const filtered = schema.graph.clone();
+ const allowedTypes: CstType[] = (() => {
+ const result: CstType[] = [];
+ if (params.allowBase) result.push(CstType.BASE);
+ if (params.allowStruct) result.push(CstType.STRUCTURED);
+ if (params.allowTerm) result.push(CstType.TERM);
+ if (params.allowAxiom) result.push(CstType.AXIOM);
+ if (params.allowFunction) result.push(CstType.FUNCTION);
+ if (params.allowPredicate) result.push(CstType.PREDICATE);
+ if (params.allowConstant) result.push(CstType.CONSTANT);
+ if (params.allowTheorem) result.push(CstType.THEOREM);
+ return result;
+ })();
+
+ if (params.noHermits) {
+ filtered.removeIsolated();
+ }
+ if (params.noTemplates) {
+ schema.items.forEach(cst => {
+ if (cst !== focusCst && cst.is_template) {
+ filtered.foldNode(cst.id);
+ }
+ });
+ }
+ if (allowedTypes.length < Object.values(CstType).length) {
+ schema.items.forEach(cst => {
+ if (cst !== focusCst && !allowedTypes.includes(cst.cst_type)) {
+ filtered.foldNode(cst.id);
+ }
+ });
+ }
+ if (!focusCst && params.foldDerived) {
+ schema.items.forEach(cst => {
+ if (cst.spawner) {
+ filtered.foldNode(cst.id);
+ }
+ });
+ }
+ if (focusCst) {
+ const includes: number[] = [
+ focusCst.id,
+ ...focusCst.spawn,
+ ...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []),
+ ...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : [])
+ ];
+ schema.items.forEach(cst => {
+ if (!includes.includes(cst.id)) {
+ filtered.foldNode(cst.id);
+ }
+ });
+ }
+ if (params.noTransitive) {
+ filtered.transitiveReduction();
+ }
+
+ return filtered;
+}
diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSEditContext.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSEditContext.tsx
index decc8410..aac219da 100644
--- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSEditContext.tsx
+++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSEditContext.tsx
@@ -31,6 +31,7 @@ export enum RSTabID {
export interface IRSEditContext {
schema: IRSForm;
selected: number[];
+ focusCst: IConstituenta | null;
activeCst: IConstituenta | null;
activeVersion?: number;
@@ -48,6 +49,7 @@ export interface IRSEditContext {
deleteSchema: () => void;
+ setFocus: (newValue: IConstituenta | null) => void;
setSelected: React.Dispatch>;
select: (target: number) => void;
deselect: (target: number) => void;
@@ -103,6 +105,7 @@ export const RSEditState = ({
const [selected, setSelected] = useState([]);
const canDeleteSelected = selected.length > 0 && selected.every(id => !schema.cstByID.get(id)?.is_inherited);
+ const [focusCst, setFocusCst] = useState(null);
const activeCst = selected.length === 0 ? null : schema.cstByID.get(selected[selected.length - 1])!;
@@ -125,6 +128,11 @@ export const RSEditState = ({
[schema, adjustRole, isOwned, user, adminMode]
);
+ function handleSetFocus(newValue: IConstituenta | null) {
+ setFocusCst(newValue);
+ setSelected([]);
+ }
+
function navigateVersion(versionID?: number) {
router.push(urls.schema(schema.id, versionID));
}
@@ -311,6 +319,7 @@ export const RSEditState = ({
setSelected(prev => [...prev, target]),
deselect: (target: number) => setSelected(prev => prev.filter(id => id !== target)),
diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx
index 0559304d..6ad02335 100644
--- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx
+++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx
@@ -29,7 +29,7 @@ export function RSTabs({ activeID, activeTab }: RSTabsProps) {
const hideFooter = useAppLayoutStore(state => state.hideFooter);
const { setIsModified } = useModificationStore();
- const { schema, selected, setSelected, navigateRSForm } = useRSEdit();
+ const { schema, selected, setSelected, deselectAll, navigateRSForm } = useRSEdit();
useLayoutEffect(() => {
const oldTitle = document.title;
@@ -46,11 +46,11 @@ export function RSTabs({ activeID, activeTab }: RSTabsProps) {
if (activeID && schema.cstByID.has(activeID)) {
setSelected([activeID]);
} else {
- setSelected([]);
+ deselectAll();
}
}
return () => hideFooter(false);
- }, [activeTab, activeID, setSelected, schema, hideFooter, setIsModified]);
+ }, [activeTab, activeID, setSelected, deselectAll, schema, hideFooter, setIsModified]);
function onSelectTab(index: number, last: number, event: Event) {
if (last === index) {