Skip to content

Commit 2866a4f

Browse files
authored
Merge pull request #1396 from FalkorDB/fix-customize-panel
Fix #1395 enhance Node and Link types to include caption and size properties in…
2 parents 1bf7f7d + c87bf77 commit 2866a4f

File tree

3 files changed

+208
-3
lines changed

3 files changed

+208
-3
lines changed

app/api/graph/model.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,13 +562,16 @@ export class Graph {
562562
const currentNode = this.nodesMap.get(cell.id);
563563

564564
if (!currentNode) {
565+
const mainLabel = getLabelWithFewestElements(labels);
565566
const node: Node = {
566567
id: cell.id,
567568
labels: labels.map((l) => l.name),
568-
color: isColor ? getLabelWithFewestElements(labels).style.color : "",
569+
color: isColor ? mainLabel.style.color : "",
569570
visible: true,
570571
expand: false,
571572
collapsed,
573+
caption: mainLabel.style.caption,
574+
size: mainLabel.style.size,
572575
data: {},
573576
};
574577
Object.entries(cell.properties).forEach(([key, value]) => {
@@ -585,11 +588,14 @@ export class Graph {
585588
if (currentNode.data.fake) {
586589
currentNode.id = cell.id;
587590
currentNode.labels = labels.map((l) => l.name);
591+
const mainLabel = getLabelWithFewestElements(labels);
588592
currentNode.color = isColor
589-
? getLabelWithFewestElements(labels).style.color
593+
? mainLabel.style.color
590594
: "";
591595
currentNode.expand = false;
592596
currentNode.collapsed = collapsed;
597+
currentNode.caption = mainLabel.style.caption;
598+
currentNode.size = mainLabel.style.size;
593599
Object.entries(cell.properties).forEach(([key, value]) => {
594600
currentNode.data[key] = isSchema ? getSchemaValue(value) : value;
595601
});
@@ -644,6 +650,8 @@ export class Graph {
644650
expand: false,
645651
collapsed,
646652
visible: true,
653+
caption: label.style.caption,
654+
size: label.style.size,
647655
data: {
648656
fake: true
649657
},
@@ -681,6 +689,8 @@ export class Graph {
681689
expand: false,
682690
collapsed,
683691
visible: true,
692+
caption: label!.style.caption,
693+
size: label!.style.size,
684694
data: {
685695
fake: true
686696
},
@@ -699,6 +709,8 @@ export class Graph {
699709
expand: false,
700710
collapsed,
701711
visible: true,
712+
caption: label!.style.caption,
713+
size: label!.style.size,
702714
data: {
703715
fake: true
704716
},

app/components/ForceGraph.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ interface Props {
3232
}
3333

3434
const convertToCanvasData = (graphData: GraphData): Data => ({
35-
nodes: graphData.nodes.map(({ id, labels, color, visible, data }) => ({
35+
nodes: graphData.nodes.map(({ id, labels, color, visible, caption, size, data }) => ({
3636
id,
3737
labels,
3838
color,
3939
visible,
40+
caption,
41+
size,
4042
data
4143
})),
4244
links: graphData.links.map(({ id, relationship, color, visible, source, target, data }) => ({

e2e/tests/customizeStyle.spec.ts

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,4 +496,195 @@ test.describe("Customize Style Tests", () => {
496496

497497
await apiCall.removeGraph(graphName);
498498
});
499+
500+
test(`@readwrite Validate nodes update correctly after color change and refresh`, async () => {
501+
const graphName = getRandomString("graph");
502+
await apiCall.addGraph(graphName);
503+
const graph = await browser.createNewPage(CustomizeStylePage, urls.graphUrl);
504+
await browser.setPageToFullScreen();
505+
await graph.selectGraphByName(graphName);
506+
await graph.insertQuery(CREATE_QUERY);
507+
await graph.clickRunQuery(false);
508+
509+
// Get initial nodes from window.graph - find person1 nodes
510+
let nodes = await graph.getNodesScreenPositions("graph");
511+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
512+
const person1Nodes = nodes.filter((n: any) => n.labels?.includes("person1"));
513+
expect(person1Nodes.length).toBeGreaterThan(0);
514+
515+
// Store initial color of person1 nodes
516+
const initialColor = person1Nodes[0].color;
517+
expect(initialColor).toBeDefined();
518+
519+
// Open graph info and customize person1 style
520+
await graph.openGraphInfoButton();
521+
await graph.clickCustomizeStyleButton("person1");
522+
523+
// Change color to a different one
524+
const initialColorIndex = await graph.getSelectedColorButtonIndex();
525+
const newColorIndex = initialColorIndex === 0 ? 2 : 0;
526+
await graph.selectColorByIndex(newColorIndex);
527+
528+
// Save the style changes
529+
await graph.clickSaveStyleButton();
530+
531+
// Get the new color from localStorage
532+
const savedStyle = await graph.getLabelStyleFromLocalStorage("person1");
533+
const newColor = savedStyle?.color;
534+
expect(newColor).toBeDefined();
535+
expect(newColor).not.toBe(initialColor);
536+
537+
// Close the panel
538+
await graph.closePanelWithEscape();
539+
540+
// Refresh the page
541+
await graph.refreshPage();
542+
await graph.waitForPageIdle();
543+
544+
// Select graph and re-query to render nodes
545+
await graph.selectGraphByName(graphName);
546+
await graph.insertQuery("MATCH (n) RETURN n");
547+
await graph.clickRunQuery(false);
548+
549+
// Get nodes after refresh
550+
nodes = await graph.getNodesScreenPositions("graph");
551+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
552+
const person1NodesAfterRefresh = nodes.filter((n: any) => n.labels?.includes("person1"));
553+
expect(person1NodesAfterRefresh.length).toBeGreaterThan(0);
554+
555+
// Verify that the node caption matches the saved style
556+
const colorAfterRefresh = person1NodesAfterRefresh[0].color;
557+
expect(colorAfterRefresh).toBe(newColor);
558+
expect(colorAfterRefresh).not.toBe(initialColor);
559+
560+
await apiCall.removeGraph(graphName);
561+
});
562+
563+
test(`@readwrite Validate nodes update correctly after size change and refresh`, async () => {
564+
const graphName = getRandomString("graph");
565+
await apiCall.addGraph(graphName);
566+
const graph = await browser.createNewPage(CustomizeStylePage, urls.graphUrl);
567+
await browser.setPageToFullScreen();
568+
await graph.selectGraphByName(graphName);
569+
await graph.insertQuery(CREATE_QUERY);
570+
await graph.clickRunQuery(false);
571+
572+
// Get initial nodes - find person1 nodes
573+
let nodes = await graph.getNodesScreenPositions("graph");
574+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
575+
const person1Nodes = nodes.filter((n: any) => n.labels?.includes("person1"));
576+
expect(person1Nodes.length).toBeGreaterThan(0);
577+
578+
// Store initial size of person1 nodes
579+
const initialSize = person1Nodes[0].size;
580+
581+
// Open graph info and customize person1 style
582+
await graph.openGraphInfoButton();
583+
await graph.clickCustomizeStyleButton("person1");
584+
585+
// Change size to a different one
586+
const initialSizeIndex = await graph.getSelectedSizeButtonIndex();
587+
const newSizeIndex = initialSizeIndex === 3 ? 5 : 3;
588+
await graph.selectSizeByIndex(newSizeIndex);
589+
590+
// Save the style changes
591+
await graph.clickSaveStyleButton();
592+
593+
// Get the new size from localStorage
594+
const savedStyle = await graph.getLabelStyleFromLocalStorage("person1");
595+
const newSize = savedStyle?.size;
596+
expect(newSize).toBeDefined();
597+
expect(newSize).not.toBe(initialSize);
598+
599+
// Close the panel
600+
await graph.closePanelWithEscape();
601+
602+
// Refresh the page
603+
await graph.refreshPage();
604+
await graph.waitForPageIdle();
605+
606+
// Select graph and re-query to render nodes
607+
await graph.selectGraphByName(graphName);
608+
await graph.insertQuery("MATCH (n) RETURN n");
609+
await graph.clickRunQuery(false);
610+
611+
// Get nodes after refresh
612+
nodes = await graph.getNodesScreenPositions("graph");
613+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
614+
const person1NodesAfterRefresh = nodes.filter((n: any) => n.labels?.includes("person1"));
615+
expect(person1NodesAfterRefresh.length).toBeGreaterThan(0);
616+
617+
// Verify that the node size matches the saved style
618+
const sizeAfterRefresh = person1NodesAfterRefresh[0].size;
619+
expect(sizeAfterRefresh).toBe(newSize);
620+
expect(sizeAfterRefresh).not.toBe(initialSize);
621+
622+
await apiCall.removeGraph(graphName);
623+
});
624+
625+
test(`@readwrite Validate nodes update correctly after caption change and refresh`, async () => {
626+
const graphName = getRandomString("graph");
627+
await apiCall.addGraph(graphName);
628+
const graph = await browser.createNewPage(CustomizeStylePage, urls.graphUrl);
629+
await browser.setPageToFullScreen();
630+
await graph.selectGraphByName(graphName);
631+
await graph.insertQuery(CREATE_PERSON_RELATIONSHIP);
632+
await graph.clickRunQuery(false);
633+
634+
// Get initial nodes - find person2 nodes
635+
let nodes = await graph.getNodesScreenPositions("graph");
636+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
637+
const person1Nodes = nodes.filter((n: any) => n.labels?.includes("person1"));
638+
expect(person1Nodes.length).toBeGreaterThan(0);
639+
640+
// Store initial caption and displayName of person1 nodes
641+
const initialCaption = person1Nodes[0].caption;
642+
const initialDisplayName = person1Nodes[0].displayName;
643+
644+
// Open graph info and customize person1 style
645+
await graph.openGraphInfoButton();
646+
await graph.clickCustomizeStyleButton("person1");
647+
648+
// Change caption to "name"
649+
await graph.selectCaption("name");
650+
651+
// Save the style changes
652+
await graph.clickSaveStyleButton();
653+
654+
// Get the new caption from localStorage
655+
const savedStyle = await graph.getLabelStyleFromLocalStorage("person1");
656+
const newCaption = savedStyle?.caption;
657+
expect(newCaption).toBe("name");
658+
expect(newCaption).not.toBe(initialCaption);
659+
660+
// Close the panel
661+
await graph.closePanelWithEscape();
662+
663+
// Refresh the page
664+
await graph.refreshPage();
665+
await graph.waitForPageIdle();
666+
667+
// Select graph and re-query to render nodes
668+
await graph.selectGraphByName(graphName);
669+
await graph.insertQuery("MATCH (n) RETURN n");
670+
await graph.clickRunQuery(false);
671+
672+
// Get nodes after refresh
673+
nodes = await graph.getNodesScreenPositions("graph");
674+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
675+
const person1NodesAfterRefresh = nodes.filter((n: any) => n.labels?.includes("person1"));
676+
expect(person1NodesAfterRefresh.length).toBeGreaterThan(0);
677+
678+
// Verify that the node caption matches the saved style
679+
const captionAfterRefresh = person1NodesAfterRefresh[0].caption;
680+
expect(captionAfterRefresh).toBe(newCaption);
681+
expect(captionAfterRefresh).toBe("name");
682+
683+
// Verify that displayName also changed (displayName should reflect the caption change)
684+
const displayNameAfterRefresh = person1NodesAfterRefresh[0].displayName;
685+
expect(displayNameAfterRefresh).toBeDefined();
686+
expect(displayNameAfterRefresh).not.toEqual(initialDisplayName);
687+
688+
await apiCall.removeGraph(graphName);
689+
});
499690
});

0 commit comments

Comments
 (0)