import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { RootState } from './store'; import { MultiGraph } from 'graphology'; import { QueryMultiGraphology as QueryGraphology } from '../../querybuilder/model/graphology/utils'; import { isEqual } from 'lodash-es'; import { Graph, Query, QueryBuilderSettings, GraphQueryTranslationResultMessage, QueryGraphEdgeHandle, QueryMultiGraph, QueryUnionType, } from 'ts-common'; const defaultGraph: () => Graph = () => ({ nodes: [], edges: [], attributes: {}, options: {} }); export type QueryBuilderAttributeBeingShown = object; export type QueryBuilderState = Query & { ignoreReactivity: boolean; queryTranslation: GraphQueryTranslationResultMessage; }; export type SchemaState = { id?: number; settings: Record<string, any>; }; // Define the initial state using that type export const initialState: QueryBuilderState = { graph: defaultGraph(), ignoreReactivity: false, settings: { limit: 500, depth: { min: 1, max: 1 }, layout: 'manual', autocompleteRelation: true, unionTypes: {}, }, queryTranslation: { queryID: '', result: '', }, attributesBeingShown: [], // schemaLayout: 'Graphology_noverlap', } as QueryBuilderState; export const querybuilderSlice = createSlice({ name: 'querybuilder', initialState, reducers: { setQuerybuilderGraph: (state: QueryBuilderState, action: PayloadAction<QueryMultiGraph>) => { state.graph = action.payload; state.ignoreReactivity = false; }, /** * Sets the querybuilder nodes, settings, and attributes being shown, * if the payload contains the required information. * @param {QueryBuilderState} action.payload the payload with the new state */ setQuerybuilderNodes: (state: QueryBuilderState, action: PayloadAction<Query>) => { if (action.payload.graph?.nodes && action.payload.graph?.edges) { state.graph = action.payload.graph; state.settings = action.payload.settings; state.attributesBeingShown = action.payload.attributesBeingShown || []; // state.ignoreReactivity = true; } }, clearQB: (state: QueryBuilderState) => { state.graph = defaultGraph(); }, setQuerybuilderSettings: (state: QueryBuilderState, action: PayloadAction<QueryBuilderSettings>) => { state.settings = action.payload; }, setQueryText: (state: QueryBuilderState, action: PayloadAction<GraphQueryTranslationResultMessage>) => { state.queryTranslation = action.payload; }, attributeShownToggle: (state: QueryBuilderState, action: PayloadAction<QueryGraphEdgeHandle>) => { const existing = state.attributesBeingShown.findIndex(a => isEqual(a, action.payload)); if (existing === -1) { state.attributesBeingShown.push(action.payload); } else { state.attributesBeingShown.splice(existing, 1); } }, setQueryUnionType: (state: QueryBuilderState, action: PayloadAction<{ nodeId: string; unionType: QueryUnionType }>) => { if (state.settings.unionTypes == null) { state.settings.unionTypes = {}; } state.settings.unionTypes[action.payload.nodeId] = action.payload.unionType; }, }, }); export const queryBuilderState = (state: RootState): QueryBuilderState => state.querybuilder; export const queryBuilderSettingsState = (state: RootState): QueryBuilderSettings => state.querybuilder.settings; export const setQuerybuilderGraphology = (payload: QueryGraphology) => { return querybuilderSlice.actions.setQuerybuilderGraph(payload.export()); }; /** Select the querybuilder nodes in serialized fromat */ export const toQuerybuilderGraphology = (graph: QueryMultiGraph): QueryGraphology => { const ret = new QueryGraphology(); ret.import(MultiGraph.from(graph).export()); return ret; }; /** Select the querybuilder nodes and convert it to a graphology object */ export const selectQuerybuilderGraph = (state: RootState): QueryMultiGraph => { // This is really weird but for some reason all the attributes appeared as read-only otherwise return state.querybuilder.graph as QueryMultiGraph; }; /** Select the querybuilder nodes and convert it to a graphology object */ export const selectQuerybuilderHash = (state: RootState): string => { const hashedNodes = state.querybuilder.graph.nodes.map(n => { const node = { ...n }; if (n?.attributes) { const newAttributes = { ...n?.attributes }; newAttributes.x = 0; newAttributes.y = 0; newAttributes.height = 0; newAttributes.width = 0; node.attributes = newAttributes; } return node; }); return JSON.stringify({ nodes: hashedNodes, edges: state.querybuilder.graph.edges.map(n => ({ key: n.key, source: n.source, target: n.target, })), }); }; // /** // * selects the SchemaLayout enum // * @param {GraphLayout} state // * @returns {GraphLayout} enum of type GraphLayout // */ // export const selectSchemaLayout = (state: RootState) => // state.schema.schemaLayout; export default querybuilderSlice.reducer; export const { setQuerybuilderGraph, clearQB, setQuerybuilderSettings, setQuerybuilderNodes, setQueryText, attributeShownToggle, setQueryUnionType, } = querybuilderSlice.actions; export const queryBuilderAttributesShown = (state: RootState) => state.querybuilder.attributesBeingShown;