Skip to content

Commit

Permalink
highlight cyto and sigma
Browse files Browse the repository at this point in the history
  • Loading branch information
joon-at-sri committed Jul 17, 2024
1 parent 2f70923 commit 78ab141
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 36 deletions.
1 change: 0 additions & 1 deletion src/logics/graphImpl/cytoImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ cy.use(edgehandles)
function toCyNode(n: NodeData): cy.NodeDefinition {
let nodeColorMap = store.getState().graph.nodeColorMap
let color = n.type !== undefined ? nodeColorMap[n.type] : '#000000';
console.log(color);
return {
group: "nodes",
data: { ...n, id: n.id!.toString() },
Expand Down
79 changes: 44 additions & 35 deletions src/logics/graphImpl/sigmaImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,36 +50,34 @@ function createSigmaGraph(container: HTMLElement) {
},
});

let selectedNode: any;
let selectedEdge: any;
let selectedNode: string | undefined;
let selectedEdge: string | undefined;
let nodesOfSelectedEdge: { source: string, target: string } | undefined;

sigma.on("clickEdge", e => {
store.dispatch(setSelectedEdge(e.edge))
selectedNode = undefined;
selectEdge(e.edge);

})
sigma.on("clickNode", (e) => {
store.dispatch(setSelectedNode(e.node))
selectNode(e.node);


});

sigma.setSetting("nodeReducer", (node, data) => {
const res: Partial<NodeDisplayData> = { ...data };

if (selectedNode && selectedNode !== node) {
if ((selectedNode && selectedNode !== node) || (!selectedNode && (nodesOfSelectedEdge && nodesOfSelectedEdge.source !== node && nodesOfSelectedEdge.target !== node))) {
res.color = "#f6f6f6";
}

if (selectedNode === node) {
if (selectedNode === node || (nodesOfSelectedEdge && (nodesOfSelectedEdge.source === node || nodesOfSelectedEdge.target === node))) {
res.highlighted = true;
}

return res;
});

sigma.setSetting("edgeReducer", (edge, data) => {
const res: Partial<EdgeDisplayData> = { ...data };

if (selectedNode && !graph.hasExtremity(edge, selectedNode)) {
if ((selectedEdge && selectedEdge !== edge) || (selectedNode && !graph.hasExtremity(edge, selectedNode))) {
res.size = 0.1;
res.color = "#f2f5f3";
}
Expand All @@ -90,8 +88,14 @@ function createSigmaGraph(container: HTMLElement) {
if (node) {
selectedNode = node;
}
if (!node) {
selectedNode = undefined;
sigma.refresh();
}

function selectEdge(edge?: string) {
if (edge) {
const [source, target] = graph.extremities(edge);
nodesOfSelectedEdge = { source: source, target: target };
selectedEdge = edge;
}
sigma.refresh();
}
Expand Down Expand Up @@ -119,6 +123,9 @@ function createSigmaGraph(container: HTMLElement) {
isDragging = true;
draggedNode = e.node;
graph!.setNodeAttribute(draggedNode, "highlighted", true);
selectedEdge = undefined;
nodesOfSelectedEdge = undefined;
selectNode(e.node);
}
sigmaLayout?.stop()
store.dispatch(setIsPhysicsEnabled(false))
Expand Down Expand Up @@ -170,16 +177,18 @@ function createSigmaGraph(container: HTMLElement) {
if (jsEvent.shiftKey && !draggingEdge) {
store.dispatch(openNodeDialog({ x: params.event.x, y: params.event.y }));
}
else if (selectedNode) {
else if (selectedNode || selectedEdge || nodesOfSelectedEdge) {
nodesOfSelectedEdge = undefined;
selectedEdge = undefined;
selectedNode = undefined;
sigma.refresh();
}
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Shift' && shiftKeyDown !== true) {
shiftKeyDown = true;
}
if (e.key === 'Shift' && shiftKeyDown !== true) {
shiftKeyDown = true;
}
}
);
document.addEventListener('keyup', function (e) {
if (e.key === 'Shift' && shiftKeyDown === true) {
Expand All @@ -198,23 +207,23 @@ function curveEdges(graph: Graph) {
edgeMaxIndexAttribute: "parallelMaxIndex",
});
graph.forEachEdge((edge, { parallelIndex, parallelMinIndex, parallelMaxIndex, }:
| { parallelIndex: number; parallelMinIndex?: number; parallelMaxIndex: number }
| { parallelIndex?: null; parallelMinIndex?: null; parallelMaxIndex?: null },
) => {
if (typeof parallelMinIndex === "number") {
graph.mergeEdgeAttributes(edge, {
type: parallelIndex ? "curved" : "straight",
curvature: getCurvature(parallelIndex, parallelMaxIndex),
});
} else if (typeof parallelIndex === "number") {
graph.mergeEdgeAttributes(edge, {
type: "curved",
curvature: getCurvature(parallelIndex, parallelMaxIndex),
});
} else {
graph.setEdgeAttribute(edge, "type", "straight");
}
},
| { parallelIndex: number; parallelMinIndex?: number; parallelMaxIndex: number }
| { parallelIndex?: null; parallelMinIndex?: null; parallelMaxIndex?: null },
) => {
if (typeof parallelMinIndex === "number") {
graph.mergeEdgeAttributes(edge, {
type: parallelIndex ? "curved" : "straight",
curvature: getCurvature(parallelIndex, parallelMaxIndex),
});
} else if (typeof parallelIndex === "number") {
graph.mergeEdgeAttributes(edge, {
type: "curved",
curvature: getCurvature(parallelIndex, parallelMaxIndex),
});
} else {
graph.setEdgeAttribute(edge, "type", "straight");
}
},
);
}

Expand Down
197 changes: 197 additions & 0 deletions test/components/ModalDialog/ModalDialogComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import React from 'react';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { render, screen, waitFor, fireEvent, act, within } from '@testing-library/react';
import '@testing-library/jest-dom';
import { App } from '../../../src/App';
import userEvent from '@testing-library/user-event';
import { defaultNodeLabel, EdgeData, NodeData, extractEdgesAndNodes, storeSuggestions } from "../../../src/logics/utils";
import { setupStore } from "../../../src/app/store";
import axios from 'axios';
import { EDGE_ID_APPEND, QUERY_ENDPOINT, QUERY_RAW_ENDPOINT } from '../../../src/constants';
import { setNodePositions } from '../../../src/logics/graph';
import { addNodes, addEdges } from '../../../src/reducers/graphReducer'
import { openNodeDialog, setSuggestions } from '../../../src/reducers/dialogReducer';
import { setNodeLabels } from '../../../src/reducers/optionReducer';
import { ModalDialogComponent } from '../../../src/components/ModalDialog/ModalDialogComponent';
// jest.mock('../../../src/logics/graph', () => ({
// applyLayout: jest.fn(),
// getNodePositions: jest.fn(),
// setNodePositions: jest.fn(),
// layoutOptions: ['force-directed', 'hierarchical']
// }));
jest.mock('../../../src/logics/graphImpl/sigmaImpl', () => ({
__esModule: true, // Ensure it's treated as a module

}));

jest.mock("axios", () => ({
...jest.requireActual("axios"),
post: jest.fn(),
}));

jest.mock('../../../src/constants', () => ({
INITIAL_LABEL_MAPPINGS: {
person: 'name'
},
GRAPH_IMPL: "vis"

}));

type State = {
gremlin: {
host: string;
port: string;
query: string;
};
options: {
nodeLabels: string[];
nodeLimit: number;
queryHistory: string[];
};
graph: {
selectedNode: NodeData | null;
selectedEdge: EdgeData | null;
nodes: NodeData[],
edges: NodeData[],
};


};

const initialState: State = {
gremlin: {
host: 'localhost',
port: '8182',
query: 'g.V()'
},
options: {
nodeLabels: [],
nodeLimit: 50,
queryHistory: []
},

graph: {
selectedNode: null,
selectedEdge: null,
nodes: [],
edges: [],
}
};

test("test modalDialog renders", async () => {
let user = userEvent.setup();
let store = setupStore({});
jest.spyOn(store, 'dispatch');
store.dispatch(openNodeDialog({ x: 200, y: 200 }));
render(
<Provider store={store}>
<ModalDialogComponent />
</Provider>
);
expect(screen.queryByRole('dialog')).toBeInTheDocument();
})

test("test modalDialog renders with suggested", async () => {
const mockedAxios = axios as jest.Mocked<typeof axios>;
mockedAxios.post.mockResolvedValue({ data:{
"data": [
{
"id": 32,
"label": "person",
"properties": {
"name": "Bob",
"age": "21"
},
"edges": []
}
],
"status": 200,
"statusText": "OK",
"headers": {
"content-length": "78",
"content-type": "application/json; charset=utf-8"
},
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"adapter": [
"xhr",
"http",
"fetch"
],
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"env": {},
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json"
},
"method": "post",
"url": "http://localhost:3001/query",
"data": "{\"host\":\"localhost\",\"port\":\"8182\",\"query\":\"g.addV('person').property('name', 'Bob').property('age', '21')\",\"nodeLimit\":100}"
},
"request": {}
}});

// const argument0: NodeData[] = [
// {
// "id": 1,
// "label": "person",
// "properties": {
// "name": "Bob",
// "age": "21"
// },
// "edges": [
// {
// "id": "0",
// "from": 1,
// "to": 2,
// "label": "knows",
// "properties": {
// "length": "2"
// }
// }
// ]
// },
// {
// "id": 2,
// "label": "person",
// "properties": {
// "name": "Max",
// "age": "18"
// },
// "edges": []
// },
// ] as NodeData[]
// const argument1 = [];
let user = userEvent.setup();
let store = setupStore({});
jest.spyOn(store, 'dispatch');

// store.dispatch(setNodeLabels(nodeLabels));
store.dispatch(openNodeDialog({ x: 200, y: 200 }));
render(
<Provider store={store}>
<ModalDialogComponent />
</Provider>
);

expect(screen.queryByRole('dialog')).toBeInTheDocument();
const input = screen.getByDisplayValue('name');

// Additional checks can be performed to ensure the right element is selected, if needed
expect(input).toBeInTheDocument();
})

0 comments on commit 78ab141

Please sign in to comment.