From 0ff9e966f1dbb85ace5205c669a87ebf1c44a772 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 22 Nov 2023 14:04:37 +0800 Subject: [PATCH] neo4j-arc should be node/rel-ID agnostic (#22) * neo4j-arc should be node/rel-ID agnostic * Update documentation * Version bump --- .../pages/neo4j-arc/graph-interactions.adoc | 11 ++++--- docs/modules/ROOT/pages/neo4j-arc/index.adoc | 30 +++++++++++++++---- .../operations/on-canvas-operations.adoc | 22 +++++++++++++- .../VisualizationView/VisualizationView.tsx | 9 +++--- .../Graph/GraphEventHandlerModel.ts | 23 +++++--------- src/neo4j-arc/package.json | 2 +- 6 files changed, 63 insertions(+), 34 deletions(-) diff --git a/docs/modules/ROOT/pages/neo4j-arc/graph-interactions.adoc b/docs/modules/ROOT/pages/neo4j-arc/graph-interactions.adoc index 3ca5508ed29..faaefc5aae0 100644 --- a/docs/modules/ROOT/pages/neo4j-arc/graph-interactions.adoc +++ b/docs/modules/ROOT/pages/neo4j-arc/graph-interactions.adoc @@ -44,7 +44,7 @@ click on canvas. We will follow the steps above by first defining the event hand this.visualization.update({ updateNodes: true, updateRelationships: true }) this.graphModelChanged() - this.onGraphInteraction(NODE_ON_CANVAS_CREATE, { id: newNodeId, name: 'New Node', labels: ['Undefined'] }) + this.onGraphInteraction(NODE_ON_CANVAS_CREATE, { name: 'New Node', labels: ['Undefined'] }) } ---- @@ -99,22 +99,21 @@ As we've mentioned earlier, we would like to persist this new node to database. if (event == NODE_ON_CANVAS_CREATE) { if (properties == null) { throw new Error( - 'A property map with id, name, and labels keys are required' + 'A property map with name, and labels keys are required' ) } - const id = properties['id'] const name = properties['name'] - const variableName = `node${id}` + const variableName = `node` const labels = (properties['labels'] as string[]).map(label => `\`${label}\``).join(':') - const query = `CREATE (${variableName}:${labels} { id: ${id}, name: "${name}" });` + const query = `CREATE (${variableName}:${labels} { name: "${name}" });` this.props.bus.self( CYPHER_REQUEST, { query, - params: { labels, id, name }, + params: { labels, name }, queryType: NEO4J_BROWSER_USER_ACTION_QUERY }, (response: any) => { diff --git a/docs/modules/ROOT/pages/neo4j-arc/index.adoc b/docs/modules/ROOT/pages/neo4j-arc/index.adoc index be5a5620ae6..ccaae0339dc 100644 --- a/docs/modules/ROOT/pages/neo4j-arc/index.adoc +++ b/docs/modules/ROOT/pages/neo4j-arc/index.adoc @@ -101,14 +101,32 @@ export default function MyGraphComponent(): JSX.Element { The Neo4J Browser is logically composed of 2 parts: -1. A slightly coupled graphing module -2. A user-interface that combines the graph rendering (supported by the graphing module), database, and user +. The neo4j-arc, which is the current part we are discussing + +.. The neo4j-arc is based on D3 and implements its own layout, coloring, and link drawing. For example, the calculation + of arrow, i.e. links, between nodes uses some + https://github.com/QubitPi/neo4j-browser/blob/master/src/neo4j-arc/graph-visualization/utils/ArcArrow.ts[very complicated math] + along with very prelimiary MDN standard basic shap specification. +.. IMPORTANT + ==== + Although we see `` property for every node or relationship in the node inspection panel of Neo4J Browser, those + ID's are NOT generated by neo4j-arc, but https://stackoverflow.com/a/67702695[instead by Neo4J database] + + Note: the displayed `` is the value of NodeMode.id + ==== + + CAUTION + ==== + + neo4j-arc does not generate or manage node/rel ID. Any xref:operations/on-canvas-operations.adoc[on-canvas operation] + generates nodes/rel with *transient ID* only. Any node/rel ID that is to be persisted needs to be generated and + managed by external logics, such as database auto-ID or library user + + ==== + +. A user-interface that combines the graph rendering (supported by the graphing module), database, and user interaction together -The graphing is based on D3 and implements its own layout, coloring, and link drawing. For example, the calculation of -arrow, i.e. links, between nodes uses some -https://github.com/QubitPi/neo4j-browser/blob/master/src/neo4j-arc/graph-visualization/utils/ArcArrow.ts[very complicated math] -along with very prelimiary MDN standard basic shap specification. [WARNING] ==== diff --git a/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc b/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc index 9beb9e72903..7c0281b04c9 100644 --- a/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc +++ b/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc @@ -8,7 +8,27 @@ *Double clicking the white area* on canvas will automatically generate a new node with -1. an auto-incremented ID, i.e. (the max ID of nodes on canvas) + 1 +1. a transient ID prefixed with "transient-" followed by a random string. For example "transient-rxnnzr6t4x" + + [NOTE] + ==== + + The reason that the ID being transient is due to the fact that this ID won't be persisted into database. Refreshing + the browser will replace this transient ID with a database-generated ID (in the form of a number, such as 65). + + Normally, neo4j-browser feeds into neo4j-arc, which is the graphing module of neo4j-browser, with a set of + fully-hydrated set of nodes and relationships. This results in the design in neo4j-arc which is: to render a node or + relationship, the ID of it must be provided (i.e. a required argument to node/rel constructor). + + Generating a new node by double-clicking, however, is an operation manged by neo4j-arc, which by design is not + responsible for generating and managing node/relationship ID's. But to implement the "realtime editing" effect, the + new node/rel ID has to be genreated at the beginning. + + To resolve the conflict between original neo4j-browser design and on-canvas operation, any node/rel generated + "on-canvas" will have this transient ID. + + ==== + 2. a label of "Undefined" 3. the node caption of "New Node" diff --git a/src/browser/modules/Stream/CypherFrame/VisualizationView/VisualizationView.tsx b/src/browser/modules/Stream/CypherFrame/VisualizationView/VisualizationView.tsx index bd22a3b71b3..ea84916bda8 100644 --- a/src/browser/modules/Stream/CypherFrame/VisualizationView/VisualizationView.tsx +++ b/src/browser/modules/Stream/CypherFrame/VisualizationView/VisualizationView.tsx @@ -400,25 +400,24 @@ LIMIT ${maxNewNeighbours}` if (event == NODE_ON_CANVAS_CREATE) { if (properties == null) { throw new Error( - 'A property map with id, name, and labels keys are required' + 'A property map with name, and labels keys are required' ) } - const id = properties['id'] const name = properties['name'] const description = properties['description'] - const variableName = `node${id}` + const variableName = `node` const labels = (properties['labels'] as string[]) .map(label => `\`${label}\``) .join(':') - const query = `CREATE (${variableName}:${labels} { id: ${id}, name: "${name}", description: "${description}" });` + const query = `CREATE (${variableName}:${labels} { name: "${name}", description: "${description}" });` this.props.bus.self( CYPHER_REQUEST, { query, - params: { labels, id, name, description }, + params: { labels, name, description }, queryType: NEO4J_BROWSER_USER_ACTION_QUERY }, (response: any) => { diff --git a/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts b/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts index 3ba4a6f935b..178a18a8854 100644 --- a/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts +++ b/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts @@ -244,14 +244,12 @@ export class GraphEventHandlerModel { } onCanvasDblClicked(): void { - const maxId: number = Math.max( - ...this.graph.nodes().map(node => parseInt(node.id)) - ) - const newId = maxId + 1 + const transientId: string = + 'transient-' + Math.random().toString(36).slice(2) this.graph.addNodes([ new NodeModel( - newId.toString(), + transientId, ['Undefined'], { name: 'New Node', @@ -267,7 +265,6 @@ export class GraphEventHandlerModel { this.graphModelChanged() this.onGraphInteraction(NODE_ON_CANVAS_CREATE, { - id: newId, name: 'New Node', description: 'New Node', labels: ['Undefined'] @@ -300,18 +297,14 @@ export class GraphEventHandlerModel { ) { this.altCreatedRelTargetNode = node - const maxId: number = Math.max( - ...this.graph - .relationships() - .map(relationship => parseInt(relationship.id)) - ) - const newId = maxId + 1 + const transientId: string = + 'transient-' + Math.random().toString(36).slice(2) const altCreatedRel: RelationshipModel = new RelationshipModel( - newId.toString(), + transientId, this.altCreatedRelSourceNode, this.altCreatedRelTargetNode, - newId.toString(), + transientId, { name: 'new link' }, { name: 'string' } ) @@ -324,7 +317,7 @@ export class GraphEventHandlerModel { this.graphModelChanged() this.onGraphInteraction(REL_ON_CANVAS_CREATE, { - type: newId, + type: transientId, sourceNodeId: this.altCreatedRelSourceNode.id, targetNodeId: this.altCreatedRelTargetNode.id }) diff --git a/src/neo4j-arc/package.json b/src/neo4j-arc/package.json index fdb18f7f9d5..42833e81cd0 100644 --- a/src/neo4j-arc/package.json +++ b/src/neo4j-arc/package.json @@ -1,6 +1,6 @@ { "name": "neo4j-devtools-arc", - "version": "0.0.53", + "version": "0.0.54", "main": "dist/neo4j-arc.js", "author": "Neo4j Inc.", "license": "GPL-3.0",