From b26fa7848c6fe41303b8f52584957d101d34ab4e Mon Sep 17 00:00:00 2001
From: Dennis Collaris <d.collaris@me.com>
Date: Thu, 7 Nov 2024 18:22:43 +0100
Subject: [PATCH] feat: persist union types

---
 apps/web/src/app/App.tsx                            |  4 +---
 libs/shared/lib/data-access/api/eventBus.tsx        |  5 +----
 libs/shared/lib/data-access/store/hooks.ts          |  2 --
 .../lib/data-access/store/querybuilderSlice.ts      | 13 +++++++------
 libs/shared/lib/querybuilder/panel/ContextMenu.tsx  |  9 +++++----
 .../customFlowPills/entitypill/QueryEntityPill.tsx  |  5 +++--
 .../relationpill/QueryRelationPill.tsx              |  4 ++--
 7 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/apps/web/src/app/App.tsx b/apps/web/src/app/App.tsx
index 215d4ec57..6770b4382 100644
--- a/apps/web/src/app/App.tsx
+++ b/apps/web/src/app/App.tsx
@@ -6,7 +6,6 @@ import {
   useQuerybuilderGraph,
   useQuerybuilderSettings,
   useSessionCache,
-  useQuerybuilderUnionTypes,
 } from '@graphpolaris/shared/lib/data-access';
 import { addError, setCurrentTheme } from '@graphpolaris/shared/lib/data-access/store/configSlice';
 import { resetGraphQueryResults, queryingBackend } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
@@ -39,7 +38,6 @@ export function App(props: App) {
   const dispatch = useAppDispatch();
   const queryBuilderSettings = useQuerybuilderSettings();
   const [monitoringOpen, setMonitoringOpen] = useState<boolean>(false);
-  const unionTypes = useQuerybuilderUnionTypes();
 
   const runQuery = () => {
     if (session?.currentSaveState && query) {
@@ -47,7 +45,7 @@ export function App(props: App) {
         dispatch(resetGraphQueryResults());
       } else {
         dispatch(queryingBackend());
-        wsQueryRequest(Query2BackendQuery(session.currentSaveState, query, queryBuilderSettings, ml, unionTypes));
+        wsQueryRequest(Query2BackendQuery(session.currentSaveState, query, queryBuilderSettings, ml, queryBuilderSettings.unionTypes));
       }
     }
   };
diff --git a/libs/shared/lib/data-access/api/eventBus.tsx b/libs/shared/lib/data-access/api/eventBus.tsx
index d48c70bc6..fb61c6fe5 100644
--- a/libs/shared/lib/data-access/api/eventBus.tsx
+++ b/libs/shared/lib/data-access/api/eventBus.tsx
@@ -14,14 +14,12 @@ import {
   wsSchemaSubscription,
   useQuerybuilderAttributesShown,
   wsSchemaStatsRequest,
-  useQuerybuilderUnionTypes,
 } from '@graphpolaris/shared/lib/data-access';
 import { Broker, wsQuerySubscription, wsQueryTranslationSubscription } from '@graphpolaris/shared/lib/data-access/broker';
 import { addInfo } from '@graphpolaris/shared/lib/data-access/store/configSlice';
 import { allMLTypes, LinkPredictionInstance, setMLResult } from '@graphpolaris/shared/lib/data-access/store/mlSlice';
 import {
   QueryBuilderText,
-  queryUnionTypes,
   setQueryText,
   setQuerybuilderNodes,
 } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
@@ -70,7 +68,6 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }
   const mlHash = useMLEnabledHash();
   const visState = useVisualization();
   const queryBuilderSettings = useQuerybuilderSettings();
-  const unionTypes = useQuerybuilderUnionTypes();
 
   function loadSaveState(saveStateID: string | undefined, saveStates: Record<string, SaveStateI>) {
     if (saveStateID && saveStates && saveStateID in saveStates) {
@@ -291,7 +288,7 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }
       //   body: { type: 'query_builder_state', status: '', value: queryBuilder },
       // });
     }
-  }, [queryHash, mlHash, queryBuilderSettings, unionTypes]);
+  }, [queryHash, mlHash, queryBuilderSettings, queryBuilderSettings.unionTypes]);
 
   return <div className="hide"></div>;
 };
diff --git a/libs/shared/lib/data-access/store/hooks.ts b/libs/shared/lib/data-access/store/hooks.ts
index 16fc370b5..7df070ec3 100644
--- a/libs/shared/lib/data-access/store/hooks.ts
+++ b/libs/shared/lib/data-access/store/hooks.ts
@@ -20,7 +20,6 @@ import {
   queryBuilderState,
   selectQuerybuilderGraph,
   selectQuerybuilderHash,
-  queryUnionTypes,
   QueryUnionType
 } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
 import { activeSaveState, activeSaveStateAuthorization, SessionCacheI, sessionCacheState } from './sessionSlice';
@@ -69,7 +68,6 @@ export const useQuerybuilderHash: () => string = () => useAppSelector(selectQuer
 export const useQuerybuilderSettings: () => QueryBuilderSettings = () => useAppSelector(queryBuilderSettingsState);
 export const useQuerybuilder: () => QueryBuilderState = () => useAppSelector(queryBuilderState);
 export const useQuerybuilderAttributesShown: () => QueryGraphEdgeHandle[] = () => useAppSelector(queryBuilderAttributesShown);
-export const useQuerybuilderUnionTypes: () => {[nodeId: string]: QueryUnionType} = () => useAppSelector(queryUnionTypes);
 
 // Overall Configuration of the app
 export const useConfig: () => ConfigStateI = () => useAppSelector(configState);
diff --git a/libs/shared/lib/data-access/store/querybuilderSlice.ts b/libs/shared/lib/data-access/store/querybuilderSlice.ts
index d6b771370..79dba6327 100644
--- a/libs/shared/lib/data-access/store/querybuilderSlice.ts
+++ b/libs/shared/lib/data-access/store/querybuilderSlice.ts
@@ -13,6 +13,7 @@ export type QueryBuilderSettings = {
   depth: { min: number; max: number };
   layout: AllLayoutAlgorithms | 'manual';
   autocompleteRelation: boolean;
+  unionTypes: { [nodeId: string]: QueryUnionType };
 };
 
 export type QueryBuilderText = {
@@ -33,7 +34,6 @@ export type QueryBuilderState = {
   settings: QueryBuilderSettings;
   queryTranslation: QueryBuilderText;
   attributesBeingShown: QueryGraphEdgeHandle[];
-  unionTypes: { [nodeId: string]: QueryUnionType };
 };
 
 export type SchemaState = {
@@ -49,13 +49,13 @@ export const initialState: QueryBuilderState = {
     depth: { min: 1, max: 1 },
     layout: 'manual',
     autocompleteRelation: true,
+    unionTypes: {},
   },
   queryTranslation: {
     queryId: '',
     result: '',
   },
   attributesBeingShown: [],
-  unionTypes: {},
   // schemaLayout: 'Graphology_noverlap',
 } as QueryBuilderState;
 
@@ -100,7 +100,10 @@ export const querybuilderSlice = createSlice({
       }
     },
     setQueryUnionType: (state: QueryBuilderState, action: PayloadAction<{ nodeId: string; unionType: QueryUnionType }>) => {
-      state.unionTypes[action.payload.nodeId] = action.payload.unionType;
+      if (state.settings.unionTypes == null) {
+        state.settings.unionTypes = {};
+      }
+      state.settings.unionTypes[action.payload.nodeId] = action.payload.unionType;
     },
   },
 });
@@ -169,6 +172,4 @@ export const {
   setQueryUnionType,
 } = querybuilderSlice.actions;
 
-export const queryBuilderAttributesShown = (state: RootState) => state.querybuilder.attributesBeingShown;
-
-export const queryUnionTypes = (state: RootState) => state.querybuilder.unionTypes;
+export const queryBuilderAttributesShown = (state: RootState) => state.querybuilder.attributesBeingShown;
\ No newline at end of file
diff --git a/libs/shared/lib/querybuilder/panel/ContextMenu.tsx b/libs/shared/lib/querybuilder/panel/ContextMenu.tsx
index 283b18e2b..020d9130b 100644
--- a/libs/shared/lib/querybuilder/panel/ContextMenu.tsx
+++ b/libs/shared/lib/querybuilder/panel/ContextMenu.tsx
@@ -7,7 +7,7 @@ import {
   useQuerybuilderAttributesShown,
   useQuerybuilderGraph,
   useQuerybuilderHash,
-  useQuerybuilderUnionTypes,
+  useQuerybuilderSettings
 } from '../..';
 import { isEqual } from 'lodash-es';
 import {
@@ -31,6 +31,8 @@ export const ContextMenu = (props: {
   const dispatch = useAppDispatch();
   const graph = useQuerybuilderGraph();
   const qbHash = useQuerybuilderHash();
+  const settings = useQuerybuilderSettings();
+  const unionType = settings.unionTypes == null || props.node == null ? QueryUnionType.AND : settings.unionTypes[props.node.id];
 
   const graphologyGraph = useMemo(() => toQuerybuilderGraphology(graph), [graph, qbHash]);
 
@@ -69,7 +71,6 @@ export const ContextMenu = (props: {
     dispatch(attributeShownToggle(attribute.handleData));
   }
 
-  const unionType = useQuerybuilderUnionTypes();
   function setUnionType(unionType: QueryUnionType) {
     if (!props.node) return;
     dispatch(setQueryUnionType({ nodeId: props.node.id, unionType: unionType }));
@@ -125,12 +126,12 @@ export const ContextMenu = (props: {
             <DropdownItem
               value="AND"
               onClick={(_) => setUnionType(QueryUnionType.AND)}
-              selected={props.node ? unionType[props.node.id] != QueryUnionType.OR : false} // Also selected when null
+              selected={props.node ? unionType != QueryUnionType.OR : false} // Also selected when null
             />,
             <DropdownItem
               value="OR"
               onClick={(_) => setUnionType(QueryUnionType.OR)}
-              selected={props.node ? unionType[props.node.id] == QueryUnionType.OR : false}
+              selected={props.node ? unionType == QueryUnionType.OR : false}
             />,
           ]}
         />
diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/QueryEntityPill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/QueryEntityPill.tsx
index 5fd9ea36d..8a535d9fa 100644
--- a/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/QueryEntityPill.tsx
+++ b/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/QueryEntityPill.tsx
@@ -2,7 +2,7 @@ import {
   useQuerybuilderAttributesShown,
   useQuerybuilderGraph,
   useQuerybuilderHash,
-  useQuerybuilderUnionTypes,
+  useQuerybuilderSettings,
 } from '@graphpolaris/shared/lib/data-access';
 import {
   setQuerybuilderGraphology,
@@ -38,9 +38,10 @@ export const QueryEntityPill = React.memo((node: SchemaReactflowEntityNode) => {
     () => graph.edges.filter((edge) => edge.source === node.id && !!edge?.attributes?.sourceHandleData.attributeType),
     [graph],
   );
+  const settings = useQuerybuilderSettings();
 
   const uniqueAttributes = useMemo(() => uniqBy(data.attributes, (attr) => attr.handleData.attributeName), [data.attributes]);
-  const unionType = useQuerybuilderUnionTypes()[node.id];
+  const unionType = settings.unionTypes == null ? QueryUnionType.AND : settings.unionTypes[node.id];
 
   return (
     <div className="w-fit h-fit nowheel" ref={ref} id="asd">
diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
index de647855b..93252a7e2 100644
--- a/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
+++ b/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
@@ -4,13 +4,13 @@ import {
   useAppDispatch,
   useQuerybuilderGraph,
   useQuerybuilderSettings,
-  useQuerybuilderUnionTypes,
 } from '@graphpolaris/shared/lib/data-access';
 import { addWarning } from '@graphpolaris/shared/lib/data-access/store/configSlice';
 import {
   setQuerybuilderGraphology,
   toQuerybuilderGraphology,
   attributeShownToggle,
+  QueryUnionType
 } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
 import { PillAttributes } from '../../pillattributes/PillAttributes';
 import {
@@ -91,7 +91,7 @@ export const QueryRelationPill = memo((node: SchemaReactflowRelationNode) => {
     dispatch(attributeShownToggle(attribute.handleData));
   }
 
-  const unionType = useQuerybuilderUnionTypes()[node.id];
+  const unionType = settings.unionTypes == null ? QueryUnionType.AND : settings.unionTypes[node.id];
 
   const attributesBeingShown = useQuerybuilderAttributesShown();
   function isAttributeAdded(attribute: NodeAttribute): boolean {
-- 
GitLab