diff --git a/libs/shared/lib/graph-layout/graphology-layouts.ts b/libs/shared/lib/graph-layout/graphology-layouts.ts index 46960915b48f8579aef6e6306c6ead6e2a35d036..4074a90cc0a40e01791ea638e3dfd34799182bab 100644 --- a/libs/shared/lib/graph-layout/graphology-layouts.ts +++ b/libs/shared/lib/graph-layout/graphology-layouts.ts @@ -70,7 +70,7 @@ export class GraphologyCircular extends GraphologyLayout { public override async layout( graph: Graph<Attributes, Attributes, Attributes>, - boundingBox?: { x1: number; x2: number; y1: number; y2: number } + boundingBox?: { x1: number; x2: number; y1: number; y2: number }, ): Promise<void> { super.layout(graph, boundingBox); // To directly assign the positions to the nodes: @@ -91,15 +91,16 @@ export class GraphologyRandom extends GraphologyLayout { public override async layout( graph: Graph<Attributes, Attributes, Attributes>, - boundingBox?: { x1: number; x2: number; y1: number; y2: number } + boundingBox?: { x1: number; x2: number; y1: number; y2: number }, ): Promise<void> { super.layout(graph, boundingBox); // const positions = random(graph); // To directly assign the positions to the nodes: random.assign(graph, { - scale: graph.order * 10, + scale: graph.order * 1.5, ...this.defaultLayoutSettings, + center: 0, }); } } @@ -126,7 +127,7 @@ export class GraphologyNoverlap extends GraphologyLayout { public override async layout( graph: Graph<Attributes, Attributes, Attributes>, - boundingBox?: { x1: number; x2: number; y1: number; y2: number } + boundingBox?: { x1: number; x2: number; y1: number; y2: number }, ): Promise<void> { super.layout(graph, boundingBox); // To directly assign the positions to the nodes: @@ -168,7 +169,7 @@ export class GraphologyForceAtlas2 extends GraphologyLayout { public override async layout( graph: Graph<Attributes, Attributes, Attributes>, - boundingBox?: { x1: number; x2: number; y1: number; y2: number } + boundingBox?: { x1: number; x2: number; y1: number; y2: number }, ): Promise<void> { super.layout(graph, boundingBox); @@ -189,17 +190,20 @@ export class GraphologyForceAtlas2Webworker extends GraphologyLayout { super('Graphology_forceAtlas2_webworker'); } - public override layout( + public override async layout( graph: Graph<Attributes, Attributes, Attributes>, - boundingBox?: { x1: number; x2: number; y1: number; y2: number } - ): void { + boundingBox?: { x1: number; x2: number; y1: number; y2: number }, + ): Promise<void> { super.layout(graph, boundingBox); const sensibleSettings = forceAtlas2.inferSettings(graph); + console.log(sensibleSettings); + const layout = new FA2Layout(graph, { settings: { ...this.defaultLayoutSettings, ...sensibleSettings, + adjustSizes: graph.order < 300 ? true : false, }, }); layout.start(); @@ -207,6 +211,6 @@ export class GraphologyForceAtlas2Webworker extends GraphologyLayout { // stop the layout after 5 seconds setTimeout(() => { layout.stop(); - }, 10000); + }, 20000); } } diff --git a/libs/shared/lib/vis/visualizationManager.tsx b/libs/shared/lib/vis/visualizationManager.tsx index 1167e74a4b0c370458bb0517234ed9458b5c94f5..12b474b332630d2895e6fbb691ac878c06199d20 100644 --- a/libs/shared/lib/vis/visualizationManager.tsx +++ b/libs/shared/lib/vis/visualizationManager.tsx @@ -85,18 +85,16 @@ export const VisualizationManager = () => { try { return ( vis.activeVisualization && ( - <div className="w-full h-full"> - <visualizationComponent.VIS - data={graphQueryResult} - schema={schema} - ml={ml} - dispatch={dispatch} - globalConfig={globalConfig} - settings={visSettings} - encodings={visEncodings} - interactions={visInteractions} - /> - </div> + <visualizationComponent.VIS + data={graphQueryResult} + schema={schema} + ml={ml} + dispatch={dispatch} + globalConfig={globalConfig} + settings={visSettings} + encodings={visEncodings} + interactions={visInteractions} + /> ) ); } catch (error) { diff --git a/libs/shared/lib/vis/visualizationPanel.tsx b/libs/shared/lib/vis/visualizationPanel.tsx index ab722fc2c3c9fadaa52e4bb66ce61fe440aed42b..7a42403afc916cd67b8b4397baf40fa90a549d8e 100644 --- a/libs/shared/lib/vis/visualizationPanel.tsx +++ b/libs/shared/lib/vis/visualizationPanel.tsx @@ -103,9 +103,7 @@ export const VisualizationPanel = () => { {query.nodes.length > 0 ? <p>Query resulted in empty dataset</p> : <p>Query for data to visualize</p>} </div> ) : ( - <div className="w-full h-full"> - <VisualizationManager /> - </div> + <VisualizationManager /> )} </div> ); diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx index b8d90ed2d7cdfcfee8f52d3842a58c5677ab5202..df4e62737add52f85da8fc97737f6196e4f4dc47 100644 --- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx +++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx @@ -1,12 +1,14 @@ import { GraphType, LinkType, NodeType } from '../types'; -import { tailwindColors } from 'config'; +import { dataColors, tailwindColors } from 'config'; import { ReactEventHandler, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; -import { Application, Circle, Container, FederatedPointerEvent, Graphics, IPointData } from 'pixi.js'; -import { binaryColor, nodeColor as nodeColor } from './utils'; +import { Application, Circle, Color, Container, FederatedPointerEvent, Graphics, IPointData, Point } from 'pixi.js'; import * as force from './NLForce'; import { Viewport } from 'pixi-viewport'; import { useAppDispatch, useML, useSearchResultData } from '../../../../data-access'; import { NLPopup } from './NLPopup'; +import { hslStringToHex, nodeColor } from './utils'; +import { CytoscapeLayout, GraphologyLayout, LayoutFactory, Layouts } from '../../../../graph-layout'; +import { MultiGraph } from 'graphology'; type Props = { onClick: (node: NodeType, pos: IPointData) => void; @@ -16,11 +18,20 @@ type Props = { currentShortestPathEdges?: LinkType[]; highlightedLinks?: LinkType[]; graph?: GraphType; + layoutAlgorithm: string; }; -const app = new Application({ background: 0xffffff, antialias: true, autoDensity: true, eventMode: 'auto' }); -const nodes = new Container(); -const links = new Container(); +const app = new Application({ + background: 0xffffff, + antialias: true, + autoDensity: true, + eventMode: 'auto', + resolution: window.devicePixelRatio || 1, +}); +const nodeLayer = new Container(); +const linkLayer = new Container(); + +type LayoutState = 'reset' | 'running' | 'paused'; ////////////////// // MAIN COMPONENT @@ -33,6 +44,8 @@ export const NLPixi = (props: Props) => { const nodeMap = useRef(new Map<string, Graphics>()); const linkMap = useRef(new Map<string, Graphics>()); const viewport = useRef<Viewport>(); + const layoutState = useRef<LayoutState>('reset'); + const layoutStoppedCount = useRef(0); const ref = useRef<HTMLDivElement>(null); const mouseInCanvas = useRef<boolean>(false); const isSetup = useRef(false); @@ -42,10 +55,45 @@ export const NLPixi = (props: Props) => { const dispatch = useAppDispatch(); const searchResults = useSearchResultData(); + const layoutAlgorithm = useRef<CytoscapeLayout | GraphologyLayout>(new LayoutFactory().createLayout(Layouts.DAGRE)); + + // const cull = new Cull(); + // let cullDirty = useRef(true); + + const [config, setConfig] = useState({ + width: 1000, + height: 1000, + + LAYOUT_ALGORITHM: Layouts.FORCEATLAS2WEBWORKER, + + NODE_RADIUS: 5, + NODE_BORDER_LINE_WIDTH: 1.0, + NODE_BORDER_LINE_WIDTH_SELECTED: 1.0, // if selected and normal width are different the thicker line will be still in the gfx + NODE_BORDER_COLOR_DEFAULT: dataColors.black, + NODE_BORDER_COLOR_SELECTED: dataColors.orange[60], + + LINE_COLOR_DEFAULT: dataColors.neutral[20], + LINE_COLOR_SELECTED: tailwindColors.entity[400], + LINE_COLOR_ML: dataColors.blue[60], + LINE_WIDTH_DEFAULT: 0.8, + }); + + useEffect(() => { + setConfig((lastConfig) => { + return { + ...lastConfig, + LAYOUT_ALGORITHM: (props.layoutAlgorithm as Layouts) || lastConfig.LAYOUT_ALGORITHM, + }; + }); + }, [props.layoutAlgorithm]); + const imperative = useRef<any>(null); useImperativeHandle(imperative, () => ({ onDragStart(node: NodeType, gfx: Graphics) { + // todo: graphology does not support fixed nodes + // todo: after vis-settings panel is there, we should to also support the original d3 force to allow interactivity if needed + if (props.layoutAlgorithm === Layouts.FORCEATLAS2WEBWORKER) return; if (viewport.current) viewport.current.pause = true; dragging.current = { node, gfx }; onlyClicked.current = true; @@ -69,7 +117,7 @@ export const NLPixi = (props: Props) => { if (!dragging.current.node.fy) dragging.current.node.fy = dragging.current.node.y || 0; dragging.current.node.fx += movementX / (viewport.current?.scaled || 1); dragging.current.node.fy += movementY / (viewport.current?.scaled || 1); - force.simulation.alpha(0.1).restart(); + // force.simulation.alpha(0.1).restart(); } }, @@ -181,10 +229,10 @@ export const NLPixi = (props: Props) => { : node.isShortestPathTarget ? tailwindColors.relation[950] : node.selected - ? tailwindColors.entity[400] - : '#000000'; - const lineWidth = node.selected ? 3 : 1.5; - gfx.lineStyle(lineWidth, binaryColor(lineColor)); + ? config.NODE_BORDER_COLOR_SELECTED + : config.NODE_BORDER_COLOR_DEFAULT; + const lineWidth = node.selected ? config.NODE_BORDER_LINE_WIDTH_SELECTED : config.NODE_BORDER_LINE_WIDTH; + gfx.lineStyle(lineWidth, new Color(hslStringToHex(lineColor))); if (node?.cluster) { gfx.beginFill(node.cluster >= 0 ? nodeColor(node.cluster) : 0x000000); @@ -234,7 +282,7 @@ export const NLPixi = (props: Props) => { if (node.x === undefined || node.y === undefined) return; const gfx = new Graphics(); nodeMap.current.set(node.id, gfx); - nodes.addChild(gfx); + nodeLayer.addChild(gfx); node.selected = selected; updateNode(node); @@ -285,11 +333,12 @@ export const NLPixi = (props: Props) => { } if (gfx) { - let color = link.color || 0x000000; - let style = 0.2; + // let color = link.color || 0x000000; + let color = config.LINE_COLOR_DEFAULT; + let style = config.LINE_WIDTH_DEFAULT; let alpha = link.alpha || 1; if (link.mlEdge) { - color = 0x0000ff; + color = config.LINE_COLOR_ML; if (link.value > ml.communityDetection.jaccard_threshold) { style = link.value * 1.8; } else { @@ -299,22 +348,25 @@ export const NLPixi = (props: Props) => { } else if (props.highlightedLinks && props.highlightedLinks.includes(link)) { if (link.mlEdge && ml.communityDetection.jaccard_threshold) { if (link.value > ml.communityDetection.jaccard_threshold) { - color = 0xaa00ff; + color = dataColors.magenta[50]; + // 0xaa00ff; style = link.value * 1.8; } } else { - color = 0xff0000; + color = dataColors.red[70]; + // color = 0xff0000; style = 1.0; } } else if (props.currentShortestPathEdges && props.currentShortestPathEdges.includes(link)) { - color = 0x00ff00; + color = dataColors.green[50]; + // color = 0x00ff00; style = 3.0; } gfx.clear(); gfx.beginFill(); gfx - .lineStyle(style, color, alpha) + .lineStyle(style, hslStringToHex(color), alpha) .moveTo(source.x || 0, source.y || 0) .lineTo(target.x || 0, target.y || 0); gfx.endFill(); @@ -331,17 +383,26 @@ export const NLPixi = (props: Props) => { gfx.name = 'link_' + link.id; linkMap.current.set(link.id, gfx); updateLink(link, gfx); - links.addChild(gfx); + linkLayer.addChild(gfx); return gfx; }; + useEffect(() => { + return () => { + nodeMap.current.clear(); + linkMap.current.clear(); + nodeLayer.removeChildren(); + linkLayer.removeChildren(); + }; + }, []); + useEffect(() => { if (props.graph && ref.current && ref.current.children.length > 0 && imperative.current) { - if (!isSetup.current) setup(); - else update(); - // setup(); + console.log(props.graph); + if (isSetup.current === false) setup(); + else update(false); } - }, [props.graph]); + }, [props.graph, config]); useEffect(() => { if (props.graph) { @@ -362,16 +423,61 @@ export const NLPixi = (props: Props) => { }, [searchResults]); const tick = (delta: number) => { + if (layoutState.current === 'paused') return; + if (layoutState.current === 'reset') layoutStoppedCount.current = 0; + if (props.graph) { - props.graph.nodes.forEach((node: NodeType) => { + if (!layoutAlgorithm.current) return; + + let stopped = 0; + props.graph.nodes.forEach((node: NodeType, i) => { + if (!layoutAlgorithm.current) return; const gfx = nodeMap.current.get(node.id); if (!gfx || node.x === undefined || node.y === undefined) return; - gfx.position.copyFrom(node as IPointData); + + const position = layoutAlgorithm.current.getNodePosition(node.id); + + if (Math.abs(node.x - position.x - app.renderer.width / 2) + Math.abs(node.y - position.y - app.renderer.height / 2) < 1) { + stopped += 1; + return; + } + if (layoutAlgorithm.current.provider === 'Graphology') { + // this is a dirty hack to fix the graphology layout being out of bounds + node.x = position.x + app.renderer.width / 2; + node.y = position.y + app.renderer.height / 2; + } else { + node.x = position.x; + node.y = position.y; + } + + if (layoutState.current === 'running') { + gfx.position.copyFrom({ + x: node.fx || gfx.position.x + ((node.x || 0) - gfx.position.x) * 0.1 * delta, + y: node.fy || gfx.position.y + ((node.y || 0) - gfx.position.y) * 0.1 * delta, + }); + } else { + gfx.position.copyFrom(node as IPointData); + } }); + if (stopped === props.graph.nodes.length) { + layoutStoppedCount.current = layoutStoppedCount.current + 1; + if (layoutStoppedCount.current > 1000) { + layoutState.current = 'paused'; + console.debug('NL layout paused'); + } + } else { + layoutStoppedCount.current = 0; + } + if (layoutState.current === 'reset') { + layoutState.current = 'running'; + } + // Update forces of the links props.graph.links.forEach((link: any) => { - if (linkMap.current && !!linkMap.current.has(link.id)) updateLink(link, linkMap.current.get(link.id) as Graphics); + if (linkMap.current && !!linkMap.current.has(link.id)) { + updateLink(link, linkMap.current.get(link.id) as Graphics); + } }); } }; @@ -384,13 +490,13 @@ export const NLPixi = (props: Props) => { if (forceClear) { nodeMap.current.clear(); linkMap.current.clear(); - nodes.removeChildren(); - links.removeChildren(); + nodeLayer.removeChildren(); + linkLayer.removeChildren(); } nodeMap.current.forEach((gfx, id) => { if (!props.graph?.nodes?.find((node) => node.id === id)) { - nodes.removeChild(gfx); + nodeLayer.removeChild(gfx); gfx.destroy(); nodeMap.current.delete(id); } @@ -398,7 +504,7 @@ export const NLPixi = (props: Props) => { linkMap.current.forEach((gfx, id) => { if (!props.graph?.links?.find((link) => link.id === id)) { - links.removeChild(gfx); + linkLayer.removeChild(gfx); gfx.destroy(); linkMap.current.delete(id); } @@ -434,9 +540,11 @@ export const NLPixi = (props: Props) => { // }); // console.log(nodes.children); - force.startSimulation(props.graph, ref.current.getBoundingClientRect()); - force.simulation.on('tick', () => {}); + // force.startSimulation(props.graph, ref.current.getBoundingClientRect()); + // force.simulation.on('tick', () => {}); app.ticker.add(tick); + layoutState.current = 'reset'; + if (forceClear) setupLayout(forceClear); } }; @@ -446,8 +554,8 @@ export const NLPixi = (props: Props) => { * @param graph The graph returned from the database and that is parsed into a nodelist and edgelist. */ const setup = () => { - nodes.removeChildren(); - links.removeChildren(); + nodeLayer.removeChildren(); + linkLayer.removeChildren(); app.stage.removeChildren(); if (!props.graph) throw Error('Graph is undefined'); @@ -463,30 +571,49 @@ export const NLPixi = (props: Props) => { }); app.stage.addChild(viewport.current); // activate plugins - viewport.current.drag().pinch().wheel().animate({}).decelerate({ friction: 0.75 }); + viewport.current.drag().pinch().wheel({ smooth: 2 }).animate({}).decelerate({ friction: 0.75 }); - viewport.current.addChild(links); - viewport.current.addChild(nodes); + viewport.current.addChild(linkLayer); + viewport.current.addChild(nodeLayer); viewport.current.on('drag-start', (event) => { imperative.current.onPan(); }); - // app.stage.addChild(links); - // app.stage.addChild(nodes); app.stage.eventMode = 'dynamic'; app.stage.on('mouseup', onDragEnd); app.stage.on('pointerup', onDragEnd); app.stage.on('mousemove', onDragMove); app.stage.on('mouseup', onDragEnd); - app.ticker.add(tick); - nodeMap.current.clear(); linkMap.current.clear(); - update(); + update(true); isSetup.current = true; }; + const setupLayout = (forceClear: boolean) => { + const layoutFactory = new LayoutFactory(); + layoutAlgorithm.current = layoutFactory.createLayout(config.LAYOUT_ALGORITHM); + + if (!layoutAlgorithm) throw Error('LayoutAlgorithm is undefined'); + + const graphologyGraph = new MultiGraph(); + props.graph?.nodes.forEach((node) => { + if (forceClear) graphologyGraph.addNode(node.id, { size: node.radius || 5 }); + else graphologyGraph.addNode(node.id, { size: node.radius || 5, x: node.x || 0, y: node.y || 0 }); + }); + + props.graph?.links.forEach((link) => { + graphologyGraph.addEdge(link.source, link.target); + }); + const boundingBox = { x1: 0, x2: app.renderer.screen.width, y1: 0, y2: app.renderer.screen.height }; + + if (forceClear) { + const startingLayout = layoutFactory.createLayout('Graphology_random'); + startingLayout.layout(graphologyGraph, boundingBox); + } + layoutAlgorithm.current.layout(graphologyGraph, boundingBox); + }; return ( <> {mouseInCanvas.current && popups.map((popup) => <NLPopup onClose={() => {}} data={popup} key={popup.node.id} />)} diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx index bcbc513fdbfd7ddd681bed356a37a993425dc004..72719dc5aed97c5a7b4e1bb1e96b187f6db97dc7 100644 --- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx +++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx @@ -10,7 +10,13 @@ import { } from '../../../data-access/store'; import { configureStore } from '@reduxjs/toolkit'; import { Provider } from 'react-redux'; -import { big2ndChamberQueryResult, smallFlightsQueryResults, mockLargeQueryResults } from '../../../mock-data'; +import { + big2ndChamberQueryResult, + smallFlightsQueryResults, + mockLargeQueryResults, + recommendationPersonActedInMovieQueryResultPayload, + slackReactionToThreadedMessageQueryResultPayload, +} from '../../../mock-data'; import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice'; const Component: Meta<typeof VisualizationPanel> = { @@ -65,6 +71,33 @@ export const TestWithData = { }, }; +export const TestWithDoubleArchData = { + layout: 'fullscreen', + play: async () => { + const dispatch = Mockstore.dispatch; + + dispatch( + setNewGraphQueryResult({ + queryID: '1', + result: { + type: 'nodelink', + payload: { + nodes: [ + { id: 'agent/007', attributes: { name: 'Daniel Craig' } }, + { id: 'villain', attributes: { name: 'Le Chiffre' } }, + ], + edges: [ + { id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } }, + { id: 'escape/escape', to: 'agent/007', from: 'villain', attributes: { name: 'Escape' } }, + ], + }, + }, + }), + ); + dispatch(setActiveVisualization(Visualizations.NodeLink)); + }, +}; + export const TestWithNoData = { args: { loading: false }, play: async () => { @@ -111,4 +144,22 @@ export const TestWithLargeQueryResult = { }, }; +export const TestWithRecommendationPersonActedInMovieQueryResult = { + args: { loading: false }, + play: async () => { + const dispatch = Mockstore.dispatch; + dispatch(setNewGraphQueryResult(recommendationPersonActedInMovieQueryResultPayload)); + dispatch(setActiveVisualization(Visualizations.NodeLink)); + }, +}; + +export const TestWithSlackReactionToThreadedMessageQueryResult = { + args: { loading: false }, + play: async () => { + const dispatch = Mockstore.dispatch; + dispatch(setNewGraphQueryResult(slackReactionToThreadedMessageQueryResultPayload)); + dispatch(setActiveVisualization(Visualizations.NodeLink)); + }, +}; + export default Component; diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx index 6c86c681c506e798f44afe892a62be241c18a40d..f9a42c5d51cc9f3e34dbc256cad9987624fe6efc 100644 --- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx +++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx @@ -5,8 +5,9 @@ import { parseQueryResult } from './components/query2NL'; import { useImmer } from 'use-immer'; import { ML, setShortestPathSource, setShortestPathTarget } from '../../../data-access/store/mlSlice'; import { VisualizationPropTypes, VISComponentType } from '../../types'; +import { Layouts } from '../../../graph-layout/types'; -export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationPropTypes) => { +export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings }: VisualizationPropTypes) => { const ref = useRef<HTMLDivElement>(null); const [graph, setGraph] = useImmer<GraphType | undefined>(undefined); const [highlightNodes, setHighlightNodes] = useState<NodeType[]>([]); @@ -18,7 +19,7 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationProp parseQueryResult(data, ml, { defaultX: (ref.current?.clientWidth || 1000) / 2, defaultY: (ref.current?.clientHeight || 1000) / 2, - }) + }), ); } }, [data, ml]); @@ -55,18 +56,15 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationProp }; return ( - <> - <div className="h-full w-full overflow-hidden" ref={ref}> - <NLPixi - graph={graph} - highlightNodes={highlightNodes} - highlightedLinks={highlightedLinks} - onClick={(node, pos) => { - onClickedNode(node, ml); - }} - /> - </div> - </> + <NLPixi + graph={graph} + highlightNodes={highlightNodes} + highlightedLinks={highlightedLinks} + onClick={(node, pos) => { + onClickedNode(node, ml); + }} + layoutAlgorithm={settings.layout} + /> ); }); @@ -75,10 +73,10 @@ export const NodeLinkComponent: VISComponentType = { VIS: NodeLinkVis, settings: { layout: { - value: 'Force directed', + value: Layouts.FORCEATLAS2WEBWORKER as string, type: 'dropdown', label: 'Layout', - options: ['Force directed'], + options: Object.values(Layouts) as string[], description: 'Select a layout that is used for the visualization', }, }, diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx index bb1042048bae3f715ed0138b264a39d51fbfc898..6b20d52456c9f16f179ccd066bd9a70a4690106e 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx @@ -104,7 +104,7 @@ export const TestWithMarieBoucherSample = { const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw); dispatch(setSchema(schema.export())); - dispatch(assignNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: marieBoucherSample } })); + dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: marieBoucherSample } })); dispatch(setActiveVisualization('PaohVis')); }, }; @@ -135,7 +135,7 @@ export const TestWithRecommendationsActorMovie = { const dispatch = Mockstore.dispatch; const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw); dispatch(setSchema(schema.export())); - dispatch(assignNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } })); + dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } })); dispatch(setActiveVisualization('PaohVis')); }, }; diff --git a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx index a618ef2ae003ae9fa013255d4920889f137abcb2..752304cb0663f7cf8a7f7d920580d4bf0f29d498 100644 --- a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx +++ b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx @@ -4,7 +4,7 @@ import { VisualizationPanel } from '../../visualizationPanel'; import { SchemaUtils } from '../../../schema/schema-utils'; import { - assignNewGraphQueryResult, + setNewGraphQueryResult, graphQueryResultSlice, querybuilderSlice, schemaSlice, @@ -59,7 +59,7 @@ export const TestWithBig2ndChamber = { const dispatch = Mockstore.dispatch; const schema = SchemaUtils.schemaBackend2Graphology(big2ndChamberSchemaRaw); dispatch(setSchema(schema.export())); - dispatch(assignNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } })); + dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } })); dispatch(setActiveVisualization('SemSubstrVis')); }, }; @@ -69,7 +69,7 @@ export const TestWithRecommendationsActorMovie = { const dispatch = Mockstore.dispatch; const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw); dispatch(setSchema(schema.export())); - dispatch(assignNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } })); + dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } })); dispatch(setActiveVisualization('SemSubstrVis')); }, }; @@ -79,7 +79,7 @@ export const TestWithGOTcharacter2character = { const dispatch = Mockstore.dispatch; const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw); dispatch(setSchema(schema.export())); - dispatch(assignNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: gotCharacter2Character } })); + dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: gotCharacter2Character } })); dispatch(setActiveVisualization('SemSubstrVis')); }, };