diff --git a/flowsint-app/src/styles.css b/flowsint-app/src/styles.css index 7705d557..5308008b 100644 --- a/flowsint-app/src/styles.css +++ b/flowsint-app/src/styles.css @@ -1,4 +1,4 @@ -@import "tailwindcss"; +@import 'tailwindcss'; @plugin "@tailwindcss/typography"; @plugin "tailwindcss-animate"; @@ -70,8 +70,8 @@ body::-webkit-scrollbar-thumb:hover { body { @apply m-0; font-family: - -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', - 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', + 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: var(--tracking-normal); @@ -147,7 +147,6 @@ html { @apply rounded border border-border bg-[var(--muted)] px-1 py-0.5 text-sm; } - .minimal-tiptap-editor .ProseMirror pre { @apply relative overflow-auto rounded font-mono text-sm; @apply border-[var(--mt-pre-border)] bg-[var(--mt-pre-background)] text-[var(--mt-pre-color)]; @@ -163,7 +162,6 @@ html { } .minimal-tiptap-editor .ProseMirror pre { - .hljs-keyword, .hljs-operator, .hljs-function, @@ -256,7 +254,7 @@ html { list-style: square; } -.minimal-tiptap-editor .ProseMirror>p.is-editor-empty::before { +.minimal-tiptap-editor .ProseMirror > p.is-editor-empty::before { content: attr(data-placeholder); @apply pointer-events-none float-left h-0 text-[var(--mt-secondary)]; } @@ -344,10 +342,10 @@ html { z-index: 1; } -[data-rmiz-content="found"] img, -[data-rmiz-content="found"] svg, -[data-rmiz-content="found"] [role="img"], -[data-rmiz-content="found"] [data-zoom] { +[data-rmiz-content='found'] img, +[data-rmiz-content='found'] svg, +[data-rmiz-content='found'] [role='img'], +[data-rmiz-content='found'] [data-zoom] { cursor: inherit; } @@ -376,11 +374,11 @@ html { transition: background-color 0.3s; } -[data-rmiz-modal-overlay="hidden"] { +[data-rmiz-modal-overlay='hidden'] { background-color: rgba(255, 255, 255, 0); } -[data-rmiz-modal-overlay="visible"] { +[data-rmiz-modal-overlay='visible'] { background-color: rgba(255, 255, 255, 1); } @@ -399,7 +397,6 @@ html { } @media (prefers-reduced-motion: reduce) { - [data-rmiz-modal-overlay], [data-rmiz-modal-img] { transition-duration: 0.01ms !important; @@ -407,49 +404,49 @@ html { } :root { - --background: oklch(.99 0 0); + --background: oklch(0.99 0 0); --foreground: oklch(0.27 0 0); - --card: oklch(1.40 0 0); + --card: oklch(1.4 0 0); --card-foreground: oklch(0.27 0 0); - --popover: oklch(21.00 0 0); + --popover: oklch(21 0 0); --popover-foreground: oklch(0.27 0 0); - --primary: oklch(0.6397 0.1720 36.4421); + --primary: oklch(0.6397 0.172 36.4421); --primary-foreground: oklch(0 0 0); - --secondary: oklch(0.97 0.00 264.54); - --secondary-foreground: oklch(0.45 0.03 256.80); - --muted: oklch(0.98 0.00 247.84); + --secondary: oklch(0.97 0 264.54); + --secondary-foreground: oklch(0.45 0.03 256.8); + --muted: oklch(0.98 0 247.84); --muted-foreground: oklch(0.55 0.02 264.36); --accent: oklch(0.99 0.02 95.28); - --accent-foreground: oklch(0.47 0.12 46.20); + --accent-foreground: oklch(0.47 0.12 46.2); --destructive: oklch(0.64 0.21 25.33); - --destructive-foreground: oklch(1.00 0 0); + --destructive-foreground: oklch(1 0 0); --border: oklch(0.93 0.01 264.53); --input: oklch(0.93 0.01 264.53); --ring: oklch(0.77 0.16 70.08); --chart-1: oklch(0.77 0.16 70.08); --chart-2: oklch(0.67 0.16 58.32); - --chart-3: oklch(0.56 0.15 49.00); - --chart-4: oklch(0.47 0.12 46.20); - --chart-5: oklch(0.41 0.11 45.90); - --sidebar: oklch(0.98 0.00 247.84); + --chart-3: oklch(0.56 0.15 49); + --chart-4: oklch(0.47 0.12 46.2); + --chart-5: oklch(0.41 0.11 45.9); + --sidebar: oklch(0.98 0 247.84); --sidebar-foreground: oklch(0.27 0 0); --sidebar-primary: oklch(0.77 0.16 70.08); - --sidebar-primary-foreground: oklch(1.00 0 0); + --sidebar-primary-foreground: oklch(1 0 0); --sidebar-accent: oklch(0.99 0.02 95.28); - --sidebar-accent-foreground: oklch(0.47 0.12 46.20); + --sidebar-accent-foreground: oklch(0.47 0.12 46.2); --sidebar-border: oklch(0.93 0.01 264.53); --sidebar-ring: oklch(0.77 0.16 70.08); --font-sans: Inter, sans-serif; --font-serif: Source Serif 4, serif; --font-mono: JetBrains Mono, monospace; - --radius: 0.580rem; + --radius: 0.58rem; --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05); --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05); - --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10); - --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10); - --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10); - --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10); - --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10); + --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1); + --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1); + --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1); + --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1); + --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1); --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25); --success: oklch(0.6 0.12 145); --warning: oklch(0.7 0.12 80); @@ -466,43 +463,43 @@ html { --card-foreground: oklch(0.92 0 0); --popover: oklch(0.27 0 0); --popover-foreground: oklch(0.92 0 0); - --primary: oklch(0.6397 0.1720 36.4421); + --primary: oklch(0.6397 0.172 36.4421); --primary-foreground: oklch(0 0 0); --secondary: oklch(0.27 0 0); --secondary-foreground: oklch(0.92 0 0); --muted: oklch(0.27 0 0); --muted-foreground: oklch(0.72 0 0); - --accent: oklch(0.47 0.12 46.20); + --accent: oklch(0.47 0.12 46.2); --accent-foreground: oklch(0.92 0.12 95.75); --destructive: oklch(0.64 0.21 25.33); - --destructive-foreground: oklch(1.00 0 0); + --destructive-foreground: oklch(1 0 0); --border: oklch(0.29 0 0); --input: oklch(0.37 0 0); --ring: oklch(0.77 0.16 70.08); --chart-1: oklch(0.84 0.16 84.43); --chart-2: oklch(0.67 0.16 58.32); - --chart-3: oklch(0.47 0.12 46.20); - --chart-4: oklch(0.56 0.15 49.00); - --chart-5: oklch(0.47 0.12 46.20); + --chart-3: oklch(0.47 0.12 46.2); + --chart-4: oklch(0.56 0.15 49); + --chart-5: oklch(0.47 0.12 46.2); --sidebar: oklch(0.17 0 0); --sidebar-foreground: oklch(0.92 0 0); --sidebar-primary: oklch(0.77 0.16 70.08); - --sidebar-primary-foreground: oklch(1.00 0 0); - --sidebar-accent: oklch(0.47 0.12 46.20); + --sidebar-primary-foreground: oklch(1 0 0); + --sidebar-accent: oklch(0.47 0.12 46.2); --sidebar-accent-foreground: oklch(0.92 0.12 95.75); --sidebar-border: oklch(0.37 0 0); --sidebar-ring: oklch(0.77 0.16 70.08); --font-sans: Inter, sans-serif; --font-serif: Source Serif 4, serif; --font-mono: JetBrains Mono, monospace; - --radius: 0.580rem; + --radius: 0.58rem; --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05); --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05); - --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10); - --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10); - --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10); - --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10); - --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10); + --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1); + --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1); + --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1); + --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1); + --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1); --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25); } @@ -571,7 +568,7 @@ html { @apply z-0 outline-0; } -.minimal-tiptap-editor .ProseMirror>div.editor { +.minimal-tiptap-editor .ProseMirror > div.editor { @apply block flex-1 whitespace-pre-wrap; } @@ -604,8 +601,8 @@ html { } .minimal-tiptap-editor .ProseMirror li .text-node:has(+ .list-node), -.minimal-tiptap-editor .ProseMirror li>.list-node, -.minimal-tiptap-editor .ProseMirror li>.text-node, +.minimal-tiptap-editor .ProseMirror li > .list-node, +.minimal-tiptap-editor .ProseMirror li > .text-node, .minimal-tiptap-editor .ProseMirror li p { @apply mb-0; } @@ -658,7 +655,7 @@ html { } /* Basic editor styles */ -.tiptap> :first-child { +.tiptap > :first-child { margin-top: 0; } @@ -761,7 +758,7 @@ th, opacity: 0; } - *:hover>.resizer { + *:hover > .resizer { opacity: 1; } } @@ -795,7 +792,6 @@ th, } .hide-scrollbar { - /* Webkit browsers (Chrome, Safari, Edge) */ -webkit-scrollbar { display: none; @@ -826,7 +822,6 @@ th, transform-origin: bottom right; } - body { letter-spacing: var(--tracking-normal); } @@ -854,4 +849,4 @@ body { width: 100%; transform-origin: top left; touch-action: none; -} \ No newline at end of file +} diff --git a/flowsint-core/src/flowsint_core/core/graph/__init__.py b/flowsint-core/src/flowsint_core/core/graph/__init__.py index 75cc9a8e..38412b3d 100644 --- a/flowsint-core/src/flowsint_core/core/graph/__init__.py +++ b/flowsint-core/src/flowsint_core/core/graph/__init__.py @@ -12,12 +12,12 @@ from .connection import Neo4jConnection, neo4j_connection from .repository import Neo4jGraphRepository from .repository_protocol import GraphRepositoryProtocol from .serializer import GraphSerializer -from .service import GraphService, create_graph_service, LoggerProtocol +from .service import GraphService, LoggerProtocol, create_graph_service from .types import ( GraphData, + GraphDict, GraphEdge, GraphNode, - Neo4jDict, NodeMetadata, ) @@ -38,6 +38,6 @@ __all__ = [ "GraphData", "GraphEdge", "GraphNode", - "Neo4jDict", + "GraphDict", "NodeMetadata", ] diff --git a/flowsint-core/src/flowsint_core/core/graph/repository.py b/flowsint-core/src/flowsint_core/core/graph/repository.py index cae99897..ac3abe38 100644 --- a/flowsint-core/src/flowsint_core/core/graph/repository.py +++ b/flowsint-core/src/flowsint_core/core/graph/repository.py @@ -2,14 +2,14 @@ Graph database repository for Neo4j operations. This module provides a repository pattern implementation for Neo4j, -handling raw Neo4jDict object and operations with batching support. +handling raw GraphDict object and operations with batching support. """ from datetime import datetime, timezone from typing import Any, Dict, List, Optional, Tuple from .connection import Neo4jConnection -from .types import Neo4jDict +from .types import GraphDict class Neo4jGraphRepository: @@ -36,17 +36,17 @@ class Neo4jGraphRepository: def create_node( self, - node_obj: Neo4jDict, + node_obj: GraphDict, sketch_id: str, ) -> Optional[str]: """ Create or update a single node in Neo4j. Supported signature: - 1. Neo4jDict object: create_node(obj) + 1. GraphDict object: create_node(obj) Args: - node_obj: a Neo4jDict object + node_obj: a GraphDict object sketch_id: str Returns: @@ -61,7 +61,7 @@ class Neo4jGraphRepository: def create_relationship( self, - rel_obj: Neo4jDict, + rel_obj: GraphDict, sketch_id: str, ) -> None: """ @@ -71,7 +71,7 @@ class Neo4jGraphRepository: - Pydantic objects: create_relationship(relation, sketch_id="...") Args: - rel_obj: the Neo4jDict object + rel_obj: the GraphDict object sketch_id: Investigation sketch ID (required) """ if not self._connection: @@ -103,7 +103,7 @@ class Neo4jGraphRepository: self.flush_batch() def _build_node_query( - self, node_obj: Neo4jDict, sketch_id: str + self, node_obj: GraphDict, sketch_id: str ) -> Tuple[str, Dict[str, Any]]: node_label = node_obj.get("nodeLabel") node_type = node_obj.get("nodeType") @@ -127,7 +127,7 @@ class Neo4jGraphRepository: def _build_relationship_query( self, - rel_obj: Neo4jDict, + rel_obj: GraphDict, sketch_id: str, ) -> Tuple[str, Dict[str, Any]]: from_type = rel_obj["from_type"] @@ -183,14 +183,14 @@ class Neo4jGraphRepository: def batch_create_nodes( self, - nodes: List[Neo4jDict], + nodes: List[GraphDict], sketch_id: str, ) -> Dict[str, Any]: """ Create multiple nodes in a single batch transaction. Args: - nodes: List of Neo4jDict model instances to insert + nodes: List of GraphDict model instances to insert sketch_id: investigation sketch id Returns: @@ -256,7 +256,7 @@ class Neo4jGraphRepository: Args: edges: List of edge dictionaries, each with: - - rel_obj: Source node Neo4jDict model + - rel_obj: Source node GraphDict model Returns: Dictionary with: @@ -300,9 +300,9 @@ class Neo4jGraphRepository: def batch_create_edges_by_element_id( self, - edges: List[Neo4jDict], + edges: List[GraphDict], sketch_id: str, - ) -> Neo4jDict: + ) -> GraphDict: """ Create multiple edges/relationships using element IDs in a single batch transaction. @@ -388,7 +388,7 @@ class Neo4jGraphRepository: return {"edges_created": 0, "errors": errors} def update_node( - self, element_id: str, updates: Neo4jDict, sketch_id: str + self, element_id: str, updates: GraphDict, sketch_id: str ) -> Optional[str]: if not self._connection: return None @@ -532,7 +532,7 @@ class Neo4jGraphRepository: return {"nodes": nodes_result, "edges": rels_result or []} def update_relationship( - self, element_id: str, rel_obj: Neo4jDict, sketch_id: str + self, element_id: str, rel_obj: GraphDict, sketch_id: str ) -> Optional[Dict[str, Any]]: if not self._connection: return None diff --git a/flowsint-core/src/flowsint_core/core/graph/repository_protocol.py b/flowsint-core/src/flowsint_core/core/graph/repository_protocol.py index 9a12ed53..9f44ebb4 100644 --- a/flowsint-core/src/flowsint_core/core/graph/repository_protocol.py +++ b/flowsint-core/src/flowsint_core/core/graph/repository_protocol.py @@ -5,9 +5,9 @@ This module defines the interface contract that all graph repository implementations must follow, enabling dependency injection and easier testing. """ -from typing import Any, Dict, List, Optional, Protocol, Tuple +from typing import Any, Dict, List, Optional, Protocol -from .types import Neo4jDict +from .types import GraphDict class GraphRepositoryProtocol(Protocol): @@ -21,12 +21,12 @@ class GraphRepositoryProtocol(Protocol): """ # Core node operations - def create_node(self, node_obj: Neo4jDict, sketch_id: str) -> Optional[str]: + def create_node(self, node_obj: GraphDict, sketch_id: str) -> Optional[str]: """Create or update a single node. Returns element ID.""" ... def update_node( - self, element_id: str, updates: Neo4jDict, sketch_id: str + self, element_id: str, updates: GraphDict, sketch_id: str ) -> Optional[str]: """Update a node by its element ID. Returns element ID.""" ... @@ -52,7 +52,7 @@ class GraphRepositoryProtocol(Protocol): ... # Core relationship operations - def create_relationship(self, rel_obj: Neo4jDict, sketch_id: str) -> None: + def create_relationship(self, rel_obj: GraphDict, sketch_id: str) -> None: """Create a relationship between two nodes.""" ... @@ -67,7 +67,7 @@ class GraphRepositoryProtocol(Protocol): ... def update_relationship( - self, element_id: str, rel_obj: Neo4jDict, sketch_id: str + self, element_id: str, rel_obj: GraphDict, sketch_id: str ) -> Optional[Dict[str, Any]]: """Update a relationship by its element ID.""" ... @@ -100,13 +100,13 @@ class GraphRepositoryProtocol(Protocol): # Batch operations def batch_create_nodes( - self, nodes: List[Neo4jDict], sketch_id: str + self, nodes: List[GraphDict], sketch_id: str ) -> Dict[str, Any]: """Create multiple nodes in a single batch.""" ... def batch_create_edges_by_element_id( - self, edges: List[Neo4jDict], sketch_id: str + self, edges: List[GraphDict], sketch_id: str ) -> Dict[str, Any]: """Create multiple edges using element IDs in a single batch.""" ... diff --git a/flowsint-core/src/flowsint_core/core/graph/service.py b/flowsint-core/src/flowsint_core/core/graph/service.py index 209194ba..353615b6 100644 --- a/flowsint-core/src/flowsint_core/core/graph/service.py +++ b/flowsint-core/src/flowsint_core/core/graph/service.py @@ -13,7 +13,7 @@ from pydantic import BaseModel from .repository import Neo4jGraphRepository from .repository_protocol import GraphRepositoryProtocol from .serializer import GraphSerializer -from .types import GraphData, GraphNode, Neo4jDict +from .types import GraphData, GraphDict, GraphNode class LoggerProtocol(Protocol): @@ -90,7 +90,7 @@ class GraphService: "create_node method takes a GraphNode as input. If you want to insert a node from a FlowsintType, please use create_node_from_flowsint_type method." ) - neo4j_node_dict: Neo4jDict = GraphSerializer.graph_node_to_neo4j_dict(node_obj) + neo4j_node_dict: GraphDict = GraphSerializer.graph_node_to_neo4j_dict(node_obj) if self._enable_batching: self._repository.add_to_batch( @@ -120,7 +120,7 @@ class GraphService: "create_node_from_flowsint_type method takes a FlowsintType as input. If you want to insert a node from a GraphNode, please use create_node method." ) - neo4j_node_dict: Neo4jDict = GraphSerializer.flowsint_type_to_neo4j_dict( + neo4j_node_dict: GraphDict = GraphSerializer.flowsint_type_to_neo4j_dict( node_obj ) @@ -169,7 +169,7 @@ class GraphService: **properties: Additional relationship properties """ - neo4j_rel_dict: Neo4jDict = GraphSerializer.graph_edge_to_neo4j_dict( + neo4j_rel_dict: GraphDict = GraphSerializer.graph_edge_to_neo4j_dict( from_obj, to_obj, rel_label ) @@ -267,7 +267,7 @@ class GraphService: sketch_id=self._sketch_id, ) - def batch_create_nodes(self, nodes: List[Neo4jDict]) -> Dict[str, Any]: + def batch_create_nodes(self, nodes: List[GraphDict]) -> Dict[str, Any]: """Create multiple nodes in a single batch transaction.""" return self._repository.batch_create_nodes( nodes=nodes, @@ -275,7 +275,7 @@ class GraphService: ) def batch_create_edges_by_element_id( - self, edges: List[Neo4jDict] + self, edges: List[GraphDict] ) -> Dict[str, Any]: """Create multiple edges using element IDs in a single batch transaction.""" return self._repository.batch_create_edges_by_element_id( diff --git a/flowsint-core/src/flowsint_core/core/graph/types.py b/flowsint-core/src/flowsint_core/core/graph/types.py index f6ed4fb6..00df8d5e 100644 --- a/flowsint-core/src/flowsint_core/core/graph/types.py +++ b/flowsint-core/src/flowsint_core/core/graph/types.py @@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional, Union from flowsint_types import FlowsintType from pydantic import BaseModel, Field -Neo4jDict = Dict[str, Any] +GraphDict = Dict[str, Any] class NodeMetadata(BaseModel): @@ -36,7 +36,7 @@ class GraphNode(BaseModel): nodeFlag: Optional[str] = None nodeMetadata: NodeMetadata - nodeProperties: FlowsintType + nodeProperties: Any x: Optional[float] = 100.0 y: Optional[float] = 100.0 diff --git a/flowsint-core/src/flowsint_core/imports/json/parse_json.py b/flowsint-core/src/flowsint_core/imports/json/parse_json.py index f72181ce..d4ff8583 100644 --- a/flowsint-core/src/flowsint_core/imports/json/parse_json.py +++ b/flowsint-core/src/flowsint_core/imports/json/parse_json.py @@ -71,9 +71,9 @@ def _get_nodes(nodes: List[Dict]) -> List[EntityPreview]: results = [] for node in nodes: node_id = node.get("id") - node_type = node.get("type", None) - label = node.get("label", None) - node_obj = {"type": node_type, "label": label, **node} + node_type = node.get("nodeType", node.get("type")) + label = node.get("nodeLabel", node.get("label")) + node_obj = {"nodeType": node_type, "nodeLabel": label, **node} preview = _parse_node(node_obj) if preview: results.append( @@ -88,10 +88,10 @@ def _get_nodes(nodes: List[Dict]) -> List[EntityPreview]: def _parse_node(nodeDict: dict) -> EntityPreview | None: - type = nodeDict.get("type") + type = nodeDict.get("nodeType") first_key = next(iter(nodeDict), None) label = ( - nodeDict.get("label") + nodeDict.get("nodeLabel") or (nodeDict.get(first_key) if first_key else None) or nodeDict.get("id") ) diff --git a/flowsint-core/tests/core/graph/test_graph_serializer.py b/flowsint-core/tests/core/graph/test_graph_serializer.py index dbbd01c0..84eb8315 100644 --- a/flowsint-core/tests/core/graph/test_graph_serializer.py +++ b/flowsint-core/tests/core/graph/test_graph_serializer.py @@ -4,9 +4,9 @@ import pytest from flowsint_types import Domain, Ip from flowsint_core.core.graph import ( - GraphSerializer, GraphEdge, GraphNode, + GraphSerializer, NodeMetadata, ) @@ -184,7 +184,7 @@ class TestGraphNodeToFlowsintType: assert result.domain == "example.com" -class TestNeo4jDictToGraphEdge: +class TestGraphDictToGraphEdge: def test_converts_edge_dict(self): edge_dict = { "id": "edge-123", @@ -207,7 +207,7 @@ class TestNeo4jDictToGraphEdge: assert result.target == "2" -class TestGraphEdgeToNeo4jDict: +class TestGraphEdgeToGraphDict: def test_with_flowsint_types(self): from_obj = Domain(domain="source.com") to_obj = Domain(domain="target.com") @@ -313,7 +313,7 @@ class TestDeserializeEdges: assert result == [] -class TestNeo4jDictToGraphNodeErrors: +class TestGraphDictToGraphNodeErrors: def test_raises_on_missing_data(self): node_dict = {"id": "123"} with pytest.raises(Exception, match="Could not find node data"):